From 777c4eb75fb8db5cb811ad101c0cfb3f37122265 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 2 Jul 2022 15:41:24 +0530 Subject: [PATCH 001/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.6 (#685) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index cd918d159..42c3d81e7 100755 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "@ethersproject/strings": "^5.0.5", "@ethersproject/units": "^5.0.3", "@ethersproject/wallet": "^5.4.0", - "@snapshot-labs/snapshot.js": "^0.4.5", + "@snapshot-labs/snapshot.js": "^0.4.6", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.3.1", "cross-fetch": "^3.0.6", diff --git a/yarn.lock b/yarn.lock index 2a4ddabd1..075d2ba31 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1095,10 +1095,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.5": - version "0.4.5" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.5.tgz#7b6cebe8d9bb6ce41afcbc043ef45662f6e48c3a" - integrity sha512-01dq27FNB+j/VpXivE/Exyfhg6DzZ4K0vIzGUDMvZrZgVg8mdvxg53qzXbtI6FtJ3sHdkGDLiYQlK7hIRBa/Yw== +"@snapshot-labs/snapshot.js@^0.4.6": + version "0.4.6" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.6.tgz#3f383f065795eba93739a4f1b92c2c8bd8818462" + integrity sha512-+osD9bzRm/mXXsq437afH9giRi0ceAvmqJRbc07l36N7J2fx5lZBVoc0t1BTwXBuX2npaMSY3HvUsvYCLvwbEw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.0.4" From 09b0b497c3866289edfa8ffd82ce3e8e177d7c7d Mon Sep 17 00:00:00 2001 From: andreibadea20 <105772011+andreibadea20@users.noreply.github.com> Date: Sat, 2 Jul 2022 13:28:56 +0300 Subject: [PATCH 002/815] adding dps-nft-strategy [dps-nft-strategy] (#682) * adding dps-nft-strategy * add ReadMe, delete symbol & decimals from examples.json, add block number when request * update ReadMe * Update README.md * Update src/strategies/balancer-poolid/index.ts * Update test/index.spec.ts * Update test/index.spec.ts * Delete schema.json * Update src/strategies/dps-nft-strategy/examples.json Co-authored-by: Chaitanya --- src/strategies/dps-nft-strategy/README.md | 15 +++ src/strategies/dps-nft-strategy/examples.json | 21 +++++ src/strategies/dps-nft-strategy/index.ts | 91 +++++++++++++++++++ src/strategies/index.ts | 2 + 4 files changed, 129 insertions(+) create mode 100644 src/strategies/dps-nft-strategy/README.md create mode 100644 src/strategies/dps-nft-strategy/examples.json create mode 100644 src/strategies/dps-nft-strategy/index.ts diff --git a/src/strategies/dps-nft-strategy/README.md b/src/strategies/dps-nft-strategy/README.md new file mode 100644 index 000000000..17b577067 --- /dev/null +++ b/src/strategies/dps-nft-strategy/README.md @@ -0,0 +1,15 @@ +# dps-nft-strategy + +This is a strategy similar with ERC721, which it calculates the voting power as the balances of the voters for a specific ERC721 token, but this takes into account locked NFTs +and claimed NFTs. It is a strategy using for a game, where users can lock their NFTs in order to achive different things. + +Here is an example for calculating voting power: + +Bob balance: 40 NFTs + +Bob locked NFTs: 7 + +Bob claimed NFTs: 3 + +=> Bob voting power: 40 + 7 - 3 = 44 + diff --git a/src/strategies/dps-nft-strategy/examples.json b/src/strategies/dps-nft-strategy/examples.json new file mode 100644 index 000000000..685adf142 --- /dev/null +++ b/src/strategies/dps-nft-strategy/examples.json @@ -0,0 +1,21 @@ +[ + { + "name": "DPS NFTs query", + "strategy": { + "name": "dps-nft-strategy", + "params": { + "symbol": "DPS" + } + }, + "network": "80001", + "addresses": [ + "0x4bb7e1d5c463ec80d0b316e83a090b00f7d87d1d", + "0x15f48ab7ada1541a205eb9ee20f5a4e76ce3882a", + "0x5e733901b92bc5110779f8ee64de3d8af0629dc6", + "0xc32004eced24167e8aaef9690da3a70387a97a9b", + "0x60b5d811673a6420851d087cff84c660c14a3acb" + ], + "snapshot": 26453570 + } +] + diff --git a/src/strategies/dps-nft-strategy/index.ts b/src/strategies/dps-nft-strategy/index.ts new file mode 100644 index 000000000..0202440ea --- /dev/null +++ b/src/strategies/dps-nft-strategy/index.ts @@ -0,0 +1,91 @@ +import { getAddress } from '@ethersproject/address'; +import { subgraphRequest } from '../../utils'; + +export const author = 'andreibadea20'; +export const version = '0.1.0'; + +const DPS_SUBGRAPH_URL = { + '80001': 'https://api.thegraph.com/subgraphs/name/andreibadea20/subgraph-dps' +}; + + +const PAGE_SIZE = 1000; + +const params = { + users: { + __args: { + first: PAGE_SIZE, + skip: 0 + }, + id: true, + numberOfTokens: true + } +}; + +const paramsForNFTs = { + nftlockeds: { + __args: { + block: {number: Number(22572400)} + }, + tokenId: true, + owner: { + id: true + }, + transferedAtTimestamp: true + }, + nftafterClaimeds: { + __args: { + block: {number: Number(22572400)} + }, + tokenId: true, + owner: { + id: true + }, + transferedAtTimestamp: true + } +}; + +export async function strategy(space, network, provider, addresses, options, snapshot) { + + if (snapshot !== 'latest') { + // @ts-ignore + paramsForNFTs.nftlockeds.__args.block = { number: snapshot}; + paramsForNFTs.nftafterClaimeds.__args.block = { number: snapshot}; + } + + const resultNFTs = await subgraphRequest(DPS_SUBGRAPH_URL[network], paramsForNFTs); + const score = {}; + let page = 0; + + while (page !== -1) { + params.users.__args.skip = page * PAGE_SIZE; + const result = await subgraphRequest(DPS_SUBGRAPH_URL[network], params); + if (result && result.users && resultNFTs && resultNFTs.nftlockeds && resultNFTs.nftafterClaimeds) { + result.users.forEach((u) => { + const userAddress = getAddress(u.id); + let userScore = parseInt(u.numberOfTokens); + let lockedNFTs = 0; + let claimedNFTs = 0; + resultNFTs.nftlockeds.forEach((n) => { + if (n.owner.id === u.id) { + lockedNFTs = lockedNFTs + 1; + } + }); + resultNFTs.nftafterClaimeds.forEach((nft) => { + if(nft.owner.id === u.id) { + claimedNFTs = claimedNFTs + 1; + } + }); + userScore = userScore + lockedNFTs - claimedNFTs; + if (!score[userAddress]) + score[userAddress] = 0; + score[userAddress] = userScore; + }); + page = result.users.length < PAGE_SIZE ? -1 : page + 1; + } + else { + page = -1; + } + } + return score || {}; + } \ No newline at end of file diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 2eb040367..8b0e659c8 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -1,6 +1,7 @@ import { readFileSync } from 'fs'; import path from 'path'; +import * as dpsNFTStrategy from './dps-nft-strategy'; import * as nounsPower from './nouns-rfp-power'; import * as erc20Votes from './erc20-votes'; import * as erc20VotesWithOverride from './erc20-votes-with-override'; @@ -344,6 +345,7 @@ const strategies = { 'dextf-staked-in-vaults': dextfVaults, 'dfyn-staked-in-farms': dfynFarms, 'dfyn-staked-in-vaults': dfynVaults, + 'dps-nft-strategy': dpsNFTStrategy, 'eth-received': ethReceived, 'eth-philanthropy': ethPhilanthropy, 'ens-domains-owned': ensDomainsOwned, From 5865416344deed07e5c7bb6ccc583c08f459119f Mon Sep 17 00:00:00 2001 From: Sam <51686767+samuveth@users.noreply.github.com> Date: Sun, 3 Jul 2022 21:31:37 +0700 Subject: [PATCH 003/815] [sybil-protection] Sybil attack protection strategy (#689) * erc20-sybil * Update README.md * Update README.md * Refactor to support other strategies * Add bright Id and refactor * Fix readme * Add optional chaining * Fix comment * Hard code poh to ethereum mainnet Co-authored-by: metrox-eth <55286013+metrox-eth@users.noreply.github.com> --- src/strategies/index.ts | 2 + src/strategies/sybil-protection/README.md | 22 +++++++ src/strategies/sybil-protection/examples.json | 46 +++++++++++++ src/strategies/sybil-protection/index.ts | 66 +++++++++++++++++++ 4 files changed, 136 insertions(+) create mode 100644 src/strategies/sybil-protection/README.md create mode 100644 src/strategies/sybil-protection/examples.json create mode 100644 src/strategies/sybil-protection/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 8b0e659c8..402622030 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -313,6 +313,7 @@ import * as recusalList from './recusal-list'; import * as rowdyRoos from './rowdy-roos'; import * as ethermon721 from './ethermon-erc721'; import * as hedgey from './hedgey'; +import * as sybilProtection from './sybil-protection'; import * as veBalanceOfAtNFT from './ve-balance-of-at-nft'; import * as genzeesFromSubgraph from './genzees-from-subgraph'; import * as ginFinance from './gin-finance'; @@ -630,6 +631,7 @@ const strategies = { 'uma-voting': umaVoting, 'masterchef-pool-balance-no-rewarddebt': masterchefPoolBalanceNoRewarddebt, 'proof-of-humanity': proofOfHumanity, + 'sybil-protection': sybilProtection, 'samurailegends-generals-balance': samuraiLegendsGeneralsBalance, 'dogs-unchained': dogsUnchained, 'stakedao-governance-update': stakeDAOGovernanceUpdate, diff --git a/src/strategies/sybil-protection/README.md b/src/strategies/sybil-protection/README.md new file mode 100644 index 000000000..646e743c7 --- /dev/null +++ b/src/strategies/sybil-protection/README.md @@ -0,0 +1,22 @@ +# sybil-protection + +This is the most common strategy, it returns the balances of the voters for a specific ERC20 token. + +Here is an example of parameters: + +```json +{ + "strategy": { + "name": "erc20-balance-of", + "params": { + "address": "0xc944E90C64B2c07662A292be6244BDf05Cda44a7", + "symbol": "GRT", + "decimals": 18 + } + }, + "sybil": { + "poh": "0xC5E9dDebb09Cd64DfaCab4011A0D5cEDaf7c9BDb", + "brightId": "v5" + } +} +``` diff --git a/src/strategies/sybil-protection/examples.json b/src/strategies/sybil-protection/examples.json new file mode 100644 index 000000000..1bab98e64 --- /dev/null +++ b/src/strategies/sybil-protection/examples.json @@ -0,0 +1,46 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "sybil-protection", + "params": { + "strategy": { + "name": "erc20-balance-of", + "params": { + "address": "0xc944E90C64B2c07662A292be6244BDf05Cda44a7", + "symbol": "GRT", + "decimals": 18 + } + }, + "sybil": { + "poh": "0xC5E9dDebb09Cd64DfaCab4011A0D5cEDaf7c9BDb", + "brightId": "v5" + } + } + }, + "network": "1", + "addresses": [ + "0x7A38760C295f1ea086005214a279fb1280010483", + "0xF78108c9BBaF466dd96BE41be728Fe3220b37119", + "0xa478c2975ab1ea89e8196811f51a7b7ade33eb11", + "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", + "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", + "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", + "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e", + "0x1d5E65a087eBc3d03a294412E46CE5D6882969f4", + "0x1f254336E5c46639A851b9CfC165697150a6c327", + "0x2ec3F80BeDA63Ede96BA20375032CDD3aAfb3030", + "0x4AcBcA6BE2f8D2540bBF4CA77E45dA0A4a095Fa2", + "0x4F3D348a6D09837Ae7961B1E0cEe2cc118cec777", + "0x6D7f23A509E212Ba7773EC1b2505d1A134f54fbe", + "0x07a1f6fc89223c5ebD4e4ddaE89Ac97629856A0f", + "0x8d5F05270da470e015b67Ab5042BDbE2D2FEFB48", + "0x8d07D225a769b7Af3A923481E1FdF49180e6A265", + "0x8f60501dE5b9b01F9EAf1214dbE1924aA97F7fd0", + "0x9B8e8dD9151260c21CB6D7cc59067cd8DF306D58", + "0x17ea92D6FfbAA1c7F6B117c1E9D0c88ABdc8b84C", + "0x38C0039247A31F3939baE65e953612125cB88268" + ], + "snapshot": 15068173 + } +] diff --git a/src/strategies/sybil-protection/index.ts b/src/strategies/sybil-protection/index.ts new file mode 100644 index 000000000..a0f4108b5 --- /dev/null +++ b/src/strategies/sybil-protection/index.ts @@ -0,0 +1,66 @@ +import strategies from '..'; +import { strategy as proofOfHumanityStrategy } from '../proof-of-humanity'; +import { strategy as brightIdStrategy } from '../brightid'; + +export const author = 'samuveth'; +export const version = '0.1.0'; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + async function getProofOfHumanity() { + if (!options?.sybil?.poh) return {}; + return await proofOfHumanityStrategy( + space, + '1', + provider, + addresses, + { address: options.sybil.poh }, + snapshot + ); + } + + async function getBrightId() { + if (!options?.sybil?.brightId) return {}; + return await brightIdStrategy( + space, + network, + provider, + addresses, + { registry: options.sybil.brightId }, + snapshot + ); + } + + const [scores, proofOfHumanity, brightId] = await Promise.all([ + await strategies[options.strategy.name].strategy( + space, + network, + provider, + addresses, + options.strategy.params, + snapshot + ), + getProofOfHumanity(), + getBrightId() + ]); + + // Reduce voting power of address to zero if cybil check doesn't pass + const cybilScores = Object.keys(scores).reduce((acc, key) => { + if (proofOfHumanity?.[key] === 1) { + acc[key] = scores[key]; + } else if (brightId?.[key] === 1) { + acc[key] = scores[key]; + } else { + acc[key] = 0; + } + return acc; + }, {}); + + return cybilScores; +} From ac1d1d5ad06d5ee1f050f890076555d8e1ad25f1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 3 Jul 2022 20:04:01 +0530 Subject: [PATCH 004/815] Automated lint (#690) Co-authored-by: ChaituVR Co-authored-by: Chaitanya --- src/strategies/dps-nft-strategy/examples.json | 1 - src/strategies/dps-nft-strategy/index.ts | 152 ++++++++++-------- .../schema.json | 4 +- src/strategies/sd-boost-twavp/index.ts | 6 +- 4 files changed, 86 insertions(+), 77 deletions(-) diff --git a/src/strategies/dps-nft-strategy/examples.json b/src/strategies/dps-nft-strategy/examples.json index 685adf142..9fbbb7fae 100644 --- a/src/strategies/dps-nft-strategy/examples.json +++ b/src/strategies/dps-nft-strategy/examples.json @@ -18,4 +18,3 @@ "snapshot": 26453570 } ] - diff --git a/src/strategies/dps-nft-strategy/index.ts b/src/strategies/dps-nft-strategy/index.ts index 0202440ea..679d298e9 100644 --- a/src/strategies/dps-nft-strategy/index.ts +++ b/src/strategies/dps-nft-strategy/index.ts @@ -1,5 +1,5 @@ import { getAddress } from '@ethersproject/address'; -import { subgraphRequest } from '../../utils'; +import { subgraphRequest } from '../../utils'; export const author = 'andreibadea20'; export const version = '0.1.0'; @@ -8,84 +8,96 @@ const DPS_SUBGRAPH_URL = { '80001': 'https://api.thegraph.com/subgraphs/name/andreibadea20/subgraph-dps' }; - const PAGE_SIZE = 1000; const params = { - users: { - __args: { - first: PAGE_SIZE, - skip: 0 - }, - id: true, - numberOfTokens: true - } + users: { + __args: { + first: PAGE_SIZE, + skip: 0 + }, + id: true, + numberOfTokens: true + } }; const paramsForNFTs = { - nftlockeds: { - __args: { - block: {number: Number(22572400)} - }, - tokenId: true, - owner: { - id: true - }, - transferedAtTimestamp: true + nftlockeds: { + __args: { + block: { number: Number(22572400) } }, - nftafterClaimeds: { - __args: { - block: {number: Number(22572400)} - }, - tokenId: true, - owner: { - id: true - }, - transferedAtTimestamp: true - } + tokenId: true, + owner: { + id: true + }, + transferedAtTimestamp: true + }, + nftafterClaimeds: { + __args: { + block: { number: Number(22572400) } + }, + tokenId: true, + owner: { + id: true + }, + transferedAtTimestamp: true + } }; -export async function strategy(space, network, provider, addresses, options, snapshot) { - - if (snapshot !== 'latest') { - // @ts-ignore - paramsForNFTs.nftlockeds.__args.block = { number: snapshot}; - paramsForNFTs.nftafterClaimeds.__args.block = { number: snapshot}; - } +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + if (snapshot !== 'latest') { + // @ts-ignore + paramsForNFTs.nftlockeds.__args.block = { number: snapshot }; + paramsForNFTs.nftafterClaimeds.__args.block = { number: snapshot }; + } - const resultNFTs = await subgraphRequest(DPS_SUBGRAPH_URL[network], paramsForNFTs); - const score = {}; - let page = 0; + const resultNFTs = await subgraphRequest( + DPS_SUBGRAPH_URL[network], + paramsForNFTs + ); + const score = {}; + let page = 0; - while (page !== -1) { - params.users.__args.skip = page * PAGE_SIZE; - const result = await subgraphRequest(DPS_SUBGRAPH_URL[network], params); - if (result && result.users && resultNFTs && resultNFTs.nftlockeds && resultNFTs.nftafterClaimeds) { - result.users.forEach((u) => { - const userAddress = getAddress(u.id); - let userScore = parseInt(u.numberOfTokens); - let lockedNFTs = 0; - let claimedNFTs = 0; - resultNFTs.nftlockeds.forEach((n) => { - if (n.owner.id === u.id) { - lockedNFTs = lockedNFTs + 1; - } - }); - resultNFTs.nftafterClaimeds.forEach((nft) => { - if(nft.owner.id === u.id) { - claimedNFTs = claimedNFTs + 1; - } - }); - userScore = userScore + lockedNFTs - claimedNFTs; - if (!score[userAddress]) - score[userAddress] = 0; - score[userAddress] = userScore; - }); - page = result.users.length < PAGE_SIZE ? -1 : page + 1; - } - else { - page = -1; - } + while (page !== -1) { + params.users.__args.skip = page * PAGE_SIZE; + const result = await subgraphRequest(DPS_SUBGRAPH_URL[network], params); + if ( + result && + result.users && + resultNFTs && + resultNFTs.nftlockeds && + resultNFTs.nftafterClaimeds + ) { + result.users.forEach((u) => { + const userAddress = getAddress(u.id); + let userScore = parseInt(u.numberOfTokens); + let lockedNFTs = 0; + let claimedNFTs = 0; + resultNFTs.nftlockeds.forEach((n) => { + if (n.owner.id === u.id) { + lockedNFTs = lockedNFTs + 1; + } + }); + resultNFTs.nftafterClaimeds.forEach((nft) => { + if (nft.owner.id === u.id) { + claimedNFTs = claimedNFTs + 1; + } + }); + userScore = userScore + lockedNFTs - claimedNFTs; + if (!score[userAddress]) score[userAddress] = 0; + score[userAddress] = userScore; + }); + page = result.users.length < PAGE_SIZE ? -1 : page + 1; + } else { + page = -1; } - return score || {}; - } \ No newline at end of file + } + return score || {}; +} diff --git a/src/strategies/earthfund-child-dao-staking-balance/schema.json b/src/strategies/earthfund-child-dao-staking-balance/schema.json index b742819f1..be58e1d56 100644 --- a/src/strategies/earthfund-child-dao-staking-balance/schema.json +++ b/src/strategies/earthfund-child-dao-staking-balance/schema.json @@ -9,9 +9,7 @@ "stakingRewardsContractAddress": { "type": "string", "title": "Address of the staking rewards contract", - "examples": [ - "e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984" - ], + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], "pattern": "^0x[a-fA-F0-9]{40}$", "minLength": 42, "maxLength": 42 diff --git a/src/strategies/sd-boost-twavp/index.ts b/src/strategies/sd-boost-twavp/index.ts index 322afa67b..dc4a937ae 100644 --- a/src/strategies/sd-boost-twavp/index.ts +++ b/src/strategies/sd-boost-twavp/index.ts @@ -29,7 +29,7 @@ export async function strategy( ): Promise> { // Maximum of 5 multicall if (options.sampleStep > 5) { - throw new Error("maximum of 5 call"); + throw new Error('maximum of 5 call'); } // About the blockList @@ -39,7 +39,7 @@ export async function strategy( const nbrsEmittedBlock = Math.floor( (options.sampleSize * 60 * 60 * 24) / av_blockEmission ); - let blockTagList: number[] = []; + const blockTagList: number[] = []; for (let i = 1; i < options.sampleStep + 1; i++) { blockTagList.push( blockTag - @@ -77,7 +77,7 @@ export async function strategy( blockTag } ); - let responseOtherBlock: number[] = []; + const responseOtherBlock: number[] = []; for (let i = options.sampleStep - 1; i > 0; i--) { blockTag = blockTagList[i - 1]; responseOtherBlock.push( From 96982c8dc03ac4d029e74cdfeb643b79a3dc950e Mon Sep 17 00:00:00 2001 From: Daniyal Manzoor <49681666+DaniyalManzoor@users.noreply.github.com> Date: Sun, 3 Jul 2022 19:35:53 +0500 Subject: [PATCH 005/815] Feat: Pilot balance on unipilot protocol (#687) Co-authored-by: Chaitanya --- src/strategies/index.ts | 4 +- .../examples.json | 95 +++++++++++++++++++ .../unipilot-vault-pilot-balance/index.ts | 87 +++++++++++++++++ test/index.spec.ts | 4 +- 4 files changed, 187 insertions(+), 3 deletions(-) create mode 100644 src/strategies/unipilot-vault-pilot-balance/examples.json create mode 100644 src/strategies/unipilot-vault-pilot-balance/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 402622030..2993b5976 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -324,6 +324,7 @@ import * as arrakisFinance from './arrakis-finance'; import * as auraFinance from './aura-vlaura-vebal'; import * as rocketpoolNodeOperator from './rocketpool-node-operator'; import * as earthfundChildDaoStakingBalance from './earthfund-child-dao-staking-balance'; +import * as unipilotVaultPilotBalance from './unipilot-vault-pilot-balance'; import * as sdBoostTWAVP from './sd-boost-twavp'; const strategies = { @@ -651,7 +652,8 @@ const strategies = { 'aura-vlaura-vebal': auraFinance, 'rocketpool-node-operator': rocketpoolNodeOperator, 'earthfund-child-dao-staking-balance': earthfundChildDaoStakingBalance, - 'sd-boost-twavp': sdBoostTWAVP + 'sd-boost-twavp': sdBoostTWAVP, + 'unipilot-vault-pilot-balance': unipilotVaultPilotBalance }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/unipilot-vault-pilot-balance/examples.json b/src/strategies/unipilot-vault-pilot-balance/examples.json new file mode 100644 index 000000000..b2e072d53 --- /dev/null +++ b/src/strategies/unipilot-vault-pilot-balance/examples.json @@ -0,0 +1,95 @@ +[ + { + "name": "Unipilot vault pilot balance query", + "strategy": { + "name": "unipilot-vault-pilot-balance", + "params": { + "decimals": 18, + "unipilotSubgraphURI": "https://api.thegraph.com/subgraphs/name/unipilotvoirstudio/stats-v2", + "vaultAddress": "0x8fd23f313c147d3c2a0fb11dd6b98515b9cb0603", + "unipilotFarming": "0x52D1Cc3E97B97d3a915f2C91E0aE687c89f6F2E0", + "unipilotVaultMethodABI": [ + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "unipilotFarmingMethodABI": [ + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "userInfo", + "outputs": [ + { + "internalType": "uint256", + "name": "reward", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "altReward", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "lpLiquidity", + "type": "uint256" + }, + { + "internalType": "address", + "name": "vault", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } + ] + } + }, + "network": "1", + "addresses": [ + "0x899917ef0213b78cd9da7ff930efbd505433de56", + "0x019cdfd2a70dd4b899f330877752edfda5bd34c4" + ], + "snapshot": 15034421 + } +] diff --git a/src/strategies/unipilot-vault-pilot-balance/index.ts b/src/strategies/unipilot-vault-pilot-balance/index.ts new file mode 100644 index 000000000..5d795910b --- /dev/null +++ b/src/strategies/unipilot-vault-pilot-balance/index.ts @@ -0,0 +1,87 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; + +import { subgraphRequest, call, multicall } from '../../utils'; + +export const author = 'daniyalmanzoor'; +export const version = '0.1.0'; + +function bn(num: any): BigNumber { + return BigNumber.from(num.toString()); +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const params = { + vaults: { + __args: { + where: { + id: options.vaultAddress.toLowerCase() + } + }, + totalLockedToken0: true + } + }; + + const { vaults } = await subgraphRequest(options.unipilotSubgraphURI, params); + + const _totalLP: BigNumber = await call( + provider, + options.unipilotVaultMethodABI, + [options.vaultAddress, 'totalSupply'] + ); + + /** + * Unipilot pilot vault balance + */ + const userVaultLP = await multicall( + network, + provider, + options.unipilotVaultMethodABI, + addresses.map((_address) => [ + options.vaultAddress, + 'balanceOf', + [_address] + ]), + { blockTag } + ); + + /** + * Unipilot Farming pilot balance + */ + const userFarmingVaultLP = await multicall( + network, + provider, + options.unipilotFarmingMethodABI, + addresses.map((_address) => [ + options.unipilotFarming, + 'userInfo', + [options.vaultAddress, _address] + ]), + { blockTag } + ); + + return Object.fromEntries( + addresses.map((_address, i) => { + const _userShare = bn(userVaultLP[i]) + .add(bn(userFarmingVaultLP[i].lpLiquidity)) + .mul(bn(10 ** 18)) + .div(_totalLP); + + const _userBalance = formatUnits( + bn(_userShare).mul(bn(vaults[0].totalLockedToken0)).div(bn(10).pow(18)), + options.decimals + ); + + return [_address, parseFloat(_userBalance)]; + }) + ); +} diff --git a/test/index.spec.ts b/test/index.spec.ts index 93ed7f751..90770906c 100644 --- a/test/index.spec.ts +++ b/test/index.spec.ts @@ -46,7 +46,7 @@ describe(`\nTest strategy "${strategy}"`, () => { expect(strategy).toMatch(/^[a-z0-9\-]+$/); }); - it('Strategy name should be same as in example.json', () => { + it('Strategy name should be same as in examples.json', () => { expect(example.strategy.name).toBe(strategy); }); @@ -190,7 +190,7 @@ describe(`\nOthers:`, () => { schema = null; } (schema ? it : it.skip)( - 'Check schema (if available) is valid with example.json', + 'Check schema (if available) is valid with examples.json', async () => { expect(typeof schema).toBe('object'); expect( From 21f29e0aa380e3615ecc83efeb15be38595c7ddd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=E1=BA=A7n=20V=C4=83n=20Ti=E1=BA=BFn?= Date: Tue, 5 Jul 2022 00:02:45 +0700 Subject: [PATCH 006/815] [wanakafarm-staking] Change api url strategies wanakafarm staking (#691) Co-authored-by: Chaitanya --- src/strategies/wanakafarm-staking/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/strategies/wanakafarm-staking/index.ts b/src/strategies/wanakafarm-staking/index.ts index 872223ce6..39ee5855d 100644 --- a/src/strategies/wanakafarm-staking/index.ts +++ b/src/strategies/wanakafarm-staking/index.ts @@ -2,8 +2,8 @@ import { getAddress } from '@ethersproject/address'; import { subgraphRequest } from '../../utils'; const FLASHSTAKE_SUBGRAPH_URL = { - '1': 'https://score-api.wanakafarm.com/graphql', - '56': 'https://score-api.wanakafarm.com/graphql' + '1': 'https://score-api.wanakafarm.tech/graphql', + '56': 'https://score-api.wanakafarm.tech/graphql' }; export const author = 'TranTien139'; From 31dd9164c0910c77bad33fc106c8079ce9acb4a4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 Jul 2022 23:04:48 +0530 Subject: [PATCH 007/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.7 (#694) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 42c3d81e7..890cc6b35 100755 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "@ethersproject/strings": "^5.0.5", "@ethersproject/units": "^5.0.3", "@ethersproject/wallet": "^5.4.0", - "@snapshot-labs/snapshot.js": "^0.4.6", + "@snapshot-labs/snapshot.js": "^0.4.7", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.3.1", "cross-fetch": "^3.0.6", diff --git a/yarn.lock b/yarn.lock index 075d2ba31..07b00bcbf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1095,10 +1095,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.6": - version "0.4.6" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.6.tgz#3f383f065795eba93739a4f1b92c2c8bd8818462" - integrity sha512-+osD9bzRm/mXXsq437afH9giRi0ceAvmqJRbc07l36N7J2fx5lZBVoc0t1BTwXBuX2npaMSY3HvUsvYCLvwbEw== +"@snapshot-labs/snapshot.js@^0.4.7": + version "0.4.7" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.7.tgz#e1c6ab4fae882d2f0c41c197bba42cd4356105d0" + integrity sha512-yahrG7s1UbHn7uOfDX5wWA926SKoXkKkAhP/d4OvDL0PQxHY5rpf5z5FcVFSQyGFDoqlccYGE3PveGSz4EZ6Ig== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.0.4" From 8747556f8b1a9c501180e895bd47732d76b0c0d8 Mon Sep 17 00:00:00 2001 From: Julien THOMAS <61523188+julien-devatom@users.noreply.github.com> Date: Mon, 4 Jul 2022 19:41:14 +0200 Subject: [PATCH 008/815] :sparkles: add vesting strategy (#693) --- .../examples.json | 24 +++ .../index.ts | 137 ++++++++++++++++++ src/strategies/index.ts | 4 +- 3 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 src/strategies/balance-of-with-linear-vesting-power/examples.json create mode 100644 src/strategies/balance-of-with-linear-vesting-power/index.ts diff --git a/src/strategies/balance-of-with-linear-vesting-power/examples.json b/src/strategies/balance-of-with-linear-vesting-power/examples.json new file mode 100644 index 000000000..35c0eb321 --- /dev/null +++ b/src/strategies/balance-of-with-linear-vesting-power/examples.json @@ -0,0 +1,24 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "balance-of-with-linear-vesting-power", + "params": { + "ERC20Address": "0x9994E35Db50125E0DF82e4c2dde62496CE330999", + "DSSVestAddress": "0x6017dd61f4d0C8123f160F99058Adc5671dF6447", + "decimals": 18, + "vestingNetwork": 1, + "vestingDuration": 94608000, + "startVesting": 1656078603 + } + }, + "network": "1", + "addresses": [ + "0xd9286ab8Ac06a428Bbb45Bfd785f9A22FD0ef0Bd", + "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", + "0x9B8e8dD9151260c21CB6D7cc59067cd8DF306D58", + "0x38C0039247A31F3939baE65e953612125cB88268" + ], + "snapshot": 15076584 + } +] diff --git a/src/strategies/balance-of-with-linear-vesting-power/index.ts b/src/strategies/balance-of-with-linear-vesting-power/index.ts new file mode 100644 index 000000000..507c089a0 --- /dev/null +++ b/src/strategies/balance-of-with-linear-vesting-power/index.ts @@ -0,0 +1,137 @@ +import { call, Multicaller } from '../../utils'; +import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; + +export const author = 'morpho-labs'; +export const version = '0.1.0'; + +const DSSVestAbi = [ + 'function usr(uint256 _id) external view returns (address)', + 'function tot(uint256 _id) external view returns (uint256)', + 'function accrued(uint256 _id) external view returns (uint256)', + 'function ids() external view returns (uint256)' +]; +const ERC20abi = [ + 'function balanceOf(address account) external view returns (uint256)' +]; + +const vestedAmountPower = ( + totalVestedNotClaimed: BigNumberish, + startDate: BigNumberish, + period: BigNumberish +) => { + const amount = BigNumber.from(totalVestedNotClaimed); + const now = BigNumber.from(Math.round(Date.now() / 1000)); + if (now.lte(startDate)) return BigNumber.from(0); + if (now.gt(BigNumber.from(startDate).add(period))) + return totalVestedNotClaimed; + return now.sub(startDate).mul(amount).div(period); +}; + +const idsArray = (maxId: number) => + Array.from({ length: maxId }, (_, i) => i + 1); + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + // fetch the number of vesting accounts + const maxId: BigNumber = await call( + provider, + DSSVestAbi, + [options.DSSVestAddress, 'ids', []], + { + blockTag + } + ); + + // create an array of each vesting ID: [1:maxId] + const ids = idsArray(maxId.toNumber()); + + // We first fetch the balance of ERC20 for each addresses + const multiBalanceOf = new Multicaller(network, provider, ERC20abi, { + blockTag + }); + addresses.forEach((address) => + multiBalanceOf.call(address, options.ERC20Address, 'balanceOf', [address]) + ); + const addressesBalanceOf: Record< + string, + BigNumberish + > = await multiBalanceOf.execute(); + + // And then, we fetch the vesting data for each vesting ID + // 1. vester address + const multiVest = new Multicaller( + options.vestingNetwork, + provider, + DSSVestAbi, + { + blockTag + } + ); + + ids.forEach((id) => multiVest.call(id, options.DSSVestAddress, 'usr', [id])); + const vestedAddresses: Record = await multiVest.execute(); + + // 2. total vested + const multiVestTotCaller = new Multicaller( + options.vestingNetwork, + provider, + DSSVestAbi, + { blockTag } + ); + ids.forEach((id) => + multiVestTotCaller.call(id, options.DSSVestAddress, 'tot', [id]) + ); + const multiVestTot: Record< + string, + BigNumberish + > = await multiVestTotCaller.execute(); + + // 3. total claimed + const multiVestAccruedCaller = new Multicaller( + options.vestingNetwork, + provider, + DSSVestAbi, + { blockTag } + ); + ids.forEach((id) => + multiVestAccruedCaller.call(id, options.DSSVestAddress, 'accrued', [id]) + ); + const multiVestAccrued: Record< + string, + BigNumberish + > = await multiVestAccruedCaller.execute(); + return Object.fromEntries( + Object.entries(addressesBalanceOf).map(([address, balance]) => { + const initialVotingPower = [ + address, + parseFloat(formatUnits(balance, options.decimals)) + ]; + // fetch vested users data + const [id] = + Object.entries(vestedAddresses).find( + ([, _address]) => _address === address + ) ?? []; + if (id === undefined) return initialVotingPower; + const totalVested = multiVestTot[id]; + const totalAccrued = multiVestAccrued[id]; + if (!(id && totalAccrued && totalVested)) return initialVotingPower; + const votingPower = BigNumber.from(balance).add( + vestedAmountPower( + BigNumber.from(totalVested).sub(totalAccrued), + options.startVesting, + options.vestingDuration + ) + ); + return [address, parseFloat(formatUnits(votingPower, options.decimals))]; + }) + ); +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 2993b5976..1258afb5b 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -33,6 +33,7 @@ import * as revest from './revest'; import * as erc20Price from './erc20-price'; import * as balanceOfWithMin from './balance-of-with-min'; import * as balanceOfWithThresholds from './balance-of-with-thresholds'; +import * as balanceOfWithLinearVestingPower from './balance-of-with-linear-vesting-power'; import * as thresholds from './thresholds'; import * as ethBalance from './eth-balance'; import * as ethWithBalance from './eth-with-balance'; @@ -653,7 +654,8 @@ const strategies = { 'rocketpool-node-operator': rocketpoolNodeOperator, 'earthfund-child-dao-staking-balance': earthfundChildDaoStakingBalance, 'sd-boost-twavp': sdBoostTWAVP, - 'unipilot-vault-pilot-balance': unipilotVaultPilotBalance + 'unipilot-vault-pilot-balance': unipilotVaultPilotBalance, + 'balance-of-with-linear-vesting-power': balanceOfWithLinearVestingPower }; Object.keys(strategies).forEach(function (strategyName) { From 7f5b6f9f80e495ce317275a08efb03fad84b0230 Mon Sep 17 00:00:00 2001 From: andreibadea20 <105772011+andreibadea20@users.noreply.github.com> Date: Tue, 5 Jul 2022 09:02:06 +0300 Subject: [PATCH 009/815] [dps-nft-strategy] change an issue with request on dps-nft-strategy (#692) * adding dps-nft-strategy * add ReadMe, delete symbol & decimals from examples.json, add block number when request * update ReadMe * Update README.md * Update src/strategies/balancer-poolid/index.ts * Update test/index.spec.ts * Update test/index.spec.ts * Delete schema.json * Update src/strategies/dps-nft-strategy/examples.json * changed an issue with request Co-authored-by: Chaitanya --- src/strategies/dps-nft-strategy/examples.json | 12 +- src/strategies/dps-nft-strategy/index.ts | 136 +++++++----------- 2 files changed, 58 insertions(+), 90 deletions(-) diff --git a/src/strategies/dps-nft-strategy/examples.json b/src/strategies/dps-nft-strategy/examples.json index 9fbbb7fae..f3dacdc6c 100644 --- a/src/strategies/dps-nft-strategy/examples.json +++ b/src/strategies/dps-nft-strategy/examples.json @@ -9,12 +9,14 @@ }, "network": "80001", "addresses": [ - "0x4bb7e1d5c463ec80d0b316e83a090b00f7d87d1d", + "0x0b0db545517b9dabd652596fb26e044841ace4cd", + "0x0c328ffc95155bf02015cb04cc68f7a9cebdb214", "0x15f48ab7ada1541a205eb9ee20f5a4e76ce3882a", - "0x5e733901b92bc5110779f8ee64de3d8af0629dc6", - "0xc32004eced24167e8aaef9690da3a70387a97a9b", - "0x60b5d811673a6420851d087cff84c660c14a3acb" + "0xd88f34679b914c4c677ddc78ae0bad7cdf6760cc", + "0x8705EBf3a34D1F164cCa3Ed2Db54d5f1b7C439F0", + "0x7b64F8508b5f9F12815199F985770A5890e650D0" ], - "snapshot": 26453570 + "snapshot": 27025834 } ] + diff --git a/src/strategies/dps-nft-strategy/index.ts b/src/strategies/dps-nft-strategy/index.ts index 679d298e9..f0d09a7b6 100644 --- a/src/strategies/dps-nft-strategy/index.ts +++ b/src/strategies/dps-nft-strategy/index.ts @@ -1,5 +1,5 @@ import { getAddress } from '@ethersproject/address'; -import { subgraphRequest } from '../../utils'; +import { subgraphRequest } from '../../utils'; export const author = 'andreibadea20'; export const version = '0.1.0'; @@ -8,96 +8,62 @@ const DPS_SUBGRAPH_URL = { '80001': 'https://api.thegraph.com/subgraphs/name/andreibadea20/subgraph-dps' }; + const PAGE_SIZE = 1000; const params = { - users: { - __args: { - first: PAGE_SIZE, - skip: 0 - }, - id: true, - numberOfTokens: true - } + users: { + __args: { + block: {number: 22572401}, + first: PAGE_SIZE, + skip: 0 + }, + id: true, + numberOfTokens: true, + listOfNFTsLocked: { + tokenId: true + }, + listOfNFTsReturned: { + tokenId: true + } + } }; -const paramsForNFTs = { - nftlockeds: { - __args: { - block: { number: Number(22572400) } - }, - tokenId: true, - owner: { - id: true - }, - transferedAtTimestamp: true - }, - nftafterClaimeds: { - __args: { - block: { number: Number(22572400) } - }, - tokenId: true, - owner: { - id: true - }, - transferedAtTimestamp: true - } -}; +export async function strategy(space, network, provider, addresses, options, snapshot) { + + if (snapshot !== 'latest') { + // @ts-ignore + params.users.__args.block = {number: snapshot}; + } + + const score = {}; + let page = 0; + + while (page !== -1) { + params.users.__args.skip = page * PAGE_SIZE; + const result = await subgraphRequest(DPS_SUBGRAPH_URL[network], params); + if (result && result.users) { + result.users.forEach((u) => { + + const userAddress = getAddress(u.id); + + let userScore = parseInt(u.numberOfTokens); + + let lockedNFTs = u.listOfNFTsLocked.length; + let claimedNFTs = u.listOfNFTsReturned.length; -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - if (snapshot !== 'latest') { - // @ts-ignore - paramsForNFTs.nftlockeds.__args.block = { number: snapshot }; - paramsForNFTs.nftafterClaimeds.__args.block = { number: snapshot }; - } - const resultNFTs = await subgraphRequest( - DPS_SUBGRAPH_URL[network], - paramsForNFTs - ); - const score = {}; - let page = 0; + userScore = userScore + lockedNFTs - claimedNFTs; - while (page !== -1) { - params.users.__args.skip = page * PAGE_SIZE; - const result = await subgraphRequest(DPS_SUBGRAPH_URL[network], params); - if ( - result && - result.users && - resultNFTs && - resultNFTs.nftlockeds && - resultNFTs.nftafterClaimeds - ) { - result.users.forEach((u) => { - const userAddress = getAddress(u.id); - let userScore = parseInt(u.numberOfTokens); - let lockedNFTs = 0; - let claimedNFTs = 0; - resultNFTs.nftlockeds.forEach((n) => { - if (n.owner.id === u.id) { - lockedNFTs = lockedNFTs + 1; - } - }); - resultNFTs.nftafterClaimeds.forEach((nft) => { - if (nft.owner.id === u.id) { - claimedNFTs = claimedNFTs + 1; - } - }); - userScore = userScore + lockedNFTs - claimedNFTs; - if (!score[userAddress]) score[userAddress] = 0; - score[userAddress] = userScore; - }); - page = result.users.length < PAGE_SIZE ? -1 : page + 1; - } else { - page = -1; + if (!score[userAddress]) + score[userAddress] = 0; + score[userAddress] = userScore; + }); + page = result.users.length < PAGE_SIZE ? -1 : page + 1; + } + else { + page = -1; + } } - } - return score || {}; -} + return score || {}; + } \ No newline at end of file From 3419e6434b26c031fa33bd4a2977e48d7411e932 Mon Sep 17 00:00:00 2001 From: ixm-759 <80939098+ixm-759@users.noreply.github.com> Date: Tue, 5 Jul 2022 01:06:30 -0500 Subject: [PATCH 010/815] Feat/apeswap strategy [apeswap] (#679) * feat: Add strategy for Gnana from apeswap * fix: Readme * fix: Add addresses to example * fix: Get only active pools * fix: Remove the pools, just keep the Banana pool * Update src/strategies/apeswap/index.ts Co-authored-by: Chaitanya --- src/strategies/apeswap/README.md | 33 ++++++++++++++++ src/strategies/apeswap/examples.json | 24 ++++++++++++ src/strategies/apeswap/index.ts | 58 ++++++++++++++++++++++++++++ src/strategies/index.ts | 4 +- 4 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 src/strategies/apeswap/README.md create mode 100644 src/strategies/apeswap/examples.json create mode 100644 src/strategies/apeswap/index.ts diff --git a/src/strategies/apeswap/README.md b/src/strategies/apeswap/README.md new file mode 100644 index 000000000..90c90eefb --- /dev/null +++ b/src/strategies/apeswap/README.md @@ -0,0 +1,33 @@ +# Apeswap + +This is the most common strategy, it returns the balances of the voters for a balances GNANA token +in Apeswap project(pools, token). + +Here is an example of parameters: +```json +[ + { + "name": "Example query Apeswap", + "strategy": { + "name": "apeswap", + "params": { + "address": "0xddb3bd8645775f59496c821e4f55a7ea6a6dc299", + "symbol": "GNANA", + "decimals": 18 + } + }, + "network": "56", + "addresses": [ + "0x56E17565Ce37c0Dbb2BDDec0eC607b874785c376", + "0x0326824dB556Ab5525608851713e269Ce583B629", + "0xc47dec7ffde829043b91e904fdaf1e048bdd482c", + "0x356f74457a8002c680a0c8fa628083d619267c88", + "0x607f62572ea0c00da5048eb39d89d32110151681", + "0x75768Ea1A1C3c84121063f7A281ee3081dB1D8Ef" + ], + "snapshot": 18979451 + } +] + + +``` diff --git a/src/strategies/apeswap/examples.json b/src/strategies/apeswap/examples.json new file mode 100644 index 000000000..07d7dfa3f --- /dev/null +++ b/src/strategies/apeswap/examples.json @@ -0,0 +1,24 @@ +[ + { + "name": "Example query Apeswap", + "strategy": { + "name": "apeswap", + "params": { + "address": "0xddb3bd8645775f59496c821e4f55a7ea6a6dc299", + "symbol": "GNANA", + "decimals": 18 + } + }, + "network": "56", + "addresses": [ + "0xe5EdeA54596B385C3c8dFd5010C3Cf892d547Acb", + "0x56E17565Ce37c0Dbb2BDDec0eC607b874785c376", + "0x0326824dB556Ab5525608851713e269Ce583B629", + "0xc47dec7ffde829043b91e904fdaf1e048bdd482c", + "0x356f74457a8002c680a0c8fa628083d619267c88", + "0x607f62572ea0c00da5048eb39d89d32110151681", + "0x75768Ea1A1C3c84121063f7A281ee3081dB1D8Ef" + ], + "snapshot": 18979451 + } +] diff --git a/src/strategies/apeswap/index.ts b/src/strategies/apeswap/index.ts new file mode 100644 index 000000000..4fab8dae6 --- /dev/null +++ b/src/strategies/apeswap/index.ts @@ -0,0 +1,58 @@ +import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'ApeSwapFinance'; +export const version = '0.0.1'; + +const GNANA_POOL = '0x8F97B2E6559084CFaBA140e2AB4Da9aAF23FE7F8'; +const abi = [ + 'function balanceOf(address _owner) view returns (uint256 balance)', + 'function userInfo(address) view returns (uint256 amount, uint256 rewardDebt)' +]; + +const bn = (num: any): BigNumber => { + return BigNumber.from(num.toString()); +}; + +const addUserBalance = (userBalances, user: string, balance) => { + if (userBalances[user]) { + return (userBalances[user] = userBalances[user].add(balance)); + } else { + return (userBalances[user] = balance); + } +}; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const multicall = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address: any) => { + multicall.call(`token.${address}`, options.address, 'balanceOf', [address]); + multicall.call(`pool.${address}`, GNANA_POOL, 'userInfo', [address]); + }); + const result = await multicall.execute(); + + const userBalances: any = []; + for (let i = 0; i < addresses.length - 1; i++) { + userBalances[addresses[i]] = bn(0); + } + + addresses.forEach((address: any) => { + addUserBalance(userBalances, address, result.token[address] ?? 0); + addUserBalance(userBalances, address, result.pool[address][0] ?? 0); + }); + + return Object.fromEntries( + Object.entries(userBalances).map(([address, balance]) => [ + address, + parseFloat(formatUnits(balance, options.decimals)) + ]) + ); +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 1258afb5b..5aa5fe951 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -327,6 +327,7 @@ import * as rocketpoolNodeOperator from './rocketpool-node-operator'; import * as earthfundChildDaoStakingBalance from './earthfund-child-dao-staking-balance'; import * as unipilotVaultPilotBalance from './unipilot-vault-pilot-balance'; import * as sdBoostTWAVP from './sd-boost-twavp'; +import * as apeswap from './apeswap'; const strategies = { 'ethermon-erc721': ethermon721, @@ -655,7 +656,8 @@ const strategies = { 'earthfund-child-dao-staking-balance': earthfundChildDaoStakingBalance, 'sd-boost-twavp': sdBoostTWAVP, 'unipilot-vault-pilot-balance': unipilotVaultPilotBalance, - 'balance-of-with-linear-vesting-power': balanceOfWithLinearVestingPower + 'balance-of-with-linear-vesting-power': balanceOfWithLinearVestingPower, + apeswap }; Object.keys(strategies).forEach(function (strategyName) { From c19f1841fc0d0fd452700dec884999bcb57783ec Mon Sep 17 00:00:00 2001 From: Mitesh Mutha Date: Wed, 6 Jul 2022 11:27:29 +0200 Subject: [PATCH 011/815] [solv-voucher-claimable] Added strategy solv-voucher-claimable (#696) * Added strategy solv-voucher-claimable * Added strategy solv-voucher-claimable --- src/strategies/index.ts | 2 + .../solv-voucher-claimable/README.md | 14 ++++ .../solv-voucher-claimable/examples.json | 42 ++++++++++ .../solv-voucher-claimable/index.ts | 76 +++++++++++++++++++ .../solv-voucher-claimable/schema.json | 28 +++++++ 5 files changed, 162 insertions(+) create mode 100644 src/strategies/solv-voucher-claimable/README.md create mode 100644 src/strategies/solv-voucher-claimable/examples.json create mode 100644 src/strategies/solv-voucher-claimable/index.ts create mode 100644 src/strategies/solv-voucher-claimable/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 5aa5fe951..2e9bfc06b 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -328,6 +328,7 @@ import * as earthfundChildDaoStakingBalance from './earthfund-child-dao-staking- import * as unipilotVaultPilotBalance from './unipilot-vault-pilot-balance'; import * as sdBoostTWAVP from './sd-boost-twavp'; import * as apeswap from './apeswap'; +import * as solvVoucherClaimable from './solv-voucher-claimable'; const strategies = { 'ethermon-erc721': ethermon721, @@ -656,6 +657,7 @@ const strategies = { 'earthfund-child-dao-staking-balance': earthfundChildDaoStakingBalance, 'sd-boost-twavp': sdBoostTWAVP, 'unipilot-vault-pilot-balance': unipilotVaultPilotBalance, + 'solv-voucher-claimable': solvVoucherClaimable, 'balance-of-with-linear-vesting-power': balanceOfWithLinearVestingPower, apeswap }; diff --git a/src/strategies/solv-voucher-claimable/README.md b/src/strategies/solv-voucher-claimable/README.md new file mode 100644 index 000000000..04e7da0c6 --- /dev/null +++ b/src/strategies/solv-voucher-claimable/README.md @@ -0,0 +1,14 @@ +# solv-voucher-claimable + +This strategy is to let owners of [Solv vesting vouchers](https://solv.finance/) vote with the voting power equal to their claimable token amount in the voucher at the time of the snapshot. + +This can be combined with `erc20-balance-of` strategy to give the voting power of "amount held in wallet" + "amount available in the vesting voucher". + +The parameters are the `address` of the vesting voucher contract and the `symbol` of the underlying token. Here is an example of parameters: + +```json +{ + "address": "0x522f8fe415e08b600b8bd6c1db74a1b696845d0d", + "symbol": "PDT" +} +``` diff --git a/src/strategies/solv-voucher-claimable/examples.json b/src/strategies/solv-voucher-claimable/examples.json new file mode 100644 index 000000000..95c270dba --- /dev/null +++ b/src/strategies/solv-voucher-claimable/examples.json @@ -0,0 +1,42 @@ +[ + { + "name": "PDT Vesting Voucher Claimable Amounts", + "strategy": { + "name": "solv-voucher-claimable", + "params": { + "address": "0x522f8fe415e08b600b8bd6c1db74a1b696845d0d", + "symbol": "PDT" + } + }, + "network": "1", + "addresses": [ + "0x0d5f507074db8ead56f5875219dbf1ff73bcd429", + "0xf96225d26fa257b200420696092e02cc141cf3d8", + "0xd3be4499f28ef91a6b6dd5ab6beb0588039d72ba", + "0x661c3a6db7241f2a7b3b1c1d73fe98198d089fc2", + "0xceeab2af38e6b086cdce120c49f93b65f0b92b76", + "0xc40fc1c553737b2aa8572fdb036986510219f233" + ], + "snapshot": 14955800 + }, + { + "name": "VERA Vesting Voucher Claimable Amounts", + "strategy": { + "name": "solv-voucher-claimable", + "params": { + "address": "0x928b35660f8388042d871e82eb40234901461354", + "symbol": "VERA" + } + }, + "network": 56, + "addresses": [ + "0x0d5f507074db8ead56f5875219dbf1ff73bcd429", + "0xf96225d26fa257b200420696092e02cc141cf3d8", + "0xd3be4499f28ef91a6b6dd5ab6beb0588039d72ba", + "0x661c3a6db7241f2a7b3b1c1d73fe98198d089fc2", + "0xceeab2af38e6b086cdce120c49f93b65f0b92b76", + "0xc40fc1c553737b2aa8572fdb036986510219f233" + ], + "snapshot": 19287600 + } +] diff --git a/src/strategies/solv-voucher-claimable/index.ts b/src/strategies/solv-voucher-claimable/index.ts new file mode 100644 index 000000000..555cb3c74 --- /dev/null +++ b/src/strategies/solv-voucher-claimable/index.ts @@ -0,0 +1,76 @@ +import { BigNumber, FixedNumber} from '@ethersproject/bignumber'; +import { Multicaller } from '../../utils'; + +export const author = 'mitesh-mutha'; +export const version = '0.1.0'; + +const abi = [ + 'function balanceOf(address account) external view returns (uint256)', + 'function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256)', + 'function tokenURI(uint256 tokenId) external view returns (string)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + // Fetch the balanceOf the addresses i.e. how many vouchers do they hold? + const balanceOfMulti = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => + balanceOfMulti.call(address, options.address, 'balanceOf', [address]) + ); + const ownedCounts: Record = await balanceOfMulti.execute(); + + + + // Fetch the voucher token IDs held for each address + const tokenIdsMulti = new Multicaller(network, provider, abi, { blockTag }); + addresses.map((address) => { + var ownedCount = ownedCounts[address]; + while (ownedCount.gt(0)) { + let index = ownedCount.sub(1) + tokenIdsMulti.call(`${address}-${index.toString()}`, options.address, 'tokenOfOwnerByIndex', [address, index.toNumber()]) + ownedCount = index + } + }); + const ownerTokenIds: Record = await tokenIdsMulti.execute(); + + + + // Fetch the voucher data for each voucher held by an address among the address + const tokenURIMulti = new Multicaller(network, provider, abi, { blockTag }); + Object.entries(ownerTokenIds).map( ([addressWithIndex, tokenId]) => { + tokenURIMulti.call(`${addressWithIndex}`, options.address, `tokenURI`, [tokenId]) + }); + const ownerTokenURIs: Record = await tokenURIMulti.execute(); + + + + // Go through the list of results and sum up claimable values + const claimableVotingPower: Record = {}; + Object.entries(ownerTokenURIs).map( ([addressWithIndex, tokenURI]) => { + var address = addressWithIndex.split("-")[0] + if (tokenURI.split(",")[0] == "data:application/json"){ + var tokenData = JSON.parse(tokenURI.slice(22)) + var claimableAmount = tokenData['properties']['claimableAmount'] + if (!claimableVotingPower[address]) claimableVotingPower[address] = FixedNumber.from(0); + claimableVotingPower[address] = claimableVotingPower[address].addUnsafe(FixedNumber.fromString(claimableAmount)) + } + }); + + + // Return the computed values + return Object.fromEntries( + Object.entries(claimableVotingPower).map(([address, votingPower]) => [ + address, + votingPower.toUnsafeFloat() + ]) + ); +} diff --git a/src/strategies/solv-voucher-claimable/schema.json b/src/strategies/solv-voucher-claimable/schema.json new file mode 100644 index 000000000..7d01484de --- /dev/null +++ b/src/strategies/solv-voucher-claimable/schema.json @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Underlying Token Symbol", + "examples": ["e.g. UNI"], + "maxLength": 16 + }, + "address": { + "type": "string", + "title": "Vesting Voucher Contract address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } + }, + "required": ["address"], + "additionalProperties": false + } + } +} From acca0cf7a48b7d371d19707c9fde12d4fc40a04f Mon Sep 17 00:00:00 2001 From: Sanjay Date: Wed, 6 Jul 2022 02:35:20 -0700 Subject: [PATCH 012/815] Account for claimable fidu staking rewards in goldfinch voting power (#699) --- .../goldfinch-voting-power/examples.json | 3 ++- .../goldfinch-voting-power/index.ts | 23 ++++++++++++++++--- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/strategies/goldfinch-voting-power/examples.json b/src/strategies/goldfinch-voting-power/examples.json index 75c8ec4b6..8d8d17f02 100644 --- a/src/strategies/goldfinch-voting-power/examples.json +++ b/src/strategies/goldfinch-voting-power/examples.json @@ -10,8 +10,9 @@ "0x526C7665C5dd9cD7102C6d42D407a0d9DC1e431d", "0x721931508df2764fd4f70c53da646cb8aed16ace", "0x4902b20bB3B8e7776CBcDCB6e3397E7F6b4e449E", + "0x8f4fc35cf5ad925bcc1cae81e5da62fca1c2dd2a", "0x6C3FB1A2A55fdcFb620Ae8f19b6fc332622050DD" ], - "snapshot": 14440657 + "snapshot": 15053050 } ] diff --git a/src/strategies/goldfinch-voting-power/index.ts b/src/strategies/goldfinch-voting-power/index.ts index 6e1abb275..6433a9756 100644 --- a/src/strategies/goldfinch-voting-power/index.ts +++ b/src/strategies/goldfinch-voting-power/index.ts @@ -6,11 +6,15 @@ export const author = 'sanjayprabhu'; export const version = '0.1.0'; const COMMUNITY_REWARDS = '0x0Cd73c18C085dEB287257ED2307eC713e9Af3460'; +const STAKING_REWARDS = '0xFD6FF39DA508d281C2d255e9bBBfAb34B6be60c3'; const GFI = '0xdab396cCF3d84Cf2D07C4454e10C8A6F5b008D2b'; const COMMUNITY_REWARDS_ABI = [ 'function totalUnclaimed(address owner) view returns (uint256)' ]; +const STAKING_REWARDS_ABI = [ + 'function totalOptimisticClaimable(address owner) view returns (uint256)' +]; export async function strategy( space, @@ -48,14 +52,27 @@ export async function strategy( { blockTag } ); - // Unclaimed Fidu staking GFI is ignored until smart contract - // can be upgraded with a view function to minimize calls here + const unclaimedStakingRewards = await multicall( + network, + provider, + STAKING_REWARDS_ABI, + addresses.map((address: any) => [ + STAKING_REWARDS, + 'totalOptimisticClaimable', + [address] + ]), + { blockTag } + ); addresses.forEach((address, index) => { const parsedCommunityRewards = parseFloat( formatUnits(unclaimedCommunityRewards[index][0], options.decimals) ); - gfiResult[address] = gfiResult[address] + parsedCommunityRewards; + const parsedStakingRewards = parseFloat( + formatUnits(unclaimedStakingRewards[index][0], options.decimals) + ); + gfiResult[address] = + gfiResult[address] + parsedCommunityRewards + parsedStakingRewards; }); return gfiResult; From 24b572ac76566a2cf8609a69c9f954ad58a2e186 Mon Sep 17 00:00:00 2001 From: Idiom <69865342+idiom-bytes@users.noreply.github.com> Date: Wed, 6 Jul 2022 10:41:16 -0500 Subject: [PATCH 013/815] ocean-marketplace-v4 strategy [ocean-marketplace-v4] (#695) * Setting custom test for OceanDAO space configuration. * Updating tests and logic to work with v4. * Updating strategy, readme, tests, and utils. Verified on both mainnet and polygon. * Cleaning up some debug-related changes, and updating paramterization of strategy. Removed OCEAN token from script, and am moving it to strategy configuration inside of Snapshot space. * Fixing params. * Am commiting v3 and v4 as separate paths in order to be able to properly configure them in the snapshot space. * Configured strategy index in order to maintain ocean_v3 => ocean + ocean_v4 => ocean_v4. Final strategy name remains: ocean-marketplace + ocean-marketplace-v4 * Adjusting parameters one last time. Making them consistent with erc20-balance-of. * Making tests pass. * Reverting changes to scores.ts * Update src/strategies/ocean-marketplace-v4/index.ts Co-authored-by: Chaitanya * Updated test coverage to validate scores being calculated in EWT + MOVR. We're going to run a test ballot in our demospace, using the mainnets defined in examples.json. * Disabling code that helps us validate scores, and will be using this in the future only for debugging purposes. * Disabling test code, and updating readme. Co-authored-by: Berkay Saglam <25263018+trizin@users.noreply.github.com> Co-authored-by: Chaitanya --- src/strategies/index.ts | 2 + src/strategies/ocean-marketplace-v4/README.md | 51 +++++ .../ocean-marketplace-v4/examples.json | 94 ++++++++++ src/strategies/ocean-marketplace-v4/index.ts | 175 ++++++++++++++++++ .../ocean-marketplace-v4/oceanUtils.ts | 31 ++++ 5 files changed, 353 insertions(+) create mode 100644 src/strategies/ocean-marketplace-v4/README.md create mode 100644 src/strategies/ocean-marketplace-v4/examples.json create mode 100644 src/strategies/ocean-marketplace-v4/index.ts create mode 100644 src/strategies/ocean-marketplace-v4/oceanUtils.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 2e9bfc06b..b9c4fef3f 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -89,6 +89,7 @@ import * as work from './work'; import * as ticketValidity from './ticket-validity'; import * as opium from './opium'; import * as ocean from './ocean-marketplace'; +import * as ocean_v4 from './ocean-marketplace-v4'; import * as theGraphBalance from './the-graph-balance'; import * as theGraphDelegation from './the-graph-delegation'; import * as theGraphIndexing from './the-graph-indexing'; @@ -438,6 +439,7 @@ const strategies = { 'ticket-validity': ticketValidity, opium, 'ocean-marketplace': ocean, + 'ocean-marketplace-v4': ocean_v4, 'the-graph-balance': theGraphBalance, 'the-graph-delegation': theGraphDelegation, 'the-graph-indexing': theGraphIndexing, diff --git a/src/strategies/ocean-marketplace-v4/README.md b/src/strategies/ocean-marketplace-v4/README.md new file mode 100644 index 000000000..71121343b --- /dev/null +++ b/src/strategies/ocean-marketplace-v4/README.md @@ -0,0 +1,51 @@ +# Ocean marketplace v4 + +```version 0.1``` + +This strategy gives score aka votes to the liquidity providers on the [Ocean marketplace v4](https://market.oceanprotocol.com). This means that LP participants can vote for OceanDAO grants via Snapshot without removing their liquidity. + +## Solution description + +The solution pulls the needed data from all Ocean Protocol subgraphs using the following path: +```https://subgraph.{network}.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph``` + +This strategy is designed to give voting scores only to marketplace liquidity providers by calculating their individual pool shares. + +The remaining vote count comes from other strategies configured in [OceanDAO Snapshot Page](https://vote.oceanprotocol.com/#/). + +For v4, we only look at pools w/ OCEAN as the basetoken, and pools that have been proprely initialized. We then attributes votes to LP'ers like this: +``` +user_votes = user_pool_shares * (total_Ocean_in_the_pool / total_number_of_pool_shares) +``` +This is done for all pools and the votes for the users are added up. + +To extend or run this strategy please use the setup described [here](https://docs.snapshot.page/strategies). + +## v3 vs. v4 differences +- In v4 we have to check if the pool basetoken is Ocean. Only Ocean tokens will obtain voting power. +- In v4, pools.datatoken.holderCount is always 0 as datatokens are consumed as soon as they are purchased +- In v4, pools.isFinalized checks if the pool has been properly setup. In v3 the equivalent was pools.active + +## Ocean ERC20 Addresses +You need to submit the ERC20 Ocean tokenAddress via the stratgy parameters. These [can be found here](https://github.com/oceanprotocol/contracts/blob/v4main/addresses/address.json) + +Addresses by network: +``` +'1': '0x967da4048cD07aB37855c090aAF366e4ce1b9F48', //mainnet +'3': '0x5e8DCB2AfA23844bcc311B00Ad1A0C30025aADE9', //ropsten +'42': '0x8967bcf84170c91b0d24d4302c2376283b0b3a07', //rinkeby +'56': '0xDCe07662CA8EbC241316a15B611c89711414Dd1a', //bsc +'137': '0x282d8efCe846A88B159800bd4130ad77443Fa1A1', //poly +'246': '0x593122AAE80A6Fc3183b2AC0c4ab3336dEbeE528', //ewt +'1285': '0x99C409E5f62E4bd2AC142f17caFb6810B8F0BAAE', //movr +'1287': '0xF6410bf5d773C7a41ebFf972f38e7463FA242477', //glmr +'80001': '0xd8992Ed72C445c35Cb4A2be468568Ed1079357c8' //mumbai +``` + +## How to Test +(1) Remove comments around debug logs. +(2) Enable code block inside `index.ts` that verifies expected results. +``` +if (options.expectedResults) { +``` +(3) Use the regular testing functionality `yarn test -strategy=ocean-marktplace-v4` diff --git a/src/strategies/ocean-marketplace-v4/examples.json b/src/strategies/ocean-marketplace-v4/examples.json new file mode 100644 index 000000000..d4986c397 --- /dev/null +++ b/src/strategies/ocean-marketplace-v4/examples.json @@ -0,0 +1,94 @@ +[ + { + "name": "ERC-20 OCEAN staked in mainnet v4 marketplace via subgraph", + "strategy": { + "name": "ocean-marketplace-v4", + "params": { + "address": "0x967da4048cD07aB37855c090aAF366e4ce1b9F48", + "expectedResults": { + "scores": { + "0x7842Fa3B2d87Ff1cd52C4152382f7C4B3406E5A6": 250, + "0x99840Df5Cb42faBE0Feb8811Aaa4BC99cA6C84e0": 200, + "0x903322C7E45A60d7c8C3EA236c5beA9Af86310c7": 50 + } + } + } + }, + "network": "1", + "addresses": [ + "0x7842Fa3B2d87Ff1cd52C4152382f7C4B3406E5A6", + "0x99840Df5Cb42faBE0Feb8811Aaa4BC99cA6C84e0", + "0x903322C7E45A60d7c8C3EA236c5beA9Af86310c7" + ], + "snapshot": 15006609 + }, + { + "name": "ERC-20 OCEAN staked in polygon v4 marketplace via subgraph", + "strategy": { + "name": "ocean-marketplace-v4", + "params": { + "address": "0x282d8efCe846A88B159800bd4130ad77443Fa1A1", + "expectedResults": { + "scores": { + "0x3EFDD8f728c8e774aB81D14d0B2F07a8238960f4": 10762.326857765422, + "0xbbd33AFa85539fa65cc08A2e61a001876D2f13FE": 5752.362504190221, + "0x0363F3C31076a64b85Ceb69a28f958A7c1181CEe": 1750, + "0xC5320Dc3956484662cF3FE3B9355AEA93729783D": 778.6503526737412 + } + } + } + }, + "network": "137", + "addresses": [ + "0x3EFDD8f728c8e774aB81D14d0B2F07a8238960f4", + "0xbbd33AFa85539fa65cc08A2e61a001876D2f13FE", + "0x0363F3C31076a64b85Ceb69a28f958A7c1181CEe", + "0xC5320Dc3956484662cF3FE3B9355AEA93729783D" + ], + "snapshot": 29358635 + }, + { + "name": "ERC-20 OCEAN staked in EWT v4 marketplace via subgraph", + "strategy": { + "name": "ocean-marketplace-v4", + "params": { + "address": "0x593122AAE80A6Fc3183b2AC0c4ab3336dEbeE528", + "expectedResults": { + "scores": { + "0x159924ca0F47D6F704B97E29099b89e518A17B5E": 3489.1235163210085, + "0x4F20e69E7bA5aB2Fb2ae25A1d17C93fE5307faA9": 500.45061032028195 + } + } + } + }, + "network": "246", + "addresses": [ + "0x159924ca0F47D6F704B97E29099b89e518A17B5E", + "0x4F20e69E7bA5aB2Fb2ae25A1d17C93fE5307faA9" + ], + "snapshot": 18788160 + }, + { + "name": "ERC-20 OCEAN staked in MOVR v4 marketplace via subgraph", + "strategy": { + "name": "ocean-marketplace-v4", + "params": { + "address": "0x99C409E5f62E4bd2AC142f17caFb6810B8F0BAAE", + "expectedResults": { + "scores": { + "0xc97fa83746aDe91b0eeB16cb51326a0A980Af7c3": 200, + "0x99840Df5Cb42faBE0Feb8811Aaa4BC99cA6C84e0": 200, + "0xFcd3DfCc1E793D4D03fB4ffFf2B7Eb5A20FCfe4E": 0 + } + } + } + }, + "network": "1285", + "addresses": [ + "0xc97fa83746aDe91b0eeB16cb51326a0A980Af7c3", + "0x99840Df5Cb42faBE0Feb8811Aaa4BC99cA6C84e0", + "0xFcd3DfCc1E793D4D03fB4ffFf2B7Eb5A20FCfe4E" + ], + "snapshot": 2150228 + } +] diff --git a/src/strategies/ocean-marketplace-v4/index.ts b/src/strategies/ocean-marketplace-v4/index.ts new file mode 100644 index 000000000..1ce262366 --- /dev/null +++ b/src/strategies/ocean-marketplace-v4/index.ts @@ -0,0 +1,175 @@ +import { getAddress } from '@ethersproject/address'; +import { subgraphRequest } from '../../utils'; +import { formatUnits, parseUnits } from '@ethersproject/units'; +import { BigNumber } from '@ethersproject/bignumber'; +// import { verifyResultsLength, verifyResults } from './oceanUtils'; + +export const author = 'oceanprotocol'; +export const version = '0.1.0'; + +const OCEAN_ERC20_DECIMALS = 18; +const OCEAN_SUBGRAPH_URL = { + '1': + 'https://v4.subgraph.mainnet.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph', + '3': + 'https://v4.subgraph.ropsten.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph', + '42': + 'https://v4.subgraph.rinkeby.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph', + '56': + 'https://v4.subgraph.bsc.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph', + '137': + 'https://v4.subgraph.polygon.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph', + '246': + 'https://v4.subgraph.energyweb.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph', + '1285': + 'https://v4.subgraph.moonriver.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph', + '1287': + 'https://v4.subgraph.moonbase.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph', + '80001': + 'https://v4.subgraph.mumbai.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph' +}; + +// Returns a BigDecimal as a BigNumber with 10^decimals extra zeros +export function bdToBn(bd, decimals) { + let bn; + const splitDecimal = bd.split('.'); + + if (splitDecimal.length > 1) { + bn = `${splitDecimal[0]}.${splitDecimal[1].slice( + 0, + decimals - splitDecimal[0].length - 1 + )}`; + } else { + bn = `${splitDecimal[0]}`; + } + + const bn2 = parseUnits(bn, decimals); + return bn2; +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const oceanToken = options.address.toLowerCase(); + const params = { + pools: { + __args: { + where: { + baseToken_in: [oceanToken] + }, + first: 1000, + orderBy: 'baseTokenLiquidity', + orderDirection: 'desc' + }, + isFinalized: true, + totalShares: true, + baseTokenLiquidity: true, + shares: { + __args: { + where: { + user_in: addresses.map((address) => address.toLowerCase()) + }, + orderBy: 'shares', + orderDirection: 'desc' + }, + user: { + id: true + }, + shares: true + }, + datatoken: { + holderCount: true + } + } + }; + + if (snapshot !== 'latest') { + // @ts-ignore + params.pools.__args.block = { number: +snapshot }; + } + + // Retrieve the top 1000 pools + const graphResults = await subgraphRequest( + OCEAN_SUBGRAPH_URL[network], + params + ); + + // Get total votes, for ALL addresses, inside top 1000 pools, with a minimum of 0.0001 shares + const score = {}; + const userAddresses: string[] = []; + const return_score = {}; + + // console.log( + // `graph results for network: ${network} at snapshot: ${snapshot}` + // ); + // console.log('results: ', graphResults); + + if (graphResults && graphResults.pools) { + graphResults.pools.forEach((pool) => { + if (pool.isFinalized) { + pool.shares.map((share) => { + const userAddress = getAddress(share.user.id); + // const shares = share.shares; + // console.log( + // `High Level - User address: ${userAddress} user poolShares: ${shares} baseTokenLiquidity: ${pool.baseTokenLiquidity} poolTotalShares: ${pool.totalShares}` + // ); + if (!userAddresses.includes(userAddress)) + userAddresses.push(userAddress); + if (!score[userAddress]) score[userAddress] = BigNumber.from(0); + const userShare = + share.shares * (pool.baseTokenLiquidity / pool.totalShares); + if (userShare > 0.0001) { + score[userAddress] = score[userAddress].add( + bdToBn(userShare.toString(), OCEAN_ERC20_DECIMALS) + ); + } + }); + } + }); + + // We then sum total votes, per user address + userAddresses.forEach((address) => { + const parsedSum = parseFloat( + formatUnits(score[address], OCEAN_ERC20_DECIMALS) + ); + return_score[address] = parsedSum; + + // console.log(`Score for address: ${address} is: ${return_score[address]}`); + }); + } + + // We then filter only the addresses expected + const results = Object.fromEntries( + Object.entries(return_score).filter(([k]) => addresses.indexOf(k) >= 0) + ); + + // Test validation: Update examples.json w/ expectedResults to reflect LPs @ blockHeight + // Success criteria: Address scores and length, must match expectedResults. Order not validated. + // From GRT's graphUtils.ts => verifyResults => Scores need to match expectedResults. + // npm run test --strategy=ocean-marketplace | grep -E 'SUCCESS|ERROR' + // if (options.expectedResults) { + // const expectedResults = {}; + // Object.keys(options.expectedResults.scores).forEach(function (key) { + // expectedResults[key] = results[key]; + // }); + // + // verifyResults( + // JSON.stringify(expectedResults), + // JSON.stringify(options.expectedResults.scores), + // 'Scores' + // ); + // + // verifyResultsLength( + // Object.keys(expectedResults).length, + // Object.keys(options.expectedResults.scores).length, + // 'Scores' + // ); + // } + + return results || {}; +} diff --git a/src/strategies/ocean-marketplace-v4/oceanUtils.ts b/src/strategies/ocean-marketplace-v4/oceanUtils.ts new file mode 100644 index 000000000..be3b22095 --- /dev/null +++ b/src/strategies/ocean-marketplace-v4/oceanUtils.ts @@ -0,0 +1,31 @@ +export function verifyResultsLength( + result: number, + expectedResults: number, + type: string +): void { + if (result === expectedResults) { + console.log( + `>>> SUCCESS: ${type} result:[${result}] match expected results:[${expectedResults}] - length` + ); + } else { + console.error( + `>>> ERROR: ${type} result:[${result}] do not match expected results:[${expectedResults}] - length` + ); + } +} + +export function verifyResults( + result: string, + expectedResults: string, + type: string +): void { + if (result === expectedResults) { + console.log( + `>>> SUCCESS: ${type} result:[${result}] match expected results:[${expectedResults}]` + ); + } else { + console.error( + `>>> ERROR: ${type} result:[${result}] do not match expected results:[${expectedResults}]` + ); + } +} From e98db616fef47b71e30f0d3c3b7b7f207b2d19fd Mon Sep 17 00:00:00 2001 From: David Hunt-Mateo Date: Thu, 7 Jul 2022 02:16:22 -0400 Subject: [PATCH 014/815] Add H2O strategy [h2o] (#700) * Copy erc20-balance-of/ to create h2o/ strategy folder * Fix tests * First cut * Fix block argument assignment * Fix balance calcualation * Run `yarn lint` on h2o * Ensure returned addresses are checksummed * Add additional example addresses * Improve README --- src/strategies/h2o/README.md | 17 +++++++++++ src/strategies/h2o/examples.json | 23 +++++++++++++++ src/strategies/h2o/index.ts | 50 ++++++++++++++++++++++++++++++++ src/strategies/h2o/schema.json | 26 +++++++++++++++++ src/strategies/index.ts | 4 ++- 5 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 src/strategies/h2o/README.md create mode 100644 src/strategies/h2o/examples.json create mode 100644 src/strategies/h2o/index.ts create mode 100644 src/strategies/h2o/schema.json diff --git a/src/strategies/h2o/README.md b/src/strategies/h2o/README.md new file mode 100644 index 000000000..7fa052053 --- /dev/null +++ b/src/strategies/h2o/README.md @@ -0,0 +1,17 @@ +# h2o + +Returns the underlying collateral balance for each voter's H2O vault(s). + +## Params + +- `symbol` - (**Optional**, `string`) Symbol of collateral ERC20 token +- `collateralTypeId` - (**Required**, `string`) Collateral type ID + +Here is an example of parameters: + +```json +{ + "symbol": "OCEAN", + "collateralTypeId": "OCEAN-A", +} +``` diff --git a/src/strategies/h2o/examples.json b/src/strategies/h2o/examples.json new file mode 100644 index 000000000..220727b49 --- /dev/null +++ b/src/strategies/h2o/examples.json @@ -0,0 +1,23 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "h2o", + "params": { + "symbol": "OCEAN", + "collateralTypeId": "OCEAN-A" + } + }, + "network": "1", + "addresses": [ + "0x1EC1CcEF3e1735bdA3F4BA698e8a524AA7c93274", + "0x0ac0240f4656dc80684d0df1208bb91c0220725d", + "0x24a9689d209622fd6def27a21174c1cdfb479483", + "0x650235ffc650d3b3d95c904be345aafb97c586cf", + "0x71d5b84d22b6df54fa6cc6c325ff36c86b9f356c", + "0x933b7dfefae9e2e8385054d1c9b1143d9aeeb069", + "0x99665a5252c15ca3e24fcebab56d0721fb9d1158" + ], + "snapshot": 14678934 + } +] diff --git a/src/strategies/h2o/index.ts b/src/strategies/h2o/index.ts new file mode 100644 index 000000000..07e5122da --- /dev/null +++ b/src/strategies/h2o/index.ts @@ -0,0 +1,50 @@ +import { getAddress } from '@ethersproject/address'; +import { subgraphRequest } from '../../utils'; + +export const author = 'MantisClone'; +export const version = '0.1.0'; + +const SUBGRAPH_URL = { + '1': 'https://api.thegraph.com/subgraphs/name/h2odata/h2o-mainnet' +}; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const params = { + users: { + id: true, + safes: { + collateralType: { + __args: { + where: { + id: options.collateralTypeId + } + } + }, + collateral: true + } + } + }; + if (snapshot !== 'latest') { + // @ts-ignore + params.users.__args = { block: { number: snapshot } }; + } + + const result = await subgraphRequest(SUBGRAPH_URL[network], params); + + return Object.fromEntries( + result.users.map((user) => [ + getAddress(user.id), + user.safes.reduce( + (partialSum, safe) => partialSum + parseFloat(safe.collateral), + 0 + ) + ]) + ); +} diff --git a/src/strategies/h2o/schema.json b/src/strategies/h2o/schema.json new file mode 100644 index 000000000..9b6582082 --- /dev/null +++ b/src/strategies/h2o/schema.json @@ -0,0 +1,26 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "symbol", + "examples": ["e.g. OCEAN"], + "maxLength": 16 + }, + "collateralTypeId": { + "type": "string", + "title": "collateralTypeId", + "examples": ["e.g. OCEAN-A"], + "maxLength": 16 + } + }, + "required": ["collateralTypeId"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index b9c4fef3f..21dda0174 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -330,6 +330,7 @@ import * as unipilotVaultPilotBalance from './unipilot-vault-pilot-balance'; import * as sdBoostTWAVP from './sd-boost-twavp'; import * as apeswap from './apeswap'; import * as solvVoucherClaimable from './solv-voucher-claimable'; +import * as h2o from './h2o'; const strategies = { 'ethermon-erc721': ethermon721, @@ -661,7 +662,8 @@ const strategies = { 'unipilot-vault-pilot-balance': unipilotVaultPilotBalance, 'solv-voucher-claimable': solvVoucherClaimable, 'balance-of-with-linear-vesting-power': balanceOfWithLinearVestingPower, - apeswap + apeswap, + h2o }; Object.keys(strategies).forEach(function (strategyName) { From 6005eae99d6ff5b054ed1502b562b9def42d5e06 Mon Sep 17 00:00:00 2001 From: Idiom <69865342+idiom-bytes@users.noreply.github.com> Date: Thu, 7 Jul 2022 15:14:57 -0500 Subject: [PATCH 015/815] Fix/ocean marketplace v4 [ocean-marketplace-v4] (#703) * Setting custom test for OceanDAO space configuration. * Fixing 50% OCEAN discrepancy due to 50/50 OCEAN/DT LP. * Reverting local changes inside of oceandao repo. --- src/strategies/ocean-marketplace-v4/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategies/ocean-marketplace-v4/index.ts b/src/strategies/ocean-marketplace-v4/index.ts index 1ce262366..331cfc7ae 100644 --- a/src/strategies/ocean-marketplace-v4/index.ts +++ b/src/strategies/ocean-marketplace-v4/index.ts @@ -137,7 +137,7 @@ export async function strategy( const parsedSum = parseFloat( formatUnits(score[address], OCEAN_ERC20_DECIMALS) ); - return_score[address] = parsedSum; + return_score[address] = parsedSum * 2; //this resolves the 50% discrepancy due to 50/50 OCEAN/DT LP // console.log(`Score for address: ${address} is: ${return_score[address]}`); }); From 6ab7f3ad99bc3253f5c8762723d07314ad487579 Mon Sep 17 00:00:00 2001 From: andreibadea20 <105772011+andreibadea20@users.noreply.github.com> Date: Thu, 7 Jul 2022 23:29:22 +0300 Subject: [PATCH 016/815] dps-nft-strategy changed [dps-nft-strategy] (#701) * adding dps-nft-strategy * add ReadMe, delete symbol & decimals from examples.json, add block number when request * update ReadMe * Update README.md * Update src/strategies/balancer-poolid/index.ts * Update test/index.spec.ts * Update test/index.spec.ts * Delete schema.json * Update src/strategies/dps-nft-strategy/examples.json * changed an issue with request * network + URL for request changed * Update src/strategies/dps-nft-strategy/index.ts Co-authored-by: Chaitanya --- src/strategies/dps-nft-strategy/examples.json | 15 +++++++-------- src/strategies/dps-nft-strategy/index.ts | 11 ++++++----- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/strategies/dps-nft-strategy/examples.json b/src/strategies/dps-nft-strategy/examples.json index f3dacdc6c..11d16a78f 100644 --- a/src/strategies/dps-nft-strategy/examples.json +++ b/src/strategies/dps-nft-strategy/examples.json @@ -7,16 +7,15 @@ "symbol": "DPS" } }, - "network": "80001", + "network": "1285", "addresses": [ - "0x0b0db545517b9dabd652596fb26e044841ace4cd", - "0x0c328ffc95155bf02015cb04cc68f7a9cebdb214", - "0x15f48ab7ada1541a205eb9ee20f5a4e76ce3882a", - "0xd88f34679b914c4c677ddc78ae0bad7cdf6760cc", - "0x8705EBf3a34D1F164cCa3Ed2Db54d5f1b7C439F0", - "0x7b64F8508b5f9F12815199F985770A5890e650D0" + "0xa387c8fa7be086d01d063e3426dc3ab5c7c10462", + "0x0e32ebbfe09f59481ea8fc07a6a44501b3158e83", + "0xc0e0e7122c163a8c70c9858e8674c51fb7117e88", + "0x5114e0a7a2fc85685bc114477d7c3035d47daf8b" ], - "snapshot": 27025834 + "snapshot": 2137412 } ] + diff --git a/src/strategies/dps-nft-strategy/index.ts b/src/strategies/dps-nft-strategy/index.ts index f0d09a7b6..dc03b04cc 100644 --- a/src/strategies/dps-nft-strategy/index.ts +++ b/src/strategies/dps-nft-strategy/index.ts @@ -2,19 +2,18 @@ import { getAddress } from '@ethersproject/address'; import { subgraphRequest } from '../../utils'; export const author = 'andreibadea20'; -export const version = '0.1.0'; +export const version = '0.2.0'; const DPS_SUBGRAPH_URL = { - '80001': 'https://api.thegraph.com/subgraphs/name/andreibadea20/subgraph-dps' + '1285': 'https://api.thegraph.com/subgraphs/name/andreibadea20/dps-subgraph-moonriver' }; - const PAGE_SIZE = 1000; const params = { users: { __args: { - block: {number: 22572401}, + block: {number: 793940}, first: PAGE_SIZE, skip: 0 }, @@ -42,6 +41,7 @@ export async function strategy(space, network, provider, addresses, options, sna while (page !== -1) { params.users.__args.skip = page * PAGE_SIZE; const result = await subgraphRequest(DPS_SUBGRAPH_URL[network], params); + if (result && result.users) { result.users.forEach((u) => { @@ -52,7 +52,6 @@ export async function strategy(space, network, provider, addresses, options, sna let lockedNFTs = u.listOfNFTsLocked.length; let claimedNFTs = u.listOfNFTsReturned.length; - userScore = userScore + lockedNFTs - claimedNFTs; if (!score[userAddress]) @@ -60,10 +59,12 @@ export async function strategy(space, network, provider, addresses, options, sna score[userAddress] = userScore; }); page = result.users.length < PAGE_SIZE ? -1 : page + 1; + } else { page = -1; } } + return score || {}; } \ No newline at end of file From ceec82562338a5305409f5999d9a3c0abae585c5 Mon Sep 17 00:00:00 2001 From: 0xBoogey <35139226+crypto-dump@users.noreply.github.com> Date: Sat, 9 Jul 2022 03:51:00 +0800 Subject: [PATCH 017/815] feat: add dopamine strategy [dopamine] (#704) * feat: dopamine-strategy * fix: dopamine strategy Co-authored-by: Chaitanya --- src/strategies/dopamine/README.md | 14 +++++ src/strategies/dopamine/examples.json | 36 +++++++++++ src/strategies/dopamine/index.ts | 86 +++++++++++++++++++++++++++ src/strategies/dopamine/schema.json | 40 +++++++++++++ src/strategies/index.ts | 4 +- 5 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 src/strategies/dopamine/README.md create mode 100644 src/strategies/dopamine/examples.json create mode 100644 src/strategies/dopamine/index.ts create mode 100644 src/strategies/dopamine/schema.json diff --git a/src/strategies/dopamine/README.md b/src/strategies/dopamine/README.md new file mode 100644 index 000000000..87262fd4c --- /dev/null +++ b/src/strategies/dopamine/README.md @@ -0,0 +1,14 @@ +# dopamine + +Combines veDope governance token holders and NFT holders, returning a combined voting power as a percentage of the total. + +Here is an example of parameters: + +```json +{ + "erc20Address": "0x6b175474e89094c44da98b954eedeac495271d0f", + "erc721Address": "0x96b0f2cf48ad9ab21bb7a8a052a3d8391ee64798", + "nftMultiplier": 10000, + "decimals": 4 +} +``` diff --git a/src/strategies/dopamine/examples.json b/src/strategies/dopamine/examples.json new file mode 100644 index 000000000..846a1dc66 --- /dev/null +++ b/src/strategies/dopamine/examples.json @@ -0,0 +1,36 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "dopamine", + "params": { + "tokenAddress": "0x6b175474e89094c44da98b954eedeac495271d0f", + "nftAddress": "0x96b0f2cf48ad9ab21bb7a8a052a3d8391ee64798", + "nftMultiplier": 10000, + "decimals":8 + } + }, + "network": "1", + "addresses": [ + "0xd99c7975ef9b339d93fec21a4ab24a567d686d73", + "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", + "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", + "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", + "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e", + "0x1d5E65a087eBc3d03a294412E46CE5D6882969f4", + "0x1f254336E5c46639A851b9CfC165697150a6c327", + "0x2ec3F80BeDA63Ede96BA20375032CDD3aAfb3030", + "0x4AcBcA6BE2f8D2540bBF4CA77E45dA0A4a095Fa2", + "0x4F3D348a6D09837Ae7961B1E0cEe2cc118cec777", + "0x6D7f23A509E212Ba7773EC1b2505d1A134f54fbe", + "0x07a1f6fc89223c5ebD4e4ddaE89Ac97629856A0f", + "0x8d5F05270da470e015b67Ab5042BDbE2D2FEFB48", + "0x8d07D225a769b7Af3A923481E1FdF49180e6A265", + "0x8f60501dE5b9b01F9EAf1214dbE1924aA97F7fd0", + "0x9B8e8dD9151260c21CB6D7cc59067cd8DF306D58", + "0x17ea92D6FfbAA1c7F6B117c1E9D0c88ABdc8b84C", + "0x38C0039247A31F3939baE65e953612125cB88268" + ], + "snapshot": 15092760 + } +] diff --git a/src/strategies/dopamine/index.ts b/src/strategies/dopamine/index.ts new file mode 100644 index 000000000..9fe5ef5e6 --- /dev/null +++ b/src/strategies/dopamine/index.ts @@ -0,0 +1,86 @@ +import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller, call } from '../../utils'; + +export const author = 'crypto-dump'; +export const version = '0.1.0'; + +const nftContractAbi = [ + 'function balanceOf(address account) external view returns (uint256)', + 'function totalSupply() external view returns (uint256)' +]; + +const tokenContractAbi = [ + 'function balanceOf(address account) external view returns (uint256)', + 'function totalSupply() external view returns (uint256)', + 'function decimals() external view returns (uint256)' +]; + +interface StrategyOptions { + decimals: number; + tokenAddress: string; + nftAddress: string; + nftMultiplier: number; +} + +type MultiCallResult = Record; + +export async function strategy( + space, + network, + provider, + addresses, + options: StrategyOptions, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const callTokenDecimal = () => { + return call(provider, tokenContractAbi, [ + options.tokenAddress, + 'decimals', + [] + ]); + }; + + const makeMulticaller = (abi, contractAddress) => { + const multiCaller = new Multicaller(network, provider, abi, { + blockTag + }); + addresses.forEach((address) => + multiCaller.call(address, contractAddress, 'balanceOf', [address]) + ); + return multiCaller; + }; + + const erc20Multi = makeMulticaller(tokenContractAbi, options.tokenAddress); + const erc721Multi = makeMulticaller(nftContractAbi, options.nftAddress); + + const [tokenDecimal, tokenResults, nftResults]: [ + BigNumber, + MultiCallResult, + MultiCallResult + ] = await Promise.all([ + callTokenDecimal(), + erc20Multi.execute(), + erc721Multi.execute() + ]); + + const scores: Record = {}; + + for (const address of addresses) { + const tokenScore = BigNumber.from(tokenResults[address] || 0); + + const nftScore = BigNumber.from(nftResults[address] || 0) + .mul(options.nftMultiplier) + .mul(BigNumber.from(10).pow(tokenDecimal)); + scores[address] = tokenScore.add(nftScore); + } + + return Object.fromEntries( + Object.entries(scores).map(([address, score]) => [ + address, + parseFloat(formatUnits(score, options.decimals)) + ]) + ); +} diff --git a/src/strategies/dopamine/schema.json b/src/strategies/dopamine/schema.json new file mode 100644 index 000000000..f09f221c1 --- /dev/null +++ b/src/strategies/dopamine/schema.json @@ -0,0 +1,40 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Dopamine", + "type": "object", + "properties": { + "nftMultiplier": { + "type": "number", + "title": "Symbol", + "examples": ["e.g. 10000"] + }, + "tokenAddress": { + "type": "string", + "title": "ERC20 Token Contract address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "nftAddress": { + "type": "string", + "title": "ERC721 NFT Token Contract address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 4"] + } + }, + "required": ["tokenAddress", "nftAddress", "nftMultiplier", "decimals"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 21dda0174..cfee069f6 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -331,6 +331,7 @@ import * as sdBoostTWAVP from './sd-boost-twavp'; import * as apeswap from './apeswap'; import * as solvVoucherClaimable from './solv-voucher-claimable'; import * as h2o from './h2o'; +import * as dopamine from './dopamine'; const strategies = { 'ethermon-erc721': ethermon721, @@ -663,7 +664,8 @@ const strategies = { 'solv-voucher-claimable': solvVoucherClaimable, 'balance-of-with-linear-vesting-power': balanceOfWithLinearVestingPower, apeswap, - h2o + h2o, + dopamine }; Object.keys(strategies).forEach(function (strategyName) { From 338567c39213c3f2af33e9f55df2168e54c4c9b8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 10 Jul 2022 22:09:55 +0530 Subject: [PATCH 018/815] Automated lint (#707) Co-authored-by: ChaituVR --- src/strategies/dopamine/examples.json | 2 +- src/strategies/dps-nft-strategy/examples.json | 2 - src/strategies/dps-nft-strategy/index.ts | 99 ++++++++++--------- .../solv-voucher-claimable/index.ts | 46 ++++----- 4 files changed, 76 insertions(+), 73 deletions(-) diff --git a/src/strategies/dopamine/examples.json b/src/strategies/dopamine/examples.json index 846a1dc66..430389562 100644 --- a/src/strategies/dopamine/examples.json +++ b/src/strategies/dopamine/examples.json @@ -7,7 +7,7 @@ "tokenAddress": "0x6b175474e89094c44da98b954eedeac495271d0f", "nftAddress": "0x96b0f2cf48ad9ab21bb7a8a052a3d8391ee64798", "nftMultiplier": 10000, - "decimals":8 + "decimals": 8 } }, "network": "1", diff --git a/src/strategies/dps-nft-strategy/examples.json b/src/strategies/dps-nft-strategy/examples.json index 11d16a78f..eda6fbc77 100644 --- a/src/strategies/dps-nft-strategy/examples.json +++ b/src/strategies/dps-nft-strategy/examples.json @@ -17,5 +17,3 @@ "snapshot": 2137412 } ] - - diff --git a/src/strategies/dps-nft-strategy/index.ts b/src/strategies/dps-nft-strategy/index.ts index dc03b04cc..6f2001d5b 100644 --- a/src/strategies/dps-nft-strategy/index.ts +++ b/src/strategies/dps-nft-strategy/index.ts @@ -1,70 +1,73 @@ import { getAddress } from '@ethersproject/address'; -import { subgraphRequest } from '../../utils'; +import { subgraphRequest } from '../../utils'; export const author = 'andreibadea20'; export const version = '0.2.0'; const DPS_SUBGRAPH_URL = { - '1285': 'https://api.thegraph.com/subgraphs/name/andreibadea20/dps-subgraph-moonriver' + '1285': + 'https://api.thegraph.com/subgraphs/name/andreibadea20/dps-subgraph-moonriver' }; const PAGE_SIZE = 1000; const params = { - users: { - __args: { - block: {number: 793940}, - first: PAGE_SIZE, - skip: 0 - }, - id: true, - numberOfTokens: true, - listOfNFTsLocked: { - tokenId: true - }, - listOfNFTsReturned: { - tokenId: true - } + users: { + __args: { + block: { number: 793940 }, + first: PAGE_SIZE, + skip: 0 + }, + id: true, + numberOfTokens: true, + listOfNFTsLocked: { + tokenId: true + }, + listOfNFTsReturned: { + tokenId: true } + } }; -export async function strategy(space, network, provider, addresses, options, snapshot) { - - if (snapshot !== 'latest') { - // @ts-ignore - params.users.__args.block = {number: snapshot}; - } - - const score = {}; - let page = 0; +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + if (snapshot !== 'latest') { + // @ts-ignore + params.users.__args.block = { number: snapshot }; + } - while (page !== -1) { - params.users.__args.skip = page * PAGE_SIZE; - const result = await subgraphRequest(DPS_SUBGRAPH_URL[network], params); + const score = {}; + let page = 0; - if (result && result.users) { - result.users.forEach((u) => { + while (page !== -1) { + params.users.__args.skip = page * PAGE_SIZE; + const result = await subgraphRequest(DPS_SUBGRAPH_URL[network], params); - const userAddress = getAddress(u.id); + if (result && result.users) { + result.users.forEach((u) => { + const userAddress = getAddress(u.id); - let userScore = parseInt(u.numberOfTokens); + let userScore = parseInt(u.numberOfTokens); - let lockedNFTs = u.listOfNFTsLocked.length; - let claimedNFTs = u.listOfNFTsReturned.length; + const lockedNFTs = u.listOfNFTsLocked.length; + const claimedNFTs = u.listOfNFTsReturned.length; - userScore = userScore + lockedNFTs - claimedNFTs; + userScore = userScore + lockedNFTs - claimedNFTs; - if (!score[userAddress]) - score[userAddress] = 0; - score[userAddress] = userScore; - }); - page = result.users.length < PAGE_SIZE ? -1 : page + 1; - - } - else { - page = -1; - } + if (!score[userAddress]) score[userAddress] = 0; + score[userAddress] = userScore; + }); + page = result.users.length < PAGE_SIZE ? -1 : page + 1; + } else { + page = -1; } - - return score || {}; - } \ No newline at end of file + } + + return score || {}; +} diff --git a/src/strategies/solv-voucher-claimable/index.ts b/src/strategies/solv-voucher-claimable/index.ts index 555cb3c74..32fb035c3 100644 --- a/src/strategies/solv-voucher-claimable/index.ts +++ b/src/strategies/solv-voucher-claimable/index.ts @@ -1,4 +1,4 @@ -import { BigNumber, FixedNumber} from '@ethersproject/bignumber'; +import { BigNumber, FixedNumber } from '@ethersproject/bignumber'; import { Multicaller } from '../../utils'; export const author = 'mitesh-mutha'; @@ -18,7 +18,6 @@ export async function strategy( options, snapshot ): Promise> { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; // Fetch the balanceOf the addresses i.e. how many vouchers do they hold? @@ -27,45 +26,48 @@ export async function strategy( balanceOfMulti.call(address, options.address, 'balanceOf', [address]) ); const ownedCounts: Record = await balanceOfMulti.execute(); - - // Fetch the voucher token IDs held for each address const tokenIdsMulti = new Multicaller(network, provider, abi, { blockTag }); addresses.map((address) => { - var ownedCount = ownedCounts[address]; + let ownedCount = ownedCounts[address]; while (ownedCount.gt(0)) { - let index = ownedCount.sub(1) - tokenIdsMulti.call(`${address}-${index.toString()}`, options.address, 'tokenOfOwnerByIndex', [address, index.toNumber()]) - ownedCount = index + const index = ownedCount.sub(1); + tokenIdsMulti.call( + `${address}-${index.toString()}`, + options.address, + 'tokenOfOwnerByIndex', + [address, index.toNumber()] + ); + ownedCount = index; } }); const ownerTokenIds: Record = await tokenIdsMulti.execute(); - - // Fetch the voucher data for each voucher held by an address among the address const tokenURIMulti = new Multicaller(network, provider, abi, { blockTag }); - Object.entries(ownerTokenIds).map( ([addressWithIndex, tokenId]) => { - tokenURIMulti.call(`${addressWithIndex}`, options.address, `tokenURI`, [tokenId]) + Object.entries(ownerTokenIds).map(([addressWithIndex, tokenId]) => { + tokenURIMulti.call(`${addressWithIndex}`, options.address, `tokenURI`, [ + tokenId + ]); }); const ownerTokenURIs: Record = await tokenURIMulti.execute(); - - // Go through the list of results and sum up claimable values const claimableVotingPower: Record = {}; - Object.entries(ownerTokenURIs).map( ([addressWithIndex, tokenURI]) => { - var address = addressWithIndex.split("-")[0] - if (tokenURI.split(",")[0] == "data:application/json"){ - var tokenData = JSON.parse(tokenURI.slice(22)) - var claimableAmount = tokenData['properties']['claimableAmount'] - if (!claimableVotingPower[address]) claimableVotingPower[address] = FixedNumber.from(0); - claimableVotingPower[address] = claimableVotingPower[address].addUnsafe(FixedNumber.fromString(claimableAmount)) + Object.entries(ownerTokenURIs).map(([addressWithIndex, tokenURI]) => { + const address = addressWithIndex.split('-')[0]; + if (tokenURI.split(',')[0] == 'data:application/json') { + const tokenData = JSON.parse(tokenURI.slice(22)); + const claimableAmount = tokenData['properties']['claimableAmount']; + if (!claimableVotingPower[address]) + claimableVotingPower[address] = FixedNumber.from(0); + claimableVotingPower[address] = claimableVotingPower[address].addUnsafe( + FixedNumber.fromString(claimableAmount) + ); } }); - // Return the computed values return Object.fromEntries( Object.entries(claimableVotingPower).map(([address, votingPower]) => [ From bd6078d4436096224790f948ded87cec1a915f68 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 10 Jul 2022 22:21:46 +0530 Subject: [PATCH 019/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.8 (#708) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 25 ++++++++++++++++++++----- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 890cc6b35..57f944ee0 100755 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "@ethersproject/strings": "^5.0.5", "@ethersproject/units": "^5.0.3", "@ethersproject/wallet": "^5.4.0", - "@snapshot-labs/snapshot.js": "^0.4.7", + "@snapshot-labs/snapshot.js": "^0.4.8", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.3.1", "cross-fetch": "^3.0.6", diff --git a/yarn.lock b/yarn.lock index 07b00bcbf..f783b9ed2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -304,6 +304,21 @@ "@ethersproject/properties" "^5.5.0" "@ethersproject/strings" "^5.5.0" +"@ethersproject/abi@^5.6.4": + version "5.6.4" + resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.6.4.tgz#f6e01b6ed391a505932698ecc0d9e7a99ee60362" + integrity sha512-TTeZUlCeIHG6527/2goZA6gW5F8Emoc7MrZDC7hhP84aRGvW3TEdTnZR08Ls88YXM1m2SuK42Osw/jSi3uO8gg== + dependencies: + "@ethersproject/address" "^5.6.1" + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/constants" "^5.6.1" + "@ethersproject/hash" "^5.6.1" + "@ethersproject/keccak256" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/strings" "^5.6.1" + "@ethersproject/abstract-provider@^5.5.0": version "5.5.1" resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.5.1.tgz#2f1f6e8a3ab7d378d8ad0b5718460f85649710c5" @@ -1095,13 +1110,13 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.7": - version "0.4.7" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.7.tgz#e1c6ab4fae882d2f0c41c197bba42cd4356105d0" - integrity sha512-yahrG7s1UbHn7uOfDX5wWA926SKoXkKkAhP/d4OvDL0PQxHY5rpf5z5FcVFSQyGFDoqlccYGE3PveGSz4EZ6Ig== +"@snapshot-labs/snapshot.js@^0.4.8": + version "0.4.8" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.8.tgz#392482b441dc4d855c200a9ea566c06abc1e6886" + integrity sha512-bfyKJOghuKUfHyTIVLQZxqjEcR2vwvAmRoPyOZhpTXk6bU00iDaSqoqWykW6MBIP23SGIlxBPT1kD1PMbve+fw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" - "@ethersproject/abi" "^5.0.4" + "@ethersproject/abi" "^5.6.4" "@ethersproject/bytes" "^5.6.1" "@ethersproject/contracts" "^5.0.3" "@ethersproject/hash" "^5.6.1" From e9f5b6a6a579711abd7050fcec2aced49532a464 Mon Sep 17 00:00:00 2001 From: Shadab Khan Date: Mon, 11 Jul 2022 00:45:58 +0530 Subject: [PATCH 020/815] feat: add lrc subgraph balance strategy [lrc-l2-subgraph-balance-of] (#705) * feat: add lrc subgraph balance strategy * feat: increase lrc-l2-subgraph-balance-of limit Co-authored-by: Chaitanya --- src/strategies/index.ts | 4 +- .../lrc-l2-subgraph-balance-of/README.md | 14 +++ .../lrc-l2-subgraph-balance-of/examples.json | 35 +++++++ .../lrc-l2-subgraph-balance-of/index.ts | 93 +++++++++++++++++++ 4 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 src/strategies/lrc-l2-subgraph-balance-of/README.md create mode 100644 src/strategies/lrc-l2-subgraph-balance-of/examples.json create mode 100644 src/strategies/lrc-l2-subgraph-balance-of/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index cfee069f6..0d7e249fd 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -332,6 +332,7 @@ import * as apeswap from './apeswap'; import * as solvVoucherClaimable from './solv-voucher-claimable'; import * as h2o from './h2o'; import * as dopamine from './dopamine'; +import * as lrcL2SubgraphBalanceOf from './lrc-l2-subgraph-balance-of'; const strategies = { 'ethermon-erc721': ethermon721, @@ -665,7 +666,8 @@ const strategies = { 'balance-of-with-linear-vesting-power': balanceOfWithLinearVestingPower, apeswap, h2o, - dopamine + dopamine, + 'lrc-l2-subgraph-balance-of': lrcL2SubgraphBalanceOf }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/lrc-l2-subgraph-balance-of/README.md b/src/strategies/lrc-l2-subgraph-balance-of/README.md new file mode 100644 index 000000000..e77643f32 --- /dev/null +++ b/src/strategies/lrc-l2-subgraph-balance-of/README.md @@ -0,0 +1,14 @@ +# lrc-l2-subgraph-balance-of + +Strategy to read account LRC balance from LoopringV2 subgraph. + +Here is an example of parameters: + +```json +{ + "address": "0x17ea92d6ffbaa1c7f6b117c1e9d0c88abdc8b84c", + "symbol": "LRC", + "tokenId": 1, + "graph": "https://api.thegraph.com/subgraphs/name/juanmardefago/loopring36" +} +``` diff --git a/src/strategies/lrc-l2-subgraph-balance-of/examples.json b/src/strategies/lrc-l2-subgraph-balance-of/examples.json new file mode 100644 index 000000000..e5e058071 --- /dev/null +++ b/src/strategies/lrc-l2-subgraph-balance-of/examples.json @@ -0,0 +1,35 @@ +[ + { + "name": "LoopringV2", + "strategy": { + "name": "lrc-l2-subgraph-balance-of", + "params": { + "symbol": "LRC", + "tokenId": 1, + "graph": "https://api.thegraph.com/subgraphs/name/juanmardefago/loopring36" + } + }, + "network": "1", + "addresses": [ + "0xa478c2975ab1ea89e8196811f51a7b7ade33eb11", + "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", + "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", + "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", + "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e", + "0x1d5E65a087eBc3d03a294412E46CE5D6882969f4", + "0x1f254336E5c46639A851b9CfC165697150a6c327", + "0x2ec3F80BeDA63Ede96BA20375032CDD3aAfb3030", + "0x4AcBcA6BE2f8D2540bBF4CA77E45dA0A4a095Fa2", + "0x4F3D348a6D09837Ae7961B1E0cEe2cc118cec777", + "0x6D7f23A509E212Ba7773EC1b2505d1A134f54fbe", + "0x07a1f6fc89223c5ebD4e4ddaE89Ac97629856A0f", + "0x8d5F05270da470e015b67Ab5042BDbE2D2FEFB48", + "0x8d07D225a769b7Af3A923481E1FdF49180e6A265", + "0x8f60501dE5b9b01F9EAf1214dbE1924aA97F7fd0", + "0x9B8e8dD9151260c21CB6D7cc59067cd8DF306D58", + "0x17ea92D6FfbAA1c7F6B117c1E9D0c88ABdc8b84C", + "0x38C0039247A31F3939baE65e953612125cB88268" + ], + "snapshot": 14437846 + } +] diff --git a/src/strategies/lrc-l2-subgraph-balance-of/index.ts b/src/strategies/lrc-l2-subgraph-balance-of/index.ts new file mode 100644 index 000000000..c144566e8 --- /dev/null +++ b/src/strategies/lrc-l2-subgraph-balance-of/index.ts @@ -0,0 +1,93 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import { subgraphRequest } from '../../utils'; + +export const author = 'shad-k'; +export const version = '0.1.1'; + +const LIMIT = 500; + +function makeQuery(snapshot, addresses, tokenId) { + const query: any = { + accounts: { + __args: { + where: { + address_in: addresses + }, + first: LIMIT + }, + balances: { + __args: { + where: { + token_in: [`${tokenId}`] + } + }, + balance: true, + token: { + decimals: true + } + }, + address: true + } + }; + + if (snapshot !== 'latest') { + query.accounts.__args = { + ...query.accounts.__args, + block: { + number: snapshot + } + }; + } + + return query; +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const _addresses = addresses.map((address) => address.toLowerCase()); + const addressSubsets = Array.apply( + null, + Array(Math.ceil(_addresses.length / LIMIT)) + ).map((_e, i) => _addresses.slice(i * LIMIT, (i + 1) * LIMIT)); + + const response = await Promise.all( + addressSubsets.map((subset) => + subgraphRequest( + options.graph, + makeQuery(snapshot, subset, options.tokenId) + ) + ) + ); + + const accounts = response.map((data) => data.accounts).flat(); + const addressToBalanceMap = Object.fromEntries( + accounts.map((account) => { + if (account.balances.length > 0) { + return [ + account.address, + BigNumber.from(account.balances[0].balance) + .div( + BigNumber.from(10).pow(account.balances[0]?.token?.decimals ?? 18) + ) + .toNumber() + ]; + } + + return [account.address, 0]; + }) + ); + + const scores = Object.fromEntries( + addresses.map((address) => [ + address, + addressToBalanceMap[address.toLowerCase()] + ]) + ); + return scores; +} From 39e1cf07d47466621029f08efcac695252b50e8d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 11 Jul 2022 23:58:26 +0530 Subject: [PATCH 021/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.9 (#709) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 42 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 57f944ee0..eed480471 100755 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "@ethersproject/strings": "^5.0.5", "@ethersproject/units": "^5.0.3", "@ethersproject/wallet": "^5.4.0", - "@snapshot-labs/snapshot.js": "^0.4.8", + "@snapshot-labs/snapshot.js": "^0.4.9", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.3.1", "cross-fetch": "^3.0.6", diff --git a/yarn.lock b/yarn.lock index f783b9ed2..6dae28cbf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1110,10 +1110,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.8": - version "0.4.8" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.8.tgz#392482b441dc4d855c200a9ea566c06abc1e6886" - integrity sha512-bfyKJOghuKUfHyTIVLQZxqjEcR2vwvAmRoPyOZhpTXk6bU00iDaSqoqWykW6MBIP23SGIlxBPT1kD1PMbve+fw== +"@snapshot-labs/snapshot.js@^0.4.9": + version "0.4.9" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.9.tgz#fdac2800d57e52b201aa8e5fc1f5db2bbd15402c" + integrity sha512-5y5sM34tZm1VVxHzwJ5nnm4kb1eRI6CDcBRu0if9gK2H+qadG+yWH9f/boPIB6cskPvH760chRR8bdjseAB25Q== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" @@ -1124,7 +1124,7 @@ "@ethersproject/wallet" "^5.4.0" ajv "^8.6.0" ajv-formats "^2.1.0" - cross-fetch "^3.0.6" + cross-fetch "^3.1.5" json-to-graphql-query "^2.0.0" lodash.set "^4.3.2" @@ -1820,6 +1820,13 @@ cross-fetch@^3.0.6: dependencies: node-fetch "2.6.1" +cross-fetch@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" + integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== + dependencies: + node-fetch "2.6.7" + cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" @@ -3411,6 +3418,13 @@ node-fetch@2.6.1: resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== +node-fetch@2.6.7: + version "2.6.7" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" + integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== + dependencies: + whatwg-url "^5.0.0" + node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -4161,6 +4175,11 @@ toformat@^2.0.0: resolved "https://registry.yarnpkg.com/toformat/-/toformat-2.0.0.tgz#7a043fd2dfbe9021a4e36e508835ba32056739d8" integrity sha512-03SWBVop6nU8bpyZCx7SodpYznbZF5R4ljwNLBcTQzKOD9xuihRo/psX58llS1BMFhhAI08H3luot5GoXJz2pQ== +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + ts-jest@^28.0.5: version "28.0.5" resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-28.0.5.tgz#31776f768fba6dfc8c061d488840ed0c8eeac8b9" @@ -4272,6 +4291,19 @@ walker@^1.0.8: dependencies: makeerror "1.0.12" +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + which-boxed-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" From 7ccfa04d12627e4e13dcc7ce7fb80549df6fa7fc Mon Sep 17 00:00:00 2001 From: Emanuel <34749913+emanuel-sol@users.noreply.github.com> Date: Wed, 13 Jul 2022 12:45:11 -0400 Subject: [PATCH 022/815] Add Forta Shares Voting Strategy [forta-shares] (#710) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🚧 Forta Snapshot Voting Strategy V1 * 🚧 Strategy update * 🚀 Forta Voting Strategy --- src/strategies/forta-shares/README.md | 3 + src/strategies/forta-shares/examples.json | 13 ++++ src/strategies/forta-shares/index.ts | 83 +++++++++++++++++++++++ src/strategies/index.ts | 2 + 4 files changed, 101 insertions(+) create mode 100644 src/strategies/forta-shares/README.md create mode 100644 src/strategies/forta-shares/examples.json create mode 100644 src/strategies/forta-shares/index.ts diff --git a/src/strategies/forta-shares/README.md b/src/strategies/forta-shares/README.md new file mode 100644 index 000000000..bd71ce204 --- /dev/null +++ b/src/strategies/forta-shares/README.md @@ -0,0 +1,3 @@ +# forta-shares + +This strategy calculates the voting power of the FORT shares owned by an address. This strategy requires no parameters. \ No newline at end of file diff --git a/src/strategies/forta-shares/examples.json b/src/strategies/forta-shares/examples.json new file mode 100644 index 000000000..eb58ee0db --- /dev/null +++ b/src/strategies/forta-shares/examples.json @@ -0,0 +1,13 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "forta-shares" + }, + "network": "137", + "addresses": [ + "0x8eedf056de8d0b0fd282cc0d7333488cc5b5d242" + ], + "snapshot": 30451309 + } +] \ No newline at end of file diff --git a/src/strategies/forta-shares/index.ts b/src/strategies/forta-shares/index.ts new file mode 100644 index 000000000..45730ef8d --- /dev/null +++ b/src/strategies/forta-shares/index.ts @@ -0,0 +1,83 @@ +import fetch from 'cross-fetch'; +import { multicall } from '../../utils'; +import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; + +export const author = 'emanuel-sol'; +export const version = '0.0.1'; + +const STAKING_CONTRACT = '0xd2863157539b1D11F39ce23fC4834B62082F6874'; +const abi = [ + 'function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) view returns (uint256[] memory)' +]; + +const calculateVotingPower = (userVotingPower, addresses, balances) => { + for (let i = 0; i < addresses.length; i++) { + userVotingPower[addresses[i]] = userVotingPower[addresses[i]] || BigNumber.from(0); + + const balance = balances[i]; + + userVotingPower[addresses[i]] = userVotingPower[addresses[i]].add(balance); + } + return userVotingPower +}; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const params = { + 'addresses': addresses + } + + const response = await fetch("https://api.forta.network/stats/shares", { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify(params) + }); + + const data = await response.json(); + + const batchAddresses = []; + const batchShareIds = []; + + data.shares.forEach((valuePair) => { + if (valuePair.shares) { + valuePair.shares.forEach((share) => { + batchAddresses.push(addresses.find((addr) => addr.toLowerCase() === share.shareholder.toLowerCase())); + batchShareIds.push(share.shareId); + }); + } + }); + + const result = await multicall( + network, + provider, + abi, + [ + [STAKING_CONTRACT, 'balanceOfBatch', [batchAddresses, batchShareIds]] + ], + { blockTag } + ); + + let userVotingPower = {}; + + userVotingPower = calculateVotingPower(userVotingPower, batchAddresses, result[0][0]); + + + return Object.fromEntries( + Object.entries(userVotingPower).map((addressBalancePair) => [ + addressBalancePair[0], + parseFloat(formatUnits(addressBalancePair[1], 18)) + ]) + ); +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 0d7e249fd..0eef640c0 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -329,12 +329,14 @@ import * as earthfundChildDaoStakingBalance from './earthfund-child-dao-staking- import * as unipilotVaultPilotBalance from './unipilot-vault-pilot-balance'; import * as sdBoostTWAVP from './sd-boost-twavp'; import * as apeswap from './apeswap'; +import * as fortaShares from './forta-shares'; import * as solvVoucherClaimable from './solv-voucher-claimable'; import * as h2o from './h2o'; import * as dopamine from './dopamine'; import * as lrcL2SubgraphBalanceOf from './lrc-l2-subgraph-balance-of'; const strategies = { + 'forta-shares': fortaShares, 'ethermon-erc721': ethermon721, 'recusal-list': recusalList, 'landdao-token-tiers': landDaoTiers, From 16c7c916079c987e6a8704562009e55c37642f17 Mon Sep 17 00:00:00 2001 From: Fabien Date: Fri, 15 Jul 2022 10:14:04 +0700 Subject: [PATCH 023/815] Add getVp and getDelegations functions (#706) * Add getVp and getDelegations functions * Update dependencies * Fix lint * Rename delegation functions Co-authored-by: Chaitanya --- .eslintignore | 1 - .eslintrc | 1 + .prettierrc | 4 + .prettierrc.js | 4 - jest.config.js | 2 +- package.json | 58 +- src/strategies/aavegotchi-agip-17/index.ts | 4 +- .../index.ts | 18 +- src/strategies/banksy-dao/index.ts | 18 +- .../blockzerolabs-cryptonauts/index.ts | 6 +- src/strategies/bsc-mvb/index.ts | 8 +- src/strategies/coinswap/index.ts | 18 +- .../crucible-erc20-balance-of/index.ts | 18 +- .../decentraland-wearable-rarity/index.ts | 6 +- .../erc1155-all-balances-of/index.ts | 3 +- src/strategies/erc20-received/index.ts | 2 +- src/strategies/erc721-with-metadata/index.ts | 12 +- .../index.ts | 12 +- .../ethercats-founder-series/index.ts | 3 +- .../ethercats-founders-series/index.ts | 3 +- src/strategies/faraland-staking/index.ts | 6 +- src/strategies/flashstake/index.ts | 3 +- src/strategies/forta-shares/examples.json | 6 +- src/strategies/forta-shares/index.ts | 30 +- src/strategies/galaxy-nft-with-score/index.ts | 8 +- src/strategies/gamium-voting/index.ts | 6 +- .../giveth-balancer-balance/index.ts | 9 +- src/strategies/index.ts | 6 +- .../infinityprotocol-liquidity-pools/index.ts | 3 +- src/strategies/landdao-token-tiers/index.ts | 12 +- .../liquidity-token-provide/index.ts | 3 +- .../index.ts | 7 +- .../masterchef-pool-balance/index.ts | 7 +- src/strategies/math/index.ts | 127 +- src/strategies/ocean-dao-brightid/index.ts | 6 +- src/strategies/ocean-marketplace-v4/index.ts | 12 +- src/strategies/ocean-marketplace/index.ts | 9 +- src/strategies/pob-hash/index.ts | 6 +- src/strategies/polis-balance/index.ts | 18 +- .../protofi-erc721-tier-weighted/index.ts | 24 +- src/strategies/reverse-voting-escrow/index.ts | 18 +- .../rocketpool-node-operator/index.ts | 6 +- src/strategies/rowdy-roos/index.ts | 6 +- .../safety-module-bpt-power/index.ts | 31 +- src/strategies/saffron-finance/index.ts | 3 +- src/strategies/sandman-dao/index.ts | 18 +- src/strategies/snowswap/index.ts | 6 +- .../staking-claimed-unclaimed/index.ts | 6 +- .../synthetix-non-quadratic/index.ts | 5 +- src/strategies/synthetix-quadratic/index.ts | 5 +- src/strategies/synthetix/index.ts | 3 +- src/strategies/synthetix_1/index.ts | 12 +- src/strategies/the-graph/graphUtils.ts | 6 +- src/strategies/the-graph/tokenLockWallets.ts | 8 +- src/strategies/tokenlon/index.ts | 19 +- src/strategies/ve-balance-of-at-nft/index.ts | 18 +- src/strategies/ve-ribbon/index.ts | 6 +- src/strategies/volt-voting-power/index.ts | 3 +- src/strategies/xdai-stake-delegation/index.ts | 6 +- src/utils/delegations.json | 9 + src/utils/vp.ts | 218 +++ test/__snapshots__/delegation.test.ts.snap | 37 + test/__snapshots__/vp.test.ts.snap | 27 + test/delegation.test.ts | 14 + test/{ => examples}/delegation.ts | 2 +- test/{ => examples}/scores.ts | 4 +- test/{index.spec.ts => strategy.test.ts} | 2 +- test/vp.test.ts | 59 + tsconfig.json | 2 +- yarn.lock | 1367 ++++++++--------- 70 files changed, 1319 insertions(+), 1116 deletions(-) delete mode 100644 .eslintignore create mode 100644 .prettierrc delete mode 100644 .prettierrc.js create mode 100644 src/utils/delegations.json create mode 100644 src/utils/vp.ts create mode 100644 test/__snapshots__/delegation.test.ts.snap create mode 100644 test/__snapshots__/vp.test.ts.snap create mode 100644 test/delegation.test.ts rename test/{ => examples}/delegation.ts (91%) rename test/{ => examples}/scores.ts (98%) rename test/{index.spec.ts => strategy.test.ts} (100%) create mode 100644 test/vp.test.ts diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 53c37a166..000000000 --- a/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -dist \ No newline at end of file diff --git a/.eslintrc b/.eslintrc index 815d5b6e6..6118d728d 100644 --- a/.eslintrc +++ b/.eslintrc @@ -21,6 +21,7 @@ "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/ban-ts-comment": "off", "@typescript-eslint/no-var-requires": "off", + "@typescript-eslint/no-loss-of-precision": "off", "prefer-spread": "off" } } diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..32ebab4e5 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +{ + "singleQuote": true, + "trailingComma": "none" +} diff --git a/.prettierrc.js b/.prettierrc.js deleted file mode 100644 index f0722fd99..000000000 --- a/.prettierrc.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - singleQuote: true, - trailingComma: 'none' -}; diff --git a/jest.config.js b/jest.config.js index 6e67c3cfc..54b6941a8 100644 --- a/jest.config.js +++ b/jest.config.js @@ -4,5 +4,5 @@ module.exports = { transform: { '^.+\\.tsx?$': 'ts-jest' }, - testRegex: '/test(/(integration|unit))?/.*\\.spec\\.ts$' + testRegex: '/test(/(integration|unit))?/.*\\.test\\.ts$' }; diff --git a/package.json b/package.json index eed480471..bee71e2ca 100755 --- a/package.json +++ b/package.json @@ -13,45 +13,47 @@ "license": "MIT", "scripts": { "build": "tsc -p .", - "test": "jest -i", + "test": "jest -i strategy.test.ts", + "test:vp": "jest -i vp.test.ts", + "test:delegation": "jest -i delegation.test.ts", "prepublishOnly": "npm run build", "prepare": "npm run build", "postbuild": "copyfiles -u 1 src/**/*.md dist/ && copyfiles -u 1 src/**/*.json dist/", - "lint": "eslint . --ext .ts,.json --fix" + "lint": "eslint src/ test/ --ext .ts,.json --fix" }, "dependencies": { - "@ethersproject/abi": "^5.0.4", - "@ethersproject/address": "^5.0.4", - "@ethersproject/bignumber": "^5.0.12", - "@ethersproject/bytes": "^5.0.8", - "@ethersproject/contracts": "^5.0.3", - "@ethersproject/hash": "^5.0.9", - "@ethersproject/providers": "^5.3.1", - "@ethersproject/solidity": "^5.0.10", - "@ethersproject/strings": "^5.0.5", - "@ethersproject/units": "^5.0.3", - "@ethersproject/wallet": "^5.4.0", - "@snapshot-labs/snapshot.js": "^0.4.9", + "@ethersproject/abi": "^5.6.4", + "@ethersproject/address": "^5.6.1", + "@ethersproject/bignumber": "^5.6.2", + "@ethersproject/bytes": "^5.6.1", + "@ethersproject/contracts": "^5.6.2", + "@ethersproject/hash": "^5.6.1", + "@ethersproject/providers": "^5.6.8", + "@ethersproject/solidity": "^5.6.1", + "@ethersproject/strings": "^5.6.1", + "@ethersproject/units": "^5.6.1", + "@ethersproject/wallet": "^5.6.2", + "@snapshot-labs/snapshot.js": "^0.4.8", "@uniswap/sdk-core": "^3.0.1", - "@uniswap/v3-sdk": "^3.3.1", - "cross-fetch": "^3.0.6", + "@uniswap/v3-sdk": "^3.9.0", + "cross-fetch": "^3.1.5", "eth-ens-namehash": "^2.0.8", - "json-to-graphql-query": "^2.0.0" + "json-to-graphql-query": "^2.2.4" }, "devDependencies": { - "@types/jest": "^26.0.23", - "@types/node": "^13.9.5", - "@typescript-eslint/eslint-plugin": "^4.28.2", - "@typescript-eslint/parser": "^4.28.2", + "@types/jest": "^28.1.4", + "@types/node": "^18.0.3", + "@typescript-eslint/eslint-plugin": "^5.30.5", + "@typescript-eslint/parser": "^5.30.5", "copyfiles": "^2.4.1", - "eslint": "^6.8.0", - "eslint-config-airbnb-base": "^14.1.0", - "eslint-plugin-import": "^2.20.2", - "eslint-plugin-prettier": "^3.4.0", - "jest": "^28.1.1", - "prettier": "2.2.0", + "eslint": "^8.19.0", + "eslint-config-airbnb-base": "^15.0.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-prettier": "^4.2.1", + "jest": "^28.1.2", + "prettier": "^2.7.1", "ts-jest": "^28.0.5", - "typescript": "^4.2.3" + "typescript": "^4.7.4" }, "engines": { "node": ">=14" diff --git a/src/strategies/aavegotchi-agip-17/index.ts b/src/strategies/aavegotchi-agip-17/index.ts index 308de7604..981cc2b24 100644 --- a/src/strategies/aavegotchi-agip-17/index.ts +++ b/src/strategies/aavegotchi-agip-17/index.ts @@ -84,12 +84,12 @@ export async function strategy( let realmVotingPowerValue = 0; const res = userToInfo[addr.toLowerCase()]; if (res) { - const parcelsOwned = (Object.entries(res) + const parcelsOwned = Object.entries(res) .map(([key, val]) => { if (key.startsWith('parcelsOwned')) return val; else return []; }) - .flat(1) as unknown) as { size: number }[]; + .flat(1) as unknown as { size: number }[]; if (parcelsOwned.length > 0) { parcelsOwned.map((r: { size: number }) => { let votePower = realmSizeVotePower[r.size]; diff --git a/src/strategies/balance-of-with-linear-vesting-power/index.ts b/src/strategies/balance-of-with-linear-vesting-power/index.ts index 507c089a0..a504ec5e0 100644 --- a/src/strategies/balance-of-with-linear-vesting-power/index.ts +++ b/src/strategies/balance-of-with-linear-vesting-power/index.ts @@ -61,10 +61,8 @@ export async function strategy( addresses.forEach((address) => multiBalanceOf.call(address, options.ERC20Address, 'balanceOf', [address]) ); - const addressesBalanceOf: Record< - string, - BigNumberish - > = await multiBalanceOf.execute(); + const addressesBalanceOf: Record = + await multiBalanceOf.execute(); // And then, we fetch the vesting data for each vesting ID // 1. vester address @@ -90,10 +88,8 @@ export async function strategy( ids.forEach((id) => multiVestTotCaller.call(id, options.DSSVestAddress, 'tot', [id]) ); - const multiVestTot: Record< - string, - BigNumberish - > = await multiVestTotCaller.execute(); + const multiVestTot: Record = + await multiVestTotCaller.execute(); // 3. total claimed const multiVestAccruedCaller = new Multicaller( @@ -105,10 +101,8 @@ export async function strategy( ids.forEach((id) => multiVestAccruedCaller.call(id, options.DSSVestAddress, 'accrued', [id]) ); - const multiVestAccrued: Record< - string, - BigNumberish - > = await multiVestAccruedCaller.execute(); + const multiVestAccrued: Record = + await multiVestAccruedCaller.execute(); return Object.fromEntries( Object.entries(addressesBalanceOf).map(([address, balance]) => { const initialVotingPower = [ diff --git a/src/strategies/banksy-dao/index.ts b/src/strategies/banksy-dao/index.ts index 939d5effa..37b5d2bb6 100644 --- a/src/strategies/banksy-dao/index.ts +++ b/src/strategies/banksy-dao/index.ts @@ -34,10 +34,8 @@ export async function strategy( walletAddress ]); } - const walletToBalanceOf: Record< - string, - BigNumber - > = await callWalletToBalanceOf.execute(); + const walletToBalanceOf: Record = + await callWalletToBalanceOf.execute(); // Second, get the tokenId's for each nft const callWalletToAddresses = new Multicaller( @@ -58,10 +56,8 @@ export async function strategy( ); } } - const walletIDToAddresses: Record< - string, - BigNumber - > = await callWalletToAddresses.execute(); + const walletIDToAddresses: Record = + await callWalletToAddresses.execute(); // Third, get skil's for each tokenId const callTokenToSkill = new Multicaller(network, provider, factoryNftABI, { @@ -73,10 +69,8 @@ export async function strategy( tokenId ]); } - const walletIDToSkills: Record< - string, - any - > = await callTokenToSkill.execute(); + const walletIDToSkills: Record = + await callTokenToSkill.execute(); const results = {} as Record; for (const [walletID, values] of Object.entries(walletIDToSkills)) { diff --git a/src/strategies/blockzerolabs-cryptonauts/index.ts b/src/strategies/blockzerolabs-cryptonauts/index.ts index 2c36e3dd2..36a23f879 100644 --- a/src/strategies/blockzerolabs-cryptonauts/index.ts +++ b/src/strategies/blockzerolabs-cryptonauts/index.ts @@ -62,10 +62,8 @@ export async function strategy( ]); } } - const vaultBalance: Record< - number, - BigNumberish - > = await vaultBalanceMulti.execute(); + const vaultBalance: Record = + await vaultBalanceMulti.execute(); // Iterate over each address provided const balances: Record = {}; diff --git a/src/strategies/bsc-mvb/index.ts b/src/strategies/bsc-mvb/index.ts index 513ece97b..552cdedcb 100644 --- a/src/strategies/bsc-mvb/index.ts +++ b/src/strategies/bsc-mvb/index.ts @@ -117,8 +117,8 @@ export async function strategy( addresses.map((addr) => [addr.toLowerCase(), {}]) ); const ownerToScore: OwnerToScore = {}; - const ownersWithNfts: OwnerWithNfts[] = graphqlData.data.allNFTsByOwnersCoresAndChain.reduce( - (map, item) => { + const ownersWithNfts: OwnerWithNfts[] = + graphqlData.data.allNFTsByOwnersCoresAndChain.reduce((map, item) => { map[item.owner.toLowerCase()] = item.nfts.reduce((m, i) => { if (!options.params.blacklistNFTID?.includes(i.id)) { m[ @@ -130,9 +130,7 @@ export async function strategy( return m; }, {}); return map; - }, - {} - ); + }, {}); const subgraphOwnersWithNfts: OwnerWithNfts[] = subgraphData.accounts.reduce( (map, item) => { map[item.id] = item.balances.reduce((m, i) => { diff --git a/src/strategies/coinswap/index.ts b/src/strategies/coinswap/index.ts index f4f3e86b9..589a167cc 100644 --- a/src/strategies/coinswap/index.ts +++ b/src/strategies/coinswap/index.ts @@ -64,10 +64,8 @@ export async function strategy( addresses.forEach((address) => multiMasterCSS.call(address, options.masterCSS, 'userInfo', ['0', address]) ); - const resultMasterCSS: Record< - string, - BigNumberish - > = await multiMasterCSS.execute(); + const resultMasterCSS: Record = + await multiMasterCSS.execute(); /* Balance in Launch pools @@ -91,10 +89,8 @@ export async function strategy( ) ); }); - const communityStakeCSS: Record< - string, - BigNumberish - > = await multiCommunityStake.execute(); + const communityStakeCSS: Record = + await multiCommunityStake.execute(); /* Staked LPs in CSS farms @@ -116,10 +112,8 @@ export async function strategy( ) ); }); - const resultCssLPs: Record< - string, - BigNumberish - > = await multiCssLPs.execute(); + const resultCssLPs: Record = + await multiCssLPs.execute(); const userBalances: any = []; for (let i = 0; i < addresses.length - 1; i++) { diff --git a/src/strategies/crucible-erc20-balance-of/index.ts b/src/strategies/crucible-erc20-balance-of/index.ts index f92a9ecea..d18eea6cc 100644 --- a/src/strategies/crucible-erc20-balance-of/index.ts +++ b/src/strategies/crucible-erc20-balance-of/index.ts @@ -42,10 +42,8 @@ export async function strategy( [walletAddress] ); } - const walletToCrucibleCount: Record< - string, - BigNumber - > = await callWalletToCrucibleCount.execute(); + const walletToCrucibleCount: Record = + await callWalletToCrucibleCount.execute(); // get the address of each crucible // wallet_address : crucible_index => crucible_address @@ -70,10 +68,8 @@ export async function strategy( ); } } - const walletIDToCrucibleAddresses: Record< - string, - BigNumber - > = await callWalletToCrucibleAddresses.execute(); + const walletIDToCrucibleAddresses: Record = + await callWalletToCrucibleAddresses.execute(); // get the balance of each crucible // crucible_address => lp_balance @@ -88,10 +84,8 @@ export async function strategy( hexZeroPad(crucibleAddress.toHexString(), 20) ]); } - const walletIDToLpBalance: Record< - string, - BigNumber - > = await callCrucibleToLpBalance.execute(); + const walletIDToLpBalance: Record = + await callCrucibleToLpBalance.execute(); // sum the amount of LP tokens held across all crucibles // wallet_address => lp_balance diff --git a/src/strategies/decentraland-wearable-rarity/index.ts b/src/strategies/decentraland-wearable-rarity/index.ts index 358bb3c76..85257adb6 100644 --- a/src/strategies/decentraland-wearable-rarity/index.ts +++ b/src/strategies/decentraland-wearable-rarity/index.ts @@ -5,10 +5,8 @@ export const author = '2fd'; export const version = '0.1.0'; const DECENTRALAND_COLLECTIONS_SUBGRAPH_URL = { - '1': - 'https://api.thegraph.com/subgraphs/name/decentraland/collections-ethereum-mainnet', - '3': - 'https://api.thegraph.com/subgraphs/name/decentraland/collections-ethereum-ropsten', + '1': 'https://api.thegraph.com/subgraphs/name/decentraland/collections-ethereum-mainnet', + '3': 'https://api.thegraph.com/subgraphs/name/decentraland/collections-ethereum-ropsten', '137': 'https://api.thegraph.com/subgraphs/name/decentraland/collections-matic-mainnet', '80001': diff --git a/src/strategies/erc1155-all-balances-of/index.ts b/src/strategies/erc1155-all-balances-of/index.ts index 0d20a4f20..d73fce64e 100644 --- a/src/strategies/erc1155-all-balances-of/index.ts +++ b/src/strategies/erc1155-all-balances-of/index.ts @@ -5,8 +5,7 @@ export const author = 'snapshot-labs'; export const version = '0.2.0'; const SUBGRAPH_URL = { - '1': - 'https://gateway.thegraph.com/api/94c3f5dd3947e2f62fc6e0e757549ee7/subgraphs/id/GCQVLurkeZrdMf4t5v5NyeWJY8pHhfE9sinjFMjLYd9C' + '1': 'https://gateway.thegraph.com/api/94c3f5dd3947e2f62fc6e0e757549ee7/subgraphs/id/GCQVLurkeZrdMf4t5v5NyeWJY8pHhfE9sinjFMjLYd9C' }; const HOSTED_SUBGRAPH_URL = { diff --git a/src/strategies/erc20-received/index.ts b/src/strategies/erc20-received/index.ts index 7a5effb07..99c8bba03 100644 --- a/src/strategies/erc20-received/index.ts +++ b/src/strategies/erc20-received/index.ts @@ -56,7 +56,7 @@ export async function strategy( }, body: JSON.stringify({ query: /* GraphQL */ ` - query( + query ( $query: String! $sort: SORT $low: Int64 diff --git a/src/strategies/erc721-with-metadata/index.ts b/src/strategies/erc721-with-metadata/index.ts index 570a8f2db..d866b0361 100644 --- a/src/strategies/erc721-with-metadata/index.ts +++ b/src/strategies/erc721-with-metadata/index.ts @@ -32,10 +32,8 @@ export async function strategy( walletAddress ]); } - const walletToBalanceOf: Record< - string, - BigNumber - > = await callWalletToBalanceOf.execute(); + const walletToBalanceOf: Record = + await callWalletToBalanceOf.execute(); // 3rd, get tokenIds for each address, and index const callWalletIdToTokenID = new Multicaller(network, provider, abi, { @@ -53,10 +51,8 @@ export async function strategy( } } } - const walletIdToTokenID: Record< - string, - BigNumber - > = await callWalletIdToTokenID.execute(); + const walletIdToTokenID: Record = + await callWalletIdToTokenID.execute(); // 4th, sum up metadata value for each address const walletToAttributeValue = {} as Record; diff --git a/src/strategies/erc721-with-tokenid-range-weights/index.ts b/src/strategies/erc721-with-tokenid-range-weights/index.ts index a0e91ed29..f88e86999 100644 --- a/src/strategies/erc721-with-tokenid-range-weights/index.ts +++ b/src/strategies/erc721-with-tokenid-range-weights/index.ts @@ -28,10 +28,8 @@ export async function strategy( walletAddress ]); } - const walletToBalanceOf: Record< - string, - BigNumber - > = await callWalletToBalanceOf.execute(); + const walletToBalanceOf: Record = + await callWalletToBalanceOf.execute(); // Second, get the tokenId's for each token const callWalletToAddresses = new Multicaller(network, provider, abi, { @@ -47,10 +45,8 @@ export async function strategy( ); } } - const walletIDToAddresses: Record< - string, - BigNumber - > = await callWalletToAddresses.execute(); + const walletIDToAddresses: Record = + await callWalletToAddresses.execute(); // Third, sum the weights for each tokenId by finding it's range const walletToLpBalance = {} as Record; diff --git a/src/strategies/ethercats-founder-series/index.ts b/src/strategies/ethercats-founder-series/index.ts index 8a077344a..2a4736594 100644 --- a/src/strategies/ethercats-founder-series/index.ts +++ b/src/strategies/ethercats-founder-series/index.ts @@ -5,8 +5,7 @@ export const version = '1.0.0'; // Constants const url = { - '1': - 'https://gateway.thegraph.com/api/656e05ff867c74eeb11bf0199ff5de86/subgraphs/id/0x7859821024e633c5dc8a4fcf86fc52e7720ce525-1' + '1': 'https://gateway.thegraph.com/api/656e05ff867c74eeb11bf0199ff5de86/subgraphs/id/0x7859821024e633c5dc8a4fcf86fc52e7720ce525-1' }; const getPower = (id, value) => { diff --git a/src/strategies/ethercats-founders-series/index.ts b/src/strategies/ethercats-founders-series/index.ts index 7f75a0580..06ca6d8cb 100644 --- a/src/strategies/ethercats-founders-series/index.ts +++ b/src/strategies/ethercats-founders-series/index.ts @@ -5,8 +5,7 @@ export const version = '1.0.0'; // Constants const url = { - '1': - 'https://gateway.thegraph.com/api/656e05ff867c74eeb11bf0199ff5de86/subgraphs/id/0x7859821024e633c5dc8a4fcf86fc52e7720ce525-1' + '1': 'https://gateway.thegraph.com/api/656e05ff867c74eeb11bf0199ff5de86/subgraphs/id/0x7859821024e633c5dc8a4fcf86fc52e7720ce525-1' }; const getPower = (id, value) => { diff --git a/src/strategies/faraland-staking/index.ts b/src/strategies/faraland-staking/index.ts index 8f2429af4..1357adde0 100644 --- a/src/strategies/faraland-staking/index.ts +++ b/src/strategies/faraland-staking/index.ts @@ -2,10 +2,8 @@ import { getAddress } from '@ethersproject/address'; import { subgraphRequest } from '../../utils'; const FLASHSTAKE_SUBGRAPH_URL = { - '1': - 'https://queries-graphnode.faraland.io/subgraphs/name/edwardevans094/farastore-v12', - '56': - 'https://queries-graphnode.faraland.io/subgraphs/name/edwardevans094/farastore-v12' + '1': 'https://queries-graphnode.faraland.io/subgraphs/name/edwardevans094/farastore-v12', + '56': 'https://queries-graphnode.faraland.io/subgraphs/name/edwardevans094/farastore-v12' }; export const author = 'edwardEvans094'; diff --git a/src/strategies/flashstake/index.ts b/src/strategies/flashstake/index.ts index c7025d8c8..e6e0e0fd9 100644 --- a/src/strategies/flashstake/index.ts +++ b/src/strategies/flashstake/index.ts @@ -2,8 +2,7 @@ import { getAddress } from '@ethersproject/address'; import { subgraphRequest } from '../../utils'; const FLASHSTAKE_SUBGRAPH_URL = { - '1': - 'https://api.thegraph.com/subgraphs/name/blockzerohello/flash-stake-stats-v2-subgraph' + '1': 'https://api.thegraph.com/subgraphs/name/blockzerohello/flash-stake-stats-v2-subgraph' }; export const author = 'anassohail99'; diff --git a/src/strategies/forta-shares/examples.json b/src/strategies/forta-shares/examples.json index eb58ee0db..26e25c56c 100644 --- a/src/strategies/forta-shares/examples.json +++ b/src/strategies/forta-shares/examples.json @@ -5,9 +5,7 @@ "name": "forta-shares" }, "network": "137", - "addresses": [ - "0x8eedf056de8d0b0fd282cc0d7333488cc5b5d242" - ], + "addresses": ["0x8eedf056de8d0b0fd282cc0d7333488cc5b5d242"], "snapshot": 30451309 } -] \ No newline at end of file +] diff --git a/src/strategies/forta-shares/index.ts b/src/strategies/forta-shares/index.ts index 45730ef8d..9bc71f1c4 100644 --- a/src/strategies/forta-shares/index.ts +++ b/src/strategies/forta-shares/index.ts @@ -13,13 +13,14 @@ const abi = [ const calculateVotingPower = (userVotingPower, addresses, balances) => { for (let i = 0; i < addresses.length; i++) { - userVotingPower[addresses[i]] = userVotingPower[addresses[i]] || BigNumber.from(0); + userVotingPower[addresses[i]] = + userVotingPower[addresses[i]] || BigNumber.from(0); const balance = balances[i]; userVotingPower[addresses[i]] = userVotingPower[addresses[i]].add(balance); } - return userVotingPower + return userVotingPower; }; export async function strategy( @@ -33,10 +34,10 @@ export async function strategy( const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; const params = { - 'addresses': addresses - } + addresses: addresses + }; - const response = await fetch("https://api.forta.network/stats/shares", { + const response = await fetch('https://api.forta.network/stats/shares', { method: 'POST', headers: { Accept: 'application/json', @@ -48,12 +49,16 @@ export async function strategy( const data = await response.json(); const batchAddresses = []; - const batchShareIds = []; + const batchShareIds = []; data.shares.forEach((valuePair) => { if (valuePair.shares) { valuePair.shares.forEach((share) => { - batchAddresses.push(addresses.find((addr) => addr.toLowerCase() === share.shareholder.toLowerCase())); + batchAddresses.push( + addresses.find( + (addr) => addr.toLowerCase() === share.shareholder.toLowerCase() + ) + ); batchShareIds.push(share.shareId); }); } @@ -63,16 +68,17 @@ export async function strategy( network, provider, abi, - [ - [STAKING_CONTRACT, 'balanceOfBatch', [batchAddresses, batchShareIds]] - ], + [[STAKING_CONTRACT, 'balanceOfBatch', [batchAddresses, batchShareIds]]], { blockTag } ); let userVotingPower = {}; - userVotingPower = calculateVotingPower(userVotingPower, batchAddresses, result[0][0]); - + userVotingPower = calculateVotingPower( + userVotingPower, + batchAddresses, + result[0][0] + ); return Object.fromEntries( Object.entries(userVotingPower).map((addressBalancePair) => [ diff --git a/src/strategies/galaxy-nft-with-score/index.ts b/src/strategies/galaxy-nft-with-score/index.ts index cd9066337..2797aba1f 100644 --- a/src/strategies/galaxy-nft-with-score/index.ts +++ b/src/strategies/galaxy-nft-with-score/index.ts @@ -136,8 +136,8 @@ export async function strategy( ); const ownerToScore: OwnerToScore = {}; - const ownersWithNfts: OwnerWithNfts = graphqlData.data.allNFTsByOwnersCoresAndChain.reduce( - (map, item) => { + const ownersWithNfts: OwnerWithNfts = + graphqlData.data.allNFTsByOwnersCoresAndChain.reduce((map, item) => { map[item.owner.toLowerCase()] = item.nfts.reduce((m, i) => { if (!options.params.blacklistNFTID?.includes(i.id)) { m[i.nftCore.contractAddress.toLowerCase() + '-' + i.id] = i.name; @@ -145,9 +145,7 @@ export async function strategy( return m; }, {}); return map; - }, - {} - ); + }, {}); const subgraphOwnersWithNfts: OwnerWithNfts = {}; subgraphData.nftContracts.forEach((nftContract) => { diff --git a/src/strategies/gamium-voting/index.ts b/src/strategies/gamium-voting/index.ts index f720ba608..09e43ff02 100644 --- a/src/strategies/gamium-voting/index.ts +++ b/src/strategies/gamium-voting/index.ts @@ -50,10 +50,8 @@ export async function strategy( ); liquidityPoolMulticaller.call('lpReserves', options.lp_token, 'getReserves'); - const { - lpTotalSupply, - lpReserves - } = await liquidityPoolMulticaller.execute(); + const { lpTotalSupply, lpReserves } = + await liquidityPoolMulticaller.execute(); const liquidityPoolTokenRatio = parseFloat(formatUnits(lpReserves[0], options.decimals)) / diff --git a/src/strategies/giveth-balancer-balance/index.ts b/src/strategies/giveth-balancer-balance/index.ts index 177b2296e..3e15cbfdc 100644 --- a/src/strategies/giveth-balancer-balance/index.ts +++ b/src/strategies/giveth-balancer-balance/index.ts @@ -83,13 +83,8 @@ export async function strategy( const score = {}; dataBalances.map((addressBalance) => { - const { - id, - balance, - givStaked, - balancerLp, - balancerLpStaked - } = addressBalance; + const { id, balance, givStaked, balancerLp, balancerLpStaked } = + addressBalance; const totalGIV = BigNumber.from(balance).add(givStaked); const balGIV = calcGivAmount( diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 0eef640c0..8e2cbb25a 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -390,7 +390,8 @@ const strategies = { 'protofi-erc721-tier-weighted': protofiErc721TierWeighted, 'erc721-with-tokenid': erc721WithTokenId, 'erc721-with-tokenid-range-weights': erc721WithTokenIdRangeWeights, - 'erc721-with-tokenid-range-weights-simple': erc721WithTokenIdRangeWeightsSimple, + 'erc721-with-tokenid-range-weights-simple': + erc721WithTokenIdRangeWeightsSimple, 'erc721-with-tokenid-weighted': erc721WithTokenIdWeighted, 'erc721-with-metadata': erc721WithMetadata, 'erc721-with-metadata-by-ownerof': erc721WithMetadataByOwnerOf, @@ -587,7 +588,8 @@ const strategies = { 'snet-stakers': snetStakers, 'snet-liquidity-providers': snetLiquidityProviders, 'minmax-mcn-farm': minMaxMcnFarm, - 'unstackedtoadz-and-stackedtoadz-stakers': unstackedToadzAndStackedToadzStakers, + 'unstackedtoadz-and-stackedtoadz-stakers': + unstackedToadzAndStackedToadzStakers, 'jade-smrt': jadeSmrt, 'ocean-dao-brightid': oceanDAOBrightID, 'saddle-finance': saddleFinance, diff --git a/src/strategies/infinityprotocol-liquidity-pools/index.ts b/src/strategies/infinityprotocol-liquidity-pools/index.ts index f56272ca5..14982f5b0 100644 --- a/src/strategies/infinityprotocol-liquidity-pools/index.ts +++ b/src/strategies/infinityprotocol-liquidity-pools/index.ts @@ -2,8 +2,7 @@ import { getAddress } from '@ethersproject/address'; import { subgraphRequest } from '../../utils'; const INFINITYPROTOCOL_SUBGRAPH_URL = { - '56': - 'https://api.thegraph.com/subgraphs/name/infinitywallet/infinity-protocol' + '56': 'https://api.thegraph.com/subgraphs/name/infinitywallet/infinity-protocol' }; export const author = 'vfatouros'; diff --git a/src/strategies/landdao-token-tiers/index.ts b/src/strategies/landdao-token-tiers/index.ts index e3b29e420..1cb860f33 100644 --- a/src/strategies/landdao-token-tiers/index.ts +++ b/src/strategies/landdao-token-tiers/index.ts @@ -29,10 +29,8 @@ export async function strategy( walletAddress ]); } - const walletToBalanceOf: Record< - string, - BigNumber - > = await callWalletToBalanceOf.execute(); + const walletToBalanceOf: Record = + await callWalletToBalanceOf.execute(); // get tokenIds const callWalletToAddresses = new Multicaller(network, provider, abi, { @@ -48,10 +46,8 @@ export async function strategy( ); } } - const walletIDToAddresses: Record< - string, - BigNumber - > = await callWalletToAddresses.execute(); + const walletIDToAddresses: Record = + await callWalletToAddresses.execute(); // fetch ipfs tier weights const response = await fetch( diff --git a/src/strategies/liquidity-token-provide/index.ts b/src/strategies/liquidity-token-provide/index.ts index 159aaf26e..800b30d08 100644 --- a/src/strategies/liquidity-token-provide/index.ts +++ b/src/strategies/liquidity-token-provide/index.ts @@ -2,8 +2,7 @@ import { getAddress } from '@ethersproject/address'; import { subgraphRequest } from '../../utils'; const SUBGRAPH_URL = { - '1': - 'https://api.thegraph.com/subgraphs/name/dinngodev/furucombo-tokenomics-mainnet', + '1': 'https://api.thegraph.com/subgraphs/name/dinngodev/furucombo-tokenomics-mainnet', '137': 'https://api.thegraph.com/subgraphs/name/dinngodev/furucombo-tokenomics-polygon' }; diff --git a/src/strategies/masterchef-pool-balance-no-rewarddebt/index.ts b/src/strategies/masterchef-pool-balance-no-rewarddebt/index.ts index dda11a56c..0d7650ab9 100644 --- a/src/strategies/masterchef-pool-balance-no-rewarddebt/index.ts +++ b/src/strategies/masterchef-pool-balance-no-rewarddebt/index.ts @@ -89,9 +89,8 @@ export async function strategy( ); return Object.fromEntries( // chunk to response so that we can process values for each address - arrayChunk( - response, - options.uniPairAddress == null ? 1 : 3 - ).map((value, i) => [addresses[i], processValues(value, options)]) + arrayChunk(response, options.uniPairAddress == null ? 1 : 3).map( + (value, i) => [addresses[i], processValues(value, options)] + ) ); } diff --git a/src/strategies/masterchef-pool-balance/index.ts b/src/strategies/masterchef-pool-balance/index.ts index 0e83bb0f7..08f553e3d 100644 --- a/src/strategies/masterchef-pool-balance/index.ts +++ b/src/strategies/masterchef-pool-balance/index.ts @@ -155,9 +155,8 @@ export async function strategy( ); return Object.fromEntries( // chunk to response so that we can process values for each address - arrayChunk( - response, - options.uniPairAddress == null ? 1 : 3 - ).map((value, i) => [addresses[i], processValues(value, options)]) + arrayChunk(response, options.uniPairAddress == null ? 1 : 3).map( + (value, i) => [addresses[i], processValues(value, options)] + ) ); } diff --git a/src/strategies/math/index.ts b/src/strategies/math/index.ts index 0fbdf3501..73384e18c 100644 --- a/src/strategies/math/index.ts +++ b/src/strategies/math/index.ts @@ -27,11 +27,10 @@ export async function strategy( const strategyOptions: Options = validateOptions(rawOptions); // Recursively resolve operands - const operandPromises: Promise< - Record - >[] = strategyOptions.operands.map((item) => - resolveOperand(item, addresses, space, network, provider, snapshot) - ); + const operandPromises: Promise>[] = + strategyOptions.operands.map((item) => + resolveOperand(item, addresses, space, network, provider, snapshot) + ); const resolvedOperands: Record[] = await Promise.all( operandPromises ); @@ -51,100 +50,94 @@ function resolveOperation( switch (operation) { case Operation.SquareRoot: { return Object.fromEntries( - Object.entries( - resolvedOperands[0] - ).map(([address, score]: [string, number]) => [ - address, - Math.sqrt(score) - ]) + Object.entries(resolvedOperands[0]).map( + ([address, score]: [string, number]) => [address, Math.sqrt(score)] + ) ); } case Operation.CubeRoot: { return Object.fromEntries( - Object.entries( - resolvedOperands[0] - ).map(([address, score]: [string, number]) => [ - address, - Math.cbrt(score) - ]) + Object.entries(resolvedOperands[0]).map( + ([address, score]: [string, number]) => [address, Math.cbrt(score)] + ) ); } case Operation.Min: { return Object.fromEntries( - Object.entries( - resolvedOperands[0] - ).map(([address, score]: [string, number]) => [ - address, - Math.min(score, resolvedOperands[1][address]) - ]) + Object.entries(resolvedOperands[0]).map( + ([address, score]: [string, number]) => [ + address, + Math.min(score, resolvedOperands[1][address]) + ] + ) ); } case Operation.Max: { return Object.fromEntries( - Object.entries( - resolvedOperands[0] - ).map(([address, score]: [string, number]) => [ - address, - Math.max(score, resolvedOperands[1][address]) - ]) + Object.entries(resolvedOperands[0]).map( + ([address, score]: [string, number]) => [ + address, + Math.max(score, resolvedOperands[1][address]) + ] + ) ); } case Operation.AIfLtB: { return Object.fromEntries( - Object.entries( - resolvedOperands[0] - ).map(([address, score]: [string, number]) => [ - address, - score < resolvedOperands[2][address] - ? resolvedOperands[1][address] - : score - ]) + Object.entries(resolvedOperands[0]).map( + ([address, score]: [string, number]) => [ + address, + score < resolvedOperands[2][address] + ? resolvedOperands[1][address] + : score + ] + ) ); } case Operation.AIfLteB: { return Object.fromEntries( - Object.entries( - resolvedOperands[0] - ).map(([address, score]: [string, number]) => [ - address, - score <= resolvedOperands[2][address] - ? resolvedOperands[1][address] - : score - ]) + Object.entries(resolvedOperands[0]).map( + ([address, score]: [string, number]) => [ + address, + score <= resolvedOperands[2][address] + ? resolvedOperands[1][address] + : score + ] + ) ); } case Operation.AIfGtB: { return Object.fromEntries( - Object.entries( - resolvedOperands[0] - ).map(([address, score]: [string, number]) => [ - address, - score > resolvedOperands[2][address] - ? resolvedOperands[1][address] - : score - ]) + Object.entries(resolvedOperands[0]).map( + ([address, score]: [string, number]) => [ + address, + score > resolvedOperands[2][address] + ? resolvedOperands[1][address] + : score + ] + ) ); } case Operation.AIfGteB: { return Object.fromEntries( - Object.entries( - resolvedOperands[0] - ).map(([address, score]: [string, number]) => [ - address, - score >= resolvedOperands[2][address] - ? resolvedOperands[1][address] - : score - ]) + Object.entries(resolvedOperands[0]).map( + ([address, score]: [string, number]) => [ + address, + score >= resolvedOperands[2][address] + ? resolvedOperands[1][address] + : score + ] + ) ); } case Operation.Multiply: { return Object.fromEntries( - Object.entries( - resolvedOperands[0] - ).map(([address, score]: [string, number]) => [ - address, - score * resolvedOperands[1][address] - ]) + Object.entries(resolvedOperands[0]).map( + ([address, score]: [string, number]) => [ + address, + score * resolvedOperands[1][address] + ] + ) ); } } diff --git a/src/strategies/ocean-dao-brightid/index.ts b/src/strategies/ocean-dao-brightid/index.ts index be4dde645..b62449ead 100644 --- a/src/strategies/ocean-dao-brightid/index.ts +++ b/src/strategies/ocean-dao-brightid/index.ts @@ -71,9 +71,9 @@ export async function strategy( ); const totalScores = {}; - const delegatorAddresses = Object.values( - delegations - ).reduce((a: string[], b: string[]) => a.concat(b)); + const delegatorAddresses = Object.values(delegations).reduce( + (a: string[], b: string[]) => a.concat(b) + ); // remove duplicates const allAddresses = addresses diff --git a/src/strategies/ocean-marketplace-v4/index.ts b/src/strategies/ocean-marketplace-v4/index.ts index 331cfc7ae..b86da3220 100644 --- a/src/strategies/ocean-marketplace-v4/index.ts +++ b/src/strategies/ocean-marketplace-v4/index.ts @@ -9,14 +9,10 @@ export const version = '0.1.0'; const OCEAN_ERC20_DECIMALS = 18; const OCEAN_SUBGRAPH_URL = { - '1': - 'https://v4.subgraph.mainnet.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph', - '3': - 'https://v4.subgraph.ropsten.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph', - '42': - 'https://v4.subgraph.rinkeby.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph', - '56': - 'https://v4.subgraph.bsc.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph', + '1': 'https://v4.subgraph.mainnet.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph', + '3': 'https://v4.subgraph.ropsten.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph', + '42': 'https://v4.subgraph.rinkeby.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph', + '56': 'https://v4.subgraph.bsc.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph', '137': 'https://v4.subgraph.polygon.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph', '246': diff --git a/src/strategies/ocean-marketplace/index.ts b/src/strategies/ocean-marketplace/index.ts index 503cb0eb2..de9b9bfdc 100644 --- a/src/strategies/ocean-marketplace/index.ts +++ b/src/strategies/ocean-marketplace/index.ts @@ -9,12 +9,9 @@ export const version = '0.1.0'; const OCEAN_ERC20_DECIMALS = 18; const OCEAN_SUBGRAPH_URL = { - '1': - 'https://subgraph.mainnet.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph', - '42': - 'https://subgraph.rinkeby.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph', - '56': - 'https://subgraph.bsc.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph', + '1': 'https://subgraph.mainnet.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph', + '42': 'https://subgraph.rinkeby.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph', + '56': 'https://subgraph.bsc.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph', '137': 'https://subgraph.polygon.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph' }; diff --git a/src/strategies/pob-hash/index.ts b/src/strategies/pob-hash/index.ts index 29a1630ee..9931089a6 100644 --- a/src/strategies/pob-hash/index.ts +++ b/src/strategies/pob-hash/index.ts @@ -49,9 +49,9 @@ export async function strategy( } else { console.error('Subgraph request failed'); } - const scores: [string, number][] = Object.entries( - scoresMap - ).map(([address, score]) => [address, score]); + const scores: [string, number][] = Object.entries(scoresMap).map( + ([address, score]) => [address, score] + ); return Object.fromEntries(scores); } diff --git a/src/strategies/polis-balance/index.ts b/src/strategies/polis-balance/index.ts index 0b42e5dce..6ba9ba0de 100644 --- a/src/strategies/polis-balance/index.ts +++ b/src/strategies/polis-balance/index.ts @@ -60,10 +60,8 @@ export async function strategy( ); const result_pools: Record = await multi_pool.execute(); - const result_delegated_pools: Record< - string, - BigNumberish[] - > = await multi_delegated.execute(); + const result_delegated_pools: Record = + await multi_delegated.execute(); const multi_own_staked = new Multicaller( network, @@ -99,15 +97,11 @@ export async function strategy( const final_balances = {}; - const result_pools_own: Record< - string, - BigNumberish - > = await multi_own_staked.execute(); + const result_pools_own: Record = + await multi_own_staked.execute(); - const result_pools_staked: Record< - string, - BigNumberish - > = await multi_staked.execute(); + const result_pools_staked: Record = + await multi_staked.execute(); Object.keys(result_pools_own).map((addr) => { final_balances[addr] = parseFloat( diff --git a/src/strategies/protofi-erc721-tier-weighted/index.ts b/src/strategies/protofi-erc721-tier-weighted/index.ts index ec43a1c87..de84fa575 100644 --- a/src/strategies/protofi-erc721-tier-weighted/index.ts +++ b/src/strategies/protofi-erc721-tier-weighted/index.ts @@ -30,10 +30,8 @@ export async function strategy( walletAddress ]); } - const walletToBalanceOf: Record< - string, - BigNumber - > = await callWalletToBalanceOf.execute(); + const walletToBalanceOf: Record = + await callWalletToBalanceOf.execute(); // Second, get the tokenId's for each token const callWalletToAddresses = new Multicaller(network, provider, abi, { @@ -49,10 +47,8 @@ export async function strategy( ); } } - const walletIDToAddresses: Record< - string, - BigNumber - > = await callWalletToAddresses.execute(); + const walletIDToAddresses: Record = + await callWalletToAddresses.execute(); // Third, given the tokenIds for each token const callWalletToTiers = new Multicaller(network, provider, abi, { @@ -67,10 +63,8 @@ export async function strategy( ); } - const walletIDToTiers: Record< - string, - number - > = await callWalletToTiers.execute(); + const walletIDToTiers: Record = + await callWalletToTiers.execute(); // Third, given the tokenIds for each token get if the token is used const callWalletToUsed = new Multicaller(network, provider, abi, { @@ -84,10 +78,8 @@ export async function strategy( [tokenId] ); } - const walletIDToUsed: Record< - string, - boolean - > = await callWalletToUsed.execute(); + const walletIDToUsed: Record = + await callWalletToUsed.execute(); // Ultimately, sum the weights for each tokenId and assign votes based on the // strategy parameters diff --git a/src/strategies/reverse-voting-escrow/index.ts b/src/strategies/reverse-voting-escrow/index.ts index aeb647690..b12ce4ee0 100644 --- a/src/strategies/reverse-voting-escrow/index.ts +++ b/src/strategies/reverse-voting-escrow/index.ts @@ -43,10 +43,8 @@ export async function strategy( walletAddress ]); } - const walletToClubBalance: Record< - string, - BigNumber - > = await callWalletToClubBalance.execute(); + const walletToClubBalance: Record = + await callWalletToClubBalance.execute(); for (const [walletID, balance] of Object.entries(walletToClubBalance)) { const address = walletID.split('-')[0]; @@ -114,10 +112,8 @@ export async function strategy( // ** Execute the vested multicall ** // try { // This should return a mapping of wallet addresses to vested amounts - const tempWalletVestedAmounts: Record< - string, - BigNumber - > = await getWalletToVestedAmount.execute(); + const tempWalletVestedAmounts: Record = + await getWalletToVestedAmount.execute(); walletToVestedAmount = Object.assign( walletToVestedAmount, tempWalletVestedAmounts @@ -128,10 +124,8 @@ export async function strategy( } // ** Execute the claimed multicall ** // - const walletToClaimedAmount: Record< - string, - BigNumber - > = await getWalletToClaimedAmount.execute(); + const walletToClaimedAmount: Record = + await getWalletToClaimedAmount.execute(); // ** Map address to its full amount of claimable tokens ** // const listOfFullAmounts = Object.entries(allDataJSON) diff --git a/src/strategies/rocketpool-node-operator/index.ts b/src/strategies/rocketpool-node-operator/index.ts index 17f31f1d7..b687bb50d 100644 --- a/src/strategies/rocketpool-node-operator/index.ts +++ b/src/strategies/rocketpool-node-operator/index.ts @@ -36,10 +36,8 @@ export async function strategy( ); }); - const effectiveStakeResponse: Record< - string, - BigNumberish - > = await effectiveStake.execute(); + const effectiveStakeResponse: Record = + await effectiveStake.execute(); return Object.fromEntries( Object.entries(effectiveStakeResponse).map(([address, balance]) => [ diff --git a/src/strategies/rowdy-roos/index.ts b/src/strategies/rowdy-roos/index.ts index af45a7d60..7721695f2 100644 --- a/src/strategies/rowdy-roos/index.ts +++ b/src/strategies/rowdy-roos/index.ts @@ -48,10 +48,8 @@ export async function strategy( }); }); - const stakedRewardsResponse: Record< - string, - BigNumberish[] - > = await stakingPool.execute(); + const stakedRewardsResponse: Record = + await stakingPool.execute(); return Object.fromEntries( addresses.map((address) => { diff --git a/src/strategies/safety-module-bpt-power/index.ts b/src/strategies/safety-module-bpt-power/index.ts index e9d0f8da4..4cbc5ea8f 100644 --- a/src/strategies/safety-module-bpt-power/index.ts +++ b/src/strategies/safety-module-bpt-power/index.ts @@ -150,23 +150,20 @@ export async function strategy( options: Options, snapshot: number ) { - const [ - safetyModuleScore, - accountsStakesAndRewards, - safetyModuleGlobalState - ] = await Promise.all( - [ - fetchSafetyModuleScore, - fetchAccountsSafetyModuleStakesAndRewards, - fetchSafetyModuleGlobalState - ].map((fn) => - fn(space, network, provider, addresses, options, snapshot) - ) as [ - FetchSafetyModuleScoreOutput, - FetchAccountsSafetyModuleStakesAndRewardsOuput, - FetchSafetyModuleGlobalStateOutput - ] - ); + const [safetyModuleScore, accountsStakesAndRewards, safetyModuleGlobalState] = + await Promise.all( + [ + fetchSafetyModuleScore, + fetchAccountsSafetyModuleStakesAndRewards, + fetchSafetyModuleGlobalState + ].map((fn) => + fn(space, network, provider, addresses, options, snapshot) + ) as [ + FetchSafetyModuleScoreOutput, + FetchAccountsSafetyModuleStakesAndRewardsOuput, + FetchSafetyModuleGlobalStateOutput + ] + ); const safetyModuleStakedToken = safetyModuleGlobalState[STAKED_TOKEN_ATTR]; diff --git a/src/strategies/saffron-finance/index.ts b/src/strategies/saffron-finance/index.ts index 787e2a9ea..fad38fa4c 100644 --- a/src/strategies/saffron-finance/index.ts +++ b/src/strategies/saffron-finance/index.ts @@ -133,7 +133,8 @@ class VoteScorer { string, VotingScheme >(); - private dexReserveData: Array = new Array(); + private dexReserveData: Array = + new Array(); constructor(dexReserveData: Array) { this.dexReserveData = dexReserveData; diff --git a/src/strategies/sandman-dao/index.ts b/src/strategies/sandman-dao/index.ts index aac1d9c0a..d1083ca2b 100644 --- a/src/strategies/sandman-dao/index.ts +++ b/src/strategies/sandman-dao/index.ts @@ -34,10 +34,8 @@ export async function strategy( walletAddress ]); } - const walletToBalanceOf: Record< - string, - BigNumber - > = await callWalletToBalanceOf.execute(); + const walletToBalanceOf: Record = + await callWalletToBalanceOf.execute(); // Second, get the tokenId's for each nft const callWalletToAddresses = new Multicaller( @@ -58,10 +56,8 @@ export async function strategy( ); } } - const walletIDToAddresses: Record< - string, - BigNumber - > = await callWalletToAddresses.execute(); + const walletIDToAddresses: Record = + await callWalletToAddresses.execute(); // Third, get skil's for each tokenId const callTokenToSkill = new Multicaller(network, provider, factoryNftABI, { @@ -73,10 +69,8 @@ export async function strategy( tokenId ]); } - const walletIDToSkills: Record< - string, - any - > = await callTokenToSkill.execute(); + const walletIDToSkills: Record = + await callTokenToSkill.execute(); const results = {} as Record; for (const [walletID, values] of Object.entries(walletIDToSkills)) { diff --git a/src/strategies/snowswap/index.ts b/src/strategies/snowswap/index.ts index a492f1aea..bcccaa601 100644 --- a/src/strategies/snowswap/index.ts +++ b/src/strategies/snowswap/index.ts @@ -39,10 +39,8 @@ export async function strategy( address ]) ); - const result: Record< - string, - number | BigNumberish - > = await stakedTokenBalances.execute(); + const result: Record = + await stakedTokenBalances.execute(); return Object.fromEntries( Object.entries(result).map(([address, output]) => [ diff --git a/src/strategies/staking-claimed-unclaimed/index.ts b/src/strategies/staking-claimed-unclaimed/index.ts index 56cfa1039..7ac2e80d8 100644 --- a/src/strategies/staking-claimed-unclaimed/index.ts +++ b/src/strategies/staking-claimed-unclaimed/index.ts @@ -51,10 +51,8 @@ export async function strategy( ]); }); - const rewardsResponse: Record< - string, - BigNumberish[] - > = await stakingPool.execute(); + const rewardsResponse: Record = + await stakingPool.execute(); return Object.fromEntries( addresses.map((address) => { diff --git a/src/strategies/synthetix-non-quadratic/index.ts b/src/strategies/synthetix-non-quadratic/index.ts index 40c674335..0d42dd088 100644 --- a/src/strategies/synthetix-non-quadratic/index.ts +++ b/src/strategies/synthetix-non-quadratic/index.ts @@ -28,8 +28,7 @@ const DebtCacheContractAddress = '0xe92B4c7428152052B0930c81F4c687a5F1A12292'; const defaultGraphs = { '1': 'https://api.thegraph.com/subgraphs/name/killerbyte/synthetix', - '10': - 'https://api.thegraph.com/subgraphs/name/synthetixio-team/optimism-issuance' + '10': 'https://api.thegraph.com/subgraphs/name/synthetixio-team/optimism-issuance' }; // @TODO: update with the latest ovm snapshot @@ -133,7 +132,7 @@ export async function strategy( )) as SNXHoldersResult; // @notice fallback for when subgraph is down - /* + /* const OVMSnapshot = await ipfsGet('gateway.pinata.cloud', ovmSnapshotJSON); const array = Object.assign( {}, diff --git a/src/strategies/synthetix-quadratic/index.ts b/src/strategies/synthetix-quadratic/index.ts index f07a89c7d..a53d17279 100644 --- a/src/strategies/synthetix-quadratic/index.ts +++ b/src/strategies/synthetix-quadratic/index.ts @@ -28,8 +28,7 @@ const DebtCacheContractAddress = '0xe92B4c7428152052B0930c81F4c687a5F1A12292'; const defaultGraphs = { '1': 'https://api.thegraph.com/subgraphs/name/killerbyte/synthetix', - '10': - 'https://api.thegraph.com/subgraphs/name/synthetixio-team/optimism-issuance' + '10': 'https://api.thegraph.com/subgraphs/name/synthetixio-team/optimism-issuance' }; // @TODO: update with the latest ovm snapshot @@ -133,7 +132,7 @@ export async function strategy( )) as SNXHoldersResult; // @notice fallback for when subgraph is down - /* + /* const OVMSnapshot = await ipfsGet('gateway.pinata.cloud', ovmSnapshotJSON); const array = Object.assign( {}, diff --git a/src/strategies/synthetix/index.ts b/src/strategies/synthetix/index.ts index 2de6162c3..c05ec10af 100644 --- a/src/strategies/synthetix/index.ts +++ b/src/strategies/synthetix/index.ts @@ -14,8 +14,7 @@ const DebtCacheContractAddress = '0x9bB05EF2cA7DBAafFC3da1939D1492e6b00F39b8'; const defaultGraphs = { '1': 'https://api.thegraph.com/subgraphs/name/synthetixio-team/synthetix', - '10': - 'https://api.thegraph.com/subgraphs/name/synthetixio-team/optimism-general' + '10': 'https://api.thegraph.com/subgraphs/name/synthetixio-team/optimism-general' }; const ovmSnapshotJSON = 'QmNwvhq4By1Mownjycg7bWSXqbJWMVyAWRZ1K4mjxuvGXg'; diff --git a/src/strategies/synthetix_1/index.ts b/src/strategies/synthetix_1/index.ts index 39b3a4fd3..6c2590f2b 100644 --- a/src/strategies/synthetix_1/index.ts +++ b/src/strategies/synthetix_1/index.ts @@ -85,10 +85,8 @@ export async function strategy( ]); } - const L1SDSBalances: Record< - string, - BigNumber - > = await callL1SDSBalance.execute(); + const L1SDSBalances: Record = + await callL1SDSBalance.execute(); Object.entries(L1SDSBalances).forEach(([address, balance]) => { score[getAddress(address)] = Number(formatEther(balance)) * L1SDSValue; @@ -104,10 +102,8 @@ export async function strategy( ]); } - const L2SDSBalances: Record< - string, - BigNumber - > = await callL2SDSBalance.execute(); + const L2SDSBalances: Record = + await callL2SDSBalance.execute(); Object.entries(L2SDSBalances).forEach(([address, balance]) => { score[getAddress(address)] += Number(formatEther(balance)) * L2SDSValue; diff --git a/src/strategies/the-graph/graphUtils.ts b/src/strategies/the-graph/graphUtils.ts index 1311b4e01..9470d2644 100644 --- a/src/strategies/the-graph/graphUtils.ts +++ b/src/strategies/the-graph/graphUtils.ts @@ -3,10 +3,8 @@ import { BigNumber } from '@ethersproject/bignumber'; import { Provider } from '@ethersproject/providers'; export const GRAPH_NETWORK_SUBGRAPH_URL = { - '1': - 'https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-mainnet', - '4': - 'https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-testnet' + '1': 'https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-mainnet', + '4': 'https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-testnet' }; export const bnWEI = BigNumber.from('1000000000000000000'); diff --git a/src/strategies/the-graph/tokenLockWallets.ts b/src/strategies/the-graph/tokenLockWallets.ts index 82c93a6b8..aa523ddbe 100644 --- a/src/strategies/the-graph/tokenLockWallets.ts +++ b/src/strategies/the-graph/tokenLockWallets.ts @@ -3,10 +3,8 @@ import { subgraphRequest } from '../../utils'; import { verifyResults } from './graphUtils'; export const TOKEN_DISTRIBUTION_SUBGRAPH_URL = { - '1': - 'https://api.thegraph.com/subgraphs/name/graphprotocol/token-distribution', - '4': - 'https://api.thegraph.com/subgraphs/name/davekaj/token-distribution-rinkeby' + '1': 'https://api.thegraph.com/subgraphs/name/graphprotocol/token-distribution', + '4': 'https://api.thegraph.com/subgraphs/name/davekaj/token-distribution-rinkeby' }; interface TokenLockWallets { [key: string]: string[]; @@ -14,7 +12,7 @@ interface TokenLockWallets { /** @dev Queries the subgraph to find if an address owns any token lock wallets - @returns An object with the beneficiaries as keys and TLWs as values in an array + @returns An object with the beneficiaries as keys and TLWs as values in an array */ export async function getTokenLockWallets( _space: string, diff --git a/src/strategies/tokenlon/index.ts b/src/strategies/tokenlon/index.ts index 04a107acb..cfd6cd6d8 100644 --- a/src/strategies/tokenlon/index.ts +++ b/src/strategies/tokenlon/index.ts @@ -273,9 +273,8 @@ export async function strategy( lonEarnedBalancesUniswapStaking2[i][0]; const lonEarnedBalanceUniswapStaking3 = lonEarnedBalancesUniswapStaking3[i][0]; - let lonEarnedBalanceUniswapStaking = lonEarnedBalanceUniswapStaking2.add( - lonEarnedBalanceUniswapStaking3 - ); + let lonEarnedBalanceUniswapStaking = + lonEarnedBalanceUniswapStaking2.add(lonEarnedBalanceUniswapStaking3); const lpBalanceSushiSwap = lpBalancesSushiSwap[i][0]; const lpBalanceSushiSwapStaking2 = lpBalancesSushiSwapStaking2[i][0]; @@ -289,9 +288,10 @@ export async function strategy( lonEarnedBalancesSushiSwapStaking2[i][0]; const lonEarnedBalanceSushiSwapStaking3 = lonEarnedBalancesSushiSwapStaking3[i][0]; - let lonEarnedBalanceSushiSwapStaking = lonEarnedBalanceSushiSwapStaking2.add( - lonEarnedBalanceSushiSwapStaking3 - ); + let lonEarnedBalanceSushiSwapStaking = + lonEarnedBalanceSushiSwapStaking2.add( + lonEarnedBalanceSushiSwapStaking3 + ); if (options.stakingRewardUniswap4 && options.stakingRewardSushiSwap4) { const lpBalanceUniswapStaking4 = lpBalancesUniswapStaking4[i][0]; @@ -312,9 +312,10 @@ export async function strategy( const lonEarnedBalanceSushiSwapStaking4 = lonEarnedBalancesSushiSwapStaking4[i][0]; - lonEarnedBalanceSushiSwapStaking = lonEarnedBalanceSushiSwapStaking.add( - lonEarnedBalanceSushiSwapStaking4 - ); + lonEarnedBalanceSushiSwapStaking = + lonEarnedBalanceSushiSwapStaking.add( + lonEarnedBalanceSushiSwapStaking4 + ); } lonLpBalanceUniswap = lonLpBalanceUniswap .mul(lonPerLPUniswap) diff --git a/src/strategies/ve-balance-of-at-nft/index.ts b/src/strategies/ve-balance-of-at-nft/index.ts index c78e93bdb..76fb4bee4 100644 --- a/src/strategies/ve-balance-of-at-nft/index.ts +++ b/src/strategies/ve-balance-of-at-nft/index.ts @@ -27,10 +27,8 @@ export async function strategy( addresses.forEach((address) => multiCallBalanceOf.call(address, options.address, 'balanceOf', [address]) ); - const walletBalanceOf: Record< - string, - BigNumber - > = await multiCallBalanceOf.execute(); + const walletBalanceOf: Record = + await multiCallBalanceOf.execute(); const multiCallTokenOfOwner = new Multicaller(network, provider, abi, { blockTag @@ -45,10 +43,8 @@ export async function strategy( ); } } - const walletIDToAddresses: Record< - string, - BigNumber - > = await multiCallTokenOfOwner.execute(); + const walletIDToAddresses: Record = + await multiCallTokenOfOwner.execute(); // Third, get voting power for each tokenId const multiCallBalanceOfNFT = new Multicaller(network, provider, abi, { @@ -59,10 +55,8 @@ export async function strategy( tokenId ]); } - const walletVotingPower: Record< - string, - BigNumber - > = await multiCallBalanceOfNFT.execute(); + const walletVotingPower: Record = + await multiCallBalanceOfNFT.execute(); const result = {} as Record; for (const [walletID, value] of Object.entries(walletVotingPower)) { diff --git a/src/strategies/ve-ribbon/index.ts b/src/strategies/ve-ribbon/index.ts index b6d2c4c79..e2d24e4c4 100644 --- a/src/strategies/ve-ribbon/index.ts +++ b/src/strategies/ve-ribbon/index.ts @@ -29,10 +29,8 @@ export async function strategy( addresses.forEach((address) => multi.call(address, VOTING_ESCROW, 'locked', [address]) ); - const resultLocked: Record< - string, - [BigNumberish, BigNumberish] - > = await multi.execute(); + const resultLocked: Record = + await multi.execute(); return Object.fromEntries( Object.entries(resultUnlocked).map(([address, balance]) => [ diff --git a/src/strategies/volt-voting-power/index.ts b/src/strategies/volt-voting-power/index.ts index ba7759c93..f01b22c5c 100644 --- a/src/strategies/volt-voting-power/index.ts +++ b/src/strategies/volt-voting-power/index.ts @@ -8,8 +8,7 @@ export const author = 'philipappiah'; export const version = '0.1.2'; const VOLTSWAP_SUBGRAPH = { - '82': - 'https://graph-meter.voltswap.finance/subgraphs/name/meterio/uniswap-v2-subgraph', + '82': 'https://graph-meter.voltswap.finance/subgraphs/name/meterio/uniswap-v2-subgraph', '361': 'https://graph-theta.voltswap.finance/subgraphs/name/theta/uniswap-v2-subgraph' }; diff --git a/src/strategies/xdai-stake-delegation/index.ts b/src/strategies/xdai-stake-delegation/index.ts index bd6486aa8..be294890c 100644 --- a/src/strategies/xdai-stake-delegation/index.ts +++ b/src/strategies/xdai-stake-delegation/index.ts @@ -18,9 +18,9 @@ export async function strategy( const delegations = await getDelegations(space, network, addresses, snapshot); if (Object.keys(delegations).length === 0) return {}; - const delegationsArray = Object.values( - delegations - ).reduce((a: string[], b: string[]) => a.concat(b)); + const delegationsArray = Object.values(delegations).reduce( + (a: string[], b: string[]) => a.concat(b) + ); const erc20Balances = await erc20BalanceOfStrategy( space, network, diff --git a/src/utils/delegations.json b/src/utils/delegations.json new file mode 100644 index 000000000..545cfb58e --- /dev/null +++ b/src/utils/delegations.json @@ -0,0 +1,9 @@ +{ + "1": "https://gateway.thegraph.com/api/0f15b42bdeff7a063a4e1757d7e2f99e/deployments/id/QmXvEzRJXby7KFuTr7NJsM47hGefM5VckEXZrQyZzL9eJd", + "4": "https://api.thegraph.com/subgraphs/name/snapshot-labs/snapshot-rinkeby", + "42": "https://api.thegraph.com/subgraphs/name/snapshot-labs/snapshot-kovan", + "56": "https://api.thegraph.com/subgraphs/name/snapshot-labs/snapshot-binance-smart-chain", + "100": "https://api.thegraph.com/subgraphs/name/snapshot-labs/snapshot-gnosis-chain", + "137": "https://api.thegraph.com/subgraphs/name/snapshot-labs/snapshot-polygon", + "250": "https://api.thegraph.com/subgraphs/name/snapshot-labs/snapshot-fantom" +} diff --git a/src/utils/vp.ts b/src/utils/vp.ts new file mode 100644 index 000000000..879ddb430 --- /dev/null +++ b/src/utils/vp.ts @@ -0,0 +1,218 @@ +import { formatBytes32String } from '@ethersproject/strings'; +import { getAddress } from '@ethersproject/address'; +import { + getProvider, + getSnapshots, + Multicaller, + subgraphRequest +} from '../utils'; +import _strategies from '../strategies'; +import subgraphs from './delegations.json'; + +const DELEGATION_CONTRACT = '0x469788fE6E9E9681C6ebF3bF78e7Fd26Fc015446'; +const EMPTY_ADDRESS = '0x0000000000000000000000000000000000000000'; +const EMPTY_SPACE = formatBytes32String(''); +const abi = ['function delegation(address, bytes32) view returns (address)']; + +interface Delegation { + in: string[]; + out: string | null; +} + +export async function getVp( + address: string, + network: string, + strategies: any[], + snapshot: number | 'latest', + space: string, + delegation: boolean +) { + const networks = [...new Set(strategies.map((s) => s.network || network))]; + const snapshots = await getSnapshots( + network, + snapshot, + getProvider(network), + networks + ); + + const delegations = {}; + if (delegation) { + const ds = await Promise.all( + networks.map((n) => getDelegations(address, n, snapshots[n], space)) + ); + ds.forEach((d, i) => (delegations[networks[i]] = d)); + } + + const p = strategies.map((strategy) => { + const n = strategy.network || network; + let addresses = [address]; + + if (delegation) { + addresses = delegations[n].in; + if (!delegations[n].out) addresses.push(address); + addresses = [...new Set(addresses)]; + if (addresses.length === 0) return {}; + } + + return _strategies[strategy.name].strategy( + space, + n, + getProvider(n), + addresses, + strategy.params, + snapshots[n] + ); + }); + const scores = await Promise.all(p); + + const vpByStrategy = scores.map((score, i) => { + const n = strategies[i].network || network; + let addresses = [address]; + + if (delegation) { + addresses = delegations[n].in; + if (!delegations[n].out) addresses.push(address); + addresses = [...new Set(addresses)]; + } + + return addresses.reduce((a, b) => a + score[b], 0); + }); + const vp = vpByStrategy.reduce((a, b) => a + b, 0); + let vpState = 'final'; + if (snapshot === 'latest') vpState = 'pending'; + + return { + vp, + vp_by_strategy: vpByStrategy, + vp_state: vpState + }; +} + +export async function getDelegationsOut( + addresses: string[], + network: string, + snapshot: number | 'latest', + space: string +) { + if (!subgraphs[network]) + return Object.fromEntries(addresses.map((address) => [address, null])); + + const id = formatBytes32String(space); + const options = { blockTag: snapshot }; + const multi = new Multicaller(network, getProvider(network), abi, options); + addresses.forEach((account) => { + multi.call(`${account}.base`, DELEGATION_CONTRACT, 'delegation', [ + account, + EMPTY_SPACE + ]); + multi.call(`${account}.space`, DELEGATION_CONTRACT, 'delegation', [ + account, + id + ]); + }); + const delegations = await multi.execute(); + + return Object.fromEntries( + Object.entries(delegations).map(([address, delegation]: any) => { + if (delegation.space !== EMPTY_ADDRESS) + return [address, delegation.space]; + if (delegation.base !== EMPTY_ADDRESS) return [address, delegation.base]; + return [address, null]; + }) + ); +} + +export async function getDelegationOut( + address: string, + network: string, + snapshot: number | 'latest', + space: string +): Promise { + const usersDelegationOut = await getDelegationsOut( + [address], + network, + snapshot, + space + ); + return usersDelegationOut[address] || null; +} + +export async function getDelegationsIn( + address: string, + network: string, + snapshot: number | 'latest', + space: string +): Promise { + if (!subgraphs[network]) return []; + + const max = 1000; + let result = []; + let page = 0; + + const query = { + delegations: { + __args: { + first: max, + skip: 0, + block: { number: snapshot }, + where: { + space_in: ['', space], + delegate: address + } + }, + delegator: true, + space: true + } + }; + // @ts-ignore + if (snapshot === 'latest') delete query.delegations.__args.block; + while (true) { + query.delegations.__args.skip = page * max; + const pageResult = await subgraphRequest(subgraphs[network], query); + const pageDelegations = pageResult.delegations || []; + result = result.concat(pageDelegations); + page++; + if (pageDelegations.length < max) break; + } + + const delegations: string[] = []; + let baseDelegations: string[] = []; + result.forEach((delegation: any) => { + const delegator = getAddress(delegation.delegator); + if (delegation.space === space) delegations.push(delegator); + if ([null, ''].includes(delegation.space)) baseDelegations.push(delegator); + }); + + baseDelegations = baseDelegations.filter( + (delegator) => !delegations.includes(delegator) + ); + if (baseDelegations.length > 0) { + const delegationsOut = await getDelegationsOut( + baseDelegations, + network, + snapshot, + space + ); + Object.entries(delegationsOut).map(([delegator, out]: any) => { + if (out === address) delegations.push(delegator); + }); + } + + return [...new Set(delegations)]; +} + +export async function getDelegations( + address: string, + network: string, + snapshot: number | 'latest', + space: string +): Promise { + const [delegationOut, delegationsIn] = await Promise.all([ + getDelegationOut(address, network, snapshot, space), + getDelegationsIn(address, network, snapshot, space) + ]); + return { + in: delegationsIn, + out: delegationOut + }; +} diff --git a/test/__snapshots__/delegation.test.ts.snap b/test/__snapshots__/delegation.test.ts.snap new file mode 100644 index 000000000..50cfedd58 --- /dev/null +++ b/test/__snapshots__/delegation.test.ts.snap @@ -0,0 +1,37 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` getDelegations 1`] = ` +Object { + "in": Array [ + "0x073aBA73177668Ba1c6661A4CCddbF77dfC8809a", + "0x0D996171E7883A286eF720030935f72D0Bac8219", + "0x186E20ae3530520C9F3E6C46F2f5d1062b784761", + "0x19BB34410c9a0f70E89d1b9ab054059Ed1cf5aa8", + "0x1eccd61c9fa53a8D2e823A26cD72A7efD7D0E92e", + "0x1f575DC287742BDe83a5D7156f420d671A7C9b67", + "0x3406402caE1f745714a9aFFc45939854e7Fbe12B", + "0x37729c5948bb726a505B9633cAab02521c67d89a", + "0x3A2D016124DF975850b84A6A970ECd5725bF793D", + "0x3ff634ce65cDb8CC0D569D6d1697c41aa666cEA9", + "0x53D8EDF6a54239eB785eC72213919Fb6b6B73598", + "0x595238341089097155d46A79970c38099ee011bC", + "0x5A27DBBfF05F36DC927137855E3381f0c20C1CDd", + "0x604eB5D4126E3318EC27721Bd5059307684F5C89", + "0x628E8Ece00424f6EC1EBE2CBA684319f18079Bd5", + "0x83b9711b4a5eA2A89606B4f0E4B0A0295B180Ab1", + "0x843604564aA6fB2a28C06E20B02C30483BC2BcdC", + "0x87fB47c2B9EB41d362BAb44F5Ec81514b6b1de13", + "0x898111d1F4eB55025D0036568212425EE2274082", + "0xa8e75d99D8D207B2916987c45722baC63D24D79f", + "0xaBe780bDc3872B4DEC16bD44B2bB999f9151aE28", + "0xB1139E0d8AE27B8a6EE26EC5296B9b18414eD856", + "0xCA1D1A11074b1d86aC3fBD44771C7043126839c9", + "0xcEd29BA48490C51E4348e654C313AC97762beCCC", + "0xd8827D60486E01a6c54F7fc2ddCD9527a26af8ba", + "0xE3e202b2CAC2B3eC41219C69fE0D2352b19cef69", + "0xF7434638a7d52E44859A55fCf7c13DC9ddC4B140", + "0xFd8dc2E9c828f87336042764784C042e489DB521", + ], + "out": null, +} +`; diff --git a/test/__snapshots__/vp.test.ts.snap b/test/__snapshots__/vp.test.ts.snap new file mode 100644 index 000000000..25b20c6de --- /dev/null +++ b/test/__snapshots__/vp.test.ts.snap @@ -0,0 +1,27 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` getVp with delegation 1`] = ` +Object { + "vp": 10.077130335431244, + "vp_by_strategy": Array [ + 0, + 10.028706352441185, + 0, + 0.04842398299005922, + ], + "vp_state": "final", +} +`; + +exports[` getVp without delegation 1`] = ` +Object { + "vp": 20.491128299590727, + "vp_by_strategy": Array [ + 0, + 9.998985610441185, + 10.443718706159482, + 0.04842398299005922, + ], + "vp_state": "final", +} +`; diff --git a/test/delegation.test.ts b/test/delegation.test.ts new file mode 100644 index 000000000..d62dc6ee8 --- /dev/null +++ b/test/delegation.test.ts @@ -0,0 +1,14 @@ +import { getDelegations } from '../src/utils/vp'; + +const address = '0x14F83fF95D4Ec5E8812DDf42DA1232b0ba1015e6'; +const space = 'cvx.eth'; +const network = '1'; +const snapshot = 15109700; + +describe('', () => { + it('getDelegations', async () => { + const delegations = await getDelegations(address, network, snapshot, space); + expect(delegations).toMatchSnapshot(); + console.log(delegations); + }, 20e3); +}); diff --git a/test/delegation.ts b/test/examples/delegation.ts similarity index 91% rename from test/delegation.ts rename to test/examples/delegation.ts index 5e0287d9e..699b60f07 100644 --- a/test/delegation.ts +++ b/test/examples/delegation.ts @@ -1,4 +1,4 @@ -const snapshot = require('../').default; +import snapshot from '../../src'; const space = 'cvx.eth'; const network = '1'; diff --git a/test/scores.ts b/test/examples/scores.ts similarity index 98% rename from test/scores.ts rename to test/examples/scores.ts index 58f0058a0..ca21d9ade 100644 --- a/test/scores.ts +++ b/test/examples/scores.ts @@ -1,6 +1,6 @@ const { JsonRpcProvider } = require('@ethersproject/providers'); -const networks = require('@snapshot-labs/snapshot.js/src/networks.json'); -const utils = require('../src/utils'); +import networks from '@snapshot-labs/snapshot.js/src/networks.json'; +import utils from '../../src/utils'; const space = 'yam.eth'; const network = '1'; diff --git a/test/index.spec.ts b/test/strategy.test.ts similarity index 100% rename from test/index.spec.ts rename to test/strategy.test.ts index 90770906c..1e9a416d4 100644 --- a/test/index.spec.ts +++ b/test/strategy.test.ts @@ -2,8 +2,8 @@ import { JsonRpcProvider } from '@ethersproject/providers'; import { getAddress } from '@ethersproject/address'; import { performance } from 'perf_hooks'; import fetch from 'cross-fetch'; -import snapshot from '../src'; import networks from '@snapshot-labs/snapshot.js/src/networks.json'; +import snapshot from '../src'; import snapshotjs from '@snapshot-labs/snapshot.js'; import addresses from './addresses.json'; diff --git a/test/vp.test.ts b/test/vp.test.ts new file mode 100644 index 000000000..000e48147 --- /dev/null +++ b/test/vp.test.ts @@ -0,0 +1,59 @@ +import { getVp } from '../src/utils/vp'; + +const address = '0xeF8305E140ac520225DAf050e2f71d5fBcC543e7'; +const space = 'cvx.eth'; +const network = '1'; +const snapshot = 15109700; +const strategies = [ + { + name: 'erc20-balance-of', + params: { + symbol: 'CVX', + address: '0x72a19342e8F1838460eBFCCEf09F6585e32db86E', + decimals: 18 + } + }, + { + name: 'eth-balance', + network: '100', + params: {} + }, + { + name: 'eth-balance', + network: '1', + params: {} + }, + { + name: 'eth-balance', + network: '10', + params: {} + } +]; + +describe('', () => { + it('getVp without delegation', async () => { + const scores = await getVp( + address, + network, + strategies, + snapshot, + space, + false + ); + expect(scores).toMatchSnapshot(); + console.log(scores); + }, 20e3); + + it('getVp with delegation', async () => { + const scores = await getVp( + address, + network, + strategies, + snapshot, + space, + true + ); + expect(scores).toMatchSnapshot(); + console.log(scores); + }, 20e3); +}); diff --git a/tsconfig.json b/tsconfig.json index b4973e961..e9631bfdf 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,6 +12,6 @@ "resolveJsonModule": true, "allowSyntheticDefaultImports": true }, - "include": ["src"], + "include": ["src", "test"], "files": ["./src/typings.d.ts"] } diff --git a/yarn.lock b/yarn.lock index 6dae28cbf..c2fb30f98 100644 --- a/yarn.lock +++ b/yarn.lock @@ -289,7 +289,22 @@ resolved "https://registry.yarnpkg.com/@ensdomains/eth-ens-namehash/-/eth-ens-namehash-2.0.15.tgz#5e5f2f24ba802aff8bc19edd822c9a11200cdf4a" integrity sha512-JRDFP6+Hczb1E0/HhIg0PONgBYasfGfDheujmfxaZaAv/NAH4jE6Kf48WbqfRZdxt4IZI3jl3Ri7sZ1nP09lgw== -"@ethersproject/abi@^5.0.12", "@ethersproject/abi@^5.0.4", "@ethersproject/abi@^5.5.0": +"@eslint/eslintrc@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.0.tgz#29f92c30bb3e771e4a2048c95fa6855392dfac4f" + integrity sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.3.2" + globals "^13.15.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@ethersproject/abi@^5.0.12", "@ethersproject/abi@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.5.0.tgz#fb52820e22e50b854ff15ce1647cc508d6660613" integrity sha512-loW7I4AohP5KycATvc0MgujU6JyCHPqHdeoo9z3Nr9xEiNioxa65ccdm1+fsoJhkuhdRtfcL8cfyGamz2AxZ5w== @@ -304,7 +319,7 @@ "@ethersproject/properties" "^5.5.0" "@ethersproject/strings" "^5.5.0" -"@ethersproject/abi@^5.6.4": +"@ethersproject/abi@^5.6.3", "@ethersproject/abi@^5.6.4": version "5.6.4" resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.6.4.tgz#f6e01b6ed391a505932698ecc0d9e7a99ee60362" integrity sha512-TTeZUlCeIHG6527/2goZA6gW5F8Emoc7MrZDC7hhP84aRGvW3TEdTnZR08Ls88YXM1m2SuK42Osw/jSi3uO8gg== @@ -367,7 +382,7 @@ "@ethersproject/logger" "^5.6.0" "@ethersproject/properties" "^5.6.0" -"@ethersproject/address@^5.0.2", "@ethersproject/address@^5.0.4", "@ethersproject/address@^5.5.0": +"@ethersproject/address@^5.0.2", "@ethersproject/address@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.5.0.tgz#bcc6f576a553f21f3dd7ba17248f81b473c9c78f" integrity sha512-l4Nj0eWlTUh6ro5IbPTgbpT4wRbdH5l8CQf7icF7sb/SI3Nhd9Y9HzhonTSTi6CefI0necIw7LJqQPopPLZyWw== @@ -411,7 +426,15 @@ "@ethersproject/bytes" "^5.5.0" "@ethersproject/properties" "^5.5.0" -"@ethersproject/bignumber@^5.0.12", "@ethersproject/bignumber@^5.5.0": +"@ethersproject/basex@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.6.1.tgz#badbb2f1d4a6f52ce41c9064f01eab19cc4c5305" + integrity sha512-a52MkVz4vuBXR06nvflPMotld1FJWSj2QT0985v7P/emPZO00PucFAkbcmq2vpVU7Ts7umKiSI6SppiLykVWsA== + dependencies: + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/properties" "^5.6.0" + +"@ethersproject/bignumber@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.5.0.tgz#875b143f04a216f4f8b96245bde942d42d279527" integrity sha512-6Xytlwvy6Rn3U3gKEc1vP7nR92frHkv6wtVr95LFR3jREXiCPzdWxKQ1cx4JGQBXxcguAwjA8murlYN2TSiEbg== @@ -429,7 +452,7 @@ "@ethersproject/logger" "^5.6.0" bn.js "^5.2.1" -"@ethersproject/bytes@^5.0.8", "@ethersproject/bytes@^5.5.0": +"@ethersproject/bytes@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.5.0.tgz#cb11c526de657e7b45d2e0f0246fb3b9d29a601c" integrity sha512-ABvc7BHWhZU9PNM/tANm/Qx4ostPGadAuQzWTr3doklZOhDlmcBqclrQe/ZXUIj3K8wC28oYeuRa+A37tX9kog== @@ -473,7 +496,23 @@ "@ethersproject/properties" "^5.5.0" "@ethersproject/transactions" "^5.5.0" -"@ethersproject/hash@^5.0.9", "@ethersproject/hash@^5.5.0": +"@ethersproject/contracts@^5.6.2": + version "5.6.2" + resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.6.2.tgz#20b52e69ebc1b74274ff8e3d4e508de971c287bc" + integrity sha512-hguUA57BIKi6WY0kHvZp6PwPlWF87MCeB4B7Z7AbUpTxfFXFdn/3b0GmjZPagIHS+3yhcBJDnuEfU4Xz+Ks/8g== + dependencies: + "@ethersproject/abi" "^5.6.3" + "@ethersproject/abstract-provider" "^5.6.1" + "@ethersproject/abstract-signer" "^5.6.2" + "@ethersproject/address" "^5.6.1" + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/constants" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/transactions" "^5.6.2" + +"@ethersproject/hash@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.5.0.tgz#7cee76d08f88d1873574c849e0207dcb32380cc9" integrity sha512-dnGVpK1WtBjmnp3mUT0PlU2MpapnwWI0PibldQEq1408tQBAbZpPidkWoVVuNMOl/lISO3+4hXZWCL3YV7qzfg== @@ -519,6 +558,24 @@ "@ethersproject/transactions" "^5.5.0" "@ethersproject/wordlists" "^5.5.0" +"@ethersproject/hdnode@^5.6.2": + version "5.6.2" + resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.6.2.tgz#26f3c83a3e8f1b7985c15d1db50dc2903418b2d2" + integrity sha512-tERxW8Ccf9CxW2db3WsN01Qao3wFeRsfYY9TCuhmG0xNpl2IO8wgXU3HtWIZ49gUWPggRy4Yg5axU0ACaEKf1Q== + dependencies: + "@ethersproject/abstract-signer" "^5.6.2" + "@ethersproject/basex" "^5.6.1" + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/pbkdf2" "^5.6.1" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/sha2" "^5.6.1" + "@ethersproject/signing-key" "^5.6.2" + "@ethersproject/strings" "^5.6.1" + "@ethersproject/transactions" "^5.6.2" + "@ethersproject/wordlists" "^5.6.1" + "@ethersproject/json-wallets@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.5.0.tgz#dd522d4297e15bccc8e1427d247ec8376b60e325" @@ -538,6 +595,25 @@ aes-js "3.0.0" scrypt-js "3.0.1" +"@ethersproject/json-wallets@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.6.1.tgz#3f06ba555c9c0d7da46756a12ac53483fe18dd91" + integrity sha512-KfyJ6Zwz3kGeX25nLihPwZYlDqamO6pfGKNnVMWWfEVVp42lTfCZVXXy5Ie8IZTN0HKwAngpIPi7gk4IJzgmqQ== + dependencies: + "@ethersproject/abstract-signer" "^5.6.2" + "@ethersproject/address" "^5.6.1" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/hdnode" "^5.6.2" + "@ethersproject/keccak256" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/pbkdf2" "^5.6.1" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/random" "^5.6.1" + "@ethersproject/strings" "^5.6.1" + "@ethersproject/transactions" "^5.6.2" + aes-js "3.0.0" + scrypt-js "3.0.1" + "@ethersproject/keccak256@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.5.0.tgz#e4b1f9d7701da87c564ffe336f86dcee82983492" @@ -586,6 +662,14 @@ "@ethersproject/bytes" "^5.5.0" "@ethersproject/sha2" "^5.5.0" +"@ethersproject/pbkdf2@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.6.1.tgz#f462fe320b22c0d6b1d72a9920a3963b09eb82d1" + integrity sha512-k4gRQ+D93zDRPNUfmduNKq065uadC2YjMP/CqwwX5qG6R05f47boq6pLZtV/RnC4NZAYOPH1Cyo54q0c9sshRQ== + dependencies: + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/sha2" "^5.6.1" + "@ethersproject/properties@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.5.0.tgz#61f00f2bb83376d2071baab02245f92070c59995" @@ -625,6 +709,32 @@ bech32 "1.1.4" ws "7.4.6" +"@ethersproject/providers@^5.6.8": + version "5.6.8" + resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.6.8.tgz#22e6c57be215ba5545d3a46cf759d265bb4e879d" + integrity sha512-Wf+CseT/iOJjrGtAOf3ck9zS7AgPmr2fZ3N97r4+YXN3mBePTG2/bJ8DApl9mVwYL+RpYbNxMEkEp4mPGdwG/w== + dependencies: + "@ethersproject/abstract-provider" "^5.6.1" + "@ethersproject/abstract-signer" "^5.6.2" + "@ethersproject/address" "^5.6.1" + "@ethersproject/base64" "^5.6.1" + "@ethersproject/basex" "^5.6.1" + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/constants" "^5.6.1" + "@ethersproject/hash" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/networks" "^5.6.3" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/random" "^5.6.1" + "@ethersproject/rlp" "^5.6.1" + "@ethersproject/sha2" "^5.6.1" + "@ethersproject/strings" "^5.6.1" + "@ethersproject/transactions" "^5.6.2" + "@ethersproject/web" "^5.6.1" + bech32 "1.1.4" + ws "7.4.6" + "@ethersproject/random@^5.5.0": version "5.5.1" resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.5.1.tgz#7cdf38ea93dc0b1ed1d8e480ccdaf3535c555415" @@ -633,6 +743,14 @@ "@ethersproject/bytes" "^5.5.0" "@ethersproject/logger" "^5.5.0" +"@ethersproject/random@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.6.1.tgz#66915943981bcd3e11bbd43733f5c3ba5a790255" + integrity sha512-/wtPNHwbmng+5yi3fkipA8YBT59DdkGRoC2vWk09Dci/q5DlgnMkhIycjHlavrvrjJBkFjO/ueLyT+aUDfc4lA== + dependencies: + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/rlp@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.5.0.tgz#530f4f608f9ca9d4f89c24ab95db58ab56ab99a0" @@ -658,6 +776,15 @@ "@ethersproject/logger" "^5.5.0" hash.js "1.1.7" +"@ethersproject/sha2@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.6.1.tgz#211f14d3f5da5301c8972a8827770b6fd3e51656" + integrity sha512-5K2GyqcW7G4Yo3uenHegbXRPDgARpWUiXc6RiF7b6i/HXUoWlb7uCARh7BAHg7/qT/Q5ydofNwiZcim9qpjB6g== + dependencies: + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + hash.js "1.1.7" + "@ethersproject/signing-key@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.5.0.tgz#2aa37169ce7e01e3e80f2c14325f624c29cedbe0" @@ -682,7 +809,7 @@ elliptic "6.5.4" hash.js "1.1.7" -"@ethersproject/solidity@^5.0.10", "@ethersproject/solidity@^5.0.9": +"@ethersproject/solidity@^5.0.9": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.5.0.tgz#2662eb3e5da471b85a20531e420054278362f93f" integrity sha512-9NgZs9LhGMj6aCtHXhtmFQ4AN4sth5HuFXVvAQtzmm0jpSCNOTGtrHZJAeYTh7MBjRR8brylWZxBZR9zDStXbw== @@ -694,7 +821,19 @@ "@ethersproject/sha2" "^5.5.0" "@ethersproject/strings" "^5.5.0" -"@ethersproject/strings@^5.0.5", "@ethersproject/strings@^5.5.0": +"@ethersproject/solidity@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.6.1.tgz#5845e71182c66d32e6ec5eefd041fca091a473e2" + integrity sha512-KWqVLkUUoLBfL1iwdzUVlkNqAUIFMpbbeH0rgCfKmJp0vFtY4AsaN91gHKo9ZZLkC4UOm3cI3BmMV4N53BOq4g== + dependencies: + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/keccak256" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/sha2" "^5.6.1" + "@ethersproject/strings" "^5.6.1" + +"@ethersproject/strings@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.5.0.tgz#e6784d00ec6c57710755699003bc747e98c5d549" integrity sha512-9fy3TtF5LrX/wTrBaT8FGE6TDJyVjOvXynXJz5MT5azq+E6D92zuKNx7i29sWW2FjVOaWjAsiZ1ZWznuduTIIQ== @@ -742,14 +881,14 @@ "@ethersproject/rlp" "^5.6.1" "@ethersproject/signing-key" "^5.6.2" -"@ethersproject/units@^5.0.3": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.5.0.tgz#104d02db5b5dc42cc672cc4587bafb87a95ee45e" - integrity sha512-7+DpjiZk4v6wrikj+TCyWWa9dXLNU73tSTa7n0TSJDxkYbV3Yf1eRh9ToMLlZtuctNYu9RDNNy2USq3AdqSbag== +"@ethersproject/units@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.6.1.tgz#ecc590d16d37c8f9ef4e89e2005bda7ddc6a4e6f" + integrity sha512-rEfSEvMQ7obcx3KWD5EWWx77gqv54K6BKiZzKxkQJqtpriVsICrktIQmKl8ReNToPeIYPnFHpXvKpi068YFZXw== dependencies: - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/constants" "^5.5.0" - "@ethersproject/logger" "^5.5.0" + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/constants" "^5.6.1" + "@ethersproject/logger" "^5.6.0" "@ethersproject/wallet@^5.4.0": version "5.5.0" @@ -772,6 +911,27 @@ "@ethersproject/transactions" "^5.5.0" "@ethersproject/wordlists" "^5.5.0" +"@ethersproject/wallet@^5.6.2": + version "5.6.2" + resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.6.2.tgz#cd61429d1e934681e413f4bc847a5f2f87e3a03c" + integrity sha512-lrgh0FDQPuOnHcF80Q3gHYsSUODp6aJLAdDmDV0xKCN/T7D99ta1jGVhulg3PY8wiXEngD0DfM0I2XKXlrqJfg== + dependencies: + "@ethersproject/abstract-provider" "^5.6.1" + "@ethersproject/abstract-signer" "^5.6.2" + "@ethersproject/address" "^5.6.1" + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/hash" "^5.6.1" + "@ethersproject/hdnode" "^5.6.2" + "@ethersproject/json-wallets" "^5.6.1" + "@ethersproject/keccak256" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/random" "^5.6.1" + "@ethersproject/signing-key" "^5.6.2" + "@ethersproject/transactions" "^5.6.2" + "@ethersproject/wordlists" "^5.6.1" + "@ethersproject/web@^5.5.0": version "5.5.1" resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.5.1.tgz#cfcc4a074a6936c657878ac58917a61341681316" @@ -805,6 +965,31 @@ "@ethersproject/properties" "^5.5.0" "@ethersproject/strings" "^5.5.0" +"@ethersproject/wordlists@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.6.1.tgz#1e78e2740a8a21e9e99947e47979d72e130aeda1" + integrity sha512-wiPRgBpNbNwCQFoCr8bcWO8o5I810cqO6mkdtKfLKFlLxeCWcnzDi4Alu8iyNzlhYuS9npCwivMbRWF19dyblw== + dependencies: + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/hash" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/strings" "^5.6.1" + +"@humanwhocodes/config-array@^0.9.2": + version "0.9.5" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.5.tgz#2cbaf9a89460da24b5ca6531b8bbfc23e1df50c7" + integrity sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.4" + +"@humanwhocodes/object-schema@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -833,15 +1018,15 @@ jest-util "^28.1.1" slash "^3.0.0" -"@jest/core@^28.1.1": - version "28.1.1" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-28.1.1.tgz#086830bec6267accf9af5ca76f794858e9f9f092" - integrity sha512-3pYsBoZZ42tXMdlcFeCc/0j9kOlK7MYuXs2B1QbvDgMoW1K9NJ4G/VYvIbMb26iqlkTfPHo7SC2JgjDOk/mxXw== +"@jest/core@^28.1.2": + version "28.1.2" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-28.1.2.tgz#eac519b9acbd154313854b8823a47b5c645f785a" + integrity sha512-Xo4E+Sb/nZODMGOPt2G3cMmCBqL4/W2Ijwr7/mrXlq4jdJwcFQ/9KrrJZT2adQRk2otVBXXOz1GRQ4Z5iOgvRQ== dependencies: "@jest/console" "^28.1.1" - "@jest/reporters" "^28.1.1" + "@jest/reporters" "^28.1.2" "@jest/test-result" "^28.1.1" - "@jest/transform" "^28.1.1" + "@jest/transform" "^28.1.2" "@jest/types" "^28.1.1" "@types/node" "*" ansi-escapes "^4.2.1" @@ -850,15 +1035,15 @@ exit "^0.1.2" graceful-fs "^4.2.9" jest-changed-files "^28.0.2" - jest-config "^28.1.1" + jest-config "^28.1.2" jest-haste-map "^28.1.1" jest-message-util "^28.1.1" jest-regex-util "^28.0.2" jest-resolve "^28.1.1" - jest-resolve-dependencies "^28.1.1" - jest-runner "^28.1.1" - jest-runtime "^28.1.1" - jest-snapshot "^28.1.1" + jest-resolve-dependencies "^28.1.2" + jest-runner "^28.1.2" + jest-runtime "^28.1.2" + jest-snapshot "^28.1.2" jest-util "^28.1.1" jest-validate "^28.1.1" jest-watcher "^28.1.1" @@ -868,12 +1053,12 @@ slash "^3.0.0" strip-ansi "^6.0.0" -"@jest/environment@^28.1.1": - version "28.1.1" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-28.1.1.tgz#c4cbf85283278d768f816ebd1a258ea6f9e39d4f" - integrity sha512-9auVQ2GzQ7nrU+lAr8KyY838YahElTX9HVjbQPPS2XjlxQ+na18G113OoBhyBGBtD6ZnO/SrUy5WR8EzOj1/Uw== +"@jest/environment@^28.1.2": + version "28.1.2" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-28.1.2.tgz#94a052c0c5f9f8c8e6d13ea6da78dbc5d7d9b85b" + integrity sha512-I0CR1RUMmOzd0tRpz10oUfaChBWs+/Hrvn5xYhMEF/ZqrDaaeHwS8yDBqEWCrEnkH2g+WE/6g90oBv3nKpcm8Q== dependencies: - "@jest/fake-timers" "^28.1.1" + "@jest/fake-timers" "^28.1.2" "@jest/types" "^28.1.1" "@types/node" "*" jest-mock "^28.1.1" @@ -885,46 +1070,46 @@ dependencies: jest-get-type "^28.0.2" -"@jest/expect@^28.1.1": - version "28.1.1" - resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-28.1.1.tgz#ea4fcc8504b45835029221c0dc357c622a761326" - integrity sha512-/+tQprrFoT6lfkMj4mW/mUIfAmmk/+iQPmg7mLDIFOf2lyf7EBHaS+x3RbeR0VZVMe55IvX7QRoT/2aK3AuUXg== +"@jest/expect@^28.1.2": + version "28.1.2" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-28.1.2.tgz#0b25acedff46e1e1e5606285306c8a399c12534f" + integrity sha512-HBzyZBeFBiOelNbBKN0pilWbbrGvwDUwAqMC46NVJmWm8AVkuE58NbG1s7DR4cxFt4U5cVLxofAoHxgvC5MyOw== dependencies: expect "^28.1.1" - jest-snapshot "^28.1.1" + jest-snapshot "^28.1.2" -"@jest/fake-timers@^28.1.1": - version "28.1.1" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-28.1.1.tgz#47ce33296ab9d680c76076d51ddbe65ceb3337f1" - integrity sha512-BY/3+TyLs5+q87rGWrGUY5f8e8uC3LsVHS9Diz8+FV3ARXL4sNnkLlIB8dvDvRrp+LUCGM+DLqlsYubizGUjIA== +"@jest/fake-timers@^28.1.2": + version "28.1.2" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-28.1.2.tgz#d49e8ee4e02ba85a6e844a52a5e7c59c23e3b76f" + integrity sha512-xSYEI7Y0D5FbZN2LsCUj/EKRR1zfQYmGuAUVh6xTqhx7V5JhjgMcK5Pa0iR6WIk0GXiHDe0Ke4A+yERKE9saqg== dependencies: "@jest/types" "^28.1.1" - "@sinonjs/fake-timers" "^9.1.1" + "@sinonjs/fake-timers" "^9.1.2" "@types/node" "*" jest-message-util "^28.1.1" jest-mock "^28.1.1" jest-util "^28.1.1" -"@jest/globals@^28.1.1": - version "28.1.1" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-28.1.1.tgz#c0a7977f85e26279cc090d9adcdf82b8a34c4061" - integrity sha512-dEgl/6v7ToB4vXItdvcltJBgny0xBE6xy6IYQrPJAJggdEinGxCDMivNv7sFzPcTITGquXD6UJwYxfJ/5ZwDSg== +"@jest/globals@^28.1.2": + version "28.1.2" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-28.1.2.tgz#92fab296e337c7309c25e4202fb724f62249d83f" + integrity sha512-cz0lkJVDOtDaYhvT3Fv2U1B6FtBnV+OpEyJCzTHM1fdoTsU4QNLAt/H4RkiwEUU+dL4g/MFsoTuHeT2pvbo4Hg== dependencies: - "@jest/environment" "^28.1.1" - "@jest/expect" "^28.1.1" + "@jest/environment" "^28.1.2" + "@jest/expect" "^28.1.2" "@jest/types" "^28.1.1" -"@jest/reporters@^28.1.1": - version "28.1.1" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-28.1.1.tgz#9389f4bb3cce4d9b586f6195f83c79cd2a1c8662" - integrity sha512-597Zj4D4d88sZrzM4atEGLuO7SdA/YrOv9SRXHXRNC+/FwPCWxZhBAEzhXoiJzfRwn8zes/EjS8Lo6DouGN5Gg== +"@jest/reporters@^28.1.2": + version "28.1.2" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-28.1.2.tgz#0327be4ce4d0d9ae49e7908656f89669d0c2a260" + integrity sha512-/whGLhiwAqeCTmQEouSigUZJPVl7sW8V26EiboImL+UyXznnr1a03/YZ2BX8OlFw0n+Zlwu+EZAITZtaeRTxyA== dependencies: "@bcoe/v8-coverage" "^0.2.3" "@jest/console" "^28.1.1" "@jest/test-result" "^28.1.1" - "@jest/transform" "^28.1.1" + "@jest/transform" "^28.1.2" "@jest/types" "^28.1.1" - "@jridgewell/trace-mapping" "^0.3.7" + "@jridgewell/trace-mapping" "^0.3.13" "@types/node" "*" chalk "^4.0.0" collect-v8-coverage "^1.0.0" @@ -943,7 +1128,7 @@ string-length "^4.0.1" strip-ansi "^6.0.0" terminal-link "^2.0.0" - v8-to-istanbul "^9.0.0" + v8-to-istanbul "^9.0.1" "@jest/schemas@^28.0.2": version "28.0.2" @@ -952,12 +1137,12 @@ dependencies: "@sinclair/typebox" "^0.23.3" -"@jest/source-map@^28.0.2": - version "28.0.2" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-28.0.2.tgz#914546f4410b67b1d42c262a1da7e0406b52dc90" - integrity sha512-Y9dxC8ZpN3kImkk0LkK5XCEneYMAXlZ8m5bflmSL5vrwyeUpJfentacCUg6fOb8NOpOO7hz2+l37MV77T6BFPw== +"@jest/source-map@^28.1.2": + version "28.1.2" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-28.1.2.tgz#7fe832b172b497d6663cdff6c13b0a920e139e24" + integrity sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww== dependencies: - "@jridgewell/trace-mapping" "^0.3.7" + "@jridgewell/trace-mapping" "^0.3.13" callsites "^3.0.0" graceful-fs "^4.2.9" @@ -981,14 +1166,14 @@ jest-haste-map "^28.1.1" slash "^3.0.0" -"@jest/transform@^28.1.1": - version "28.1.1" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-28.1.1.tgz#83541f2a3f612077c8501f49cc4e205d4e4a6b27" - integrity sha512-PkfaTUuvjUarl1EDr5ZQcCA++oXkFCP9QFUkG0yVKVmNObjhrqDy0kbMpMebfHWm3CCDHjYNem9eUSH8suVNHQ== +"@jest/transform@^28.1.2": + version "28.1.2" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-28.1.2.tgz#b367962c53fd53821269bde050ce373e111327c1" + integrity sha512-3o+lKF6iweLeJFHBlMJysdaPbpoMmtbHEFsjzSv37HIq/wWt5ijTeO2Yf7MO5yyczCopD507cNwNLeX8Y/CuIg== dependencies: "@babel/core" "^7.11.6" "@jest/types" "^28.1.1" - "@jridgewell/trace-mapping" "^0.3.7" + "@jridgewell/trace-mapping" "^0.3.13" babel-plugin-istanbul "^6.1.1" chalk "^4.0.0" convert-source-map "^1.4.0" @@ -1002,17 +1187,6 @@ slash "^3.0.0" write-file-atomic "^4.0.1" -"@jest/types@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" - integrity sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^15.0.0" - chalk "^4.0.0" - "@jest/types@^28.1.1": version "28.1.1" resolved "https://registry.yarnpkg.com/@jest/types/-/types-28.1.1.tgz#d059bbc80e6da6eda9f081f293299348bd78ee0b" @@ -1057,7 +1231,15 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz#b6461fb0c2964356c469e115f504c95ad97ab88c" integrity sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w== -"@jridgewell/trace-mapping@^0.3.7", "@jridgewell/trace-mapping@^0.3.9": +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.13": + version "0.3.14" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed" + integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@jridgewell/trace-mapping@^0.3.9": version "0.3.13" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz#dcfe3e95f224c8fe97a87a5235defec999aa92ea" integrity sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w== @@ -1091,6 +1273,11 @@ resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.4.1-solc-0.7-2.tgz#371c67ebffe50f551c3146a9eec5fe6ffe862e92" integrity sha512-tAG9LWg8+M2CMu7hIsqHPaTyG4uDzjr6mhvH96LvOpLZZj6tgzTluBt+LsCf1/QaYrlis6pITvpIaIhE+iZB+Q== +"@openzeppelin/contracts@3.4.2-solc-0.7": + version "3.4.2-solc-0.7" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.4.2-solc-0.7.tgz#38f4dbab672631034076ccdf2f3201fab1726635" + integrity sha512-W6QmqgkADuFcTLzHL8vVoNBtkwjvQRpYIAom7KiUNoLKghyx3FgH0GBjt8NRvigV1ZmMOBllvE1By1C+bi8WpA== + "@sinclair/typebox@^0.23.3": version "0.23.5" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.23.5.tgz#93f7b9f4e3285a7a9ade7557d9a8d36809cbc47d" @@ -1103,14 +1290,14 @@ dependencies: type-detect "4.0.8" -"@sinonjs/fake-timers@^9.1.1": +"@sinonjs/fake-timers@^9.1.2": version "9.1.2" resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz#4eaab737fab77332ab132d396a3c0d364bd0ea8c" integrity sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw== dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.9": +"@snapshot-labs/snapshot.js@^0.4.8": version "0.4.9" resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.9.tgz#fdac2800d57e52b201aa8e5fc1f5db2bbd15402c" integrity sha512-5y5sM34tZm1VVxHzwJ5nnm4kb1eRI6CDcBRu0if9gK2H+qadG+yWH9f/boPIB6cskPvH760chRR8bdjseAB25Q== @@ -1187,18 +1374,18 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@^26.0.23": - version "26.0.24" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.24.tgz#943d11976b16739185913a1936e0de0c4a7d595a" - integrity sha512-E/X5Vib8BWqZNRlDxj9vYXhsDwPYbPINqKF9BsnSoon4RQ0D9moEuLD8txgyypFLH7J4+Lho9Nr/c8H0Fi+17w== +"@types/jest@^28.1.4": + version "28.1.4" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-28.1.4.tgz#a11ee6c8fd0b52c19c9c18138b78bbcc201dad5a" + integrity sha512-telv6G5N7zRJiLcI3Rs3o+ipZ28EnE+7EvF0pSrt2pZOMnAVI/f+6/LucDxOvcBcTeTL3JMF744BbVQAVBUQRA== dependencies: - jest-diff "^26.0.0" - pretty-format "^26.0.0" + jest-matcher-utils "^28.0.0" + pretty-format "^28.0.0" -"@types/json-schema@^7.0.7": - version "7.0.9" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" - integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== +"@types/json-schema@^7.0.9": + version "7.0.11" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" + integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== "@types/json5@^0.0.29": version "0.0.29" @@ -1210,10 +1397,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.0.0.tgz#67c7b724e1bcdd7a8821ce0d5ee184d3b4dd525a" integrity sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA== -"@types/node@^13.9.5": - version "13.13.52" - resolved "https://registry.yarnpkg.com/@types/node/-/node-13.13.52.tgz#03c13be70b9031baaed79481c0c0cfb0045e53f7" - integrity sha512-s3nugnZumCC//n4moGGe6tkNMyYEdaDBitVjwPxXmR5lnMG5dHePinH2EdxkG3Rh1ghFHHixAG4NJhpJW1rthQ== +"@types/node@^18.0.3": + version "18.0.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.0.3.tgz#463fc47f13ec0688a33aec75d078a0541a447199" + integrity sha512-HzNRZtp4eepNitP+BD6k2L6DROIDG4Q0fm4x+dwfsr6LGmROENnok75VGw40628xf+iR24WeMFcHuuBDUAzzsQ== "@types/prettier@^2.1.5": version "2.6.3" @@ -1230,13 +1417,6 @@ resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== -"@types/yargs@^15.0.0": - version "15.0.14" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.14.tgz#26d821ddb89e70492160b66d10a0eb6df8f6fb06" - integrity sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ== - dependencies: - "@types/yargs-parser" "*" - "@types/yargs@^17.0.8": version "17.0.10" resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.10.tgz#591522fce85d8739bca7b8bb90d048e4478d186a" @@ -1244,75 +1424,85 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^4.28.2": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz#c24dc7c8069c7706bc40d99f6fa87edcb2005276" - integrity sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg== +"@typescript-eslint/eslint-plugin@^5.30.5": + version "5.30.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.5.tgz#e9a0afd6eb3b1d663db91cf1e7bc7584d394503d" + integrity sha512-lftkqRoBvc28VFXEoRgyZuztyVUQ04JvUnATSPtIRFAccbXTWL6DEtXGYMcbg998kXw1NLUJm7rTQ9eUt+q6Ig== dependencies: - "@typescript-eslint/experimental-utils" "4.33.0" - "@typescript-eslint/scope-manager" "4.33.0" - debug "^4.3.1" + "@typescript-eslint/scope-manager" "5.30.5" + "@typescript-eslint/type-utils" "5.30.5" + "@typescript-eslint/utils" "5.30.5" + debug "^4.3.4" functional-red-black-tree "^1.0.1" - ignore "^5.1.8" - regexpp "^3.1.0" - semver "^7.3.5" + ignore "^5.2.0" + regexpp "^3.2.0" + semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/experimental-utils@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz#6f2a786a4209fa2222989e9380b5331b2810f7fd" - integrity sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q== +"@typescript-eslint/parser@^5.30.5": + version "5.30.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.30.5.tgz#f667c34e4e4c299d98281246c9b1e68c03a92522" + integrity sha512-zj251pcPXI8GO9NDKWWmygP6+UjwWmrdf9qMW/L/uQJBM/0XbU2inxe5io/234y/RCvwpKEYjZ6c1YrXERkK4Q== dependencies: - "@types/json-schema" "^7.0.7" - "@typescript-eslint/scope-manager" "4.33.0" - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/typescript-estree" "4.33.0" - eslint-scope "^5.1.1" - eslint-utils "^3.0.0" + "@typescript-eslint/scope-manager" "5.30.5" + "@typescript-eslint/types" "5.30.5" + "@typescript-eslint/typescript-estree" "5.30.5" + debug "^4.3.4" -"@typescript-eslint/parser@^4.28.2": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.33.0.tgz#dfe797570d9694e560528d18eecad86c8c744899" - integrity sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA== - dependencies: - "@typescript-eslint/scope-manager" "4.33.0" - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/typescript-estree" "4.33.0" - debug "^4.3.1" - -"@typescript-eslint/scope-manager@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz#d38e49280d983e8772e29121cf8c6e9221f280a3" - integrity sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ== - dependencies: - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/visitor-keys" "4.33.0" - -"@typescript-eslint/types@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72" - integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ== - -"@typescript-eslint/typescript-estree@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz#0dfb51c2908f68c5c08d82aefeaf166a17c24609" - integrity sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA== - dependencies: - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/visitor-keys" "4.33.0" - debug "^4.3.1" - globby "^11.0.3" - is-glob "^4.0.1" - semver "^7.3.5" +"@typescript-eslint/scope-manager@5.30.5": + version "5.30.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.30.5.tgz#7f90b9d6800552c856a5f3644f5e55dd1469d964" + integrity sha512-NJ6F+YHHFT/30isRe2UTmIGGAiXKckCyMnIV58cE3JkHmaD6e5zyEYm5hBDv0Wbin+IC0T1FWJpD3YqHUG/Ydg== + dependencies: + "@typescript-eslint/types" "5.30.5" + "@typescript-eslint/visitor-keys" "5.30.5" + +"@typescript-eslint/type-utils@5.30.5": + version "5.30.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.30.5.tgz#7a9656f360b4b1daea635c4621dab053d08bf8a9" + integrity sha512-k9+ejlv1GgwN1nN7XjVtyCgE0BTzhzT1YsQF0rv4Vfj2U9xnslBgMYYvcEYAFVdvhuEscELJsB7lDkN7WusErw== + dependencies: + "@typescript-eslint/utils" "5.30.5" + debug "^4.3.4" tsutils "^3.21.0" -"@typescript-eslint/visitor-keys@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz#2a22f77a41604289b7a186586e9ec48ca92ef1dd" - integrity sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg== +"@typescript-eslint/types@5.30.5": + version "5.30.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.30.5.tgz#36a0c05a72af3623cdf9ee8b81ea743b7de75a98" + integrity sha512-kZ80w/M2AvsbRvOr3PjaNh6qEW1LFqs2pLdo2s5R38B2HYXG8Z0PP48/4+j1QHJFL3ssHIbJ4odPRS8PlHrFfw== + +"@typescript-eslint/typescript-estree@5.30.5": + version "5.30.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.5.tgz#c520e4eba20551c4ec76af8d344a42eb6c9767bb" + integrity sha512-qGTc7QZC801kbYjAr4AgdOfnokpwStqyhSbiQvqGBLixniAKyH+ib2qXIVo4P9NgGzwyfD9I0nlJN7D91E1VpQ== dependencies: - "@typescript-eslint/types" "4.33.0" - eslint-visitor-keys "^2.0.0" + "@typescript-eslint/types" "5.30.5" + "@typescript-eslint/visitor-keys" "5.30.5" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/utils@5.30.5": + version "5.30.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.30.5.tgz#3999cbd06baad31b9e60d084f20714d1b2776765" + integrity sha512-o4SSUH9IkuA7AYIfAvatldovurqTAHrfzPApOZvdUq01hHojZojCFXx06D/aFpKCgWbMPRdJBWAC3sWp3itwTA== + dependencies: + "@types/json-schema" "^7.0.9" + "@typescript-eslint/scope-manager" "5.30.5" + "@typescript-eslint/types" "5.30.5" + "@typescript-eslint/typescript-estree" "5.30.5" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + +"@typescript-eslint/visitor-keys@5.30.5": + version "5.30.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.5.tgz#d4bb969202019d5d5d849a0aaedc7370cc044b14" + integrity sha512-D+xtGo9HUMELzWIUqcQc0p2PO4NyvTrgIOK/VnSH083+8sq0tiLozNRKuLarwHYGRuA6TVBQSuuLwJUDWd3aaA== + dependencies: + "@typescript-eslint/types" "5.30.5" + eslint-visitor-keys "^3.3.0" "@uniswap/lib@^4.0.1-alpha": version "4.0.1-alpha" @@ -1331,6 +1521,18 @@ tiny-invariant "^1.1.0" toformat "^2.0.0" +"@uniswap/swap-router-contracts@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@uniswap/swap-router-contracts/-/swap-router-contracts-1.2.1.tgz#223c8b6672b7754080d95ca917763d98feb5e696" + integrity sha512-aRNiZYIOpJ0uYxujPxvQsUEuNJWLC4bvnmU40TlNej1rGWHPyDL1PmnVzebu8UpW9EGeKlvDjsNGTyo53dih9Q== + dependencies: + "@openzeppelin/contracts" "3.4.2-solc-0.7" + "@uniswap/v2-core" "1.0.1" + "@uniswap/v3-core" "1.0.0" + "@uniswap/v3-periphery" "1.4.1" + dotenv "^14.2.0" + hardhat-watcher "^2.1.1" + "@uniswap/v2-core@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@uniswap/v2-core/-/v2-core-1.0.1.tgz#af8f508bf183204779938969e2e54043e147d425" @@ -1341,6 +1543,18 @@ resolved "https://registry.yarnpkg.com/@uniswap/v3-core/-/v3-core-1.0.0.tgz#6c24adacc4c25dceee0ba3ca142b35adbd7e359d" integrity sha512-kSC4djMGKMHj7sLMYVnn61k9nu+lHjMIxgg9CDQT+s2QYLoA56GbSK9Oxr+qJXzzygbkrmuY6cwgP6cW2JXPFA== +"@uniswap/v3-periphery@1.4.1": + version "1.4.1" + resolved "https://registry.yarnpkg.com/@uniswap/v3-periphery/-/v3-periphery-1.4.1.tgz#b90f08b7386163c0abfd7258831caef6339c7862" + integrity sha512-Ab0ZCKOQrQMKIcpBTezTsEhWfQjItd0TtkCG8mPhoQu+wC67nPaf4hYUhM6wGHeFUmDiYY5MpEQuokB0ENvoTg== + dependencies: + "@openzeppelin/contracts" "3.4.2-solc-0.7" + "@uniswap/lib" "^4.0.1-alpha" + "@uniswap/v2-core" "1.0.1" + "@uniswap/v3-core" "1.0.0" + base64-sol "1.0.1" + hardhat-watcher "^2.1.1" + "@uniswap/v3-periphery@^1.0.1", "@uniswap/v3-periphery@^1.1.1": version "1.4.0" resolved "https://registry.yarnpkg.com/@uniswap/v3-periphery/-/v3-periphery-1.4.0.tgz#9abb733fc596916718070c688b5f426fd8d01fe3" @@ -1353,14 +1567,15 @@ base64-sol "1.0.1" hardhat-watcher "^2.1.1" -"@uniswap/v3-sdk@^3.3.1": - version "3.8.1" - resolved "https://registry.yarnpkg.com/@uniswap/v3-sdk/-/v3-sdk-3.8.1.tgz#111f50a5da32ae3827d9ef500a29dcb38c7e2e43" - integrity sha512-Fn+h9zNVzgX8DE0hTWqMyXNF1AhT1ovmzE2dpSsTZmJkxVbc70+DzENeuknTfA+nmemtB915mq4vHrJL3lZGjA== +"@uniswap/v3-sdk@^3.9.0": + version "3.9.0" + resolved "https://registry.yarnpkg.com/@uniswap/v3-sdk/-/v3-sdk-3.9.0.tgz#de93fa19f89c29d460996aa4d0b4bb6531641105" + integrity sha512-LuoF3UcY1DxSAQKJ3E4/1Eq4HaNp+x+7q9mvbpiu+/PBj+O1DjLforAMrKxu+RsA0aarmZtz7yBnAPy+akgfgQ== dependencies: "@ethersproject/abi" "^5.0.12" "@ethersproject/solidity" "^5.0.9" "@uniswap/sdk-core" "^3.0.1" + "@uniswap/swap-router-contracts" "^1.2.1" "@uniswap/v3-periphery" "^1.1.1" "@uniswap/v3-staker" "1.0.0" tiny-invariant "^1.1.0" @@ -1375,15 +1590,15 @@ "@uniswap/v3-core" "1.0.0" "@uniswap/v3-periphery" "^1.0.1" -acorn-jsx@^5.2.0: +acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^7.1.1: - version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== +acorn@^8.7.1: + version "8.7.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" + integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== aes-js@3.0.0: version "3.0.0" @@ -1397,7 +1612,7 @@ ajv-formats@^2.1.0: dependencies: ajv "^8.0.0" -ajv@^6.10.0, ajv@^6.10.2: +ajv@^6.10.0, ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -1424,17 +1639,12 @@ ansi-escapes@^4.2.1: dependencies: type-fest "^0.21.3" -ansi-regex@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" - integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== - -ansi-regex@^5.0.0, ansi-regex@^5.0.1: +ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== -ansi-styles@^3.2.0, ansi-styles@^3.2.1: +ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== @@ -1468,6 +1678,11 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + array-includes@^3.1.4: version "3.1.4" resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.4.tgz#f5b493162c760f3539631f005ba2bb46acb45ba9" @@ -1493,17 +1708,12 @@ array.prototype.flat@^1.2.5: define-properties "^1.1.3" es-abstract "^1.19.0" -astral-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" - integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== - -babel-jest@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-28.1.1.tgz#2a3a4ae50964695b2d694ccffe4bec537c5a3586" - integrity sha512-MEt0263viUdAkTq5D7upHPNxvt4n9uLUGa6pPz3WviNBMtOmStb1lIXS3QobnoqM+qnH+vr4EKlvhe8QcmxIYw== +babel-jest@^28.1.2: + version "28.1.2" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-28.1.2.tgz#2b37fb81439f14d34d8b2cc4a4bd7efabf9acbfe" + integrity sha512-pfmoo6sh4L/+5/G2OOfQrGJgvH7fTa1oChnuYH2G/6gA+JwDvO8PELwvwnofKBMNrQsam0Wy/Rw+QSrBNewq2Q== dependencies: - "@jest/transform" "^28.1.1" + "@jest/transform" "^28.1.2" "@types/babel__core" "^7.1.14" babel-plugin-istanbul "^6.1.1" babel-preset-jest "^28.1.1" @@ -1671,7 +1881,7 @@ caniuse-lite@^1.0.30001349: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001357.tgz#dec7fc4158ef6ad24690d0eec7b91f32b8cb1b5d" integrity sha512-b+KbWHdHePp+ZpNj+RDHFChZmuN+J5EvuQUlee9jOQIUAdhv9uvAZeEtUeLAknXbkiu1uxjQ9NLp1ie894CuWg== -chalk@^2.0.0, chalk@^2.1.0: +chalk@^2.0.0: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -1680,7 +1890,7 @@ chalk@^2.0.0, chalk@^2.1.0: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.0.0, chalk@^4.1.0: +chalk@^4.0.0: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -1693,11 +1903,6 @@ char-regex@^1.0.2: resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== -chardet@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== - chokidar@^3.4.3: version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" @@ -1723,18 +1928,6 @@ cjs-module-lexer@^1.0.0: resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== -cli-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" - integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== - dependencies: - restore-cursor "^3.1.0" - -cli-width@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" - integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== - cliui@^7.0.2: version "7.0.4" resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" @@ -1813,13 +2006,6 @@ core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== -cross-fetch@^3.0.6: - version "3.1.4" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.4.tgz#9723f3a3a247bf8b89039f3a380a9244e8fa2f39" - integrity sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ== - dependencies: - node-fetch "2.6.1" - cross-fetch@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" @@ -1827,18 +2013,7 @@ cross-fetch@^3.1.5: dependencies: node-fetch "2.6.7" -cross-spawn@^6.0.5: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - -cross-spawn@^7.0.3: +cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -1861,14 +2036,7 @@ debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.0.1, debug@^4.3.1: - version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== - dependencies: - ms "2.1.2" - -debug@^4.1.0, debug@^4.1.1: +debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -1885,7 +2053,7 @@ dedent@^0.7.0: resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== -deep-is@~0.1.3: +deep-is@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== @@ -1907,11 +2075,6 @@ detect-newline@^3.0.0: resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== -diff-sequences@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" - integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q== - diff-sequences@^28.1.1: version "28.1.1" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-28.1.1.tgz#9989dc731266dc2903457a70e996f3a041913ac6" @@ -1938,6 +2101,11 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" +dotenv@^14.2.0: + version "14.3.2" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-14.3.2.tgz#7c30b3a5f777c79a3429cb2db358eef6751e8369" + integrity sha512-vwEppIphpFdvaMCaHfCEv9IgwcxMljMw2TnAQBB4VWPvzXQLTb82jwmdOKzlEVUL3gNFT4l4TPKO+Bn+sqcrVQ== + electron-to-chromium@^1.4.147: version "1.4.161" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.161.tgz#49cb5b35385bfee6cc439d0a04fbba7a7a7f08a1" @@ -1961,11 +2129,6 @@ emittery@^0.10.2: resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.10.2.tgz#902eec8aedb8c41938c46e9385e9db7e03182933" integrity sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw== -emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" - integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== - emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" @@ -2028,14 +2191,20 @@ escape-string-regexp@^2.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== -eslint-config-airbnb-base@^14.1.0: - version "14.2.1" - resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.1.tgz#8a2eb38455dc5a312550193b319cdaeef042cd1e" - integrity sha512-GOrQyDtVEc1Xy20U7vsB2yAoB4nBlfH5HZJeatRXHleO+OS5Ot+MWij4Dpltw4/DyIkqUfqz1epfhVR5XWWQPA== +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-config-airbnb-base@^15.0.0: + version "15.0.0" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz#6b09add90ac79c2f8d723a2580e07f3925afd236" + integrity sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig== dependencies: confusing-browser-globals "^1.0.10" object.assign "^4.1.2" - object.entries "^1.1.2" + object.entries "^1.1.5" + semver "^6.3.0" eslint-import-resolver-node@^0.3.6: version "0.3.6" @@ -2045,41 +2214,41 @@ eslint-import-resolver-node@^0.3.6: debug "^3.2.7" resolve "^1.20.0" -eslint-module-utils@^2.7.2: - version "2.7.2" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.2.tgz#1d0aa455dcf41052339b63cada8ab5fd57577129" - integrity sha512-zquepFnWCY2ISMFwD/DqzaM++H+7PDzOpUvotJWm/y1BAFt5R4oeULgdrTejKqLkz7MA/tgstsUMNYc7wNdTrg== +eslint-module-utils@^2.7.3: + version "2.7.3" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz#ad7e3a10552fdd0642e1e55292781bd6e34876ee" + integrity sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ== dependencies: debug "^3.2.7" find-up "^2.1.0" -eslint-plugin-import@^2.20.2: - version "2.25.4" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz#322f3f916a4e9e991ac7af32032c25ce313209f1" - integrity sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA== +eslint-plugin-import@^2.26.0: + version "2.26.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz#f812dc47be4f2b72b478a021605a59fc6fe8b88b" + integrity sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA== dependencies: array-includes "^3.1.4" array.prototype.flat "^1.2.5" debug "^2.6.9" doctrine "^2.1.0" eslint-import-resolver-node "^0.3.6" - eslint-module-utils "^2.7.2" + eslint-module-utils "^2.7.3" has "^1.0.3" - is-core-module "^2.8.0" + is-core-module "^2.8.1" is-glob "^4.0.3" - minimatch "^3.0.4" + minimatch "^3.1.2" object.values "^1.1.5" - resolve "^1.20.0" - tsconfig-paths "^3.12.0" + resolve "^1.22.0" + tsconfig-paths "^3.14.1" -eslint-plugin-prettier@^3.4.0: - version "3.4.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz#e9ddb200efb6f3d05ffe83b1665a716af4a387e5" - integrity sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g== +eslint-plugin-prettier@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz#651cbb88b1dab98bfd42f017a12fa6b2d993f94b" + integrity sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ== dependencies: prettier-linter-helpers "^1.0.0" -eslint-scope@^5.0.0, eslint-scope@^5.1.1: +eslint-scope@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== @@ -2087,12 +2256,13 @@ eslint-scope@^5.0.0, eslint-scope@^5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" -eslint-utils@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" - integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== +eslint-scope@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" + integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== dependencies: - eslint-visitor-keys "^1.1.0" + esrecurse "^4.3.0" + estraverse "^5.2.0" eslint-utils@^3.0.0: version "3.0.0" @@ -2101,74 +2271,72 @@ eslint-utils@^3.0.0: dependencies: eslint-visitor-keys "^2.0.0" -eslint-visitor-keys@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== - eslint-visitor-keys@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== -eslint@^6.8.0: - version "6.8.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb" - integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig== +eslint-visitor-keys@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" + integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== + +eslint@^8.19.0: + version "8.19.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.19.0.tgz#7342a3cbc4fbc5c106a1eefe0fd0b50b6b1a7d28" + integrity sha512-SXOPj3x9VKvPe81TjjUJCYlV4oJjQw68Uek+AM0X4p+33dj2HY5bpTZOgnQHcG2eAm1mtCU9uNMnJi7exU/kYw== dependencies: - "@babel/code-frame" "^7.0.0" + "@eslint/eslintrc" "^1.3.0" + "@humanwhocodes/config-array" "^0.9.2" ajv "^6.10.0" - chalk "^2.1.0" - cross-spawn "^6.0.5" - debug "^4.0.1" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" doctrine "^3.0.0" - eslint-scope "^5.0.0" - eslint-utils "^1.4.3" - eslint-visitor-keys "^1.1.0" - espree "^6.1.2" - esquery "^1.0.1" + escape-string-regexp "^4.0.0" + eslint-scope "^7.1.1" + eslint-utils "^3.0.0" + eslint-visitor-keys "^3.3.0" + espree "^9.3.2" + esquery "^1.4.0" esutils "^2.0.2" - file-entry-cache "^5.0.1" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" functional-red-black-tree "^1.0.1" - glob-parent "^5.0.0" - globals "^12.1.0" - ignore "^4.0.6" + glob-parent "^6.0.1" + globals "^13.15.0" + ignore "^5.2.0" import-fresh "^3.0.0" imurmurhash "^0.1.4" - inquirer "^7.0.0" is-glob "^4.0.0" - js-yaml "^3.13.1" + js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" - lodash "^4.17.14" - minimatch "^3.0.4" - mkdirp "^0.5.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" natural-compare "^1.4.0" - optionator "^0.8.3" - progress "^2.0.0" - regexpp "^2.0.1" - semver "^6.1.2" - strip-ansi "^5.2.0" - strip-json-comments "^3.0.1" - table "^5.2.3" + optionator "^0.9.1" + regexpp "^3.2.0" + strip-ansi "^6.0.1" + strip-json-comments "^3.1.0" text-table "^0.2.0" v8-compile-cache "^2.0.3" -espree@^6.1.2: - version "6.2.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a" - integrity sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw== +espree@^9.3.2: + version "9.3.2" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.2.tgz#f58f77bd334731182801ced3380a8cc859091596" + integrity sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA== dependencies: - acorn "^7.1.1" - acorn-jsx "^5.2.0" - eslint-visitor-keys "^1.1.0" + acorn "^8.7.1" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.3.0" esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.0.1: +esquery@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== @@ -2236,16 +2404,7 @@ expect@^28.1.1: jest-message-util "^28.1.1" jest-util "^28.1.1" -external-editor@^3.0.3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" - integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== - dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - -fast-deep-equal@^3.1.1: +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== @@ -2271,7 +2430,7 @@ fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== -fast-levenshtein@~2.0.6: +fast-levenshtein@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== @@ -2290,19 +2449,12 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" -figures@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" - integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== - dependencies: - escape-string-regexp "^1.0.5" - -file-entry-cache@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" - integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== dependencies: - flat-cache "^2.0.1" + flat-cache "^3.0.4" fill-range@^7.0.1: version "7.0.1" @@ -2326,19 +2478,18 @@ find-up@^4.0.0, find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" -flat-cache@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" - integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== dependencies: - flatted "^2.0.0" - rimraf "2.6.3" - write "1.0.3" + flatted "^3.1.0" + rimraf "^3.0.2" -flatted@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" - integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== +flatted@^3.1.0: + version "3.2.6" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.6.tgz#022e9218c637f9f3fc9c35ab9c9193f05add60b2" + integrity sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ== fs.realpath@^1.0.0: version "1.0.0" @@ -2397,13 +2548,20 @@ get-symbol-description@^1.0.0: call-bind "^1.0.2" get-intrinsic "^1.1.1" -glob-parent@^5.0.0, glob-parent@^5.1.2, glob-parent@~5.1.2: +glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" +glob-parent@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + glob@^7.0.5: version "7.2.0" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" @@ -2433,14 +2591,14 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -globals@^12.1.0: - version "12.4.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" - integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== +globals@^13.15.0: + version "13.16.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.16.0.tgz#9be4aca28f311aaeb974ea54978ebbb5e35ce46a" + integrity sha512-A1lrQfpNF+McdPOnnFqY3kSN0AFTy485bTi1bkLk4mVPODIUEcSfhHgRqA+QdXPksrSTTztYXx37NFV+GpGk3Q== dependencies: - type-fest "^0.8.1" + type-fest "^0.20.2" -globby@^11.0.3: +globby@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== @@ -2525,13 +2683,6 @@ human-signals@^2.1.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== -iconv-lite@^0.4.24: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - idna-uts46-hx@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz#a1dc5c4df37eee522bf66d969cc980e00e8711f9" @@ -2539,17 +2690,12 @@ idna-uts46-hx@^2.3.1: dependencies: punycode "2.1.0" -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - -ignore@^5.1.8, ignore@^5.2.0: +ignore@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== -import-fresh@^3.0.0: +import-fresh@^3.0.0, import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== @@ -2583,25 +2729,6 @@ inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -inquirer@^7.0.0: - version "7.3.3" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" - integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== - dependencies: - ansi-escapes "^4.2.1" - chalk "^4.1.0" - cli-cursor "^3.1.0" - cli-width "^3.0.0" - external-editor "^3.0.3" - figures "^3.0.0" - lodash "^4.17.19" - mute-stream "0.0.8" - run-async "^2.4.0" - rxjs "^6.6.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - through "^2.3.6" - internal-slot@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" @@ -2643,7 +2770,7 @@ is-callable@^1.1.4, is-callable@^1.2.4: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== -is-core-module@^2.8.0: +is-core-module@^2.8.0, is-core-module@^2.8.1, is-core-module@^2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69" integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A== @@ -2662,11 +2789,6 @@ is-extglob@^2.1.1: resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= - is-fullwidth-code-point@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" @@ -2805,13 +2927,13 @@ jest-changed-files@^28.0.2: execa "^5.0.0" throat "^6.0.1" -jest-circus@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-28.1.1.tgz#3d27da6a974d85a466dc0cdc6ddeb58daaa57bb4" - integrity sha512-75+BBVTsL4+p2w198DQpCeyh1RdaS2lhEG87HkaFX/UG0gJExVq2skG2pT7XZEGBubNj2CytcWSPan4QEPNosw== +jest-circus@^28.1.2: + version "28.1.2" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-28.1.2.tgz#0d5a5623eccb244efe87d1edc365696e4fcf80ce" + integrity sha512-E2vdPIJG5/69EMpslFhaA46WkcrN74LI5V/cSJ59L7uS8UNoXbzTxmwhpi9XrIL3zqvMt5T0pl5k2l2u2GwBNQ== dependencies: - "@jest/environment" "^28.1.1" - "@jest/expect" "^28.1.1" + "@jest/environment" "^28.1.2" + "@jest/expect" "^28.1.2" "@jest/test-result" "^28.1.1" "@jest/types" "^28.1.1" "@types/node" "*" @@ -2822,52 +2944,52 @@ jest-circus@^28.1.1: jest-each "^28.1.1" jest-matcher-utils "^28.1.1" jest-message-util "^28.1.1" - jest-runtime "^28.1.1" - jest-snapshot "^28.1.1" + jest-runtime "^28.1.2" + jest-snapshot "^28.1.2" jest-util "^28.1.1" pretty-format "^28.1.1" slash "^3.0.0" stack-utils "^2.0.3" throat "^6.0.1" -jest-cli@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-28.1.1.tgz#23ddfde8940e1818585ae4a568877b33b0e51cfe" - integrity sha512-+sUfVbJqb1OjBZ0OdBbI6OWfYM1i7bSfzYy6gze1F1w3OKWq8ZTEKkZ8a7ZQPq6G/G1qMh/uKqpdWhgl11NFQQ== +jest-cli@^28.1.2: + version "28.1.2" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-28.1.2.tgz#b89012e5bad14135e71b1628b85475d3773a1bbc" + integrity sha512-l6eoi5Do/IJUXAFL9qRmDiFpBeEJAnjJb1dcd9i/VWfVWbp3mJhuH50dNtX67Ali4Ecvt4eBkWb4hXhPHkAZTw== dependencies: - "@jest/core" "^28.1.1" + "@jest/core" "^28.1.2" "@jest/test-result" "^28.1.1" "@jest/types" "^28.1.1" chalk "^4.0.0" exit "^0.1.2" graceful-fs "^4.2.9" import-local "^3.0.2" - jest-config "^28.1.1" + jest-config "^28.1.2" jest-util "^28.1.1" jest-validate "^28.1.1" prompts "^2.0.1" yargs "^17.3.1" -jest-config@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-28.1.1.tgz#e90b97b984f14a6c24a221859e81b258990fce2f" - integrity sha512-tASynMhS+jVV85zKvjfbJ8nUyJS/jUSYZ5KQxLUN2ZCvcQc/OmhQl2j6VEL3ezQkNofxn5pQ3SPYWPHb0unTZA== +jest-config@^28.1.2: + version "28.1.2" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-28.1.2.tgz#ba00ad30caf62286c86e7c1099e915218a0ac8c6" + integrity sha512-g6EfeRqddVbjPVBVY4JWpUY4IvQoFRIZcv4V36QkqzE0IGhEC/VkugFeBMAeUE7PRgC8KJF0yvJNDeQRbamEVA== dependencies: "@babel/core" "^7.11.6" "@jest/test-sequencer" "^28.1.1" "@jest/types" "^28.1.1" - babel-jest "^28.1.1" + babel-jest "^28.1.2" chalk "^4.0.0" ci-info "^3.2.0" deepmerge "^4.2.2" glob "^7.1.3" graceful-fs "^4.2.9" - jest-circus "^28.1.1" - jest-environment-node "^28.1.1" + jest-circus "^28.1.2" + jest-environment-node "^28.1.2" jest-get-type "^28.0.2" jest-regex-util "^28.0.2" jest-resolve "^28.1.1" - jest-runner "^28.1.1" + jest-runner "^28.1.2" jest-util "^28.1.1" jest-validate "^28.1.1" micromatch "^4.0.4" @@ -2876,16 +2998,6 @@ jest-config@^28.1.1: slash "^3.0.0" strip-json-comments "^3.1.1" -jest-diff@^26.0.0: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.6.2.tgz#1aa7468b52c3a68d7d5c5fdcdfcd5e49bd164394" - integrity sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA== - dependencies: - chalk "^4.0.0" - diff-sequences "^26.6.2" - jest-get-type "^26.3.0" - pretty-format "^26.6.2" - jest-diff@^28.1.1: version "28.1.1" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-28.1.1.tgz#1a3eedfd81ae79810931c63a1d0f201b9120106c" @@ -2914,23 +3026,18 @@ jest-each@^28.1.1: jest-util "^28.1.1" pretty-format "^28.1.1" -jest-environment-node@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-28.1.1.tgz#1c86c59003a7d319fa06ea3b1bbda6c193715c67" - integrity sha512-2aV/eeY/WNgUUJrrkDJ3cFEigjC5fqT1+fCclrY6paqJ5zVPoM//sHmfgUUp7WLYxIdbPwMiVIzejpN56MxnNA== +jest-environment-node@^28.1.2: + version "28.1.2" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-28.1.2.tgz#3e2eb47f6d173b0648d5f7c717cb1c26651d5c8a" + integrity sha512-oYsZz9Qw27XKmOgTtnl0jW7VplJkN2oeof+SwAwKFQacq3CLlG9u4kTGuuLWfvu3J7bVutWlrbEQMOCL/jughw== dependencies: - "@jest/environment" "^28.1.1" - "@jest/fake-timers" "^28.1.1" + "@jest/environment" "^28.1.2" + "@jest/fake-timers" "^28.1.2" "@jest/types" "^28.1.1" "@types/node" "*" jest-mock "^28.1.1" jest-util "^28.1.1" -jest-get-type@^26.3.0: - version "26.3.0" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" - integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig== - jest-get-type@^28.0.2: version "28.0.2" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-28.0.2.tgz#34622e628e4fdcd793d46db8a242227901fcf203" @@ -2963,7 +3070,7 @@ jest-leak-detector@^28.1.1: jest-get-type "^28.0.2" pretty-format "^28.1.1" -jest-matcher-utils@^28.1.1: +jest-matcher-utils@^28.0.0, jest-matcher-utils@^28.1.1: version "28.1.1" resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-28.1.1.tgz#a7c4653c2b782ec96796eb3088060720f1e29304" integrity sha512-NPJPRWrbmR2nAJ+1nmnfcKKzSwgfaciCCrYZzVnNoxVoyusYWIjkBMNvu0RHJe7dNj4hH3uZOPZsQA+xAYWqsw== @@ -3006,13 +3113,13 @@ jest-regex-util@^28.0.2: resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-28.0.2.tgz#afdc377a3b25fb6e80825adcf76c854e5bf47ead" integrity sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw== -jest-resolve-dependencies@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.1.tgz#3dffaaa56f4b41bc6b61053899d1756401763a27" - integrity sha512-p8Y150xYJth4EXhOuB8FzmS9r8IGLEioiaetgdNGb9VHka4fl0zqWlVe4v7mSkYOuEUg2uB61iE+zySDgrOmgQ== +jest-resolve-dependencies@^28.1.2: + version "28.1.2" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.2.tgz#ca528858e0c6642d5a1dda8fc7cda10230c275bc" + integrity sha512-OXw4vbOZuyRTBi3tapWBqdyodU+T33ww5cPZORuTWkg+Y8lmsxQlVu3MWtJh6NMlKRTHQetF96yGPv01Ye7Mbg== dependencies: jest-regex-util "^28.0.2" - jest-snapshot "^28.1.1" + jest-snapshot "^28.1.2" jest-resolve@^28.1.1: version "28.1.1" @@ -3029,44 +3136,44 @@ jest-resolve@^28.1.1: resolve.exports "^1.1.0" slash "^3.0.0" -jest-runner@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-28.1.1.tgz#9ecdb3f27a00059986797aa6b012ba8306aa436c" - integrity sha512-W5oFUiDBgTsCloTAj6q95wEvYDB0pxIhY6bc5F26OucnwBN+K58xGTGbliSMI4ChQal5eANDF+xvELaYkJxTmA== +jest-runner@^28.1.2: + version "28.1.2" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-28.1.2.tgz#f293409592a62234285a71237e38499a3554e350" + integrity sha512-6/k3DlAsAEr5VcptCMdhtRhOoYClZQmxnVMZvZ/quvPGRpN7OBQYPIC32tWSgOnbgqLXNs5RAniC+nkdFZpD4A== dependencies: "@jest/console" "^28.1.1" - "@jest/environment" "^28.1.1" + "@jest/environment" "^28.1.2" "@jest/test-result" "^28.1.1" - "@jest/transform" "^28.1.1" + "@jest/transform" "^28.1.2" "@jest/types" "^28.1.1" "@types/node" "*" chalk "^4.0.0" emittery "^0.10.2" graceful-fs "^4.2.9" jest-docblock "^28.1.1" - jest-environment-node "^28.1.1" + jest-environment-node "^28.1.2" jest-haste-map "^28.1.1" jest-leak-detector "^28.1.1" jest-message-util "^28.1.1" jest-resolve "^28.1.1" - jest-runtime "^28.1.1" + jest-runtime "^28.1.2" jest-util "^28.1.1" jest-watcher "^28.1.1" jest-worker "^28.1.1" source-map-support "0.5.13" throat "^6.0.1" -jest-runtime@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-28.1.1.tgz#569e1dc3c36c6c4c0b29516c1c49b6ad580abdaf" - integrity sha512-J89qEJWW0leOsqyi0D9zHpFEYHwwafFdS9xgvhFHtIdRghbadodI0eA+DrthK/1PebBv3Px8mFSMGKrtaVnleg== +jest-runtime@^28.1.2: + version "28.1.2" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-28.1.2.tgz#d68f34f814a848555a345ceda23289f14d59a688" + integrity sha512-i4w93OsWzLOeMXSi9epmakb2+3z0AchZtUQVF1hesBmcQQy4vtaql5YdVe9KexdJaVRyPDw8DoBR0j3lYsZVYw== dependencies: - "@jest/environment" "^28.1.1" - "@jest/fake-timers" "^28.1.1" - "@jest/globals" "^28.1.1" - "@jest/source-map" "^28.0.2" + "@jest/environment" "^28.1.2" + "@jest/fake-timers" "^28.1.2" + "@jest/globals" "^28.1.2" + "@jest/source-map" "^28.1.2" "@jest/test-result" "^28.1.1" - "@jest/transform" "^28.1.1" + "@jest/transform" "^28.1.2" "@jest/types" "^28.1.1" chalk "^4.0.0" cjs-module-lexer "^1.0.0" @@ -3079,15 +3186,15 @@ jest-runtime@^28.1.1: jest-mock "^28.1.1" jest-regex-util "^28.0.2" jest-resolve "^28.1.1" - jest-snapshot "^28.1.1" + jest-snapshot "^28.1.2" jest-util "^28.1.1" slash "^3.0.0" strip-bom "^4.0.0" -jest-snapshot@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-28.1.1.tgz#ab825c16c8d8b5e883bd57eee6ca8748c42ab848" - integrity sha512-1KjqHJ98adRcbIdMizjF5DipwZFbvxym/kFO4g4fVZCZRxH/dqV8TiBFCa6rqic3p0karsy8RWS1y4E07b7P0A== +jest-snapshot@^28.1.2: + version "28.1.2" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-28.1.2.tgz#93d31b87b11b384f5946fe0767541496135f8d52" + integrity sha512-wzrieFttZYfLvrCVRJxX+jwML2YTArOUqFpCoSVy1QUapx+LlV9uLbV/mMEhYj4t7aMeE9aSQFHSvV/oNoDAMA== dependencies: "@babel/core" "^7.11.6" "@babel/generator" "^7.7.2" @@ -3095,7 +3202,7 @@ jest-snapshot@^28.1.1: "@babel/traverse" "^7.7.2" "@babel/types" "^7.3.3" "@jest/expect-utils" "^28.1.1" - "@jest/transform" "^28.1.1" + "@jest/transform" "^28.1.2" "@jest/types" "^28.1.1" "@types/babel__traverse" "^7.0.6" "@types/prettier" "^2.1.5" @@ -3160,15 +3267,15 @@ jest-worker@^28.1.1: merge-stream "^2.0.0" supports-color "^8.0.0" -jest@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest/-/jest-28.1.1.tgz#3c39a3a09791e16e9ef283597d24ab19a0df701e" - integrity sha512-qw9YHBnjt6TCbIDMPMpJZqf9E12rh6869iZaN08/vpOGgHJSAaLLUn6H8W3IAEuy34Ls3rct064mZLETkxJ2XA== +jest@^28.1.2: + version "28.1.2" + resolved "https://registry.yarnpkg.com/jest/-/jest-28.1.2.tgz#451ff24081ce31ca00b07b60c61add13aa96f8eb" + integrity sha512-Tuf05DwLeCh2cfWCQbcz9UxldoDyiR1E9Igaei5khjonKncYdc6LDfynKCEWozK0oLE3GD+xKAo2u8x/0s6GOg== dependencies: - "@jest/core" "^28.1.1" + "@jest/core" "^28.1.2" "@jest/types" "^28.1.1" import-local "^3.0.2" - jest-cli "^28.1.1" + jest-cli "^28.1.2" js-sha3@0.8.0: version "0.8.0" @@ -3193,6 +3300,13 @@ js-yaml@^3.13.1: argparse "^1.0.7" esprima "^4.0.0" +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + jsbi@^3.1.4: version "3.2.5" resolved "https://registry.yarnpkg.com/jsbi/-/jsbi-3.2.5.tgz#b37bb90e0e5c2814c1c2a1bcd8c729888a2e37d6" @@ -3228,6 +3342,11 @@ json-to-graphql-query@^2.0.0: resolved "https://registry.yarnpkg.com/json-to-graphql-query/-/json-to-graphql-query-2.2.0.tgz#7e62fcf4a4d1e16ad1b1972cd3eac0b335c32679" integrity sha512-HiySSlJHm1tiFk95TAJOz1t3Dhp0cvbCnb59L2C5cNq0UhDmsbXt+gdi8enLcMOfhTkI42um1hlbondUazJ64A== +json-to-graphql-query@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/json-to-graphql-query/-/json-to-graphql-query-2.2.4.tgz#ada9cfdbb9bf38589fd2661e1588d1edd0a882cc" + integrity sha512-vNvsOKDSlEqYCzejI1xHS9Hm738dSnG4Upy09LUGqyybZXSIIb7NydDphB/6WxW2EEVpPU4JeU/Yo63Nw9dEJg== + json5@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" @@ -3250,13 +3369,13 @@ leven@^3.1.0: resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== -levn@^0.3.0, levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" + prelude-ls "^1.2.1" + type-check "~0.4.0" lines-and-columns@^1.1.6: version "1.2.4" @@ -3283,16 +3402,16 @@ lodash.memoize@4.x: resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + lodash.set@^4.3.2: version "4.3.2" resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23" integrity sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM= -lodash@^4.17.14, lodash@^4.17.19: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -3359,25 +3478,18 @@ minimatch@^3.0.3: dependencies: brace-expansion "^1.1.7" -minimatch@^3.0.4, minimatch@^3.1.1: +minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" -minimist@^1.2.0, minimist@^1.2.5: +minimist@^1.2.0, minimist@^1.2.6: version "1.2.6" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== -mkdirp@^0.5.1: - version "0.5.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" - integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== - dependencies: - minimist "^1.2.5" - mkdirp@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" @@ -3398,26 +3510,11 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -mute-stream@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" - integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== - natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - -node-fetch@2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" - integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== - node-fetch@2.6.7: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" @@ -3475,7 +3572,7 @@ object.assign@^4.1.2: has-symbols "^1.0.1" object-keys "^1.1.1" -object.entries@^1.1.2: +object.entries@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.5.tgz#e1acdd17c4de2cd96d5a08487cfb9db84d881861" integrity sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g== @@ -3500,29 +3597,24 @@ once@^1.3.0: dependencies: wrappy "1" -onetime@^5.1.0, onetime@^5.1.2: +onetime@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== dependencies: mimic-fn "^2.1.0" -optionator@^0.8.3: - version "0.8.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" - integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.6" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - word-wrap "~1.2.3" - -os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" p-limit@^1.1.0: version "1.3.0" @@ -3594,11 +3686,6 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== -path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== - path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" @@ -3636,10 +3723,10 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== prettier-linter-helpers@^1.0.0: version "1.0.0" @@ -3648,22 +3735,12 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" -prettier@2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.0.tgz#8a03c7777883b29b37fb2c4348c66a78e980418b" - integrity sha512-yYerpkvseM4iKD/BXLYUkQV5aKt4tQPqaGW6EsZjzyu0r7sVZZNPJW4Y8MyKmicp6t42XUPcBVA+H6sB3gqndw== +prettier@^2.7.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" + integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== -pretty-format@^26.0.0, pretty-format@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93" - integrity sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg== - dependencies: - "@jest/types" "^26.6.2" - ansi-regex "^5.0.0" - ansi-styles "^4.0.0" - react-is "^17.0.1" - -pretty-format@^28.1.1: +pretty-format@^28.0.0, pretty-format@^28.1.1: version "28.1.1" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-28.1.1.tgz#f731530394e0f7fcd95aba6b43c50e02d86b95cb" integrity sha512-wwJbVTGFHeucr5Jw2bQ9P+VYHyLdAqedFLEkdQUVaBF/eiidDwH5OpilINq4mEfhbCjLnirt6HTTDhv1HaTIQw== @@ -3678,11 +3755,6 @@ process-nextick-args@~2.0.0: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - prompts@^2.0.1: version "2.4.2" resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" @@ -3706,11 +3778,6 @@ queue-microtask@^1.2.2: resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== -react-is@^17.0.1: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" - integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== - react-is@^18.0.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" @@ -3746,12 +3813,7 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" -regexpp@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" - integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== - -regexpp@^3.1.0: +regexpp@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== @@ -3797,38 +3859,27 @@ resolve@^1.20.0: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -restore-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" - integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== +resolve@^1.22.0: + version "1.22.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" + integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== dependencies: - onetime "^5.1.0" - signal-exit "^3.0.2" + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" reusify@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rimraf@2.6.3: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" - -rimraf@^3.0.0: +rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== dependencies: glob "^7.1.3" -run-async@^2.4.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" - integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== - run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -3836,41 +3887,24 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -rxjs@^6.6.0: - version "6.6.7" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" - integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== - dependencies: - tslib "^1.9.0" - safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -"safer-buffer@>= 2.1.2 < 3": - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - scrypt-js@3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== -semver@7.x: +semver@7.x, semver@^7.3.7: version "7.3.7" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== dependencies: lru-cache "^6.0.0" -semver@^5.5.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - -semver@^6.0.0, semver@^6.1.2, semver@^6.3.0: +semver@^6.0.0, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== @@ -3882,13 +3916,6 @@ semver@^7.3.5: dependencies: lru-cache "^6.0.0" -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg== - dependencies: - shebang-regex "^1.0.0" - shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -3896,11 +3923,6 @@ shebang-command@^2.0.0: dependencies: shebang-regex "^3.0.0" -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ== - shebang-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" @@ -3915,7 +3937,7 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" -signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: +signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== @@ -3930,15 +3952,6 @@ slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -slice-ansi@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" - integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== - dependencies: - ansi-styles "^3.2.0" - astral-regex "^1.0.0" - is-fullwidth-code-point "^2.0.0" - source-map-support@0.5.13: version "0.5.13" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" @@ -3972,15 +3985,6 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -string-width@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" - integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" - string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" @@ -4018,13 +4022,6 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -strip-ansi@^5.1.0, strip-ansi@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" - integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== - dependencies: - ansi-regex "^4.1.0" - strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" @@ -4047,7 +4044,7 @@ strip-final-newline@^2.0.0: resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== -strip-json-comments@^3.0.1, strip-json-comments@^3.1.1: +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== @@ -4086,16 +4083,6 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -table@^5.2.3: - version "5.4.6" - resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" - integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== - dependencies: - ajv "^6.10.2" - lodash "^4.17.14" - slice-ansi "^2.1.0" - string-width "^3.0.0" - terminal-link@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" @@ -4131,11 +4118,6 @@ through2@^2.0.1: readable-stream "~2.3.6" xtend "~4.0.1" -through@^2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - tiny-invariant@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.2.0.tgz#a1141f86b672a9148c72e978a19a73b9b94a15a9" @@ -4146,13 +4128,6 @@ tiny-warning@^1.0.3: resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - tmpl@1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" @@ -4194,17 +4169,17 @@ ts-jest@^28.0.5: semver "7.x" yargs-parser "^21.0.1" -tsconfig-paths@^3.12.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz#19769aca6ee8f6a1a341e38c8fa45dd9fb18899b" - integrity sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg== +tsconfig-paths@^3.14.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" + integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ== dependencies: "@types/json5" "^0.0.29" json5 "^1.0.1" - minimist "^1.2.0" + minimist "^1.2.6" strip-bom "^3.0.0" -tslib@^1.8.1, tslib@^1.9.0: +tslib@^1.8.1: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== @@ -4216,32 +4191,32 @@ tsutils@^3.21.0: dependencies: tslib "^1.8.1" -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg== +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== dependencies: - prelude-ls "~1.1.2" + prelude-ls "^1.2.1" type-detect@4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + type-fest@^0.21.3: version "0.21.3" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== -type-fest@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" - integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== - -typescript@^4.2.3: - version "4.5.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.4.tgz#a17d3a0263bf5c8723b9c52f43c5084edf13c2e8" - integrity sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg== +typescript@^4.7.4: + version "4.7.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235" + integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== unbox-primitive@^1.0.1: version "1.0.1" @@ -4275,12 +4250,12 @@ v8-compile-cache@^2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== -v8-to-istanbul@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.0.0.tgz#be0dae58719fc53cb97e5c7ac1d7e6d4f5b19511" - integrity sha512-HcvgY/xaRm7isYmyx+lFKA4uQmfUbN0J4M0nNItvzTvH/iQ9kW5j/t4YSR+Ge323/lrgDAWJoF46tzGQHwBHFw== +v8-to-istanbul@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz#b6f994b0b5d4ef255e17a0d17dc444a9f5132fa4" + integrity sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w== dependencies: - "@jridgewell/trace-mapping" "^0.3.7" + "@jridgewell/trace-mapping" "^0.3.12" "@types/istanbul-lib-coverage" "^2.0.1" convert-source-map "^1.6.0" @@ -4315,13 +4290,6 @@ which-boxed-primitive@^1.0.2: is-string "^1.0.5" is-symbol "^1.0.3" -which@^1.2.9: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - which@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" @@ -4329,7 +4297,7 @@ which@^2.0.1: dependencies: isexe "^2.0.0" -word-wrap@~1.2.3: +word-wrap@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== @@ -4356,13 +4324,6 @@ write-file-atomic@^4.0.1: imurmurhash "^0.1.4" signal-exit "^3.0.7" -write@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" - integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== - dependencies: - mkdirp "^0.5.1" - ws@7.4.6: version "7.4.6" resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" From 3470ba7486c40dd0a402bac957e58be554c9b474 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Fri, 15 Jul 2022 17:23:19 +0530 Subject: [PATCH 024/815] Fix build issues (#712) * Fix build issues * Fix build issues * Change node version in workflow * Change node version in workflow --- .github/workflows/main.yml | 2 +- .github/workflows/nodejs.yml | 2 +- .github/workflows/publish.yml | 18 ------------------ package.json | 10 +++++----- 4 files changed, 7 insertions(+), 25 deletions(-) delete mode 100644 .github/workflows/publish.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0b55115e8..3b9e5d41d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -11,7 +11,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v1 with: - node-version: '14.x' + node-version: '16.10.x' - name: Run lint script run: | yarn install --frozen-lockfile diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index ea69d046e..d83b782f3 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -9,7 +9,7 @@ jobs: strategy: matrix: - node-version: [14.x] + node-version: [16.10.x] steps: - uses: actions/checkout@v1 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml deleted file mode 100644 index ee3b4f320..000000000 --- a/.github/workflows/publish.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: Node.js Package -on: - release: - types: [created] -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - # Setup .npmrc file to publish to npm - - uses: actions/setup-node@v1 - with: - node-version: '12.x' - registry-url: 'https://registry.npmjs.org' - - run: yarn install --frozen-lockfile - - run: yarn publish - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} diff --git a/package.json b/package.json index bee71e2ca..0717d3053 100755 --- a/package.json +++ b/package.json @@ -1,10 +1,10 @@ { "name": "@snapshot-labs/strategies", "version": "0.1.0", - "main": "dist/index.js", - "types": "dist/index.d.ts", + "main": "dist/src/index.js", + "types": "dist/src/index.d.ts", "exports": { - ".": "./dist/index.js" + ".": "./dist/src/index.js" }, "files": [ "dist" @@ -36,6 +36,7 @@ "@snapshot-labs/snapshot.js": "^0.4.8", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", + "copyfiles": "^2.4.1", "cross-fetch": "^3.1.5", "eth-ens-namehash": "^2.0.8", "json-to-graphql-query": "^2.2.4" @@ -45,7 +46,6 @@ "@types/node": "^18.0.3", "@typescript-eslint/eslint-plugin": "^5.30.5", "@typescript-eslint/parser": "^5.30.5", - "copyfiles": "^2.4.1", "eslint": "^8.19.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-plugin-import": "^2.26.0", @@ -56,6 +56,6 @@ "typescript": "^4.7.4" }, "engines": { - "node": ">=14" + "node": ">=16.10.0" } } From a13d05d5edfd4eca02a1419262aec998594b3b8c Mon Sep 17 00:00:00 2001 From: Fabien Date: Fri, 15 Jul 2022 23:23:32 +0700 Subject: [PATCH 025/815] Export functions getVp and getDelegations (#713) * Add getVp and getDelegations functions * Update dependencies * Export functions getVp and getDelegations * Remove unused file --- src/utils.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/utils.ts b/src/utils.ts index 92aa718b9..2764b5552 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -2,6 +2,7 @@ import fetch from 'cross-fetch'; import _strategies from './strategies'; import snapshot from '@snapshot-labs/snapshot.js'; import { getDelegations } from './utils/delegation'; +import { getVp, getDelegations as getCoreDelegations } from './utils/vp'; async function callStrategy(space, network, addresses, strategy, snapshot) { if ( @@ -90,5 +91,7 @@ export default { getProvider, getDelegations, getSnapshots, - SNAPSHOT_SUBGRAPH_URL + SNAPSHOT_SUBGRAPH_URL, + getVp, + getCoreDelegations }; From 63bbd5cdb69a44ad694bdf4136f03b356750dc70 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 17 Jul 2022 23:57:38 +0530 Subject: [PATCH 026/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.10 (#716) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 175 +++++++-------------------------------------------- 2 files changed, 24 insertions(+), 153 deletions(-) diff --git a/package.json b/package.json index 0717d3053..130ad12b6 100755 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.8", + "@snapshot-labs/snapshot.js": "^0.4.10", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", "copyfiles": "^2.4.1", diff --git a/yarn.lock b/yarn.lock index c2fb30f98..0e9ede97b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -304,7 +304,7 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@ethersproject/abi@^5.0.12", "@ethersproject/abi@^5.5.0": +"@ethersproject/abi@^5.0.12": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.5.0.tgz#fb52820e22e50b854ff15ce1647cc508d6660613" integrity sha512-loW7I4AohP5KycATvc0MgujU6JyCHPqHdeoo9z3Nr9xEiNioxa65ccdm1+fsoJhkuhdRtfcL8cfyGamz2AxZ5w== @@ -418,14 +418,6 @@ dependencies: "@ethersproject/bytes" "^5.6.1" -"@ethersproject/basex@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.5.0.tgz#e40a53ae6d6b09ab4d977bd037010d4bed21b4d3" - integrity sha512-ZIodwhHpVJ0Y3hUCfUucmxKsWQA5TMnavp5j/UOuDdzZWzJlRmuOjcTMIGgHCYuZmHt36BfiSyQPSRskPxbfaQ== - dependencies: - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/basex@^5.6.1": version "5.6.1" resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.6.1.tgz#badbb2f1d4a6f52ce41c9064f01eab19cc4c5305" @@ -480,22 +472,6 @@ dependencies: "@ethersproject/bignumber" "^5.6.2" -"@ethersproject/contracts@^5.0.3": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.5.0.tgz#b735260d4bd61283a670a82d5275e2a38892c197" - integrity sha512-2viY7NzyvJkh+Ug17v7g3/IJC8HqZBDcOjYARZLdzRxrfGlRgmYgl6xPRKVbEzy1dWKw/iv7chDcS83pg6cLxg== - dependencies: - "@ethersproject/abi" "^5.5.0" - "@ethersproject/abstract-provider" "^5.5.0" - "@ethersproject/abstract-signer" "^5.5.0" - "@ethersproject/address" "^5.5.0" - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/constants" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/transactions" "^5.5.0" - "@ethersproject/contracts@^5.6.2": version "5.6.2" resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.6.2.tgz#20b52e69ebc1b74274ff8e3d4e508de971c287bc" @@ -540,24 +516,6 @@ "@ethersproject/properties" "^5.6.0" "@ethersproject/strings" "^5.6.1" -"@ethersproject/hdnode@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.5.0.tgz#4a04e28f41c546f7c978528ea1575206a200ddf6" - integrity sha512-mcSOo9zeUg1L0CoJH7zmxwUG5ggQHU1UrRf8jyTYy6HxdZV+r0PBoL1bxr+JHIPXRzS6u/UW4mEn43y0tmyF8Q== - dependencies: - "@ethersproject/abstract-signer" "^5.5.0" - "@ethersproject/basex" "^5.5.0" - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/pbkdf2" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/sha2" "^5.5.0" - "@ethersproject/signing-key" "^5.5.0" - "@ethersproject/strings" "^5.5.0" - "@ethersproject/transactions" "^5.5.0" - "@ethersproject/wordlists" "^5.5.0" - "@ethersproject/hdnode@^5.6.2": version "5.6.2" resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.6.2.tgz#26f3c83a3e8f1b7985c15d1db50dc2903418b2d2" @@ -576,25 +534,6 @@ "@ethersproject/transactions" "^5.6.2" "@ethersproject/wordlists" "^5.6.1" -"@ethersproject/json-wallets@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.5.0.tgz#dd522d4297e15bccc8e1427d247ec8376b60e325" - integrity sha512-9lA21XQnCdcS72xlBn1jfQdj2A1VUxZzOzi9UkNdnokNKke/9Ya2xA9aIK1SC3PQyBDLt4C+dfps7ULpkvKikQ== - dependencies: - "@ethersproject/abstract-signer" "^5.5.0" - "@ethersproject/address" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/hdnode" "^5.5.0" - "@ethersproject/keccak256" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/pbkdf2" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/random" "^5.5.0" - "@ethersproject/strings" "^5.5.0" - "@ethersproject/transactions" "^5.5.0" - aes-js "3.0.0" - scrypt-js "3.0.1" - "@ethersproject/json-wallets@^5.6.1": version "5.6.1" resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.6.1.tgz#3f06ba555c9c0d7da46756a12ac53483fe18dd91" @@ -654,14 +593,6 @@ dependencies: "@ethersproject/logger" "^5.6.0" -"@ethersproject/pbkdf2@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.5.0.tgz#e25032cdf02f31505d47afbf9c3e000d95c4a050" - integrity sha512-SaDvQFvXPnz1QGpzr6/HToLifftSXGoXrbpZ6BvoZhmx4bNLHrxDe8MZisuecyOziP1aVEwzC2Hasj+86TgWVg== - dependencies: - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/sha2" "^5.5.0" - "@ethersproject/pbkdf2@^5.6.1": version "5.6.1" resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.6.1.tgz#f462fe320b22c0d6b1d72a9920a3963b09eb82d1" @@ -684,31 +615,6 @@ dependencies: "@ethersproject/logger" "^5.6.0" -"@ethersproject/providers@^5.3.1": - version "5.5.2" - resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.5.2.tgz#131ccf52dc17afd0ab69ed444b8c0e3a27297d99" - integrity sha512-hkbx7x/MKcRjyrO4StKXCzCpWer6s97xnm34xkfPiarhtEUVAN4TBBpamM+z66WcTt7H5B53YwbRj1n7i8pZoQ== - dependencies: - "@ethersproject/abstract-provider" "^5.5.0" - "@ethersproject/abstract-signer" "^5.5.0" - "@ethersproject/address" "^5.5.0" - "@ethersproject/basex" "^5.5.0" - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/constants" "^5.5.0" - "@ethersproject/hash" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/networks" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/random" "^5.5.0" - "@ethersproject/rlp" "^5.5.0" - "@ethersproject/sha2" "^5.5.0" - "@ethersproject/strings" "^5.5.0" - "@ethersproject/transactions" "^5.5.0" - "@ethersproject/web" "^5.5.0" - bech32 "1.1.4" - ws "7.4.6" - "@ethersproject/providers@^5.6.8": version "5.6.8" resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.6.8.tgz#22e6c57be215ba5545d3a46cf759d265bb4e879d" @@ -735,14 +641,6 @@ bech32 "1.1.4" ws "7.4.6" -"@ethersproject/random@^5.5.0": - version "5.5.1" - resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.5.1.tgz#7cdf38ea93dc0b1ed1d8e480ccdaf3535c555415" - integrity sha512-YaU2dQ7DuhL5Au7KbcQLHxcRHfgyNgvFV4sQOo0HrtW3Zkrc9ctWNz8wXQ4uCSfSDsqX2vcjhroxU5RQRV0nqA== - dependencies: - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/random@^5.6.1": version "5.6.1" resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.6.1.tgz#66915943981bcd3e11bbd43733f5c3ba5a790255" @@ -890,27 +788,6 @@ "@ethersproject/constants" "^5.6.1" "@ethersproject/logger" "^5.6.0" -"@ethersproject/wallet@^5.4.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.5.0.tgz#322a10527a440ece593980dca6182f17d54eae75" - integrity sha512-Mlu13hIctSYaZmUOo7r2PhNSd8eaMPVXe1wxrz4w4FCE4tDYBywDH+bAR1Xz2ADyXGwqYMwstzTrtUVIsKDO0Q== - dependencies: - "@ethersproject/abstract-provider" "^5.5.0" - "@ethersproject/abstract-signer" "^5.5.0" - "@ethersproject/address" "^5.5.0" - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/hash" "^5.5.0" - "@ethersproject/hdnode" "^5.5.0" - "@ethersproject/json-wallets" "^5.5.0" - "@ethersproject/keccak256" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/random" "^5.5.0" - "@ethersproject/signing-key" "^5.5.0" - "@ethersproject/transactions" "^5.5.0" - "@ethersproject/wordlists" "^5.5.0" - "@ethersproject/wallet@^5.6.2": version "5.6.2" resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.6.2.tgz#cd61429d1e934681e413f4bc847a5f2f87e3a03c" @@ -954,17 +831,6 @@ "@ethersproject/properties" "^5.6.0" "@ethersproject/strings" "^5.6.1" -"@ethersproject/wordlists@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.5.0.tgz#aac74963aa43e643638e5172353d931b347d584f" - integrity sha512-bL0UTReWDiaQJJYOC9sh/XcRu/9i2jMrzf8VLRmPKx58ckSlOJiohODkECCO50dtLZHcGU6MLXQ4OOrgBwP77Q== - dependencies: - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/hash" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/strings" "^5.5.0" - "@ethersproject/wordlists@^5.6.1": version "5.6.1" resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.6.1.tgz#1e78e2740a8a21e9e99947e47979d72e130aeda1" @@ -1297,22 +1163,22 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.8": - version "0.4.9" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.9.tgz#fdac2800d57e52b201aa8e5fc1f5db2bbd15402c" - integrity sha512-5y5sM34tZm1VVxHzwJ5nnm4kb1eRI6CDcBRu0if9gK2H+qadG+yWH9f/boPIB6cskPvH760chRR8bdjseAB25Q== +"@snapshot-labs/snapshot.js@^0.4.10": + version "0.4.10" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.10.tgz#0e83ac8b8518ae627a17f178c102bfb122228236" + integrity sha512-eNJ8wEw+CrPNj3mUJ/p7vTz9dTgXHBgJFZ4cuKaMjlWo014Rtz2nAbF/1QKPwVD1Hw/BlBZgz1aRkK9kbzQTZA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" "@ethersproject/bytes" "^5.6.1" - "@ethersproject/contracts" "^5.0.3" + "@ethersproject/contracts" "^5.6.2" "@ethersproject/hash" "^5.6.1" - "@ethersproject/providers" "^5.3.1" - "@ethersproject/wallet" "^5.4.0" - ajv "^8.6.0" - ajv-formats "^2.1.0" + "@ethersproject/providers" "^5.6.8" + "@ethersproject/wallet" "^5.6.2" + ajv "^8.11.0" + ajv-formats "^2.1.1" cross-fetch "^3.1.5" - json-to-graphql-query "^2.0.0" + json-to-graphql-query "^2.2.4" lodash.set "^4.3.2" "@types/babel__core@^7.1.14": @@ -1605,7 +1471,7 @@ aes-js@3.0.0: resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" integrity sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0= -ajv-formats@^2.1.0: +ajv-formats@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== @@ -1622,7 +1488,7 @@ ajv@^6.10.0, ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.0, ajv@^8.6.0: +ajv@^8.0.0: version "8.9.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.9.0.tgz#738019146638824dea25edcf299dcba1b0e7eb18" integrity sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ== @@ -1632,6 +1498,16 @@ ajv@^8.0.0, ajv@^8.6.0: require-from-string "^2.0.2" uri-js "^4.2.2" +ajv@^8.11.0: + version "8.11.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" + integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + ansi-escapes@^4.2.1: version "4.3.2" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" @@ -3337,11 +3213,6 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= -json-to-graphql-query@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/json-to-graphql-query/-/json-to-graphql-query-2.2.0.tgz#7e62fcf4a4d1e16ad1b1972cd3eac0b335c32679" - integrity sha512-HiySSlJHm1tiFk95TAJOz1t3Dhp0cvbCnb59L2C5cNq0UhDmsbXt+gdi8enLcMOfhTkI42um1hlbondUazJ64A== - json-to-graphql-query@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/json-to-graphql-query/-/json-to-graphql-query-2.2.4.tgz#ada9cfdbb9bf38589fd2661e1588d1edd0a882cc" From c1d26049d1839d7350e5b71ae3380583ded092bd Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Mon, 18 Jul 2022 16:32:10 +0530 Subject: [PATCH 027/815] Use brovider in test files (#717) * Use brovider in test files * use getProvider --- test/examples/scores.ts | 5 ++--- test/strategy.test.ts | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/test/examples/scores.ts b/test/examples/scores.ts index ca21d9ade..f3d8d2a08 100644 --- a/test/examples/scores.ts +++ b/test/examples/scores.ts @@ -1,5 +1,3 @@ -const { JsonRpcProvider } = require('@ethersproject/providers'); -import networks from '@snapshot-labs/snapshot.js/src/networks.json'; import utils from '../../src/utils'; const space = 'yam.eth'; @@ -177,11 +175,12 @@ const addresses = [ (async () => { console.time('getScores'); try { + const provider = utils.getProvider(network); const scores = await utils.getScoresDirect( space, strategies, network, - new JsonRpcProvider(networks[network].rpc[0]), + provider, addresses, snapshotBlockNumber ); diff --git a/test/strategy.test.ts b/test/strategy.test.ts index 1e9a416d4..263d2273c 100644 --- a/test/strategy.test.ts +++ b/test/strategy.test.ts @@ -1,8 +1,6 @@ -import { JsonRpcProvider } from '@ethersproject/providers'; import { getAddress } from '@ethersproject/address'; import { performance } from 'perf_hooks'; import fetch from 'cross-fetch'; -import networks from '@snapshot-labs/snapshot.js/src/networks.json'; import snapshot from '../src'; import snapshotjs from '@snapshot-labs/snapshot.js'; import addresses from './addresses.json'; @@ -28,11 +26,12 @@ if (!strategy) throw 'Strategy not found'; const example = require(`../src/strategies/${strategy}/examples.json`)[0]; function callGetScores(example) { + const provider = snapshot.utils.getProvider(example.network); return snapshot.utils.getScoresDirect( 'yam.eth', [example.strategy], example.network, - new JsonRpcProvider(networks[example.network].rpc[0]), + provider, example.addresses, example.snapshot ); From 813e0ac3344fe7360534aaf5bf44923927b602f6 Mon Sep 17 00:00:00 2001 From: MantisClone Date: Tue, 19 Jul 2022 01:40:46 -0400 Subject: [PATCH 028/815] Add rari-fuse strategy [rari-fuse] (#714) * Copy erc20-balance-of/ and rename to rari-fuse/ * Fix tests * Call `FusePoolLens.getPoolUsersWithData(poolAddress, absMaxHealth)` * Update examples and schema * Use MaxUint256 because BigNumber.from(2**256-1) causes overflow error * Add fusePoolLensImplementation * Revert "Add fusePoolLensImplementation" This reverts commit 68e28830fbc286599e3d9693dc416a92eea2b4d4. * Try using getAllBorrowers and getPoolAssetWithData - Hardcode return values to 1 - Comment out unused code * Try calling getPoolAssetsWithData * Both getPoolUsersWithData and getPoolAssetsWithData revert when called - Comment them out for now. * Add cTokenAddress (the market address) to parameters list - The Rari Fuse app links to this address. I think there's one cToken for each distinct collateral type within a fuse pool. The example address given is for the BANK cToken. * Strip out code related to getPoolUsersWithData and getPoolAssetsWithData * Try using cToken.balanceOfUnderlying(address owner) * Use balanceOf, remove unneded parameters * yarn lint * Update README * Update README for readability * Rename underlyingTokenDecimals back to decimals * Add more addresses to the examples.json * Update README for readability * Rename cToken to fToken * Change parameters to `token` and `fToken` * Add functions for calculating underlying token balance, console logging * Update schema example * Remove unncessary comma * More changes to examples.json * Attempt to fix errors * Trying to fix * Update examples to use checksummed addresses * Fixed! Now I can see the console logs. * Add error if token param != fToken.underlying() * Add code from Rari Docs * Finish implementing index.js * It's not working. Add console logging * Adjust logic so div is last operation * Rename base to divisor * Remove console logging * Add additional addresses to examples.json --- src/strategies/index.ts | 4 +- src/strategies/rari-fuse/README.md | 22 +++++++++ src/strategies/rari-fuse/examples.json | 22 +++++++++ src/strategies/rari-fuse/index.ts | 62 ++++++++++++++++++++++++++ src/strategies/rari-fuse/schema.json | 36 +++++++++++++++ 5 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 src/strategies/rari-fuse/README.md create mode 100644 src/strategies/rari-fuse/examples.json create mode 100644 src/strategies/rari-fuse/index.ts create mode 100644 src/strategies/rari-fuse/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 8e2cbb25a..87640ac90 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -334,6 +334,7 @@ import * as solvVoucherClaimable from './solv-voucher-claimable'; import * as h2o from './h2o'; import * as dopamine from './dopamine'; import * as lrcL2SubgraphBalanceOf from './lrc-l2-subgraph-balance-of'; +import * as rariFuse from './rari-fuse'; const strategies = { 'forta-shares': fortaShares, @@ -671,7 +672,8 @@ const strategies = { apeswap, h2o, dopamine, - 'lrc-l2-subgraph-balance-of': lrcL2SubgraphBalanceOf + 'lrc-l2-subgraph-balance-of': lrcL2SubgraphBalanceOf, + 'rari-fuse': rariFuse }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/rari-fuse/README.md b/src/strategies/rari-fuse/README.md new file mode 100644 index 000000000..5e5a70b1c --- /dev/null +++ b/src/strategies/rari-fuse/README.md @@ -0,0 +1,22 @@ +# rari-fuse + +Returns the voter's underlying collateral balances in a given Rari Fuse market (fToken). + +Here is an example of parameters: + +- `symbol` - (**Optional**, `string`) Symbol of the underlying ERC20 token +- `token` - (**Required**, `string`) Address of the underlying token. +- `fToken` - (**Required**, `string`) Address of the fToken (Rari Fuse market) + +```json +{ + "symbol": "BANK", + "token": "0x2d94AA3e47d9D5024503Ca8491fcE9A2fB4DA198", + "fToken": "0x250316B3E46600417654b13bEa68b5f64D61E609" +} +``` + +## Reference + +For details about exchange rate between fTokens and underlying tokens, see +https://docs.rari.capital/fuse/#interpreting-exchange-rates diff --git a/src/strategies/rari-fuse/examples.json b/src/strategies/rari-fuse/examples.json new file mode 100644 index 000000000..a733c48b6 --- /dev/null +++ b/src/strategies/rari-fuse/examples.json @@ -0,0 +1,22 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "rari-fuse", + "params": { + "symbol": "BANK", + "token": "0x2d94AA3e47d9D5024503Ca8491fcE9A2fB4DA198", + "fToken": "0x250316B3E46600417654b13bEa68b5f64D61E609" + } + }, + "network": "1", + "addresses": [ + "0x3839AcF1ee7699D1F46b1BE840D8aD8317FDf757", + "0x0cf861f96378dbd5194d74cbe6b0424fafaed940", + "0x0f1d41cc51e97dc9d0cad80dc681777eed3675e3", + "0xb6ac0341fcf3fb507a8208d34a97f13779e1393d", + "0x173ff4db38c3fcde0584f8ea7930c44969a29ba4" + ], + "snapshot": 14482171 + } +] diff --git a/src/strategies/rari-fuse/index.ts b/src/strategies/rari-fuse/index.ts new file mode 100644 index 000000000..8979152e9 --- /dev/null +++ b/src/strategies/rari-fuse/index.ts @@ -0,0 +1,62 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'MantisClone'; +export const version = '0.1.0'; + +const abi = [ + 'function underlying() public view returns (address)', + 'function decimals() public view returns (uint8)', + 'function exchangeRateStored() public view returns (uint256)', + 'function balanceOf(address owner) external returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multi = new Multicaller(network, provider, abi, { blockTag }); + multi.call('underlying', options.fToken, 'underlying', []); + multi.call('tokenDecimals', options.token, 'decimals', []); + multi.call('fTokenDecimals', options.fToken, 'decimals', []); + multi.call('exchangeRate', options.fToken, 'exchangeRateStored', []); + addresses.forEach((address) => + multi.call(`fTokenBalances.${address}`, options.fToken, 'balanceOf', [ + address + ]) + ); + const result = await multi.execute(); + + const underlying: string = result.underlying; + const tokenDecimals: BigNumber = result.tokenDecimals; + const fTokenDecimals: BigNumber = result.fTokenDecimals; + const exchangeRate: BigNumber = result.exchangeRate; + const fTokenBalances: Record = result.fTokenBalances; + + if (options.token !== underlying) { + throw new Error( + `token parameter doesn't match fToken.underlying(). token=${options.token}, underlying=${underlying}` + ); + } + + const mantissa: BigNumber = BigNumber.from(18) + .add(tokenDecimals) + .sub(fTokenDecimals); + const divisor: BigNumber = BigNumber.from(10).pow(mantissa); + + return Object.fromEntries( + Object.entries(fTokenBalances).map(([address, balance]) => [ + address, + parseFloat( + formatUnits(balance.mul(exchangeRate).div(divisor), fTokenDecimals) + ) + ]) + ); +} diff --git a/src/strategies/rari-fuse/schema.json b/src/strategies/rari-fuse/schema.json new file mode 100644 index 000000000..71e3fecc6 --- /dev/null +++ b/src/strategies/rari-fuse/schema.json @@ -0,0 +1,36 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "symbol", + "examples": ["e.g. BANK"], + "maxLength": 16 + }, + "token": { + "type": "string", + "title": "token", + "examples": ["e.g. 0x2d94AA3e47d9D5024503Ca8491fcE9A2fB4DA198"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "fToken": { + "type": "string", + "title": "fToken", + "examples": ["e.g. 0x250316B3E46600417654b13bEa68b5f64D61E609"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } + }, + "required": ["token", "fToken"], + "additionalProperties": false + } + } +} From d9404686988c3cb130d3049d3bf222b6d58df29f Mon Sep 17 00:00:00 2001 From: charq <73696209+buchaoqun@users.noreply.github.com> Date: Wed, 20 Jul 2022 03:27:11 +0800 Subject: [PATCH 029/815] added a policy for vesting voucher [erc3525-vesting-voucher] (#718) * add vesting voucher strategies * vesting-voucher rename erc3525-vesting-voucher * Update src/strategies/erc3525-vesting-voucher/index.ts Co-authored-by: Chaitanya * Update src/strategies/erc3525-vesting-voucher/index.ts Co-authored-by: Chaitanya * optimization Co-authored-by: Chaitanya --- .../erc3525-vesting-voucher/examples.json | 19 +++++++++ .../erc3525-vesting-voucher/index.ts | 40 +++++++++++++++++++ .../erc3525-vesting-voucher/utils.ts | 33 +++++++++++++++ src/strategies/index.ts | 2 + 4 files changed, 94 insertions(+) create mode 100644 src/strategies/erc3525-vesting-voucher/examples.json create mode 100644 src/strategies/erc3525-vesting-voucher/index.ts create mode 100644 src/strategies/erc3525-vesting-voucher/utils.ts diff --git a/src/strategies/erc3525-vesting-voucher/examples.json b/src/strategies/erc3525-vesting-voucher/examples.json new file mode 100644 index 000000000..0c736a063 --- /dev/null +++ b/src/strategies/erc3525-vesting-voucher/examples.json @@ -0,0 +1,19 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "erc3525-vesting-voucher", + "params": { + "symbol": "SOLV", + "address": "0x3788cab48c6090dfc312c92a9ff67eee034cdf84", + "tokenId": "550", + "decimals": 18 + } + }, + "network": "4", + "addresses": [ + "0x1a71c8EF63aB6f578b1702a35367cA81c9281A8c" + ], + "snapshot": 10037271 + } +] diff --git a/src/strategies/erc3525-vesting-voucher/index.ts b/src/strategies/erc3525-vesting-voucher/index.ts new file mode 100644 index 000000000..a61c4e89f --- /dev/null +++ b/src/strategies/erc3525-vesting-voucher/index.ts @@ -0,0 +1,40 @@ +import { formatUnits } from '@ethersproject/units'; +import { multicall } from '../../utils'; +import { claimCoefficient, maturitiesCoefficient } from './utils'; + +export const author = 'buchaoqun'; +export const version = '0.1.0'; + +const abi = [ + 'function getSnapshot(uint256 tokenId_) view returns (uint8 claimType_, uint64 term_, uint256 vestingAmount_, uint256 principal_, uint64[] maturities_, uint32[] percentages_, uint256 availableWithdrawAmount_, string originalInvestor_, bool isValid_)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const snapshotData = await multicall( + network, + provider, + abi, + addresses.map((address: any) => [ + options.address, + 'getSnapshot', + [options.tokenId] + ]), + { blockTag } + ); + + return Object.fromEntries( + snapshotData.map((value, i) => [ + addresses[i], + parseFloat(formatUnits(value[6].toString(), options.decimals)) * claimCoefficient(value[0]) * maturitiesCoefficient(value[4]) + ]) + ); +} diff --git a/src/strategies/erc3525-vesting-voucher/utils.ts b/src/strategies/erc3525-vesting-voucher/utils.ts new file mode 100644 index 000000000..bd20b7996 --- /dev/null +++ b/src/strategies/erc3525-vesting-voucher/utils.ts @@ -0,0 +1,33 @@ +const oneDaySeconds = 86400; + +export const maturitiesCoefficient = ( + maturities: Array +) => { + const nowData = Date.parse(new Date().toString()) / 1000 + const difference = maturities[maturities.length - 1].toNumber() - nowData; + + if (difference <= (90 * oneDaySeconds)) { + return 1.1; + } else if (difference > (90 * oneDaySeconds) && difference <= (183 * oneDaySeconds)) { + return 1.2; + } else if (difference > (183 * oneDaySeconds) && difference <= (365 * oneDaySeconds)) { + return 1.5; + } else { + return 2; + } +}; + + +export const claimCoefficient = ( + claimType: number +) => { + if (claimType == 0) { + return 2; + } else if (claimType == 1) { + return 1.2; + } else if (claimType == 2) { + return 1.5; + } else { + return 1; + } +}; diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 87640ac90..1403cf0e2 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -334,6 +334,7 @@ import * as solvVoucherClaimable from './solv-voucher-claimable'; import * as h2o from './h2o'; import * as dopamine from './dopamine'; import * as lrcL2SubgraphBalanceOf from './lrc-l2-subgraph-balance-of'; +import * as erc3525VestingVoucher from './erc3525-vesting-voucher'; import * as rariFuse from './rari-fuse'; const strategies = { @@ -673,6 +674,7 @@ const strategies = { h2o, dopamine, 'lrc-l2-subgraph-balance-of': lrcL2SubgraphBalanceOf, + 'erc3525-vesting-voucher': erc3525VestingVoucher, 'rari-fuse': rariFuse }; From 2a92068cee186974f18abb2d989b938adbc35306 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Thu, 21 Jul 2022 02:18:39 +0530 Subject: [PATCH 030/815] Fix copyfiles path (#722) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 130ad12b6..14b73ed05 100755 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "test:delegation": "jest -i delegation.test.ts", "prepublishOnly": "npm run build", "prepare": "npm run build", - "postbuild": "copyfiles -u 1 src/**/*.md dist/ && copyfiles -u 1 src/**/*.json dist/", + "postbuild": "copyfiles -u 1 src/**/*.md dist/src/ && copyfiles -u 1 src/**/*.json dist/src/", "lint": "eslint src/ test/ --ext .ts,.json --fix" }, "dependencies": { From c3866964d391a16977c60594b777de32abab4db5 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Thu, 21 Jul 2022 03:18:09 +0530 Subject: [PATCH 031/815] Fix copyfiles issue in linux env (#723) * Fix copyfiles path * Fix copyfiles issue in linux env --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 14b73ed05..30feceeb6 100755 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "test:delegation": "jest -i delegation.test.ts", "prepublishOnly": "npm run build", "prepare": "npm run build", - "postbuild": "copyfiles -u 1 src/**/*.md dist/src/ && copyfiles -u 1 src/**/*.json dist/src/", + "postbuild": "copyfiles -u 1 \"src/**/*.md\" dist/src/ && copyfiles -u 1 \"src/**/*.json\" dist/src/", "lint": "eslint src/ test/ --ext .ts,.json --fix" }, "dependencies": { From 4f8f062747a8aaf071de9df1d020083304265b17 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Fri, 22 Jul 2022 01:03:20 +0530 Subject: [PATCH 032/815] Replace prepare with postinstall and also lint fixes (#724) * Replace prepare with postinstall * Fixes * Fix * Lint --- package.json | 10 ++-- .../erc3525-vesting-voucher/examples.json | 4 +- .../erc3525-vesting-voucher/index.ts | 46 +++++++++---------- .../erc3525-vesting-voucher/utils.ts | 23 +++++----- tsconfig.json | 2 +- 5 files changed, 41 insertions(+), 44 deletions(-) diff --git a/package.json b/package.json index 30feceeb6..5247c7745 100755 --- a/package.json +++ b/package.json @@ -1,10 +1,10 @@ { "name": "@snapshot-labs/strategies", "version": "0.1.0", - "main": "dist/src/index.js", - "types": "dist/src/index.d.ts", + "main": "dist/index.js", + "types": "dist/index.d.ts", "exports": { - ".": "./dist/src/index.js" + ".": "./dist/index.js" }, "files": [ "dist" @@ -17,8 +17,8 @@ "test:vp": "jest -i vp.test.ts", "test:delegation": "jest -i delegation.test.ts", "prepublishOnly": "npm run build", - "prepare": "npm run build", - "postbuild": "copyfiles -u 1 \"src/**/*.md\" dist/src/ && copyfiles -u 1 \"src/**/*.json\" dist/src/", + "postinstall": "npm run build", + "postbuild": "copyfiles -u 1 \"src/**/*.md\" dist/ && copyfiles -u 1 \"src/**/*.json\" dist/", "lint": "eslint src/ test/ --ext .ts,.json --fix" }, "dependencies": { diff --git a/src/strategies/erc3525-vesting-voucher/examples.json b/src/strategies/erc3525-vesting-voucher/examples.json index 0c736a063..873e87606 100644 --- a/src/strategies/erc3525-vesting-voucher/examples.json +++ b/src/strategies/erc3525-vesting-voucher/examples.json @@ -11,9 +11,7 @@ } }, "network": "4", - "addresses": [ - "0x1a71c8EF63aB6f578b1702a35367cA81c9281A8c" - ], + "addresses": ["0x1a71c8EF63aB6f578b1702a35367cA81c9281A8c"], "snapshot": 10037271 } ] diff --git a/src/strategies/erc3525-vesting-voucher/index.ts b/src/strategies/erc3525-vesting-voucher/index.ts index a61c4e89f..6aa2294e8 100644 --- a/src/strategies/erc3525-vesting-voucher/index.ts +++ b/src/strategies/erc3525-vesting-voucher/index.ts @@ -10,31 +10,29 @@ const abi = [ ]; export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot + space, + network, + provider, + addresses, + options, + snapshot ) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - const snapshotData = await multicall( - network, - provider, - abi, - addresses.map((address: any) => [ - options.address, - 'getSnapshot', - [options.tokenId] - ]), - { blockTag } - ); + const snapshotData = await multicall( + network, + provider, + abi, + addresses.map(() => [options.address, 'getSnapshot', [options.tokenId]]), + { blockTag } + ); - return Object.fromEntries( - snapshotData.map((value, i) => [ - addresses[i], - parseFloat(formatUnits(value[6].toString(), options.decimals)) * claimCoefficient(value[0]) * maturitiesCoefficient(value[4]) - ]) - ); + return Object.fromEntries( + snapshotData.map((value, i) => [ + addresses[i], + parseFloat(formatUnits(value[6].toString(), options.decimals)) * + claimCoefficient(value[0]) * + maturitiesCoefficient(value[4]) + ]) + ); } diff --git a/src/strategies/erc3525-vesting-voucher/utils.ts b/src/strategies/erc3525-vesting-voucher/utils.ts index bd20b7996..3684e9df1 100644 --- a/src/strategies/erc3525-vesting-voucher/utils.ts +++ b/src/strategies/erc3525-vesting-voucher/utils.ts @@ -1,26 +1,27 @@ const oneDaySeconds = 86400; -export const maturitiesCoefficient = ( - maturities: Array -) => { - const nowData = Date.parse(new Date().toString()) / 1000 +export const maturitiesCoefficient = (maturities: Array) => { + const nowData = Date.parse(new Date().toString()) / 1000; const difference = maturities[maturities.length - 1].toNumber() - nowData; - if (difference <= (90 * oneDaySeconds)) { + if (difference <= 90 * oneDaySeconds) { return 1.1; - } else if (difference > (90 * oneDaySeconds) && difference <= (183 * oneDaySeconds)) { + } else if ( + difference > 90 * oneDaySeconds && + difference <= 183 * oneDaySeconds + ) { return 1.2; - } else if (difference > (183 * oneDaySeconds) && difference <= (365 * oneDaySeconds)) { + } else if ( + difference > 183 * oneDaySeconds && + difference <= 365 * oneDaySeconds + ) { return 1.5; } else { return 2; } }; - -export const claimCoefficient = ( - claimType: number -) => { +export const claimCoefficient = (claimType: number) => { if (claimType == 0) { return 2; } else if (claimType == 1) { diff --git a/tsconfig.json b/tsconfig.json index e9631bfdf..b4973e961 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,6 +12,6 @@ "resolveJsonModule": true, "allowSyntheticDefaultImports": true }, - "include": ["src", "test"], + "include": ["src"], "files": ["./src/typings.d.ts"] } From eea953d83bbef100fb9870079f5152d5bc8752c0 Mon Sep 17 00:00:00 2001 From: TudorSante <41923863+TudorSante@users.noreply.github.com> Date: Thu, 21 Jul 2022 23:42:56 +0300 Subject: [PATCH 033/815] xROOK strategy [xrook-balance-of-underlying-weighted] (#721) * Added xROOK strategy * Changed .gitignore to prev version * Update src/strategies/xrook-balance-of-underlying-weighted/index.ts Co-authored-by: Chaitanya --- src/strategies/index.ts | 4 +- .../examples.json | 37 ++++++++++++++ .../index.ts | 51 +++++++++++++++++++ 3 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 src/strategies/xrook-balance-of-underlying-weighted/examples.json create mode 100644 src/strategies/xrook-balance-of-underlying-weighted/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 1403cf0e2..062134429 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -336,6 +336,7 @@ import * as dopamine from './dopamine'; import * as lrcL2SubgraphBalanceOf from './lrc-l2-subgraph-balance-of'; import * as erc3525VestingVoucher from './erc3525-vesting-voucher'; import * as rariFuse from './rari-fuse'; +import * as xrookBalanceOfUnderlyingWeighted from './xrook-balance-of-underlying-weighted'; const strategies = { 'forta-shares': fortaShares, @@ -675,7 +676,8 @@ const strategies = { dopamine, 'lrc-l2-subgraph-balance-of': lrcL2SubgraphBalanceOf, 'erc3525-vesting-voucher': erc3525VestingVoucher, - 'rari-fuse': rariFuse + 'rari-fuse': rariFuse, + 'xrook-balance-of-underlying-weighted': xrookBalanceOfUnderlyingWeighted }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/xrook-balance-of-underlying-weighted/examples.json b/src/strategies/xrook-balance-of-underlying-weighted/examples.json new file mode 100644 index 000000000..fb4e85a6d --- /dev/null +++ b/src/strategies/xrook-balance-of-underlying-weighted/examples.json @@ -0,0 +1,37 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "xrook-balance-of-underlying-weighted", + "params": { + "symbol": "xROOK", + "address": "0x8aC32F0a635a0896a8428A9c31fBf1AB06ecf489", + "decimals": 18, + "weight": 1.2, + "underlyingTokenAddress": "0xfA5047c9c78B8877af97BDcb85Db743fD7313d4a", + "liquidityPoolAddress": "0x4F868C1aa37fCf307ab38D215382e88FCA6275E2" + } + }, + "network": "1", + "addresses": [ + "0x759a159D78342340EbACffB027c05910c093f430", + "0x2D21170928854F7Da6dC4b1C89dcb95BBc948338", + "0x722f531740937fc21A2FaC7648670C7f2872A1c7", + "0xA1ebb64d1f19D36A31221fFAd19747EF573Cd5A4", + "0x698EE32575dc58DDC0dd2e8B80d2EaB8Af1E94e1", + "0xBE6DcFDf4F1bf2ec0d3dEbD894a02a0765af6D69", + "0xFe4C4A27BeD5E9113480C84A177068F7421A1Eb7", + "0x0054D2575820cf60F5B6D350fb8d3d352BB3B6FD", + "0x4A9A3815060C3Bd08fb4d44C9e74513874771b0C", + "0x99BcEa6bB0403927fB3c038163478D5b42082Fd9", + "0x04b92e3b5De16Dc7e307ea4CEBc5d7dabaE1894F", + "0xe41eeB9ab53Ab208fD57A5E10dFC2FeE464Ca216", + "0x51F13C84b49B64ba6B1615e7D91b11066908BF3C", + "0x2ee8D80de1c389f1254e94bc44D2d1Bc391eD402", + "0x7453019b806919563EaC33870Fe5f8e5154fdF38", + "0x0B72513E73BB60375a4329FABF9BA16f861C0f12", + "0x9a82d59f46913913808bFE905F6157F967AAa28E" + ], + "snapshot": 15039737 + } +] diff --git a/src/strategies/xrook-balance-of-underlying-weighted/index.ts b/src/strategies/xrook-balance-of-underlying-weighted/index.ts new file mode 100644 index 000000000..b00d62545 --- /dev/null +++ b/src/strategies/xrook-balance-of-underlying-weighted/index.ts @@ -0,0 +1,51 @@ +import { call } from '../../utils'; +import { formatUnits } from '@ethersproject/units'; +import { strategy as erc20BalanceOfStrategy } from '../erc20-balance-of'; + +export const author = 'TudorSante'; +export const version = '1.0.0'; + +const erc20ABI = [ + 'function balanceOf(address account) external view returns (uint256)', + 'function totalSupply() external view returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const score = await erc20BalanceOfStrategy( + space, + network, + provider, + addresses, + options, + snapshot + ); + + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const xROOKTotalSupply = await call( + provider, + erc20ABI, + [options.address, 'totalSupply', []], + { blockTag } + ).then((res) => parseFloat(formatUnits(res, options.decimals))); + + const liquidityPoolBalance = await call( + provider, + erc20ABI, + [options.underlyingTokenAddress, 'balanceOf', [options.liquidityPoolAddress]], + { blockTag } + ).then((res) => parseFloat(formatUnits(res, options.decimals))); + + const underlyingValue = liquidityPoolBalance / xROOKTotalSupply; + + return Object.fromEntries( + Object.entries(score).map((res: any) => [res[0], res[1] * options.weight * underlyingValue]) + ); +} From b9556875f82cd686dfd9cf9ac6b63b92daaaa04e Mon Sep 17 00:00:00 2001 From: Cr3k <99047920+Cr3k@users.noreply.github.com> Date: Fri, 22 Jul 2022 10:19:29 +0200 Subject: [PATCH 034/815] Add self strategy [selfswap] (#719) * Add self strategy * deleted what we don't need * Update src/strategies/self/index.ts * changed self to selfswap * Update src/strategies/selfswap/README.md Co-authored-by: Chaitanya --- src/strategies/index.ts | 4 +- src/strategies/selfswap/README.md | 9 ++ src/strategies/selfswap/examples.json | 19 +++ src/strategies/selfswap/index.ts | 225 ++++++++++++++++++++++++++ 4 files changed, 256 insertions(+), 1 deletion(-) create mode 100644 src/strategies/selfswap/README.md create mode 100644 src/strategies/selfswap/examples.json create mode 100644 src/strategies/selfswap/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 062134429..cf9d2b536 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -336,6 +336,7 @@ import * as dopamine from './dopamine'; import * as lrcL2SubgraphBalanceOf from './lrc-l2-subgraph-balance-of'; import * as erc3525VestingVoucher from './erc3525-vesting-voucher'; import * as rariFuse from './rari-fuse'; +import * as selfswap from './selfswap'; import * as xrookBalanceOfUnderlyingWeighted from './xrook-balance-of-underlying-weighted'; const strategies = { @@ -675,8 +676,9 @@ const strategies = { h2o, dopamine, 'lrc-l2-subgraph-balance-of': lrcL2SubgraphBalanceOf, - 'erc3525-vesting-voucher': erc3525VestingVoucher, 'rari-fuse': rariFuse, + selfswap, + 'erc3525-vesting-voucher': erc3525VestingVoucher, 'xrook-balance-of-underlying-weighted': xrookBalanceOfUnderlyingWeighted }; diff --git a/src/strategies/selfswap/README.md b/src/strategies/selfswap/README.md new file mode 100644 index 000000000..42c764887 --- /dev/null +++ b/src/strategies/selfswap/README.md @@ -0,0 +1,9 @@ +# selfswap + +Fetches [SELF](https://bscscan.com/address/0x7a364484303b38bce7b0ab60a20da8f2f4370129) balance from the following sources: + +- Wallet +- SELF-BNB LP Farm +- SELF Pool +- SELF Vault +- Pools that were active at the time of the snapshot diff --git a/src/strategies/selfswap/examples.json b/src/strategies/selfswap/examples.json new file mode 100644 index 000000000..82b20d8c5 --- /dev/null +++ b/src/strategies/selfswap/examples.json @@ -0,0 +1,19 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "selfswap", + "params": { + "symbol": "SELF" + } + }, + "network": "56", + "addresses": [ + "0x26e82CB17cfd4ef12096f38f3ba0DAD6ea5B5035", + "0x21fF20E7e1B820020415707298b92299CF0951fE", + "0x2b3D1D31ac5C053cf89a92EE9c94dbF3774D6366", + "0x273e3fD65450032a44AC6CA36F6551D74A459B6A" + ], + "snapshot": 16308675 + } +] diff --git a/src/strategies/selfswap/index.ts b/src/strategies/selfswap/index.ts new file mode 100644 index 000000000..2b27f1409 --- /dev/null +++ b/src/strategies/selfswap/index.ts @@ -0,0 +1,225 @@ +import { strategy as erc20BalanceOfStrategy } from '../erc20-balance-of'; +import { strategy as masterChefPoolBalanceStrategy } from '../masterchef-pool-balance'; +import { formatEther } from '@ethersproject/units'; +import { Zero, WeiPerEther } from '@ethersproject/constants'; +import { BigNumber } from '@ethersproject/bignumber'; +import { subgraphRequest, Multicaller } from '../../utils'; + +const chunk = (arr, size) => + Array.from({ length: Math.ceil(arr.length / size) }, (v, i) => + arr.slice(i * size, i * size + size) + ); + +const PAGE_SIZE = 1000; + +export const author = 'Cr3k'; +export const version = '0.0.1'; + +const SELF_ADDRESS = '0x7a364484303b38bce7b0ab60a20da8f2f4370129'; +const SELF_VAULT_ADDRESS = '0xeb4f1307DE7DF263E8e54d083fE7db1e281e710D'; +const SELF_BNB_LP_ADDRESS = '0x9C6FF656A563Ec9057460D8a400E2AC7c2AE0a1C'; + +const MASTER_CHEF_ADDRESS = { + v1: '0x3d03d12F95Bdc4509804f9Bcee4139b7789DC516' +}; + +const vaultAbi = [ + 'function getPricePerFullShare() view returns (uint256)', + 'function userInfo(address) view returns (uint256 shares, uint256 lastDepositedTime, uint256 selfAtLastUserAction, uint256 lastUserActionTime)' +]; + +const smartChefUrl = + 'https://api.thegraph.com/subgraphs/name/cr3k/smartchef'; + +async function getPools(provider, snapshot: any) { + let blockNumber = snapshot; + if (blockNumber === 'latest') { + blockNumber = await provider.getBlockNumber(); + } + + const params = { + smartChefs: { + __args: { + where: { + stakeToken: SELF_ADDRESS.toLowerCase(), + endBlock_gte: blockNumber, + startBlock_lt: blockNumber + } + }, + id: true + } + }; + + const pools = await subgraphRequest(smartChefUrl, params); + + return pools.smartChefs; +} + +async function getSmartChefStakedSELFAmount( + snapshot: any, + poolAddresses: string[], + addresses: string[] +) { + const addressChunks = chunk(addresses, 1500); + let results: any[] = []; + + for (const addressChunk of addressChunks) { + const params = { + users: { + __args: { + where: { + pool_in: poolAddresses.map((addr) => addr.toLowerCase()), + address_in: addressChunk.map((addr) => addr.toLowerCase()), + stakeAmount_gt: '0' + }, + first: PAGE_SIZE + }, + address: true, + stakeAmount: true + } + }; + + let page = 0; + let triedBlockNumber = false; + + while (true) { + // @ts-ignore + params.users.__args.skip = page * PAGE_SIZE; + if (snapshot !== 'latest' && !triedBlockNumber) { + // @ts-ignore + params.users.__args.block = { number: snapshot }; + } else { + // @ts-ignore + delete params.users.__args.block; + } + let result; + try { + result = await subgraphRequest(smartChefUrl, params); + } catch (error) { + if (!triedBlockNumber) { + triedBlockNumber = true; + continue; + } else { + throw error; + } + } + if (!Array.isArray(result.users) && !triedBlockNumber) { + triedBlockNumber = true; + continue; + } + results = results.concat(result.users); + page++; + if (result.users.length < PAGE_SIZE) break; + } + } + + return results.reduce>((acc, user) => { + if (acc[user.address]) { + acc[user.address] = (acc[user.address] as BigNumber).add( + user.stakeAmount + ); + } else { + acc[user.address] = BigNumber.from(user.stakeAmount); + } + return acc; + }, {}); +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const pools = await getPools(provider, snapshot); + + const userPoolBalance = await getSmartChefStakedSELFAmount( + snapshot, + pools.map((p) => p.id), + addresses + ); + + const blockTag = snapshot; + + const erc20Balance = await erc20BalanceOfStrategy( + space, + network, + provider, + addresses, + { + address: SELF_ADDRESS, + symbol: 'SELF', + decimals: 18 + }, + snapshot + ); + + const selfBnbLpBalance = await masterChefPoolBalanceStrategy( + space, + network, + provider, + addresses, + { + chefAddress: MASTER_CHEF_ADDRESS.v1, + uniPairAddress: SELF_BNB_LP_ADDRESS, + pid: '251', + symbol: 'SELF-BNB LP', + tokenIndex: 0 + }, + snapshot + ); + + const selfVaultBalance = await getVaultBalance( + network, + provider, + addresses, + blockTag + ); + + return Object.fromEntries( + addresses.map((address) => [ + address, + erc20Balance[address] + + selfBnbLpBalance[address] + + parseFloat( + formatEther( + (userPoolBalance[address.toLowerCase()] || Zero).add( + selfVaultBalance[address] || Zero + ) + ) + ) + ]) + ); +} + +async function getVaultBalance(network, provider, addresses, blockTag) { + const vaultMulti = new Multicaller(network, provider, vaultAbi, { blockTag }); + + vaultMulti.call( + SELF_VAULT_ADDRESS, + SELF_VAULT_ADDRESS, + 'getPricePerFullShare' + ); + + addresses.forEach((address) => + vaultMulti.call( + `${SELF_VAULT_ADDRESS}-${address}`, + SELF_VAULT_ADDRESS, + 'userInfo', + [address] + ) + ); + + const vaultMultiRes = await vaultMulti.execute(); + + return Object.fromEntries( + addresses.map((address) => [ + address, + (vaultMultiRes[SELF_VAULT_ADDRESS] || Zero) + .mul(vaultMultiRes[`${SELF_VAULT_ADDRESS}-${address}`]?.shares || Zero) + .div(WeiPerEther) + ]) + ); +} From 72e320471da91107393675d66459ca7a97aa301c Mon Sep 17 00:00:00 2001 From: TudorSante <41923863+TudorSante@users.noreply.github.com> Date: Fri, 22 Jul 2022 11:25:07 +0300 Subject: [PATCH 035/815] Bancor V3 strategy [bancor-pool-token-underlying-balance] (#727) * Added xROOK strategy * Changed .gitignore to prev version * Added bnROOK strategy * Updated the bnROOK strategy * Code cleanup performed * Update src/strategies/xrook-balance-of-underlying-weighted/index.ts * Minor code cleanup * Minor code cleanup * Minor code cleanup * Update src/strategies/bancor-pool-token-underlying-balance/examples.json Co-authored-by: Chaitanya --- .../examples.json | 21 ++++++++ .../index.ts | 51 +++++++++++++++++++ src/strategies/index.ts | 2 + 3 files changed, 74 insertions(+) create mode 100644 src/strategies/bancor-pool-token-underlying-balance/examples.json create mode 100644 src/strategies/bancor-pool-token-underlying-balance/index.ts diff --git a/src/strategies/bancor-pool-token-underlying-balance/examples.json b/src/strategies/bancor-pool-token-underlying-balance/examples.json new file mode 100644 index 000000000..50f07ae46 --- /dev/null +++ b/src/strategies/bancor-pool-token-underlying-balance/examples.json @@ -0,0 +1,21 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "bancor-pool-token-underlying-balance", + "params": { + "symbol": "bnROOK", + "decimals": 18, + "underlyingTokenAddress": "0xfA5047c9c78B8877af97BDcb85Db743fD7313d4a", + "bancorNetworkInfoAddress": "0x8E303D296851B320e6a697bAcB979d13c9D6E760" + } + }, + "network": "1", + "addresses": [ + "0x66e81feea36764103b755144b161c70e75906535", + "0x857eb0eb2572f7092c417cd386ba82e45eba9b8a", + "0x98625957c6b96eeecd040e5bd26bd42100d124b2" + ], + "snapshot": 15191222 + } +] diff --git a/src/strategies/bancor-pool-token-underlying-balance/index.ts b/src/strategies/bancor-pool-token-underlying-balance/index.ts new file mode 100644 index 000000000..c3db581b4 --- /dev/null +++ b/src/strategies/bancor-pool-token-underlying-balance/index.ts @@ -0,0 +1,51 @@ +import { call } from '../../utils'; +import { formatUnits } from '@ethersproject/units'; +import { strategy as erc20BalanceOfStrategy } from '../erc20-balance-of'; + +export const author = 'TudorSante'; +export const version = '1.0.0'; + +const erc20ABI = [ + 'function poolToken(address pool) external view returns (address)', + 'function poolTokenToUnderlying(address pool, uint256 poolTokenAmount) external view returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const liquidityPoolTokenAddress = await call( + provider, + erc20ABI, + [options.bancorNetworkInfoAddress, 'poolToken', [options.underlyingTokenAddress]], + { blockTag } + ); + + options.address = liquidityPoolTokenAddress; + const scores = await erc20BalanceOfStrategy( + space, + network, + provider, + addresses, + options, + snapshot + ); + + const poolTokenDecimalScaling = (10**options.decimals).toString(); + const underlyingValue = await call( + provider, + erc20ABI, + [options.bancorNetworkInfoAddress, 'poolTokenToUnderlying', [options.underlyingTokenAddress, poolTokenDecimalScaling]], + { blockTag } + ).then((res) => parseFloat(formatUnits(res, options.decimals))); + + return Object.fromEntries( + Object.entries(scores).map((res: any) => [res[0], res[1] * underlyingValue]) + ); +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index cf9d2b536..df1462ba3 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -338,6 +338,7 @@ import * as erc3525VestingVoucher from './erc3525-vesting-voucher'; import * as rariFuse from './rari-fuse'; import * as selfswap from './selfswap'; import * as xrookBalanceOfUnderlyingWeighted from './xrook-balance-of-underlying-weighted'; +import * as bancorPoolTokenUnderlyingBalance from './bancor-pool-token-underlying-balance'; const strategies = { 'forta-shares': fortaShares, @@ -677,6 +678,7 @@ const strategies = { dopamine, 'lrc-l2-subgraph-balance-of': lrcL2SubgraphBalanceOf, 'rari-fuse': rariFuse, + 'bancor-pool-token-underlying-balance': bancorPoolTokenUnderlyingBalance, selfswap, 'erc3525-vesting-voucher': erc3525VestingVoucher, 'xrook-balance-of-underlying-weighted': xrookBalanceOfUnderlyingWeighted From 64a8fde81e67f17e1f88c98713af736611f6d0a8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 24 Jul 2022 17:36:04 +0530 Subject: [PATCH 036/815] Automated lint (#728) Co-authored-by: ChaituVR --- .../bancor-pool-token-underlying-balance/index.ts | 14 +++++++++++--- src/strategies/selfswap/index.ts | 5 ++--- .../xrook-balance-of-underlying-weighted/index.ts | 11 +++++++++-- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/strategies/bancor-pool-token-underlying-balance/index.ts b/src/strategies/bancor-pool-token-underlying-balance/index.ts index c3db581b4..97d3cfa91 100644 --- a/src/strategies/bancor-pool-token-underlying-balance/index.ts +++ b/src/strategies/bancor-pool-token-underlying-balance/index.ts @@ -23,7 +23,11 @@ export async function strategy( const liquidityPoolTokenAddress = await call( provider, erc20ABI, - [options.bancorNetworkInfoAddress, 'poolToken', [options.underlyingTokenAddress]], + [ + options.bancorNetworkInfoAddress, + 'poolToken', + [options.underlyingTokenAddress] + ], { blockTag } ); @@ -37,11 +41,15 @@ export async function strategy( snapshot ); - const poolTokenDecimalScaling = (10**options.decimals).toString(); + const poolTokenDecimalScaling = (10 ** options.decimals).toString(); const underlyingValue = await call( provider, erc20ABI, - [options.bancorNetworkInfoAddress, 'poolTokenToUnderlying', [options.underlyingTokenAddress, poolTokenDecimalScaling]], + [ + options.bancorNetworkInfoAddress, + 'poolTokenToUnderlying', + [options.underlyingTokenAddress, poolTokenDecimalScaling] + ], { blockTag } ).then((res) => parseFloat(formatUnits(res, options.decimals))); diff --git a/src/strategies/selfswap/index.ts b/src/strategies/selfswap/index.ts index 2b27f1409..76531aa09 100644 --- a/src/strategies/selfswap/index.ts +++ b/src/strategies/selfswap/index.ts @@ -28,8 +28,7 @@ const vaultAbi = [ 'function userInfo(address) view returns (uint256 shares, uint256 lastDepositedTime, uint256 selfAtLastUserAction, uint256 lastUserActionTime)' ]; -const smartChefUrl = - 'https://api.thegraph.com/subgraphs/name/cr3k/smartchef'; +const smartChefUrl = 'https://api.thegraph.com/subgraphs/name/cr3k/smartchef'; async function getPools(provider, snapshot: any) { let blockNumber = snapshot; @@ -142,7 +141,7 @@ export async function strategy( ); const blockTag = snapshot; - + const erc20Balance = await erc20BalanceOfStrategy( space, network, diff --git a/src/strategies/xrook-balance-of-underlying-weighted/index.ts b/src/strategies/xrook-balance-of-underlying-weighted/index.ts index b00d62545..ccd613306 100644 --- a/src/strategies/xrook-balance-of-underlying-weighted/index.ts +++ b/src/strategies/xrook-balance-of-underlying-weighted/index.ts @@ -39,13 +39,20 @@ export async function strategy( const liquidityPoolBalance = await call( provider, erc20ABI, - [options.underlyingTokenAddress, 'balanceOf', [options.liquidityPoolAddress]], + [ + options.underlyingTokenAddress, + 'balanceOf', + [options.liquidityPoolAddress] + ], { blockTag } ).then((res) => parseFloat(formatUnits(res, options.decimals))); const underlyingValue = liquidityPoolBalance / xROOKTotalSupply; return Object.fromEntries( - Object.entries(score).map((res: any) => [res[0], res[1] * options.weight * underlyingValue]) + Object.entries(score).map((res: any) => [ + res[0], + res[1] * options.weight * underlyingValue + ]) ); } From 2f19a9cf495657bc59dc3018fca03a4d96aac287 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 25 Jul 2022 16:45:41 +0530 Subject: [PATCH 037/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.11 (#730) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 5247c7745..fb1643c41 100755 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.10", + "@snapshot-labs/snapshot.js": "^0.4.11", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", "copyfiles": "^2.4.1", diff --git a/yarn.lock b/yarn.lock index 0e9ede97b..904d8a41c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.10": - version "0.4.10" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.10.tgz#0e83ac8b8518ae627a17f178c102bfb122228236" - integrity sha512-eNJ8wEw+CrPNj3mUJ/p7vTz9dTgXHBgJFZ4cuKaMjlWo014Rtz2nAbF/1QKPwVD1Hw/BlBZgz1aRkK9kbzQTZA== +"@snapshot-labs/snapshot.js@^0.4.11": + version "0.4.11" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.11.tgz#3723736f487203177c9dc815f901d7675cd46970" + integrity sha512-U7yLw1PgCVB7sW/sCNj5Htea8ePF1O80G3dAQNVZOEKhjdA2YYJ8SzjjiyTJtYEPbaqcXMi2gl3N184n2I8ROA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 225b8c8d11f270a6a5d3293dcd64513d6c302ab9 Mon Sep 17 00:00:00 2001 From: Joeh <32411671+joehquak@users.noreply.github.com> Date: Tue, 26 Jul 2022 07:13:42 +0100 Subject: [PATCH 038/815] crucible-erc20-token-and-lp-weighted [crucible-erc20-token-and-lp-weighted] (#731) * crucible-erc20-token-and-lp-weighted * Update src/strategies/crucible-erc20-token-and-lp-weighted/index.ts Co-authored-by: Chaitanya --- .../README.md | 22 +++ .../examples.json | 28 +++ .../index.ts | 174 ++++++++++++++++++ .../schema.json | 44 +++++ src/strategies/index.ts | 2 + 5 files changed, 270 insertions(+) create mode 100644 src/strategies/crucible-erc20-token-and-lp-weighted/README.md create mode 100644 src/strategies/crucible-erc20-token-and-lp-weighted/examples.json create mode 100644 src/strategies/crucible-erc20-token-and-lp-weighted/index.ts create mode 100644 src/strategies/crucible-erc20-token-and-lp-weighted/schema.json diff --git a/src/strategies/crucible-erc20-token-and-lp-weighted/README.md b/src/strategies/crucible-erc20-token-and-lp-weighted/README.md new file mode 100644 index 000000000..3afbc444b --- /dev/null +++ b/src/strategies/crucible-erc20-token-and-lp-weighted/README.md @@ -0,0 +1,22 @@ +# crucible-erc20-token-and-lp-weighted + +This strategy works on Uniswap v2 style pools or contracts utilising token0/token1 and reserves. + +This strategy calculates the qty of the specified token within a single LP, doubles it to account for both sides, and then uses it as a weight against the sum of a users LP balance across all of their Crucibles. + +This strategy also additionally adds the sum of the users token balance in all Crucibles to give a token weighted score. + +This is useful if you want to be inclusive of LP and token holdings and need to scale them to be balanced with each other. + +Here is an example of parameters: + +```json +{ + "symbol": "MIST", + "crucible_factory": "0x54e0395CFB4f39beF66DBCd5bD93Cca4E9273D56", + "tokenAddress": "0x88ACDd2a6425c3FaAE4Bc9650Fd7E27e0Bebb7aB",, + "tokenDecimals" : "18", + "lpTokenAddress": "0xcd6bcca48069f8588780dfa274960f15685aee0e", + "lpTokenDecimals" : "18" +} +``` diff --git a/src/strategies/crucible-erc20-token-and-lp-weighted/examples.json b/src/strategies/crucible-erc20-token-and-lp-weighted/examples.json new file mode 100644 index 000000000..02de06aac --- /dev/null +++ b/src/strategies/crucible-erc20-token-and-lp-weighted/examples.json @@ -0,0 +1,28 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "crucible-erc20-token-and-lp-weighted", + "params": { + "symbol": "MIST", + "crucible_factory": "0x54e0395CFB4f39beF66DBCd5bD93Cca4E9273D56", + "tokenAddress": "0x88ACDd2a6425c3FaAE4Bc9650Fd7E27e0Bebb7aB", + "lpTokenAddress": "0xcd6bcca48069f8588780dfa274960f15685aee0e" + } + }, + "network": "1", + "addresses": [ + "0x4d4902BD7E080159964f46B10feeb6482d148E5a", + "0xbD7B1a13149Da69059e4591F040D7D7dAda740c5", + "0x7F8aE988796890454A1007a6dD15eaedC549ad1e", + "0xfca399b892f4e8306fc31b312a3399f422976886", + "0x97a6c796FE543cABC2cA7aE026206e8B260C4dA0", + "0x5E91d547A6f279E6d59086E30e25C964EFE4b463", + "0xB59212Bd19aE722F1cc97A3A93542D573534cf70", + "0x777B0884f97Fd361c55e472530272Be61cEb87c8", + "0x63060f713b377AF8D7D50669ec0fDcE1D31E3f28", + "0xA5109D7E4790143a91D673Ba545405Bf396806CF" + ], + "snapshot": 13062462 + } +] diff --git a/src/strategies/crucible-erc20-token-and-lp-weighted/index.ts b/src/strategies/crucible-erc20-token-and-lp-weighted/index.ts new file mode 100644 index 000000000..941658a3a --- /dev/null +++ b/src/strategies/crucible-erc20-token-and-lp-weighted/index.ts @@ -0,0 +1,174 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import { hexZeroPad } from '@ethersproject/bytes'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller, multicall } from '../../utils'; + +export const author = 'joehquak'; +export const version = '0.1.0'; + +const abi = [ + 'function balanceOf(address owner) external view returns (uint256)', + 'function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256)', + 'function decimals() external view returns (uint8)', + 'function token0() external view returns (address)', + 'function token1() external view returns (address)', + 'function totalSupply() external view returns (uint256)', + 'function getReserves() external view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + // fetch all token and lp contract data + + const fetchContractData = await multicall( + network, + provider, + abi, + [[options.lpTokenAddress, 'token0', []], + [options.lpTokenAddress, 'token1', []], + [options.lpTokenAddress, 'getReserves', []], + [options.lpTokenAddress, 'totalSupply', []], + [options.lpTokenAddress, 'decimals', []], + [options.tokenAddress, 'decimals', []]], + { blockTag } + ); + + // assign multicall data to variables + + let token0Address = fetchContractData[0][0]; + let token1Address = fetchContractData[1][0]; + let lpTokenReserves = fetchContractData[2]; + let lpTokenTotalSupply = fetchContractData[3][0]; + let lpTokenDecimals = fetchContractData[4][0]; + let tokenDecimals = fetchContractData[5][0]; + + // calculate single lp token weight + + let tokenWeight; + + if (token0Address === options.tokenAddress) { + + tokenWeight = (parseFloat(formatUnits(lpTokenReserves._reserve0, tokenDecimals)) / parseFloat(formatUnits(lpTokenTotalSupply, lpTokenDecimals))) * 2 + + } else if (token1Address === options.tokenAddress) { + + tokenWeight = (parseFloat(formatUnits(lpTokenReserves._reserve1, tokenDecimals)) / parseFloat(formatUnits(lpTokenTotalSupply, lpTokenDecimals))) * 2 + + } else { + + tokenWeight = 0; + + } + + // get the number of crucibles owned by the wallet + // wallet_address => crucible_count + + const callWalletToCrucibleCount = new Multicaller(network, provider, abi, { + blockTag + }); + for (const walletAddress of addresses) { + callWalletToCrucibleCount.call( + walletAddress, + options.crucible_factory, + 'balanceOf', + [walletAddress] + ); + } + const walletToCrucibleCount: Record = + await callWalletToCrucibleCount.execute(); + + // get the address of each crucible + // wallet_address : crucible_index => crucible_address + + const callWalletToCrucibleAddresses = new Multicaller( + network, + provider, + abi, + { + blockTag + } + ); + for (const [walletAddress, crucibleCount] of Object.entries( + walletToCrucibleCount + )) { + for (let index = 0; index < crucibleCount.toNumber(); index++) { + callWalletToCrucibleAddresses.call( + walletAddress.toString() + '-' + index.toString(), + options.crucible_factory, + 'tokenOfOwnerByIndex', + [walletAddress, index] + ); + } + } + const walletIDToCrucibleAddresses: Record = + await callWalletToCrucibleAddresses.execute(); + + // get the lp token balance of each crucible + // crucible_address => lp_balance + + const callCrucibleToLpBalance = new Multicaller(network, provider, abi, { + blockTag + }); + for (const [walletID, crucibleAddress] of Object.entries( + walletIDToCrucibleAddresses + )) { + callCrucibleToLpBalance.call(walletID, options.lpTokenAddress, 'balanceOf', [ + hexZeroPad(crucibleAddress.toHexString(), 20) + ]); + } + const walletIDToLpBalance: Record = + await callCrucibleToLpBalance.execute(); + + // get the token balance of each crucible + // crucible_address => token_balance + + const callCrucibleToTokenBalance = new Multicaller(network, provider, abi, { + blockTag + }); + for (const [walletID, crucibleAddress] of Object.entries( + walletIDToCrucibleAddresses + )) { + callCrucibleToTokenBalance.call(walletID, options.tokenAddress, 'balanceOf', [ + hexZeroPad(crucibleAddress.toHexString(), 20) + ]); + } + const walletIDToTokenBalance: Record = + await callCrucibleToTokenBalance.execute(); + + // sum the amount of LP tokens held across all crucibles + // wallet_address => lp_balance + + const walletToLpBalance = {} as Record; + for (const [walletID, lpBalance] of Object.entries(walletIDToLpBalance)) { + const address = walletID.split('-')[0]; + walletToLpBalance[address] = walletToLpBalance[address] + ? walletToLpBalance[address].add(lpBalance) + : lpBalance; + } + + // sum the amount of tokens held across all crucibles + // wallet_address => token_balance + + const walletToTokenBalance = {} as Record; + for (const [walletID, tokenBalance] of Object.entries(walletIDToTokenBalance)) { + const address = walletID.split('-')[0]; + walletToTokenBalance[address] = walletToTokenBalance[address] + ? walletToTokenBalance[address].add(tokenBalance) + : tokenBalance; + } + + return Object.fromEntries( + Object.entries(walletToLpBalance).map(([address, balance]) => [ + address, + parseFloat(formatUnits(balance, lpTokenDecimals)) * tokenWeight + parseFloat((formatUnits(walletToTokenBalance[address], tokenDecimals))) + ]) + ); +} diff --git a/src/strategies/crucible-erc20-token-and-lp-weighted/schema.json b/src/strategies/crucible-erc20-token-and-lp-weighted/schema.json new file mode 100644 index 000000000..e2d2bd4d3 --- /dev/null +++ b/src/strategies/crucible-erc20-token-and-lp-weighted/schema.json @@ -0,0 +1,44 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Token symbol", + "examples": ["e.g. UNI"], + "maxLength": 16 + }, + "crucible_factory": { + "type": "string", + "title": "Crucible factory address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "tokenAddress": { + "type": "string", + "title": "Token address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "lpTokenAddress": { + "type": "string", + "title": "LP address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } + }, + "required": ["crucible_factory", "tokenAddress", "lpTokenAddress"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index df1462ba3..033f9b4b9 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -193,6 +193,7 @@ import * as meebitsdao from './meebitsdao'; import * as membership from './membership'; import * as holdsTokens from './holds-tokens'; import * as crucibleERC20BalanceOf from './crucible-erc20-balance-of'; +import * as crucibleERC20TokenAndLpWeighted from './crucible-erc20-token-and-lp-weighted'; import * as hasrock from './has-rock'; import * as flexaCapacityStaking from './flexa-capacity-staking'; import * as sunriseGamingUniv2Lp from './sunrisegaming-univ2-lp'; @@ -538,6 +539,7 @@ const strategies = { snowswap, meebitsdao, 'crucible-erc20-balance-of': crucibleERC20BalanceOf, + 'crucible-erc20-token-and-lp-weighted': crucibleERC20TokenAndLpWeighted, 'has-rock': hasrock, 'flexa-capacity-staking': flexaCapacityStaking, 'sunrisegaming-univ2-lp': sunriseGamingUniv2Lp, From 6a686164ed9250c1f56d83e4bdaba9433fc4644c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 26 Jul 2022 11:44:15 +0530 Subject: [PATCH 039/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.12 (#735) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index fb1643c41..a181d4fab 100755 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.11", + "@snapshot-labs/snapshot.js": "^0.4.12", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", "copyfiles": "^2.4.1", diff --git a/yarn.lock b/yarn.lock index 904d8a41c..bd152bdd7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.11": - version "0.4.11" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.11.tgz#3723736f487203177c9dc815f901d7675cd46970" - integrity sha512-U7yLw1PgCVB7sW/sCNj5Htea8ePF1O80G3dAQNVZOEKhjdA2YYJ8SzjjiyTJtYEPbaqcXMi2gl3N184n2I8ROA== +"@snapshot-labs/snapshot.js@^0.4.12": + version "0.4.12" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.12.tgz#8830f9c8553177fe0cbfe1a2351718a5ccc66d15" + integrity sha512-+Cl8XjkIqscgRiI7G1R1WxV0Cv73hGByBj4Wp6wa62hJLzgr4ZdzM8b39oKqXQPax3J8ZI5MgcHigFcCojDSow== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From b1cb3b2dd68f24e5bfd44b1742f556b4220cb11b Mon Sep 17 00:00:00 2001 From: charq <73696209+buchaoqun@users.noreply.github.com> Date: Tue, 26 Jul 2022 22:05:23 +0800 Subject: [PATCH 040/815] erc3525 vesting voucher logical change [erc3525-vesting-voucher] (#736) * add vesting voucher strategies * vesting-voucher rename erc3525-vesting-voucher * Update src/strategies/erc3525-vesting-voucher/index.ts Co-authored-by: Chaitanya * Update src/strategies/erc3525-vesting-voucher/index.ts Co-authored-by: Chaitanya * optimization * erc3525 vesting voucher logical change Co-authored-by: Chaitanya --- .../erc3525-vesting-voucher/examples.json | 7 +- .../erc3525-vesting-voucher/index.ts | 111 ++++++++++++++---- .../erc3525-vesting-voucher/utils.ts | 25 ++-- 3 files changed, 101 insertions(+), 42 deletions(-) diff --git a/src/strategies/erc3525-vesting-voucher/examples.json b/src/strategies/erc3525-vesting-voucher/examples.json index 873e87606..3e51d4982 100644 --- a/src/strategies/erc3525-vesting-voucher/examples.json +++ b/src/strategies/erc3525-vesting-voucher/examples.json @@ -4,14 +4,13 @@ "strategy": { "name": "erc3525-vesting-voucher", "params": { - "symbol": "SOLV", - "address": "0x3788cab48c6090dfc312c92a9ff67eee034cdf84", - "tokenId": "550", + "symbol": "fvSOLV", + "address": "0x4B0dd1aDEdA251ACec75140608bAd663fB0c4cAB", "decimals": 18 } }, "network": "4", "addresses": ["0x1a71c8EF63aB6f578b1702a35367cA81c9281A8c"], - "snapshot": 10037271 + "snapshot": 11090903 } ] diff --git a/src/strategies/erc3525-vesting-voucher/index.ts b/src/strategies/erc3525-vesting-voucher/index.ts index 6aa2294e8..2daa5fc81 100644 --- a/src/strategies/erc3525-vesting-voucher/index.ts +++ b/src/strategies/erc3525-vesting-voucher/index.ts @@ -1,38 +1,97 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import { hexZeroPad } from '@ethersproject/bytes'; import { formatUnits } from '@ethersproject/units'; -import { multicall } from '../../utils'; +import { Multicaller } from '../../utils'; import { claimCoefficient, maturitiesCoefficient } from './utils'; export const author = 'buchaoqun'; -export const version = '0.1.0'; +export const version = '0.1.1'; const abi = [ - 'function getSnapshot(uint256 tokenId_) view returns (uint8 claimType_, uint64 term_, uint256 vestingAmount_, uint256 principal_, uint64[] maturities_, uint32[] percentages_, uint256 availableWithdrawAmount_, string originalInvestor_, bool isValid_)' + 'function getSnapshot(uint256 tokenId_) view returns (uint8 claimType_, uint64 term_, uint256 vestingAmount_, uint256 principal_, uint64[] maturities_, uint32[] percentages_, uint256 availableWithdrawAmount_, string originalInvestor_, bool isValid_)', + 'function balanceOf(address owner) view returns (uint256)', + 'function tokenOfOwnerByIndex(address owner,uint256 index) view returns (uint256)' ]; export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - const snapshotData = await multicall( + space, network, provider, - abi, - addresses.map(() => [options.address, 'getSnapshot', [options.tokenId]]), - { blockTag } - ); - - return Object.fromEntries( - snapshotData.map((value, i) => [ - addresses[i], - parseFloat(formatUnits(value[6].toString(), options.decimals)) * - claimCoefficient(value[0]) * - maturitiesCoefficient(value[4]) - ]) - ); + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + // vesting voucher banlanceOf + const callWalletToCrucibleCount = new Multicaller(network, provider, abi, { + blockTag + }); + for (const walletAddress of addresses) { + callWalletToCrucibleCount.call( + walletAddress, + options.address, + 'balanceOf', + [walletAddress] + ); + } + + // wallet Owner Index + const walletToCrucibleCount: Record = + await callWalletToCrucibleCount.execute(); + + const callWalletToCrucibleAddresses = new Multicaller( + network, + provider, + abi, + { + blockTag + } + ); + for (const [walletAddress, crucibleCount] of Object.entries( + walletToCrucibleCount + )) { + for (let index = 0; index < crucibleCount.toNumber(); index++) { + callWalletToCrucibleAddresses.call( + walletAddress.toString() + '-' + index.toString(), + options.address, + 'tokenOfOwnerByIndex', + [walletAddress, index] + ); + } + } + const walletIDToCrucibleAddresses: Record = + await callWalletToCrucibleAddresses.execute(); + + // voucher snapshot + const callCrucibleToSnapshot = new Multicaller(network, provider, abi, { + blockTag + }); + // walletID: walletAddress-index + for (const [walletID, crucibleAddress] of Object.entries( + walletIDToCrucibleAddresses + )) { + callCrucibleToSnapshot.call(walletID, options.address, 'getSnapshot', [ + hexZeroPad(crucibleAddress.toHexString(), 20) + ]); + } + const walletIDToSnapshot: Record> = + await callCrucibleToSnapshot.execute(); + + const walletToWeights = {} as Record; + for (const [walletID, snapshot] of Object.entries(walletIDToSnapshot)) { + const address = walletID.split('-')[0]; + + const value = parseFloat(formatUnits(snapshot[6].toString(), options.decimals)) * claimCoefficient(snapshot[0]) * maturitiesCoefficient(snapshot[4]) + walletToWeights[address] = walletToWeights[address] + ? walletToWeights[address] + value + : value; + } + + return Object.fromEntries( + Object.entries(walletToWeights).map(([address, balance]) => [ + address, + balance + ]) + ); } diff --git a/src/strategies/erc3525-vesting-voucher/utils.ts b/src/strategies/erc3525-vesting-voucher/utils.ts index 3684e9df1..e1eae88b7 100644 --- a/src/strategies/erc3525-vesting-voucher/utils.ts +++ b/src/strategies/erc3525-vesting-voucher/utils.ts @@ -1,27 +1,28 @@ const oneDaySeconds = 86400; -export const maturitiesCoefficient = (maturities: Array) => { - const nowData = Date.parse(new Date().toString()) / 1000; +export const maturitiesCoefficient = ( + maturities: Array +) => { + const nowData = Date.parse(new Date().toString()) / 1000 const difference = maturities[maturities.length - 1].toNumber() - nowData; - if (difference <= 90 * oneDaySeconds) { + if (difference <= 0) { + return 1; + } else if (difference > 0 && difference <= (90 * oneDaySeconds)) { return 1.1; - } else if ( - difference > 90 * oneDaySeconds && - difference <= 183 * oneDaySeconds - ) { + } else if (difference > (90 * oneDaySeconds) && difference <= (183 * oneDaySeconds)) { return 1.2; - } else if ( - difference > 183 * oneDaySeconds && - difference <= 365 * oneDaySeconds - ) { + } else if (difference > (183 * oneDaySeconds) && difference <= (365 * oneDaySeconds)) { return 1.5; } else { return 2; } }; -export const claimCoefficient = (claimType: number) => { + +export const claimCoefficient = ( + claimType: number +) => { if (claimType == 0) { return 2; } else if (claimType == 1) { From fb2c30f8c8d812a493acec9c68b7332c6ab2bd0e Mon Sep 17 00:00:00 2001 From: gadcl Date: Tue, 26 Jul 2022 17:11:41 +0300 Subject: [PATCH 041/815] support for orbs-network-delegation strategy [orbs-network-delegation] (#733) * support for orbs-network-delegation strategy * fix omitted strategies from index.ts --- src/strategies/index.ts | 4 +- .../orbs-network-delegation/README.md | 17 ++++++ .../orbs-network-delegation/examples.json | 51 ++++++++++++++++++ .../orbs-network-delegation/index.ts | 53 +++++++++++++++++++ 4 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 src/strategies/orbs-network-delegation/README.md create mode 100644 src/strategies/orbs-network-delegation/examples.json create mode 100644 src/strategies/orbs-network-delegation/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 033f9b4b9..bc0c5b39a 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -340,6 +340,7 @@ import * as rariFuse from './rari-fuse'; import * as selfswap from './selfswap'; import * as xrookBalanceOfUnderlyingWeighted from './xrook-balance-of-underlying-weighted'; import * as bancorPoolTokenUnderlyingBalance from './bancor-pool-token-underlying-balance'; +import * as orbsNetworkDelegation from './orbs-network-delegation'; const strategies = { 'forta-shares': fortaShares, @@ -683,7 +684,8 @@ const strategies = { 'bancor-pool-token-underlying-balance': bancorPoolTokenUnderlyingBalance, selfswap, 'erc3525-vesting-voucher': erc3525VestingVoucher, - 'xrook-balance-of-underlying-weighted': xrookBalanceOfUnderlyingWeighted + 'xrook-balance-of-underlying-weighted': xrookBalanceOfUnderlyingWeighted, + 'orbs-network-delegation': orbsNetworkDelegation }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/orbs-network-delegation/README.md b/src/strategies/orbs-network-delegation/README.md new file mode 100644 index 000000000..526e5f7db --- /dev/null +++ b/src/strategies/orbs-network-delegation/README.md @@ -0,0 +1,17 @@ +# orbs-network-delegation + +This strategy is based on the Orbs Delegation contract and its underlying logic. +It returns the net delegated ORBS stake in the requested network(chain) PoS, after accounting for delegators who vote for themselves. +A delegator who chooses to vote will override its delegate vote. The voter stake is counted once, either for a delegate or for a delegator. + +Here is an example of parameters (Orbs Delegation contract on Ethereum Mainnet): + +```json +{ + "address": "0xB97178870F39d4389210086E4BcaccACD715c71d", + "symbol": "ORBS", + "decimals": 18 +} +``` + +This strategy can be combined with `multichain` for cross-chain Orbs PoS scores. diff --git a/src/strategies/orbs-network-delegation/examples.json b/src/strategies/orbs-network-delegation/examples.json new file mode 100644 index 000000000..346c4619d --- /dev/null +++ b/src/strategies/orbs-network-delegation/examples.json @@ -0,0 +1,51 @@ +[ + { + "name": "Example query 1", + "strategy": { + "name": "orbs-network-delegation", + "params": { + "address": "0xB97178870F39d4389210086E4BcaccACD715c71d", + "symbol": "ORBS", + "decimals": 18 + } + }, + "network": "1", + "addresses": [ + "0xc5e624d6824e626a6f14457810e794e4603cfee2", + "0x63aef7616882f488bca97361d1c24f05b4657ae5", + "0x3d726623456e34e8a7f5567f6249ec4d72cc3595", + "0x8ddb908c77ccc9cfde28ddf84311cb6fdf3f3125", + "0xca565ccb6434e0adf49b2d66df12b0046b013d7f", + "0x9520f53fd81c668e8088ae194c40e3f977b73d28", + "0x588c28c19e4185a2442c4c3dd9ebd592c61eccb9", + "0xa478c2975ab1ea89e8196811f51a7b7ade33eb11" + ], + "snapshot": 15210123 + }, + + { + "name": "Example query 2", + "strategy": { + "name": "orbs-network-delegation", + "params": { + "address": "0x513d30e66641cB1f2670b5994DD8E2B61ED3C23c", + "symbol": "ORBS", + "decimals": 18 + } + }, + "network": "137", + "addresses": [ + "0xc5e624d6824e626a6f14457810e794e4603cfee2", + "0x63aef7616882f488bca97361d1c24f05b4657ae5", + "0x3d726623456e34e8a7f5567f6249ec4d72cc3595", + "0x8ddb908c77ccc9cfde28ddf84311cb6fdf3f3125", + "0xca565ccb6434e0adf49b2d66df12b0046b013d7f", + "0x9520f53fd81c668e8088ae194c40e3f977b73d28", + "0x588c28c19e4185a2442c4c3dd9ebd592c61eccb9", + "0xa478c2975ab1ea89e8196811f51a7b7ade33eb11" + ], + "snapshot": 31123128 + } +] + + diff --git a/src/strategies/orbs-network-delegation/index.ts b/src/strategies/orbs-network-delegation/index.ts new file mode 100644 index 000000000..963b76c17 --- /dev/null +++ b/src/strategies/orbs-network-delegation/index.ts @@ -0,0 +1,53 @@ +import { BigNumberish, BigNumber } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'gadcl'; +export const version = '0.1.1'; + +const abi = [ + 'function getDelegatedStake(address addr) external view returns (uint256)', + 'function getDelegationInfo(address addr) external view returns (address delegation, uint256 delegatorStake)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multi = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => + multi.call(address, options.address, 'getDelegatedStake', [address]) + ); + const delegations: Record = await multi.execute(); + + Object.entries(delegations) + .filter(([, delegatedStake]) => + BigNumber.from(0).eq(delegatedStake)) + .forEach(([address,]) => + multi.call(address, options.address, 'getDelegationInfo', [address]) + ); + const override: Record = await multi.execute(); + + Object.entries(override).forEach(([address, [delegation, delegatorStake]]) => { + const from = address.toLowerCase(); + const to = delegation.toLocaleLowerCase(); + delegations[from] = delegatorStake; + if (delegations[to]) { + delegations[to] = BigNumber.from(delegations[to]).sub(delegatorStake); + } + }); + + return Object.fromEntries(Object.entries(delegations).map(([address, delegatedStake]) => [ + address, + parseFloat(formatUnits(delegatedStake, options.decimals)) + ])); +} + + From 39f970ba7afa651c42e2c288f4d998176c9327de Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 26 Jul 2022 19:45:45 +0530 Subject: [PATCH 042/815] Automated lint (#737) Co-authored-by: ChaituVR --- .../index.ts | 67 ++++---- .../erc3525-vesting-voucher/index.ts | 153 +++++++++--------- .../erc3525-vesting-voucher/utils.ts | 23 +-- .../orbs-network-delegation/examples.json | 2 - .../orbs-network-delegation/index.ts | 39 ++--- 5 files changed, 150 insertions(+), 134 deletions(-) diff --git a/src/strategies/crucible-erc20-token-and-lp-weighted/index.ts b/src/strategies/crucible-erc20-token-and-lp-weighted/index.ts index 941658a3a..d10415572 100644 --- a/src/strategies/crucible-erc20-token-and-lp-weighted/index.ts +++ b/src/strategies/crucible-erc20-token-and-lp-weighted/index.ts @@ -32,40 +32,42 @@ export async function strategy( network, provider, abi, - [[options.lpTokenAddress, 'token0', []], - [options.lpTokenAddress, 'token1', []], - [options.lpTokenAddress, 'getReserves', []], - [options.lpTokenAddress, 'totalSupply', []], - [options.lpTokenAddress, 'decimals', []], - [options.tokenAddress, 'decimals', []]], + [ + [options.lpTokenAddress, 'token0', []], + [options.lpTokenAddress, 'token1', []], + [options.lpTokenAddress, 'getReserves', []], + [options.lpTokenAddress, 'totalSupply', []], + [options.lpTokenAddress, 'decimals', []], + [options.tokenAddress, 'decimals', []] + ], { blockTag } ); // assign multicall data to variables - let token0Address = fetchContractData[0][0]; - let token1Address = fetchContractData[1][0]; - let lpTokenReserves = fetchContractData[2]; - let lpTokenTotalSupply = fetchContractData[3][0]; - let lpTokenDecimals = fetchContractData[4][0]; - let tokenDecimals = fetchContractData[5][0]; + const token0Address = fetchContractData[0][0]; + const token1Address = fetchContractData[1][0]; + const lpTokenReserves = fetchContractData[2]; + const lpTokenTotalSupply = fetchContractData[3][0]; + const lpTokenDecimals = fetchContractData[4][0]; + const tokenDecimals = fetchContractData[5][0]; // calculate single lp token weight let tokenWeight; if (token0Address === options.tokenAddress) { - - tokenWeight = (parseFloat(formatUnits(lpTokenReserves._reserve0, tokenDecimals)) / parseFloat(formatUnits(lpTokenTotalSupply, lpTokenDecimals))) * 2 - + tokenWeight = + (parseFloat(formatUnits(lpTokenReserves._reserve0, tokenDecimals)) / + parseFloat(formatUnits(lpTokenTotalSupply, lpTokenDecimals))) * + 2; } else if (token1Address === options.tokenAddress) { - - tokenWeight = (parseFloat(formatUnits(lpTokenReserves._reserve1, tokenDecimals)) / parseFloat(formatUnits(lpTokenTotalSupply, lpTokenDecimals))) * 2 - + tokenWeight = + (parseFloat(formatUnits(lpTokenReserves._reserve1, tokenDecimals)) / + parseFloat(formatUnits(lpTokenTotalSupply, lpTokenDecimals))) * + 2; } else { - tokenWeight = 0; - } // get the number of crucibles owned by the wallet @@ -120,9 +122,12 @@ export async function strategy( for (const [walletID, crucibleAddress] of Object.entries( walletIDToCrucibleAddresses )) { - callCrucibleToLpBalance.call(walletID, options.lpTokenAddress, 'balanceOf', [ - hexZeroPad(crucibleAddress.toHexString(), 20) - ]); + callCrucibleToLpBalance.call( + walletID, + options.lpTokenAddress, + 'balanceOf', + [hexZeroPad(crucibleAddress.toHexString(), 20)] + ); } const walletIDToLpBalance: Record = await callCrucibleToLpBalance.execute(); @@ -136,9 +141,12 @@ export async function strategy( for (const [walletID, crucibleAddress] of Object.entries( walletIDToCrucibleAddresses )) { - callCrucibleToTokenBalance.call(walletID, options.tokenAddress, 'balanceOf', [ - hexZeroPad(crucibleAddress.toHexString(), 20) - ]); + callCrucibleToTokenBalance.call( + walletID, + options.tokenAddress, + 'balanceOf', + [hexZeroPad(crucibleAddress.toHexString(), 20)] + ); } const walletIDToTokenBalance: Record = await callCrucibleToTokenBalance.execute(); @@ -158,7 +166,9 @@ export async function strategy( // wallet_address => token_balance const walletToTokenBalance = {} as Record; - for (const [walletID, tokenBalance] of Object.entries(walletIDToTokenBalance)) { + for (const [walletID, tokenBalance] of Object.entries( + walletIDToTokenBalance + )) { const address = walletID.split('-')[0]; walletToTokenBalance[address] = walletToTokenBalance[address] ? walletToTokenBalance[address].add(tokenBalance) @@ -168,7 +178,8 @@ export async function strategy( return Object.fromEntries( Object.entries(walletToLpBalance).map(([address, balance]) => [ address, - parseFloat(formatUnits(balance, lpTokenDecimals)) * tokenWeight + parseFloat((formatUnits(walletToTokenBalance[address], tokenDecimals))) + parseFloat(formatUnits(balance, lpTokenDecimals)) * tokenWeight + + parseFloat(formatUnits(walletToTokenBalance[address], tokenDecimals)) ]) ); } diff --git a/src/strategies/erc3525-vesting-voucher/index.ts b/src/strategies/erc3525-vesting-voucher/index.ts index 2daa5fc81..48603f811 100644 --- a/src/strategies/erc3525-vesting-voucher/index.ts +++ b/src/strategies/erc3525-vesting-voucher/index.ts @@ -8,90 +8,95 @@ export const author = 'buchaoqun'; export const version = '0.1.1'; const abi = [ - 'function getSnapshot(uint256 tokenId_) view returns (uint8 claimType_, uint64 term_, uint256 vestingAmount_, uint256 principal_, uint64[] maturities_, uint32[] percentages_, uint256 availableWithdrawAmount_, string originalInvestor_, bool isValid_)', - 'function balanceOf(address owner) view returns (uint256)', - 'function tokenOfOwnerByIndex(address owner,uint256 index) view returns (uint256)' + 'function getSnapshot(uint256 tokenId_) view returns (uint8 claimType_, uint64 term_, uint256 vestingAmount_, uint256 principal_, uint64[] maturities_, uint32[] percentages_, uint256 availableWithdrawAmount_, string originalInvestor_, bool isValid_)', + 'function balanceOf(address owner) view returns (uint256)', + 'function tokenOfOwnerByIndex(address owner,uint256 index) view returns (uint256)' ]; export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot + space, + network, + provider, + addresses, + options, + snapshot ) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - // vesting voucher banlanceOf - const callWalletToCrucibleCount = new Multicaller(network, provider, abi, { - blockTag - }); - for (const walletAddress of addresses) { - callWalletToCrucibleCount.call( - walletAddress, - options.address, - 'balanceOf', - [walletAddress] - ); - } + // vesting voucher banlanceOf + const callWalletToCrucibleCount = new Multicaller(network, provider, abi, { + blockTag + }); + for (const walletAddress of addresses) { + callWalletToCrucibleCount.call( + walletAddress, + options.address, + 'balanceOf', + [walletAddress] + ); + } - // wallet Owner Index - const walletToCrucibleCount: Record = - await callWalletToCrucibleCount.execute(); + // wallet Owner Index + const walletToCrucibleCount: Record = + await callWalletToCrucibleCount.execute(); - const callWalletToCrucibleAddresses = new Multicaller( - network, - provider, - abi, - { - blockTag - } - ); - for (const [walletAddress, crucibleCount] of Object.entries( - walletToCrucibleCount - )) { - for (let index = 0; index < crucibleCount.toNumber(); index++) { - callWalletToCrucibleAddresses.call( - walletAddress.toString() + '-' + index.toString(), - options.address, - 'tokenOfOwnerByIndex', - [walletAddress, index] - ); - } + const callWalletToCrucibleAddresses = new Multicaller( + network, + provider, + abi, + { + blockTag } - const walletIDToCrucibleAddresses: Record = - await callWalletToCrucibleAddresses.execute(); - - // voucher snapshot - const callCrucibleToSnapshot = new Multicaller(network, provider, abi, { - blockTag - }); - // walletID: walletAddress-index - for (const [walletID, crucibleAddress] of Object.entries( - walletIDToCrucibleAddresses - )) { - callCrucibleToSnapshot.call(walletID, options.address, 'getSnapshot', [ - hexZeroPad(crucibleAddress.toHexString(), 20) - ]); + ); + for (const [walletAddress, crucibleCount] of Object.entries( + walletToCrucibleCount + )) { + for (let index = 0; index < crucibleCount.toNumber(); index++) { + callWalletToCrucibleAddresses.call( + walletAddress.toString() + '-' + index.toString(), + options.address, + 'tokenOfOwnerByIndex', + [walletAddress, index] + ); } - const walletIDToSnapshot: Record> = - await callCrucibleToSnapshot.execute(); + } + const walletIDToCrucibleAddresses: Record = + await callWalletToCrucibleAddresses.execute(); - const walletToWeights = {} as Record; - for (const [walletID, snapshot] of Object.entries(walletIDToSnapshot)) { - const address = walletID.split('-')[0]; + // voucher snapshot + const callCrucibleToSnapshot = new Multicaller(network, provider, abi, { + blockTag + }); + // walletID: walletAddress-index + for (const [walletID, crucibleAddress] of Object.entries( + walletIDToCrucibleAddresses + )) { + callCrucibleToSnapshot.call(walletID, options.address, 'getSnapshot', [ + hexZeroPad(crucibleAddress.toHexString(), 20) + ]); + } + const walletIDToSnapshot: Record< + string, + Array + > = await callCrucibleToSnapshot.execute(); - const value = parseFloat(formatUnits(snapshot[6].toString(), options.decimals)) * claimCoefficient(snapshot[0]) * maturitiesCoefficient(snapshot[4]) - walletToWeights[address] = walletToWeights[address] - ? walletToWeights[address] + value - : value; - } + const walletToWeights = {} as Record; + for (const [walletID, snapshot] of Object.entries(walletIDToSnapshot)) { + const address = walletID.split('-')[0]; - return Object.fromEntries( - Object.entries(walletToWeights).map(([address, balance]) => [ - address, - balance - ]) - ); + const value = + parseFloat(formatUnits(snapshot[6].toString(), options.decimals)) * + claimCoefficient(snapshot[0]) * + maturitiesCoefficient(snapshot[4]); + walletToWeights[address] = walletToWeights[address] + ? walletToWeights[address] + value + : value; + } + + return Object.fromEntries( + Object.entries(walletToWeights).map(([address, balance]) => [ + address, + balance + ]) + ); } diff --git a/src/strategies/erc3525-vesting-voucher/utils.ts b/src/strategies/erc3525-vesting-voucher/utils.ts index e1eae88b7..62e52265c 100644 --- a/src/strategies/erc3525-vesting-voucher/utils.ts +++ b/src/strategies/erc3525-vesting-voucher/utils.ts @@ -1,28 +1,29 @@ const oneDaySeconds = 86400; -export const maturitiesCoefficient = ( - maturities: Array -) => { - const nowData = Date.parse(new Date().toString()) / 1000 +export const maturitiesCoefficient = (maturities: Array) => { + const nowData = Date.parse(new Date().toString()) / 1000; const difference = maturities[maturities.length - 1].toNumber() - nowData; if (difference <= 0) { return 1; - } else if (difference > 0 && difference <= (90 * oneDaySeconds)) { + } else if (difference > 0 && difference <= 90 * oneDaySeconds) { return 1.1; - } else if (difference > (90 * oneDaySeconds) && difference <= (183 * oneDaySeconds)) { + } else if ( + difference > 90 * oneDaySeconds && + difference <= 183 * oneDaySeconds + ) { return 1.2; - } else if (difference > (183 * oneDaySeconds) && difference <= (365 * oneDaySeconds)) { + } else if ( + difference > 183 * oneDaySeconds && + difference <= 365 * oneDaySeconds + ) { return 1.5; } else { return 2; } }; - -export const claimCoefficient = ( - claimType: number -) => { +export const claimCoefficient = (claimType: number) => { if (claimType == 0) { return 2; } else if (claimType == 1) { diff --git a/src/strategies/orbs-network-delegation/examples.json b/src/strategies/orbs-network-delegation/examples.json index 346c4619d..6f28581fa 100644 --- a/src/strategies/orbs-network-delegation/examples.json +++ b/src/strategies/orbs-network-delegation/examples.json @@ -47,5 +47,3 @@ "snapshot": 31123128 } ] - - diff --git a/src/strategies/orbs-network-delegation/index.ts b/src/strategies/orbs-network-delegation/index.ts index 963b76c17..a875dbd5e 100644 --- a/src/strategies/orbs-network-delegation/index.ts +++ b/src/strategies/orbs-network-delegation/index.ts @@ -18,7 +18,6 @@ export async function strategy( options, snapshot ): Promise> { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; const multi = new Multicaller(network, provider, abi, { blockTag }); @@ -28,26 +27,28 @@ export async function strategy( const delegations: Record = await multi.execute(); Object.entries(delegations) - .filter(([, delegatedStake]) => - BigNumber.from(0).eq(delegatedStake)) - .forEach(([address,]) => + .filter(([, delegatedStake]) => BigNumber.from(0).eq(delegatedStake)) + .forEach(([address]) => multi.call(address, options.address, 'getDelegationInfo', [address]) ); - const override: Record = await multi.execute(); - - Object.entries(override).forEach(([address, [delegation, delegatorStake]]) => { - const from = address.toLowerCase(); - const to = delegation.toLocaleLowerCase(); - delegations[from] = delegatorStake; - if (delegations[to]) { - delegations[to] = BigNumber.from(delegations[to]).sub(delegatorStake); + const override: Record = + await multi.execute(); + + Object.entries(override).forEach( + ([address, [delegation, delegatorStake]]) => { + const from = address.toLowerCase(); + const to = delegation.toLocaleLowerCase(); + delegations[from] = delegatorStake; + if (delegations[to]) { + delegations[to] = BigNumber.from(delegations[to]).sub(delegatorStake); + } } - }); + ); - return Object.fromEntries(Object.entries(delegations).map(([address, delegatedStake]) => [ - address, - parseFloat(formatUnits(delegatedStake, options.decimals)) - ])); + return Object.fromEntries( + Object.entries(delegations).map(([address, delegatedStake]) => [ + address, + parseFloat(formatUnits(delegatedStake, options.decimals)) + ]) + ); } - - From d8bc970cc320d2a1f9fb0ae086088ff8ff6ceb4c Mon Sep 17 00:00:00 2001 From: Joeh <32411671+joehquak@users.noreply.github.com> Date: Wed, 27 Jul 2022 17:15:49 +0100 Subject: [PATCH 043/815] erc20-token-and-lp-weighted strategy [erc20-token-and-lp-weighted] (#732) * erc20-token-and-lp-weighted * Update src/strategies/erc20-token-and-lp-weighted/index.ts Co-authored-by: Chaitanya --- .../erc20-token-and-lp-weighted/README.md | 19 ++++ .../erc20-token-and-lp-weighted/examples.json | 27 ++++++ .../erc20-token-and-lp-weighted/index.ts | 88 +++++++++++++++++++ .../erc20-token-and-lp-weighted/schema.json | 36 ++++++++ src/strategies/index.ts | 2 + 5 files changed, 172 insertions(+) create mode 100644 src/strategies/erc20-token-and-lp-weighted/README.md create mode 100644 src/strategies/erc20-token-and-lp-weighted/examples.json create mode 100644 src/strategies/erc20-token-and-lp-weighted/index.ts create mode 100644 src/strategies/erc20-token-and-lp-weighted/schema.json diff --git a/src/strategies/erc20-token-and-lp-weighted/README.md b/src/strategies/erc20-token-and-lp-weighted/README.md new file mode 100644 index 000000000..6518e713e --- /dev/null +++ b/src/strategies/erc20-token-and-lp-weighted/README.md @@ -0,0 +1,19 @@ +# erc20-token-and-lp-weighted + +This strategy works on Uniswap v2 style pools or contracts utilising token0/token1 and reserves. + +This strategy calculates the qty of the specified token within a single LP, doubles it to account for both sides, and then uses it as a weight against the users LP balance. + +This strategy also additionally adds the users token balance to give a token weighted score. + +This is useful if you want to be inclusive of LP and token holdings and need to scale them to be balanced with each other. + +Here is an example of parameters: + +```json +{ + "tokenAddress": "0x88ACDd2a6425c3FaAE4Bc9650Fd7E27e0Bebb7aB", + "symbol": "MIST", + "lpTokenAddress": "0xcd6bcca48069f8588780dfa274960f15685aee0e" +} +``` diff --git a/src/strategies/erc20-token-and-lp-weighted/examples.json b/src/strategies/erc20-token-and-lp-weighted/examples.json new file mode 100644 index 000000000..f11fa16e7 --- /dev/null +++ b/src/strategies/erc20-token-and-lp-weighted/examples.json @@ -0,0 +1,27 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "erc20-token-and-lp-weighted", + "params": { + "tokenAddress": "0x88ACDd2a6425c3FaAE4Bc9650Fd7E27e0Bebb7aB", + "symbol": "MIST", + "lpTokenAddress": "0xcd6bcca48069f8588780dfa274960f15685aee0e" + } + }, + "network": "1", + "addresses": [ + "0xa7396dbd79c26f923faf144b7c77c9eb1ae0b634", + "0x9eedca1b19aa0d438fcf890524e6af056d95dd58", + "0xf7b4ddd4805455e108f0be5b417434c0aac88ddf", + "0xf4b1b77f3f56b58555634b64fb7ed31c60413754", + "0x1cd5698dc7cbe5b80c8b60791a8e2fb857a53a58", + "0xcf576f74ba3b01cdc04e04305055446d1649bd07", + "0x6f1234e31830097b04a8f9b3eeedf9eb8008837a", + "0xc5690c1f0f0642e76c956580b748b64cc5b3dc73", + "0x0504c6e9563d8756cb823fcbbf342301ddbc8066", + "0xee7f963391afb7d1f1ec872dbe2f80ea025d0add" + ], + "snapshot": 15206855 + } +] \ No newline at end of file diff --git a/src/strategies/erc20-token-and-lp-weighted/index.ts b/src/strategies/erc20-token-and-lp-weighted/index.ts new file mode 100644 index 000000000..a9dc53ff4 --- /dev/null +++ b/src/strategies/erc20-token-and-lp-weighted/index.ts @@ -0,0 +1,88 @@ +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller, multicall } from '../../utils'; + +export const author = 'joehquak'; +export const version = '0.1.0'; + +const abi = [ + 'function balanceOf(address account) external view returns (uint256)', + 'function decimals() external view returns (uint8)', + 'function token0() external view returns (address)', + 'function token1() external view returns (address)', + 'function totalSupply() external view returns (uint256)', + 'function getReserves() external view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + // fetch all token and lp contract data + + const fetchContractData = await multicall( + network, + provider, + abi, + [[options.lpTokenAddress, 'token0', []], + [options.lpTokenAddress, 'token1', []], + [options.lpTokenAddress, 'getReserves', []], + [options.lpTokenAddress, 'totalSupply', []], + [options.lpTokenAddress, 'decimals', []], + [options.tokenAddress, 'decimals', []]], + { blockTag } + ); + + // assign multicall data to variables + + let token0Address = fetchContractData[0][0]; + let token1Address = fetchContractData[1][0]; + let lpTokenReserves = fetchContractData[2]; + let lpTokenTotalSupply = fetchContractData[3][0]; + let lpTokenDecimals = fetchContractData[4][0]; + let tokenDecimals = fetchContractData[5][0]; + + // calculate single lp token weight + + let tokenWeight; + + if (token0Address === options.tokenAddress) { + + tokenWeight = (parseFloat(formatUnits(lpTokenReserves._reserve0, tokenDecimals)) / parseFloat(formatUnits(lpTokenTotalSupply, lpTokenDecimals))) * 2 + + } else if (token1Address === options.tokenAddress) { + + tokenWeight = (parseFloat(formatUnits(lpTokenReserves._reserve1, tokenDecimals)) / parseFloat(formatUnits(lpTokenTotalSupply, lpTokenDecimals))) * 2 + + } else { + + tokenWeight = 0; + + } + + const lpBalances = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => + lpBalances.call(address, options.lpTokenAddress, 'balanceOf', [address]) + ); + const lpBalancesResult: Record = await lpBalances.execute(); + + + const tokenBalances = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => + tokenBalances.call(address, options.tokenAddress, 'balanceOf', [address]) + ); + const tokenBalancesResult: Record = await tokenBalances.execute(); + + return Object.fromEntries( + Object.entries(lpBalancesResult).map(([address, balance]) => [ + address, + (parseFloat(formatUnits(balance, lpTokenDecimals)) * tokenWeight) + parseFloat((formatUnits(tokenBalancesResult[address], tokenDecimals))) + ]) + ); +} diff --git a/src/strategies/erc20-token-and-lp-weighted/schema.json b/src/strategies/erc20-token-and-lp-weighted/schema.json new file mode 100644 index 000000000..3462212fe --- /dev/null +++ b/src/strategies/erc20-token-and-lp-weighted/schema.json @@ -0,0 +1,36 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Token symbol", + "examples": ["e.g. UNI"], + "maxLength": 16 + }, + "tokenAddress": { + "type": "string", + "title": "Token address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "lpTokenAddress": { + "type": "string", + "title": "LP address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } + }, + "required": ["tokenAddress", "lpTokenAddress"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index bc0c5b39a..5cf1c14cf 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -193,6 +193,7 @@ import * as meebitsdao from './meebitsdao'; import * as membership from './membership'; import * as holdsTokens from './holds-tokens'; import * as crucibleERC20BalanceOf from './crucible-erc20-balance-of'; +import * as erc20TokenAndLpWeighted from './erc20-token-and-lp-weighted'; import * as crucibleERC20TokenAndLpWeighted from './crucible-erc20-token-and-lp-weighted'; import * as hasrock from './has-rock'; import * as flexaCapacityStaking from './flexa-capacity-staking'; @@ -540,6 +541,7 @@ const strategies = { snowswap, meebitsdao, 'crucible-erc20-balance-of': crucibleERC20BalanceOf, + 'erc20-token-and-lp-weighted': erc20TokenAndLpWeighted, 'crucible-erc20-token-and-lp-weighted': crucibleERC20TokenAndLpWeighted, 'has-rock': hasrock, 'flexa-capacity-staking': flexaCapacityStaking, From 7b1460c87606dd434bfb0d75c3857a7d93cd157c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 29 Jul 2022 00:13:15 +0530 Subject: [PATCH 044/815] Automated lint (#744) Co-authored-by: ChaituVR --- .../erc20-token-and-lp-weighted/examples.json | 2 +- .../erc20-token-and-lp-weighted/index.ts | 56 ++++++++++--------- 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/src/strategies/erc20-token-and-lp-weighted/examples.json b/src/strategies/erc20-token-and-lp-weighted/examples.json index f11fa16e7..20b2f8ba8 100644 --- a/src/strategies/erc20-token-and-lp-weighted/examples.json +++ b/src/strategies/erc20-token-and-lp-weighted/examples.json @@ -24,4 +24,4 @@ ], "snapshot": 15206855 } -] \ No newline at end of file +] diff --git a/src/strategies/erc20-token-and-lp-weighted/index.ts b/src/strategies/erc20-token-and-lp-weighted/index.ts index a9dc53ff4..59c3099e1 100644 --- a/src/strategies/erc20-token-and-lp-weighted/index.ts +++ b/src/strategies/erc20-token-and-lp-weighted/index.ts @@ -24,65 +24,69 @@ export async function strategy( ): Promise> { const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - // fetch all token and lp contract data + // fetch all token and lp contract data - const fetchContractData = await multicall( + const fetchContractData = await multicall( network, provider, abi, - [[options.lpTokenAddress, 'token0', []], - [options.lpTokenAddress, 'token1', []], - [options.lpTokenAddress, 'getReserves', []], - [options.lpTokenAddress, 'totalSupply', []], - [options.lpTokenAddress, 'decimals', []], - [options.tokenAddress, 'decimals', []]], + [ + [options.lpTokenAddress, 'token0', []], + [options.lpTokenAddress, 'token1', []], + [options.lpTokenAddress, 'getReserves', []], + [options.lpTokenAddress, 'totalSupply', []], + [options.lpTokenAddress, 'decimals', []], + [options.tokenAddress, 'decimals', []] + ], { blockTag } ); // assign multicall data to variables - let token0Address = fetchContractData[0][0]; - let token1Address = fetchContractData[1][0]; - let lpTokenReserves = fetchContractData[2]; - let lpTokenTotalSupply = fetchContractData[3][0]; - let lpTokenDecimals = fetchContractData[4][0]; - let tokenDecimals = fetchContractData[5][0]; + const token0Address = fetchContractData[0][0]; + const token1Address = fetchContractData[1][0]; + const lpTokenReserves = fetchContractData[2]; + const lpTokenTotalSupply = fetchContractData[3][0]; + const lpTokenDecimals = fetchContractData[4][0]; + const tokenDecimals = fetchContractData[5][0]; // calculate single lp token weight let tokenWeight; if (token0Address === options.tokenAddress) { - - tokenWeight = (parseFloat(formatUnits(lpTokenReserves._reserve0, tokenDecimals)) / parseFloat(formatUnits(lpTokenTotalSupply, lpTokenDecimals))) * 2 - + tokenWeight = + (parseFloat(formatUnits(lpTokenReserves._reserve0, tokenDecimals)) / + parseFloat(formatUnits(lpTokenTotalSupply, lpTokenDecimals))) * + 2; } else if (token1Address === options.tokenAddress) { - - tokenWeight = (parseFloat(formatUnits(lpTokenReserves._reserve1, tokenDecimals)) / parseFloat(formatUnits(lpTokenTotalSupply, lpTokenDecimals))) * 2 - + tokenWeight = + (parseFloat(formatUnits(lpTokenReserves._reserve1, tokenDecimals)) / + parseFloat(formatUnits(lpTokenTotalSupply, lpTokenDecimals))) * + 2; } else { - tokenWeight = 0; - } const lpBalances = new Multicaller(network, provider, abi, { blockTag }); addresses.forEach((address) => lpBalances.call(address, options.lpTokenAddress, 'balanceOf', [address]) ); - const lpBalancesResult: Record = await lpBalances.execute(); - + const lpBalancesResult: Record = + await lpBalances.execute(); const tokenBalances = new Multicaller(network, provider, abi, { blockTag }); addresses.forEach((address) => tokenBalances.call(address, options.tokenAddress, 'balanceOf', [address]) ); - const tokenBalancesResult: Record = await tokenBalances.execute(); + const tokenBalancesResult: Record = + await tokenBalances.execute(); return Object.fromEntries( Object.entries(lpBalancesResult).map(([address, balance]) => [ address, - (parseFloat(formatUnits(balance, lpTokenDecimals)) * tokenWeight) + parseFloat((formatUnits(tokenBalancesResult[address], tokenDecimals))) + parseFloat(formatUnits(balance, lpTokenDecimals)) * tokenWeight + + parseFloat(formatUnits(tokenBalancesResult[address], tokenDecimals)) ]) ); } From 8bb8500f8d1acac2aba1c6ef0eab88baf0348401 Mon Sep 17 00:00:00 2001 From: Timan Rebel Date: Thu, 28 Jul 2022 21:18:04 +0200 Subject: [PATCH 045/815] feat(defiplaza): update defiplaza strategy to include StablePlaza pool (#741) Co-authored-by: Trebel --- src/strategies/defiplaza/README.md | 3 +++ src/strategies/defiplaza/examples.json | 4 +++- src/strategies/defiplaza/index.ts | 29 +++++++++++++++----------- src/strategies/defiplaza/schema.json | 7 ++++++- 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/strategies/defiplaza/README.md b/src/strategies/defiplaza/README.md index 831eb8f96..5f7b4ca0c 100644 --- a/src/strategies/defiplaza/README.md +++ b/src/strategies/defiplaza/README.md @@ -2,6 +2,8 @@ This new strategy looks at `balanceOf` and the `quoteRewards` function of the DFP2 governance contract to be able to use the balance of unclaimed staking rewards in the voting process, next to the balance of DFP2 in a wallet. +It also looks at the `stakerData` function of the new StablePlaza pool contract (if given as an option) to be able to use the staked DFP2 tokens in the voting process. + The addresses in the `examples.json` are the current biggest DFP2 holders to create a real-world test scenario. This strategy is based on the `erc20-balance-of` strategy. @@ -11,6 +13,7 @@ Here is an example of the parameters: ```json { "address": "0x2F57430a6ceDA85a67121757785877b4a71b8E6D", + "stableplaza": "0x3A2b8cC91aF8bf45F3Ec61E779ee1c2ba6b7E694", "symbol": "DFP2", "decimals": 18 } diff --git a/src/strategies/defiplaza/examples.json b/src/strategies/defiplaza/examples.json index daa536875..f2e5e9b54 100644 --- a/src/strategies/defiplaza/examples.json +++ b/src/strategies/defiplaza/examples.json @@ -5,12 +5,14 @@ "name": "defiplaza", "params": { "address": "0x2F57430a6ceDA85a67121757785877b4a71b8E6D", + "stableplaza": "0x3A2b8cC91aF8bf45F3Ec61E779ee1c2ba6b7E694", "symbol": "DFP2", "decimals": 18 } }, "network": "1", "addresses": [ + "0xe461cc7406607866082b1385bf66c8d1d794e892", "0xef7ddc0852baa45cc8ae7c99d30c47b75147c2ff", "0xac0f1af3b5439d0954e83ede9b7c4a0772178217", "0xf8c95d77e4c7668c0982917b3a7f47ae3902c095", @@ -29,6 +31,6 @@ "0x27f2be297489e813dae3895a30c9ac72b01bf57a", "0xb4185c5e29a9b415efc405ec5d1eae51b65059ff" ], - "snapshot": 14159134 + "snapshot": 15202927 } ] diff --git a/src/strategies/defiplaza/index.ts b/src/strategies/defiplaza/index.ts index f946ce1a1..ec55651d7 100644 --- a/src/strategies/defiplaza/index.ts +++ b/src/strategies/defiplaza/index.ts @@ -1,4 +1,3 @@ -import { BigNumberish } from '@ethersproject/bignumber'; import { formatUnits } from '@ethersproject/units'; import { Multicaller } from '../../utils'; @@ -7,7 +6,8 @@ export const version = '0.1.0'; const abi = [ 'function balanceOf(address account) external view returns (uint256)', - 'function rewardsQuote(address stakerAddress) external view returns (uint256 rewards)' + 'function rewardsQuote(address stakerAddress) external view returns (uint256 rewards)', + 'function stakerData(address address) external view returns (uint64 stakedAmount, uint64 sharesEquivalent, uint96 rewardsPerShareWhenStaked, uint32 unlockTime)' ]; export async function strategy( @@ -23,25 +23,30 @@ export async function strategy( const multi = new Multicaller(network, provider, abi, { blockTag }); addresses.forEach((address) => { // request balance - multi.call(`balanceOf:${address}`, options.address, 'balanceOf', [address]); + multi.call(`balanceOf.${address}`, options.address, 'balanceOf', [address]); // request balance of unclaimed staking rewards - multi.call(`rewardsQuote:${address}`, options.address, 'rewardsQuote', [ - address - ]); - }); - const result: Record = await multi.execute(); + multi.call(`rewardsQuote.${address}`, options.address, 'rewardsQuote', [address]); - const returnObject = {}; + if (options.stableplaza) { + multi.call(`stableplaza.${address}`, options.stableplaza, 'stakerData', [address]); + } + }); + const result = await multi.execute(); - Object.entries(result).map(([path, balance]) => { - const address = path.split(':')[1]; + let returnObject = {}; + addresses.forEach((address) => { if (!returnObject.hasOwnProperty(address)) { returnObject[address] = 0; } - returnObject[address] += parseFloat(formatUnits(balance, options.decimals)); + returnObject[address] += parseFloat(formatUnits(result.balanceOf[address], options.decimals)); + returnObject[address] += parseFloat(formatUnits(result.rewardsQuote[address], options.decimals)); + + if (options.stableplaza) { + returnObject[address] += parseFloat(formatUnits(result.stableplaza[address][0].mul(4294967296), options.decimals)); // * 2^32 + } }); return returnObject; diff --git a/src/strategies/defiplaza/schema.json b/src/strategies/defiplaza/schema.json index 228dfabda..f4f540805 100644 --- a/src/strategies/defiplaza/schema.json +++ b/src/strategies/defiplaza/schema.json @@ -14,9 +14,14 @@ }, "address": { "type": "string", - "title": "Contract address", + "title": "Governance contract address", "examples": ["e.g. 0x2F57430a6ceDA85a67121757785877b4a71b8E6D"] }, + "stableplaza": { + "type": "string", + "title": "StablePlaza contract address", + "examples": ["e.g. 0x3A2b8cC91aF8bf45F3Ec61E779ee1c2ba6b7E694"] + }, "decimals": { "type": "number", "title": "Decimals", From d6f1f538477674e6823cc5caccaa1799e55318b7 Mon Sep 17 00:00:00 2001 From: 0xButterfield <100517047+0xButterfield@users.noreply.github.com> Date: Thu, 28 Jul 2022 21:27:20 +0200 Subject: [PATCH 046/815] feat: Add Aura vlAURA delegation (#742) Co-authored-by: Chaitanya --- .../README.md | 30 ++++++++ .../examples.json | 22 ++++++ .../aura-vlaura-vebal-with-overrides/index.ts | 76 +++++++++++++++++++ .../schema.json | 38 ++++++++++ src/strategies/index.ts | 2 + 5 files changed, 168 insertions(+) create mode 100644 src/strategies/aura-vlaura-vebal-with-overrides/README.md create mode 100644 src/strategies/aura-vlaura-vebal-with-overrides/examples.json create mode 100644 src/strategies/aura-vlaura-vebal-with-overrides/index.ts create mode 100644 src/strategies/aura-vlaura-vebal-with-overrides/schema.json diff --git a/src/strategies/aura-vlaura-vebal-with-overrides/README.md b/src/strategies/aura-vlaura-vebal-with-overrides/README.md new file mode 100644 index 000000000..8f832bb4d --- /dev/null +++ b/src/strategies/aura-vlaura-vebal-with-overrides/README.md @@ -0,0 +1,30 @@ +# aura-vlaura-vebal-with-overrides + +This strategy returns proportional voting power for vlAURA holders based on system owned veBAL. + +For example: +- there are 10000 vlAURA total supply +- a user has 2000 vlAURA (voting power, delegated to them) +- Aura's voterProxy owns 100k veBAL + +In this example, the user has 20k veBAL voting power as they own 20% of the vlAURA voting power. + +Voters can optionally override their delegated voting power. + +_Note: When depositing to the auraLocker, a user does not receive vlAURA until the next epoch has begun (Thursday at 00:00 UTC)_ + +## Params + +- `auraLocker` - (**Required**, `string`) Address of AuraLocker (vlAURA) contract +- `auraVoterProxy` - (**Required**, `string`) Address of Aura VoterProxy contract +- `votingEscrow` - (**Required**, `string`) Address of Balancer VotingEscrow contract + +Here is an example of parameters: + +```json +{ + "auraLocker": "0x3Fa73f1E5d8A792C80F426fc8F84FBF7Ce9bBCAC", + "auraVoterProxy": "0xaF52695E1bB01A16D33D7194C28C42b10e0Dbec2", + "votingEscrow": "0xC128a9954e6c874eA3d62ce62B468bA073093F25" +} +``` diff --git a/src/strategies/aura-vlaura-vebal-with-overrides/examples.json b/src/strategies/aura-vlaura-vebal-with-overrides/examples.json new file mode 100644 index 000000000..1442c1163 --- /dev/null +++ b/src/strategies/aura-vlaura-vebal-with-overrides/examples.json @@ -0,0 +1,22 @@ +[ + { + "name": "Example query Aura with overrides", + "strategy": { + "name": "aura-vlaura-vebal-with-overrides", + "params": { + "auraLocker": "0x3Fa73f1E5d8A792C80F426fc8F84FBF7Ce9bBCAC", + "auraVoterProxy": "0xaF52695E1bB01A16D33D7194C28C42b10e0Dbec2", + "votingEscrow": "0xC128a9954e6c874eA3d62ce62B468bA073093F25" + } + }, + "network": "1", + "addresses": [ + "0xB1f881f47baB744E7283851bC090bAA626df931d", + "0x808af82545A721C06D1FcCEbea915a6F5128BeF9", + "0x0CAd1d5ea8b4EeE26959cC00B4A3677f7A11e40F", + "0x3cde8fa1c73afe0828f672d197e082463c2ac8e2", + "0xca86d57519dbfe34a25eef0923b259ab07986b71" + ], + "snapshot": 15184638 + } +] diff --git a/src/strategies/aura-vlaura-vebal-with-overrides/index.ts b/src/strategies/aura-vlaura-vebal-with-overrides/index.ts new file mode 100644 index 000000000..69372c5b5 --- /dev/null +++ b/src/strategies/aura-vlaura-vebal-with-overrides/index.ts @@ -0,0 +1,76 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; +import { strategy as erc20VotesWithOverrideStrategy } from '../erc20-votes-with-override'; + +export const author = '0xMaharishi'; +export const version = '0.1.0'; + +const abi = [ + 'function delegates(address account) external view returns (address)', + 'function getVotes(address account) external view returns (uint256)', + 'function totalSupply() public view returns (uint256)', + 'function balanceOf(address account) public view returns (uint256)' +]; + +interface Options { + auraLocker: string; + auraVoterProxy: string; + votingEscrow: string; + includeSnapshotDelegations?: boolean; + delegationSpace?: string; +} + +interface Response { + vlAuraTotalSupply: BigNumber; + veBalOwnedByAura: BigNumber; +} + +/* + Based on the `erc20-votes-with-override` strategy, with global vote scaling + to represent the share of Aura's veBAL. +*/ +export async function strategy( + space, + network, + provider, + addresses, + options: Options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multi = new Multicaller(network, provider, abi, { blockTag }); + multi.call('vlAuraTotalSupply', options.auraLocker, 'totalSupply', []); + multi.call('veBalOwnedByAura', options.votingEscrow, 'balanceOf', [ + options.auraVoterProxy + ]); + const res: Response = await multi.execute(); + + const scores: Record = await erc20VotesWithOverrideStrategy( + space, + network, + provider, + addresses, + { + address: options.auraLocker, + delegatesName: 'delegates', + balanceOfName: 'balanceOf', + getVotesName: 'getVotes', + decimals: 18, + includeSnapshotDelegations: options.includeSnapshotDelegations, + delegationSpace: options.delegationSpace + }, + snapshot + ); + + const veBalOwnedByAura = parseFloat(formatUnits(res.veBalOwnedByAura)); + const vlAuraTotalSupply = parseFloat(formatUnits(res.vlAuraTotalSupply)); + + return Object.fromEntries( + Object.entries(scores).map(([address, score]) => [ + address, + (veBalOwnedByAura * score) / vlAuraTotalSupply + ]) + ); +} diff --git a/src/strategies/aura-vlaura-vebal-with-overrides/schema.json b/src/strategies/aura-vlaura-vebal-with-overrides/schema.json new file mode 100644 index 000000000..85b8c6d26 --- /dev/null +++ b/src/strategies/aura-vlaura-vebal-with-overrides/schema.json @@ -0,0 +1,38 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "auraLocker": { + "type": "string", + "title": "auraLocker", + "examples": ["e.g. 0x3Fa73f1E5d8A792C80F426fc8F84FBF7Ce9bBCAC"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "auraVoterProxy": { + "type": "string", + "title": "auraVoterProxy", + "examples": ["e.g. 0xaF52695E1bB01A16D33D7194C28C42b10e0Dbec2"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "votingEscrow": { + "type": "string", + "title": "votingEscrow", + "examples": ["e.g. 0xC128a9954e6c874eA3d62ce62B468bA073093F25"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } + }, + "required": ["auraLocker", "auraVoterProxy", "votingEscrow"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 5cf1c14cf..77c6926c2 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -326,6 +326,7 @@ import * as creditLp from './credit-lp'; import * as helix from './helix'; import * as arrakisFinance from './arrakis-finance'; import * as auraFinance from './aura-vlaura-vebal'; +import * as auraFinanceWithOverrides from './aura-vlaura-vebal-with-overrides'; import * as rocketpoolNodeOperator from './rocketpool-node-operator'; import * as earthfundChildDaoStakingBalance from './earthfund-child-dao-staking-balance'; import * as unipilotVaultPilotBalance from './unipilot-vault-pilot-balance'; @@ -672,6 +673,7 @@ const strategies = { helix, 'arrakis-finance': arrakisFinance, 'aura-vlaura-vebal': auraFinance, + 'aura-vlaura-vebal-with-overrides': auraFinanceWithOverrides, 'rocketpool-node-operator': rocketpoolNodeOperator, 'earthfund-child-dao-staking-balance': earthfundChildDaoStakingBalance, 'sd-boost-twavp': sdBoostTWAVP, From ece9afd6e9766c169f50433346417959def58e61 Mon Sep 17 00:00:00 2001 From: Joeh <32411671+joehquak@users.noreply.github.com> Date: Fri, 29 Jul 2022 05:54:04 +0100 Subject: [PATCH 047/815] Update `schema.json` [erc20-token-and-lp-weighted] (#746) * Update `schema.json` [erc20-token-and-lp-weighted] * Update token symbol example --- src/strategies/erc20-token-and-lp-weighted/schema.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/strategies/erc20-token-and-lp-weighted/schema.json b/src/strategies/erc20-token-and-lp-weighted/schema.json index 3462212fe..f937c97ec 100644 --- a/src/strategies/erc20-token-and-lp-weighted/schema.json +++ b/src/strategies/erc20-token-and-lp-weighted/schema.json @@ -9,13 +9,13 @@ "symbol": { "type": "string", "title": "Token symbol", - "examples": ["e.g. UNI"], + "examples": ["e.g. MIST"], "maxLength": 16 }, "tokenAddress": { "type": "string", "title": "Token address", - "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "examples": ["e.g. 0x88ACDd2a6425c3FaAE4Bc9650Fd7E27e0Bebb7aB"], "pattern": "^0x[a-fA-F0-9]{40}$", "minLength": 42, "maxLength": 42 @@ -23,7 +23,7 @@ "lpTokenAddress": { "type": "string", "title": "LP address", - "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "examples": ["e.g. 0xcd6bcca48069f8588780dfa274960f15685aee0e"], "pattern": "^0x[a-fA-F0-9]{40}$", "minLength": 42, "maxLength": 42 From 581f069b453d04dc466f6a5a6e8ce41f95344355 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Fri, 29 Jul 2022 10:44:42 +0530 Subject: [PATCH 048/815] Fix null issue in vp by strategy --- src/utils/vp.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/vp.ts b/src/utils/vp.ts index 879ddb430..404d4f65d 100644 --- a/src/utils/vp.ts +++ b/src/utils/vp.ts @@ -75,7 +75,7 @@ export async function getVp( addresses = [...new Set(addresses)]; } - return addresses.reduce((a, b) => a + score[b], 0); + return addresses.reduce((a, b) => a + (score[b] || 0), 0); }); const vp = vpByStrategy.reduce((a, b) => a + b, 0); let vpState = 'final'; From f9f5065108f5807c36d5c233211605e305679b70 Mon Sep 17 00:00:00 2001 From: Joeh <32411671+joehquak@users.noreply.github.com> Date: Fri, 29 Jul 2022 14:19:52 +0100 Subject: [PATCH 049/815] Updates to `crucible-erc20-token-and-lp-weighted` [crucible-erc20-token-and-lp-weighted] (#745) * Updates to `crucible-erc20-token-and-lp-weighted` [crucible-erc20-token-and-lp-weighted] * Update token symbol example Co-authored-by: Chaitanya --- .../crucible-erc20-token-and-lp-weighted/README.md | 4 ++-- .../examples.json | 2 +- .../crucible-erc20-token-and-lp-weighted/index.ts | 4 ++-- .../crucible-erc20-token-and-lp-weighted/schema.json | 12 ++++++------ 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/strategies/crucible-erc20-token-and-lp-weighted/README.md b/src/strategies/crucible-erc20-token-and-lp-weighted/README.md index 3afbc444b..56ded742c 100644 --- a/src/strategies/crucible-erc20-token-and-lp-weighted/README.md +++ b/src/strategies/crucible-erc20-token-and-lp-weighted/README.md @@ -13,8 +13,8 @@ Here is an example of parameters: ```json { "symbol": "MIST", - "crucible_factory": "0x54e0395CFB4f39beF66DBCd5bD93Cca4E9273D56", - "tokenAddress": "0x88ACDd2a6425c3FaAE4Bc9650Fd7E27e0Bebb7aB",, + "crucibleFactory": "0x54e0395CFB4f39beF66DBCd5bD93Cca4E9273D56", + "tokenAddress": "0x88ACDd2a6425c3FaAE4Bc9650Fd7E27e0Bebb7aB", "tokenDecimals" : "18", "lpTokenAddress": "0xcd6bcca48069f8588780dfa274960f15685aee0e", "lpTokenDecimals" : "18" diff --git a/src/strategies/crucible-erc20-token-and-lp-weighted/examples.json b/src/strategies/crucible-erc20-token-and-lp-weighted/examples.json index 02de06aac..317f35c97 100644 --- a/src/strategies/crucible-erc20-token-and-lp-weighted/examples.json +++ b/src/strategies/crucible-erc20-token-and-lp-weighted/examples.json @@ -5,7 +5,7 @@ "name": "crucible-erc20-token-and-lp-weighted", "params": { "symbol": "MIST", - "crucible_factory": "0x54e0395CFB4f39beF66DBCd5bD93Cca4E9273D56", + "crucibleFactory": "0x54e0395CFB4f39beF66DBCd5bD93Cca4E9273D56", "tokenAddress": "0x88ACDd2a6425c3FaAE4Bc9650Fd7E27e0Bebb7aB", "lpTokenAddress": "0xcd6bcca48069f8588780dfa274960f15685aee0e" } diff --git a/src/strategies/crucible-erc20-token-and-lp-weighted/index.ts b/src/strategies/crucible-erc20-token-and-lp-weighted/index.ts index d10415572..5b53b2e86 100644 --- a/src/strategies/crucible-erc20-token-and-lp-weighted/index.ts +++ b/src/strategies/crucible-erc20-token-and-lp-weighted/index.ts @@ -79,7 +79,7 @@ export async function strategy( for (const walletAddress of addresses) { callWalletToCrucibleCount.call( walletAddress, - options.crucible_factory, + options.crucibleFactory, 'balanceOf', [walletAddress] ); @@ -104,7 +104,7 @@ export async function strategy( for (let index = 0; index < crucibleCount.toNumber(); index++) { callWalletToCrucibleAddresses.call( walletAddress.toString() + '-' + index.toString(), - options.crucible_factory, + options.crucibleFactory, 'tokenOfOwnerByIndex', [walletAddress, index] ); diff --git a/src/strategies/crucible-erc20-token-and-lp-weighted/schema.json b/src/strategies/crucible-erc20-token-and-lp-weighted/schema.json index e2d2bd4d3..fe453aba4 100644 --- a/src/strategies/crucible-erc20-token-and-lp-weighted/schema.json +++ b/src/strategies/crucible-erc20-token-and-lp-weighted/schema.json @@ -9,13 +9,13 @@ "symbol": { "type": "string", "title": "Token symbol", - "examples": ["e.g. UNI"], + "examples": ["e.g. MIST"], "maxLength": 16 }, - "crucible_factory": { + "crucibleFactory": { "type": "string", "title": "Crucible factory address", - "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "examples": ["e.g. 0x54e0395CFB4f39beF66DBCd5bD93Cca4E9273D56"], "pattern": "^0x[a-fA-F0-9]{40}$", "minLength": 42, "maxLength": 42 @@ -23,7 +23,7 @@ "tokenAddress": { "type": "string", "title": "Token address", - "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "examples": ["e.g. 0x88ACDd2a6425c3FaAE4Bc9650Fd7E27e0Bebb7aB"], "pattern": "^0x[a-fA-F0-9]{40}$", "minLength": 42, "maxLength": 42 @@ -31,13 +31,13 @@ "lpTokenAddress": { "type": "string", "title": "LP address", - "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "examples": ["e.g. 0xCD6bcca48069f8588780dFA274960F15685aEe0e"], "pattern": "^0x[a-fA-F0-9]{40}$", "minLength": 42, "maxLength": 42 } }, - "required": ["crucible_factory", "tokenAddress", "lpTokenAddress"], + "required": ["crucibleFactory", "tokenAddress", "lpTokenAddress"], "additionalProperties": false } } From e35c8f33a3afbc3fcc94f16887edb98e69ae8cdd Mon Sep 17 00:00:00 2001 From: Arpit Karnatak <60638961+arpitkarnatak@users.noreply.github.com> Date: Sat, 30 Jul 2022 00:38:07 +0530 Subject: [PATCH 050/815] ERC721 Weighted Pairs [erc721-pair-weights] (#743) * ERC721 Weighted Pairs * Fixed formula * Cleanup * Cleanup * Cleanup * Removed package.json * Final Version with readme and real addresses * Update src/strategies/erc721-pair-weights/index.ts Co-authored-by: Chaitanya * Update src/strategies/erc721-pair-weights/index.ts Co-authored-by: Chaitanya * Update src/strategies/erc721-pair-weights/examples.json Co-authored-by: Chaitanya * Update src/strategies/erc721-pair-weights/index.ts Co-authored-by: Chaitanya --- src/strategies/erc721-pair-weights/README.md | 38 +++++++++++++++ .../erc721-pair-weights/examples.json | 26 ++++++++++ src/strategies/erc721-pair-weights/index.ts | 48 +++++++++++++++++++ src/strategies/index.ts | 4 +- 4 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 src/strategies/erc721-pair-weights/README.md create mode 100644 src/strategies/erc721-pair-weights/examples.json create mode 100644 src/strategies/erc721-pair-weights/index.ts diff --git a/src/strategies/erc721-pair-weights/README.md b/src/strategies/erc721-pair-weights/README.md new file mode 100644 index 000000000..40941e7b5 --- /dev/null +++ b/src/strategies/erc721-pair-weights/README.md @@ -0,0 +1,38 @@ +# ERC721 Weighted Pairs + +This strategy determines the voting powers for a pair of ERC721 NFT registries. This strategy supports 2 different NFT collections and it provides different voting powers to the holders of these collections, and also supports bonus powers for holders which have items from both the collections. + +```json +{ + "symbol": "OCMONK", + "registries": [ + "0x960b7a6bcd451c9968473f7bbfd9be826efd549a", + "0x86cc280d0bac0bd4ea38ba7d31e895aa20cceb4b" + ], + "weights": [ + 2, + 3 + ], + "pairWeight": 4 + } +``` + +In `example.json`, address `0xE052113bd7D7700d623414a0a4585BCaE754E9d5` has 31 items of `collection1` NFT and 35 items of `collection2` NFT. + +As we can see, there are 31 pairs, 0 items exclusively for collection1 and 4 items exclusively for collection2. So, the voting power of the address will be + +``` +(31 * pairWeight) + (collection1 * weights[0]) + (collection2 * weights[1])` += 31*4 + 0*2 + 4*3 += 136 +``` +which can be seen in the snapshot: + +``` + [ + { + '0x5F9345FdAd91Bf9757445ADc82e477B33FD3349c': 6, + '0xE052113bd7D7700d623414a0a4585BCaE754E9d5': 136 + } + ] +``` \ No newline at end of file diff --git a/src/strategies/erc721-pair-weights/examples.json b/src/strategies/erc721-pair-weights/examples.json new file mode 100644 index 000000000..aec10ba93 --- /dev/null +++ b/src/strategies/erc721-pair-weights/examples.json @@ -0,0 +1,26 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "erc721-pair-weights", + "params": { + "symbol": "OCMONK", + "registries": [ + "0x960b7a6bcd451c9968473f7bbfd9be826efd549a", + "0x86cc280d0bac0bd4ea38ba7d31e895aa20cceb4b" + ], + "weights": [ + 2, + 3 + ], + "pairWeight": 4 + } + }, + "network": "1", + "addresses": [ + "0x5F9345FdAd91Bf9757445ADc82e477B33FD3349c", + "0xE052113bd7D7700d623414a0a4585BCaE754E9d5" + ], + "snapshot": 15223064 + } +] diff --git a/src/strategies/erc721-pair-weights/index.ts b/src/strategies/erc721-pair-weights/index.ts new file mode 100644 index 000000000..4d7177981 --- /dev/null +++ b/src/strategies/erc721-pair-weights/index.ts @@ -0,0 +1,48 @@ +import { formatUnits } from '@ethersproject/units'; +import { multicall } from '../../utils'; + +export const author = 'arpitkarnatak'; +export const version = '0.1.0'; + +const abi = [ + 'function balanceOf(address account) external view returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const calls: any[] = []; + options.registries.slice(0,2).forEach((registry) => { + addresses.forEach((address: any) => { + calls.push([registry, 'balanceOf', [address]]); + }); + }); + + const response = await multicall(network, provider, abi, calls, { blockTag }); + + const merged = {}; + response.map((value: any, i: number) => { + const address = calls[i][2][0]; + const registry = calls[i][0]; + merged[registry] = merged[registry] || {}; + merged[registry][address] = merged[registry][address] ?? 0; + merged[registry][address] += parseFloat(formatUnits(value.toString(), 0)); + }); + + const powers = {}; + addresses.forEach((address: any) => { + const balance0 = merged[options.registries[0]][address] ?? 0; + const balance1 = merged[options.registries[1]][address] ?? 0; + const pairCount = Math.min(balance0, balance1); + const votePower = pairCount * options.pairWeight + (balance0 - pairCount) * options.weights[0] + (balance1 - pairCount) * options.weights[1]; + powers[address] = votePower; + }); + return powers; +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 77c6926c2..c90e71bfa 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -343,6 +343,7 @@ import * as selfswap from './selfswap'; import * as xrookBalanceOfUnderlyingWeighted from './xrook-balance-of-underlying-weighted'; import * as bancorPoolTokenUnderlyingBalance from './bancor-pool-token-underlying-balance'; import * as orbsNetworkDelegation from './orbs-network-delegation'; +import * as erc721PairWeights from './erc721-pair-weights'; const strategies = { 'forta-shares': fortaShares, @@ -689,7 +690,8 @@ const strategies = { selfswap, 'erc3525-vesting-voucher': erc3525VestingVoucher, 'xrook-balance-of-underlying-weighted': xrookBalanceOfUnderlyingWeighted, - 'orbs-network-delegation': orbsNetworkDelegation + 'orbs-network-delegation': orbsNetworkDelegation, + 'erc721-pair-weights': erc721PairWeights, }; Object.keys(strategies).forEach(function (strategyName) { From 01f61dd6009653ac9240d4775abef9c00a09df4f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 30 Jul 2022 01:58:25 +0530 Subject: [PATCH 051/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.13 (#749) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index a181d4fab..c4779fc26 100755 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.12", + "@snapshot-labs/snapshot.js": "^0.4.13", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", "copyfiles": "^2.4.1", diff --git a/yarn.lock b/yarn.lock index bd152bdd7..7ba1d6d7f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.12": - version "0.4.12" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.12.tgz#8830f9c8553177fe0cbfe1a2351718a5ccc66d15" - integrity sha512-+Cl8XjkIqscgRiI7G1R1WxV0Cv73hGByBj4Wp6wa62hJLzgr4ZdzM8b39oKqXQPax3J8ZI5MgcHigFcCojDSow== +"@snapshot-labs/snapshot.js@^0.4.13": + version "0.4.13" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.13.tgz#0294248f8272a12f1a74cebe05b7ffb2717711e2" + integrity sha512-QRAXt3YG0PXDXnhfvkXbcdafn8OBKObtM3ZeYsSgRE+vGakbdKE/MUlLB3Nn28YvF8hMelEA7aUWC/nMq+Pzpg== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 458eb19090fc77cf295b3390a42012bc579a7abb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 31 Jul 2022 16:58:37 +0530 Subject: [PATCH 052/815] Automated lint (#750) Co-authored-by: ChaituVR --- src/strategies/defiplaza/index.ts | 27 ++++++++++++++----- .../erc721-pair-weights/examples.json | 5 +--- src/strategies/erc721-pair-weights/index.ts | 7 +++-- src/strategies/index.ts | 2 +- 4 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/strategies/defiplaza/index.ts b/src/strategies/defiplaza/index.ts index ec55651d7..91a2dddf0 100644 --- a/src/strategies/defiplaza/index.ts +++ b/src/strategies/defiplaza/index.ts @@ -26,26 +26,39 @@ export async function strategy( multi.call(`balanceOf.${address}`, options.address, 'balanceOf', [address]); // request balance of unclaimed staking rewards - multi.call(`rewardsQuote.${address}`, options.address, 'rewardsQuote', [address]); + multi.call(`rewardsQuote.${address}`, options.address, 'rewardsQuote', [ + address + ]); if (options.stableplaza) { - multi.call(`stableplaza.${address}`, options.stableplaza, 'stakerData', [address]); + multi.call(`stableplaza.${address}`, options.stableplaza, 'stakerData', [ + address + ]); } }); const result = await multi.execute(); - let returnObject = {}; + const returnObject = {}; addresses.forEach((address) => { if (!returnObject.hasOwnProperty(address)) { returnObject[address] = 0; } - returnObject[address] += parseFloat(formatUnits(result.balanceOf[address], options.decimals)); - returnObject[address] += parseFloat(formatUnits(result.rewardsQuote[address], options.decimals)); - + returnObject[address] += parseFloat( + formatUnits(result.balanceOf[address], options.decimals) + ); + returnObject[address] += parseFloat( + formatUnits(result.rewardsQuote[address], options.decimals) + ); + if (options.stableplaza) { - returnObject[address] += parseFloat(formatUnits(result.stableplaza[address][0].mul(4294967296), options.decimals)); // * 2^32 + returnObject[address] += parseFloat( + formatUnits( + result.stableplaza[address][0].mul(4294967296), + options.decimals + ) + ); // * 2^32 } }); diff --git a/src/strategies/erc721-pair-weights/examples.json b/src/strategies/erc721-pair-weights/examples.json index aec10ba93..7ca4ec227 100644 --- a/src/strategies/erc721-pair-weights/examples.json +++ b/src/strategies/erc721-pair-weights/examples.json @@ -9,10 +9,7 @@ "0x960b7a6bcd451c9968473f7bbfd9be826efd549a", "0x86cc280d0bac0bd4ea38ba7d31e895aa20cceb4b" ], - "weights": [ - 2, - 3 - ], + "weights": [2, 3], "pairWeight": 4 } }, diff --git a/src/strategies/erc721-pair-weights/index.ts b/src/strategies/erc721-pair-weights/index.ts index 4d7177981..d6b20b2bd 100644 --- a/src/strategies/erc721-pair-weights/index.ts +++ b/src/strategies/erc721-pair-weights/index.ts @@ -19,7 +19,7 @@ export async function strategy( const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; const calls: any[] = []; - options.registries.slice(0,2).forEach((registry) => { + options.registries.slice(0, 2).forEach((registry) => { addresses.forEach((address: any) => { calls.push([registry, 'balanceOf', [address]]); }); @@ -41,7 +41,10 @@ export async function strategy( const balance0 = merged[options.registries[0]][address] ?? 0; const balance1 = merged[options.registries[1]][address] ?? 0; const pairCount = Math.min(balance0, balance1); - const votePower = pairCount * options.pairWeight + (balance0 - pairCount) * options.weights[0] + (balance1 - pairCount) * options.weights[1]; + const votePower = + pairCount * options.pairWeight + + (balance0 - pairCount) * options.weights[0] + + (balance1 - pairCount) * options.weights[1]; powers[address] = votePower; }); return powers; diff --git a/src/strategies/index.ts b/src/strategies/index.ts index c90e71bfa..2ba32e761 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -691,7 +691,7 @@ const strategies = { 'erc3525-vesting-voucher': erc3525VestingVoucher, 'xrook-balance-of-underlying-weighted': xrookBalanceOfUnderlyingWeighted, 'orbs-network-delegation': orbsNetworkDelegation, - 'erc721-pair-weights': erc721PairWeights, + 'erc721-pair-weights': erc721PairWeights }; Object.keys(strategies).forEach(function (strategyName) { From 858f4f00dbb79417d72ba35e9d5fe47bd85fd7e3 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Sun, 31 Jul 2022 18:05:55 +0530 Subject: [PATCH 053/815] Invalid strategies list in delegation strategy (#751) --- src/strategies/delegation/index.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/strategies/delegation/index.ts b/src/strategies/delegation/index.ts index 8e9c5846a..8ed219e16 100644 --- a/src/strategies/delegation/index.ts +++ b/src/strategies/delegation/index.ts @@ -12,6 +12,16 @@ export async function strategy( options, snapshot ) { + const invalidStrategies = [ + '{"name":"erc20-balance-of","params":{"symbol":"HOP","address":"0xed8Bdb5895B8B7f9Fdb3C087628FD8410E853D48","decimals":18}}' //https://snapshot.org/#/hop.eth/proposal/0x603f0f6e54c7be8d5db7e16ae7145e6df4b439b8aac49654cdfd6b0c03eb6492 + ]; + + if ( + options.strategies.some((s) => + invalidStrategies.includes(JSON.stringify(s)) + ) + ) + return {}; const delegationSpace = options.delegationSpace || space; const delegations = await getDelegations( delegationSpace, From a21a70d44897ce1cc3fb74b4c328002341227013 Mon Sep 17 00:00:00 2001 From: Onigiri <35141155+onigiri-x@users.noreply.github.com> Date: Thu, 4 Aug 2022 00:59:29 -0400 Subject: [PATCH 054/815] Update subgraph address for uniswap quickswap code (#754) --- src/strategies/digitalax-mona-quickswap/index.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/strategies/digitalax-mona-quickswap/index.ts b/src/strategies/digitalax-mona-quickswap/index.ts index 08bcd9cf5..2aabf90fd 100644 --- a/src/strategies/digitalax-mona-quickswap/index.ts +++ b/src/strategies/digitalax-mona-quickswap/index.ts @@ -4,8 +4,7 @@ import { strategy as erc20BalanceOfStrategy } from '../erc20-balance-of'; export const author = 'onigiri-x'; export const version = '0.1.0'; -const QUICKSWAP_SUBGRAPH = - 'https://api.thegraph.com/subgraphs/name/sameepsi/quickswap05'; +const QUICKSWAP_SUBGRAPH = 'https://api.fura.org/subgraphs/name/quickswap'; export async function strategy( space, From 02439eb120ed7c4cc0c493924b78d92d22006b40 Mon Sep 17 00:00:00 2001 From: charq <73696209+buchaoqun@users.noreply.github.com> Date: Thu, 4 Aug 2022 18:46:15 +0800 Subject: [PATCH 055/815] added flexible voucher strategies [erc3525-flexible-voucher] (#740) * add vesting voucher strategies * vesting-voucher rename erc3525-vesting-voucher * Update src/strategies/erc3525-vesting-voucher/index.ts Co-authored-by: Chaitanya * Update src/strategies/erc3525-vesting-voucher/index.ts Co-authored-by: Chaitanya * optimization * erc3525 vesting voucher logical change * added flexible voucher strategies * erc3525 vesting voucher change amount value * restore * restore Co-authored-by: Chaitanya --- .../erc3525-flexible-voucher/examples.json | 18 ++++ .../erc3525-flexible-voucher/index.ts | 100 ++++++++++++++++++ .../erc3525-flexible-voucher/utils.ts | 36 +++++++ src/strategies/index.ts | 2 + 4 files changed, 156 insertions(+) create mode 100644 src/strategies/erc3525-flexible-voucher/examples.json create mode 100644 src/strategies/erc3525-flexible-voucher/index.ts create mode 100644 src/strategies/erc3525-flexible-voucher/utils.ts diff --git a/src/strategies/erc3525-flexible-voucher/examples.json b/src/strategies/erc3525-flexible-voucher/examples.json new file mode 100644 index 000000000..bd70c81b9 --- /dev/null +++ b/src/strategies/erc3525-flexible-voucher/examples.json @@ -0,0 +1,18 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "erc3525-flexible-voucher", + "params": { + "symbol": "fvSOLV", + "address": "0xb77Ca8CB421fAE5d4790a6f5EdAD97Cfb7868aD0", + "decimals": 18 + } + }, + "network": "4", + "addresses": [ + "0x1a71c8EF63aB6f578b1702a35367cA81c9281A8c" + ], + "snapshot": 11096688 + } +] diff --git a/src/strategies/erc3525-flexible-voucher/index.ts b/src/strategies/erc3525-flexible-voucher/index.ts new file mode 100644 index 000000000..9e8e56f99 --- /dev/null +++ b/src/strategies/erc3525-flexible-voucher/index.ts @@ -0,0 +1,100 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import { hexZeroPad } from '@ethersproject/bytes'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; +import { claimCoefficient, maturitiesCoefficient } from './utils'; + +export const author = 'buchaoqun'; +export const version = '0.1.0'; + +const abi = [ + 'function getSnapshot(uint256 tokenId) view returns (tuple(tuple(address issuer, uint8 claimType, uint64 startTime, uint64 latestStartTime, uint64[] terms, uint32[] percentages, bool isValid), uint256 tokenId, uint256 vestingAmount))', + 'function balanceOf(address owner) view returns (uint256)', + 'function tokenOfOwnerByIndex(address owner,uint256 index) view returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + // flexible voucher banlanceOf + const callWalletToCrucibleCount = new Multicaller(network, provider, abi, { + blockTag + }); + for (const walletAddress of addresses) { + callWalletToCrucibleCount.call( + walletAddress, + options.address, + 'balanceOf', + [walletAddress] + ); + } + + // wallet Owner Index + const walletToCrucibleCount: Record = + await callWalletToCrucibleCount.execute(); + + const callWalletToCrucibleAddresses = new Multicaller( + network, + provider, + abi, + { + blockTag + } + ); + for (const [walletAddress, crucibleCount] of Object.entries( + walletToCrucibleCount + )) { + for (let index = 0; index < crucibleCount.toNumber(); index++) { + callWalletToCrucibleAddresses.call( + walletAddress.toString() + '-' + index.toString(), + options.address, + 'tokenOfOwnerByIndex', + [walletAddress, index] + ); + } + } + const walletIDToCrucibleAddresses: Record = + await callWalletToCrucibleAddresses.execute(); + + // voucher snapshot + const callCrucibleToSnapshot = new Multicaller(network, provider, abi, { + blockTag + }); + // walletID: walletAddress-index + for (const [walletID, crucibleAddress] of Object.entries( + walletIDToCrucibleAddresses + )) { + callCrucibleToSnapshot.call(walletID, options.address, 'getSnapshot', [ + hexZeroPad(crucibleAddress.toHexString(), 20) + ]); + } + const walletIDToSnapshot: Record> = + await callCrucibleToSnapshot.execute(); + + const walletToWeights = {} as Record; + for (const [walletID, snapshot] of Object.entries(walletIDToSnapshot)) { + const address = walletID.split('-')[0]; + const value = parseFloat( + formatUnits(snapshot[2].toString(), options.decimals)) * + claimCoefficient(snapshot[0][1]) * + maturitiesCoefficient(snapshot[0][2] == 0 ? snapshot[0][3] : snapshot[0][2], snapshot[0][4] + ); + walletToWeights[address] = walletToWeights[address] + ? walletToWeights[address] + value + : value; + } + + return Object.fromEntries( + Object.entries(walletToWeights).map(([address, balance]) => [ + address, + balance + ]) + ); +} diff --git a/src/strategies/erc3525-flexible-voucher/utils.ts b/src/strategies/erc3525-flexible-voucher/utils.ts new file mode 100644 index 000000000..d2951b55e --- /dev/null +++ b/src/strategies/erc3525-flexible-voucher/utils.ts @@ -0,0 +1,36 @@ +const oneDaySeconds = 86400; + +export const maturitiesCoefficient = ( + latestStartTime: number, + terms: Array +) => { + const nowData = Date.parse(new Date().toString()) / 1000; + const difference = (latestStartTime + terms[terms.length - 1].toNumber()) - nowData; + + if (difference <= 0) { + return 1; + } else if (difference > 0 && difference <= (90 * oneDaySeconds)) { + return 1.1; + } else if (difference > (90 * oneDaySeconds) && difference <= (183 * oneDaySeconds)) { + return 1.2; + } else if (difference > (183 * oneDaySeconds) && difference <= (365 * oneDaySeconds)) { + return 1.5; + } else { + return 2; + } +}; + + +export const claimCoefficient = ( + claimType: number +) => { + if (claimType == 0) { + return 2; + } else if (claimType == 1) { + return 1.2; + } else if (claimType == 2) { + return 1.5; + } else { + return 1; + } +}; diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 2ba32e761..a2af50b8d 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -343,6 +343,7 @@ import * as selfswap from './selfswap'; import * as xrookBalanceOfUnderlyingWeighted from './xrook-balance-of-underlying-weighted'; import * as bancorPoolTokenUnderlyingBalance from './bancor-pool-token-underlying-balance'; import * as orbsNetworkDelegation from './orbs-network-delegation'; +import * as erc3525FlexibleVoucher from './erc3525-flexible-voucher'; import * as erc721PairWeights from './erc721-pair-weights'; const strategies = { @@ -691,6 +692,7 @@ const strategies = { 'erc3525-vesting-voucher': erc3525VestingVoucher, 'xrook-balance-of-underlying-weighted': xrookBalanceOfUnderlyingWeighted, 'orbs-network-delegation': orbsNetworkDelegation, + 'erc3525-flexible-voucher': erc3525FlexibleVoucher, 'erc721-pair-weights': erc721PairWeights }; From 5924b249b748de791976895ec9396940efbe00cb Mon Sep 17 00:00:00 2001 From: Brandon Date: Thu, 4 Aug 2022 23:16:51 -0400 Subject: [PATCH 056/815] new strategy: decaying voting power for staked ERC 1155s [echelon-cached-erc1155-decay] (#753) * decaying erc1155 pk voting power * update decay rate * add readme * Update src/strategies/echelon-cached-erc1155-decay/index.ts Co-authored-by: Chaitanya Co-authored-by: Chaitanya --- .../echelon-cached-erc1155-decay/README.md | 24 +++++++++++ .../examples.json | 28 +++++++++++++ .../echelon-cached-erc1155-decay/index.ts | 42 +++++++++++++++++++ src/strategies/index.ts | 2 + 4 files changed, 96 insertions(+) create mode 100644 src/strategies/echelon-cached-erc1155-decay/README.md create mode 100644 src/strategies/echelon-cached-erc1155-decay/examples.json create mode 100644 src/strategies/echelon-cached-erc1155-decay/index.ts diff --git a/src/strategies/echelon-cached-erc1155-decay/README.md b/src/strategies/echelon-cached-erc1155-decay/README.md new file mode 100644 index 000000000..6d80e7d98 --- /dev/null +++ b/src/strategies/echelon-cached-erc1155-decay/README.md @@ -0,0 +1,24 @@ +# echelon-cached-erc1155-decay + +This strategy looks at an ERC1155 caching (staking) contract and assigns a linearly decaying amount of voting power. The business context behind this is that each cached asset is eligible to claim a set amount of ERC20s over the same period; and thus can use those tokens to vote as well. + +For example, at block 0, the voting should have equivalent to 4000 units of voting power. A year later, they should have 0 units. + +As parameters, we pass in the base amount of voting power (e.g. 4000), starting block where there's no decay, and number of months until complete decay (e.g. 12). + +At a high level, the strategy grabs the UNIX timestamp in seconds for starting block, current block, and project timestamp of final block. It then queries the contract for the amount of cached ERC1155s. A simple slope formula is then applied to calculate the decay rate; which is then applied to determine the voting power per asset at current block. + +The final value is square rooted. + +Example of parameters: + +```json + "params": { + "symbol": "PK - PRIME", + "address": "0x3399eff96D4b6Bae8a56F4852EB55736c9C2b041", + "baseValue": 4000, + "startingBlock": 15166749, + "monthsToDecay": 12 + } +``` + diff --git a/src/strategies/echelon-cached-erc1155-decay/examples.json b/src/strategies/echelon-cached-erc1155-decay/examples.json new file mode 100644 index 000000000..fb289d27d --- /dev/null +++ b/src/strategies/echelon-cached-erc1155-decay/examples.json @@ -0,0 +1,28 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "echelon-cached-erc1155-decay", + "params": { + "symbol": "PK - PRIME", + "address": "0x3399eff96D4b6Bae8a56F4852EB55736c9C2b041", + "baseValue": 4000, + "startingBlock": 15166749, + "monthsToDecay": 12 + } + }, + "network": "1", + "addresses": [ + "0xE6be99cbC7796F90baff870a2ffE838a540E27C9", + "0xf98A4A42853cC611eED664627087d4ae19740ED8", + "0xbdc3C931387e2c6647b0D7237Ed30c702260fa80", + "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", + "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", + "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e", + "0x1d5E65a087eBc3d03a294412E46CE5D6882969f4", + "0x1f254336E5c46639A851b9CfC165697150a6c327", + "0x2ec3F80BeDA63Ede96BA20375032CDD3aAfb3030" + ], + "snapshot": 15169750 + } +] diff --git a/src/strategies/echelon-cached-erc1155-decay/index.ts b/src/strategies/echelon-cached-erc1155-decay/index.ts new file mode 100644 index 000000000..0167dfda1 --- /dev/null +++ b/src/strategies/echelon-cached-erc1155-decay/index.ts @@ -0,0 +1,42 @@ +import { Multicaller } from '../../utils'; + +export const author = 'brandonleung'; +export const version = '1.0.0'; + +const cachingAbi = [ + 'function cacheInfo(uint256, address) view returns (uint256 amount, int256 rewardDebt)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const stakingPool = new Multicaller(network, provider, cachingAbi, { + blockTag + }); + + const startingBlockTimestamp = (await provider.getBlock(options.startingBlock)).timestamp; + const endingBlockTimestamp = startingBlockTimestamp + 2628288 * options.monthsToDecay; + const currentBlockTimestamp = (await provider.getBlock(snapshot)).timestamp; + + const decayRate = (0 - options.baseValue) / (endingBlockTimestamp - startingBlockTimestamp); + + const votingPowerPerKey = options.baseValue + decayRate*(currentBlockTimestamp - startingBlockTimestamp); + + addresses.forEach(address => { + stakingPool.call(address, options.address, "cacheInfo", [0, address]); + }) + const response = await stakingPool.execute(); + + return Object.fromEntries( + addresses.map((address) => { + return [address, Math.sqrt(response[address][0].toNumber() * votingPowerPerKey)]; + }) + ); +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index a2af50b8d..0a4a68b20 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -345,6 +345,7 @@ import * as bancorPoolTokenUnderlyingBalance from './bancor-pool-token-underlyin import * as orbsNetworkDelegation from './orbs-network-delegation'; import * as erc3525FlexibleVoucher from './erc3525-flexible-voucher'; import * as erc721PairWeights from './erc721-pair-weights'; +import * as echelonCachedErc1155Decay from './echelon-cached-erc1155-decay'; const strategies = { 'forta-shares': fortaShares, @@ -692,6 +693,7 @@ const strategies = { 'erc3525-vesting-voucher': erc3525VestingVoucher, 'xrook-balance-of-underlying-weighted': xrookBalanceOfUnderlyingWeighted, 'orbs-network-delegation': orbsNetworkDelegation, + 'echelon-cached-erc1155-decay': echelonCachedErc1155Decay, 'erc3525-flexible-voucher': erc3525FlexibleVoucher, 'erc721-pair-weights': erc721PairWeights }; From 44b90af44492ec47f9f501f96303926ffad7a880 Mon Sep 17 00:00:00 2001 From: charq <73696209+buchaoqun@users.noreply.github.com> Date: Fri, 5 Aug 2022 12:16:13 +0800 Subject: [PATCH 057/815] erc3525 vesting voucher change amount take value [erc3525-vesting-voucher] (#758) * add vesting voucher strategies * vesting-voucher rename erc3525-vesting-voucher * Update src/strategies/erc3525-vesting-voucher/index.ts Co-authored-by: Chaitanya * Update src/strategies/erc3525-vesting-voucher/index.ts Co-authored-by: Chaitanya * optimization * erc3525 vesting voucher logical change * added flexible voucher strategies * erc3525 vesting voucher change amount value * restore * restore * erc3525 vesting voucher change amount take value * Restore accidentally deleted code Co-authored-by: Chaitanya --- src/strategies/erc3525-vesting-voucher/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/strategies/erc3525-vesting-voucher/index.ts b/src/strategies/erc3525-vesting-voucher/index.ts index 48603f811..dac056bec 100644 --- a/src/strategies/erc3525-vesting-voucher/index.ts +++ b/src/strategies/erc3525-vesting-voucher/index.ts @@ -5,7 +5,7 @@ import { Multicaller } from '../../utils'; import { claimCoefficient, maturitiesCoefficient } from './utils'; export const author = 'buchaoqun'; -export const version = '0.1.1'; +export const version = '0.1.2'; const abi = [ 'function getSnapshot(uint256 tokenId_) view returns (uint8 claimType_, uint64 term_, uint256 vestingAmount_, uint256 principal_, uint64[] maturities_, uint32[] percentages_, uint256 availableWithdrawAmount_, string originalInvestor_, bool isValid_)', @@ -85,7 +85,7 @@ export async function strategy( const address = walletID.split('-')[0]; const value = - parseFloat(formatUnits(snapshot[6].toString(), options.decimals)) * + parseFloat(formatUnits(snapshot[3].toString(), options.decimals)) * claimCoefficient(snapshot[0]) * maturitiesCoefficient(snapshot[4]); walletToWeights[address] = walletToWeights[address] From 59eb004b3481c52bfc4935c8a16b8f11670ae5b8 Mon Sep 17 00:00:00 2001 From: Max <82761650+MaxMustermann2@users.noreply.github.com> Date: Fri, 5 Aug 2022 04:27:17 +0000 Subject: [PATCH 058/815] feat: add harmony-staking strategy [harmony-staking] (#757) * feat: add harmony-staking strategy calculates votes of validators through the total balance delegated to them (including self delegation) * chore: move author and name below imports Co-authored-by: Chaitanya --- src/strategies/harmony-staking/examples.json | 18 ++++++++ src/strategies/harmony-staking/index.ts | 44 ++++++++++++++++++++ src/strategies/index.ts | 4 +- 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 src/strategies/harmony-staking/examples.json create mode 100644 src/strategies/harmony-staking/index.ts diff --git a/src/strategies/harmony-staking/examples.json b/src/strategies/harmony-staking/examples.json new file mode 100644 index 000000000..b47c8dc5e --- /dev/null +++ b/src/strategies/harmony-staking/examples.json @@ -0,0 +1,18 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "harmony-staking", + "params": { + "symbol": "ONE" + } + }, + "network": "1666600000", + "addresses": [ + "0xF677b8EF72C34f63c43f47C30612B1A3Ec1b622F", + "0xd143988234dF9117f4Baa00b5f8D4A56d64e56eA", + "0xA5241513DA9F4463F1d4874b548dFBAC29D91f34" + ], + "snapshot": 10937992 + } + ] \ No newline at end of file diff --git a/src/strategies/harmony-staking/index.ts b/src/strategies/harmony-staking/index.ts new file mode 100644 index 000000000..cae0cce42 --- /dev/null +++ b/src/strategies/harmony-staking/index.ts @@ -0,0 +1,44 @@ +import { StaticJsonRpcProvider } from '@ethersproject/providers'; +import { formatUnits } from '@ethersproject/units'; +import { BigNumber } from '@ethersproject/bignumber'; + +export const author = 'harmony-one'; +export const version = '0.0.1'; + +type Params = { + symbol: string; + decimals: number; +}; + +export async function strategy( + _space: string, + _network: string, + provider: StaticJsonRpcProvider, + // adding a 0 value for addresses not in the result is not needed + // since they are dropped anyway in utils.ts + // https://github.com/snapshot-labs/snapshot-strategies/blob/02439eb120ed7c4cc0c493924b78d92d22006b40/src/utils.ts#L26 + _addresses: Array, + options: Params, + snapshot: number | string, + ) { + // provider = new StaticJsonRpcProvider({ + // url: "http://127.0.0.1:9500", + // timeout: 25000, + // }); + const blockTag: number | string = typeof snapshot === "number" ? snapshot : "latest"; + const response: Record = await provider.send( + "hmyv2_getValidatorsStakeByBlockNumber", + [blockTag], + ); + return Object.fromEntries( + Object.entries(response).map(([address, balance]) => [ + address, + parseFloat( + formatUnits( + BigNumber.from('0x' + balance.toString(16)), + options && options.decimals ? options.decimals: 18, + ) + ) + ]) + ); +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 0a4a68b20..f88924e82 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -345,6 +345,7 @@ import * as bancorPoolTokenUnderlyingBalance from './bancor-pool-token-underlyin import * as orbsNetworkDelegation from './orbs-network-delegation'; import * as erc3525FlexibleVoucher from './erc3525-flexible-voucher'; import * as erc721PairWeights from './erc721-pair-weights'; +import * as harmonyStaking from './harmony-staking'; import * as echelonCachedErc1155Decay from './echelon-cached-erc1155-decay'; const strategies = { @@ -693,9 +694,10 @@ const strategies = { 'erc3525-vesting-voucher': erc3525VestingVoucher, 'xrook-balance-of-underlying-weighted': xrookBalanceOfUnderlyingWeighted, 'orbs-network-delegation': orbsNetworkDelegation, + 'erc721-pair-weights': erc721PairWeights, + 'harmony-staking': harmonyStaking, 'echelon-cached-erc1155-decay': echelonCachedErc1155Decay, 'erc3525-flexible-voucher': erc3525FlexibleVoucher, - 'erc721-pair-weights': erc721PairWeights }; Object.keys(strategies).forEach(function (strategyName) { From bf4a2b279ce9e113bccb52b94d43a8896fb3eb5a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 5 Aug 2022 10:00:00 +0530 Subject: [PATCH 059/815] Automated lint (#759) Co-authored-by: ChaituVR --- .../echelon-cached-erc1155-decay/index.ts | 25 ++- .../erc3525-flexible-voucher/examples.json | 4 +- .../erc3525-flexible-voucher/index.ts | 160 +++++++++--------- .../erc3525-flexible-voucher/utils.ts | 20 ++- src/strategies/harmony-staking/examples.json | 34 ++-- src/strategies/harmony-staking/index.ts | 65 +++---- src/strategies/index.ts | 2 +- 7 files changed, 163 insertions(+), 147 deletions(-) diff --git a/src/strategies/echelon-cached-erc1155-decay/index.ts b/src/strategies/echelon-cached-erc1155-decay/index.ts index 0167dfda1..1f932adca 100644 --- a/src/strategies/echelon-cached-erc1155-decay/index.ts +++ b/src/strategies/echelon-cached-erc1155-decay/index.ts @@ -21,22 +21,31 @@ export async function strategy( blockTag }); - const startingBlockTimestamp = (await provider.getBlock(options.startingBlock)).timestamp; - const endingBlockTimestamp = startingBlockTimestamp + 2628288 * options.monthsToDecay; + const startingBlockTimestamp = ( + await provider.getBlock(options.startingBlock) + ).timestamp; + const endingBlockTimestamp = + startingBlockTimestamp + 2628288 * options.monthsToDecay; const currentBlockTimestamp = (await provider.getBlock(snapshot)).timestamp; - const decayRate = (0 - options.baseValue) / (endingBlockTimestamp - startingBlockTimestamp); + const decayRate = + (0 - options.baseValue) / (endingBlockTimestamp - startingBlockTimestamp); - const votingPowerPerKey = options.baseValue + decayRate*(currentBlockTimestamp - startingBlockTimestamp); + const votingPowerPerKey = + options.baseValue + + decayRate * (currentBlockTimestamp - startingBlockTimestamp); - addresses.forEach(address => { - stakingPool.call(address, options.address, "cacheInfo", [0, address]); - }) + addresses.forEach((address) => { + stakingPool.call(address, options.address, 'cacheInfo', [0, address]); + }); const response = await stakingPool.execute(); return Object.fromEntries( addresses.map((address) => { - return [address, Math.sqrt(response[address][0].toNumber() * votingPowerPerKey)]; + return [ + address, + Math.sqrt(response[address][0].toNumber() * votingPowerPerKey) + ]; }) ); } diff --git a/src/strategies/erc3525-flexible-voucher/examples.json b/src/strategies/erc3525-flexible-voucher/examples.json index bd70c81b9..d35be8f41 100644 --- a/src/strategies/erc3525-flexible-voucher/examples.json +++ b/src/strategies/erc3525-flexible-voucher/examples.json @@ -10,9 +10,7 @@ } }, "network": "4", - "addresses": [ - "0x1a71c8EF63aB6f578b1702a35367cA81c9281A8c" - ], + "addresses": ["0x1a71c8EF63aB6f578b1702a35367cA81c9281A8c"], "snapshot": 11096688 } ] diff --git a/src/strategies/erc3525-flexible-voucher/index.ts b/src/strategies/erc3525-flexible-voucher/index.ts index 9e8e56f99..153d97c20 100644 --- a/src/strategies/erc3525-flexible-voucher/index.ts +++ b/src/strategies/erc3525-flexible-voucher/index.ts @@ -8,93 +8,97 @@ export const author = 'buchaoqun'; export const version = '0.1.0'; const abi = [ - 'function getSnapshot(uint256 tokenId) view returns (tuple(tuple(address issuer, uint8 claimType, uint64 startTime, uint64 latestStartTime, uint64[] terms, uint32[] percentages, bool isValid), uint256 tokenId, uint256 vestingAmount))', - 'function balanceOf(address owner) view returns (uint256)', - 'function tokenOfOwnerByIndex(address owner,uint256 index) view returns (uint256)' + 'function getSnapshot(uint256 tokenId) view returns (tuple(tuple(address issuer, uint8 claimType, uint64 startTime, uint64 latestStartTime, uint64[] terms, uint32[] percentages, bool isValid), uint256 tokenId, uint256 vestingAmount))', + 'function balanceOf(address owner) view returns (uint256)', + 'function tokenOfOwnerByIndex(address owner,uint256 index) view returns (uint256)' ]; export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot + space, + network, + provider, + addresses, + options, + snapshot ) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - // flexible voucher banlanceOf - const callWalletToCrucibleCount = new Multicaller(network, provider, abi, { - blockTag - }); - for (const walletAddress of addresses) { - callWalletToCrucibleCount.call( - walletAddress, - options.address, - 'balanceOf', - [walletAddress] - ); - } + // flexible voucher banlanceOf + const callWalletToCrucibleCount = new Multicaller(network, provider, abi, { + blockTag + }); + for (const walletAddress of addresses) { + callWalletToCrucibleCount.call( + walletAddress, + options.address, + 'balanceOf', + [walletAddress] + ); + } - // wallet Owner Index - const walletToCrucibleCount: Record = - await callWalletToCrucibleCount.execute(); + // wallet Owner Index + const walletToCrucibleCount: Record = + await callWalletToCrucibleCount.execute(); - const callWalletToCrucibleAddresses = new Multicaller( - network, - provider, - abi, - { - blockTag - } - ); - for (const [walletAddress, crucibleCount] of Object.entries( - walletToCrucibleCount - )) { - for (let index = 0; index < crucibleCount.toNumber(); index++) { - callWalletToCrucibleAddresses.call( - walletAddress.toString() + '-' + index.toString(), - options.address, - 'tokenOfOwnerByIndex', - [walletAddress, index] - ); - } + const callWalletToCrucibleAddresses = new Multicaller( + network, + provider, + abi, + { + blockTag } - const walletIDToCrucibleAddresses: Record = - await callWalletToCrucibleAddresses.execute(); - - // voucher snapshot - const callCrucibleToSnapshot = new Multicaller(network, provider, abi, { - blockTag - }); - // walletID: walletAddress-index - for (const [walletID, crucibleAddress] of Object.entries( - walletIDToCrucibleAddresses - )) { - callCrucibleToSnapshot.call(walletID, options.address, 'getSnapshot', [ - hexZeroPad(crucibleAddress.toHexString(), 20) - ]); + ); + for (const [walletAddress, crucibleCount] of Object.entries( + walletToCrucibleCount + )) { + for (let index = 0; index < crucibleCount.toNumber(); index++) { + callWalletToCrucibleAddresses.call( + walletAddress.toString() + '-' + index.toString(), + options.address, + 'tokenOfOwnerByIndex', + [walletAddress, index] + ); } - const walletIDToSnapshot: Record> = - await callCrucibleToSnapshot.execute(); + } + const walletIDToCrucibleAddresses: Record = + await callWalletToCrucibleAddresses.execute(); - const walletToWeights = {} as Record; - for (const [walletID, snapshot] of Object.entries(walletIDToSnapshot)) { - const address = walletID.split('-')[0]; - const value = parseFloat( - formatUnits(snapshot[2].toString(), options.decimals)) * - claimCoefficient(snapshot[0][1]) * - maturitiesCoefficient(snapshot[0][2] == 0 ? snapshot[0][3] : snapshot[0][2], snapshot[0][4] - ); - walletToWeights[address] = walletToWeights[address] - ? walletToWeights[address] + value - : value; - } + // voucher snapshot + const callCrucibleToSnapshot = new Multicaller(network, provider, abi, { + blockTag + }); + // walletID: walletAddress-index + for (const [walletID, crucibleAddress] of Object.entries( + walletIDToCrucibleAddresses + )) { + callCrucibleToSnapshot.call(walletID, options.address, 'getSnapshot', [ + hexZeroPad(crucibleAddress.toHexString(), 20) + ]); + } + const walletIDToSnapshot: Record< + string, + Array + > = await callCrucibleToSnapshot.execute(); - return Object.fromEntries( - Object.entries(walletToWeights).map(([address, balance]) => [ - address, - balance - ]) - ); + const walletToWeights = {} as Record; + for (const [walletID, snapshot] of Object.entries(walletIDToSnapshot)) { + const address = walletID.split('-')[0]; + const value = + parseFloat(formatUnits(snapshot[2].toString(), options.decimals)) * + claimCoefficient(snapshot[0][1]) * + maturitiesCoefficient( + snapshot[0][2] == 0 ? snapshot[0][3] : snapshot[0][2], + snapshot[0][4] + ); + walletToWeights[address] = walletToWeights[address] + ? walletToWeights[address] + value + : value; + } + + return Object.fromEntries( + Object.entries(walletToWeights).map(([address, balance]) => [ + address, + balance + ]) + ); } diff --git a/src/strategies/erc3525-flexible-voucher/utils.ts b/src/strategies/erc3525-flexible-voucher/utils.ts index d2951b55e..6a949a610 100644 --- a/src/strategies/erc3525-flexible-voucher/utils.ts +++ b/src/strategies/erc3525-flexible-voucher/utils.ts @@ -5,25 +5,29 @@ export const maturitiesCoefficient = ( terms: Array ) => { const nowData = Date.parse(new Date().toString()) / 1000; - const difference = (latestStartTime + terms[terms.length - 1].toNumber()) - nowData; + const difference = + latestStartTime + terms[terms.length - 1].toNumber() - nowData; if (difference <= 0) { return 1; - } else if (difference > 0 && difference <= (90 * oneDaySeconds)) { + } else if (difference > 0 && difference <= 90 * oneDaySeconds) { return 1.1; - } else if (difference > (90 * oneDaySeconds) && difference <= (183 * oneDaySeconds)) { + } else if ( + difference > 90 * oneDaySeconds && + difference <= 183 * oneDaySeconds + ) { return 1.2; - } else if (difference > (183 * oneDaySeconds) && difference <= (365 * oneDaySeconds)) { + } else if ( + difference > 183 * oneDaySeconds && + difference <= 365 * oneDaySeconds + ) { return 1.5; } else { return 2; } }; - -export const claimCoefficient = ( - claimType: number -) => { +export const claimCoefficient = (claimType: number) => { if (claimType == 0) { return 2; } else if (claimType == 1) { diff --git a/src/strategies/harmony-staking/examples.json b/src/strategies/harmony-staking/examples.json index b47c8dc5e..fb0832e66 100644 --- a/src/strategies/harmony-staking/examples.json +++ b/src/strategies/harmony-staking/examples.json @@ -1,18 +1,18 @@ [ - { - "name": "Example query", - "strategy": { - "name": "harmony-staking", - "params": { - "symbol": "ONE" - } - }, - "network": "1666600000", - "addresses": [ - "0xF677b8EF72C34f63c43f47C30612B1A3Ec1b622F", - "0xd143988234dF9117f4Baa00b5f8D4A56d64e56eA", - "0xA5241513DA9F4463F1d4874b548dFBAC29D91f34" - ], - "snapshot": 10937992 - } - ] \ No newline at end of file + { + "name": "Example query", + "strategy": { + "name": "harmony-staking", + "params": { + "symbol": "ONE" + } + }, + "network": "1666600000", + "addresses": [ + "0xF677b8EF72C34f63c43f47C30612B1A3Ec1b622F", + "0xd143988234dF9117f4Baa00b5f8D4A56d64e56eA", + "0xA5241513DA9F4463F1d4874b548dFBAC29D91f34" + ], + "snapshot": 10937992 + } +] diff --git a/src/strategies/harmony-staking/index.ts b/src/strategies/harmony-staking/index.ts index cae0cce42..113a840ca 100644 --- a/src/strategies/harmony-staking/index.ts +++ b/src/strategies/harmony-staking/index.ts @@ -6,39 +6,40 @@ export const author = 'harmony-one'; export const version = '0.0.1'; type Params = { - symbol: string; - decimals: number; + symbol: string; + decimals: number; }; export async function strategy( - _space: string, - _network: string, - provider: StaticJsonRpcProvider, - // adding a 0 value for addresses not in the result is not needed - // since they are dropped anyway in utils.ts - // https://github.com/snapshot-labs/snapshot-strategies/blob/02439eb120ed7c4cc0c493924b78d92d22006b40/src/utils.ts#L26 - _addresses: Array, - options: Params, - snapshot: number | string, - ) { - // provider = new StaticJsonRpcProvider({ - // url: "http://127.0.0.1:9500", - // timeout: 25000, - // }); - const blockTag: number | string = typeof snapshot === "number" ? snapshot : "latest"; - const response: Record = await provider.send( - "hmyv2_getValidatorsStakeByBlockNumber", - [blockTag], - ); - return Object.fromEntries( - Object.entries(response).map(([address, balance]) => [ - address, - parseFloat( - formatUnits( - BigNumber.from('0x' + balance.toString(16)), - options && options.decimals ? options.decimals: 18, - ) - ) - ]) - ); + _space: string, + _network: string, + provider: StaticJsonRpcProvider, + // adding a 0 value for addresses not in the result is not needed + // since they are dropped anyway in utils.ts + // https://github.com/snapshot-labs/snapshot-strategies/blob/02439eb120ed7c4cc0c493924b78d92d22006b40/src/utils.ts#L26 + _addresses: Array, + options: Params, + snapshot: number | string +) { + // provider = new StaticJsonRpcProvider({ + // url: "http://127.0.0.1:9500", + // timeout: 25000, + // }); + const blockTag: number | string = + typeof snapshot === 'number' ? snapshot : 'latest'; + const response: Record = await provider.send( + 'hmyv2_getValidatorsStakeByBlockNumber', + [blockTag] + ); + return Object.fromEntries( + Object.entries(response).map(([address, balance]) => [ + address, + parseFloat( + formatUnits( + BigNumber.from('0x' + balance.toString(16)), + options && options.decimals ? options.decimals : 18 + ) + ) + ]) + ); } diff --git a/src/strategies/index.ts b/src/strategies/index.ts index f88924e82..8963ed8c3 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -697,7 +697,7 @@ const strategies = { 'erc721-pair-weights': erc721PairWeights, 'harmony-staking': harmonyStaking, 'echelon-cached-erc1155-decay': echelonCachedErc1155Decay, - 'erc3525-flexible-voucher': erc3525FlexibleVoucher, + 'erc3525-flexible-voucher': erc3525FlexibleVoucher }; Object.keys(strategies).forEach(function (strategyName) { From 13d6b64a644764848221398c4df96e61426b55c2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 5 Aug 2022 16:53:39 +0530 Subject: [PATCH 060/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.14 (#761) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index c4779fc26..9de626d28 100755 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.13", + "@snapshot-labs/snapshot.js": "^0.4.14", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", "copyfiles": "^2.4.1", diff --git a/yarn.lock b/yarn.lock index 7ba1d6d7f..c509ae213 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.13": - version "0.4.13" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.13.tgz#0294248f8272a12f1a74cebe05b7ffb2717711e2" - integrity sha512-QRAXt3YG0PXDXnhfvkXbcdafn8OBKObtM3ZeYsSgRE+vGakbdKE/MUlLB3Nn28YvF8hMelEA7aUWC/nMq+Pzpg== +"@snapshot-labs/snapshot.js@^0.4.14": + version "0.4.14" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.14.tgz#838057afa61eac92bde8b82f1b79241baf7e2e37" + integrity sha512-JX2TwYUWkldMeqcXIevDHXCyuqV27VaarbgdBaV/MmG2PXOxC/+A5CAutxC79WRMAjQNcAsKifh00mOeACqWbg== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 2857341d4d82d325f63426edb28b6d7616f4de68 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 5 Aug 2022 18:15:58 +0530 Subject: [PATCH 061/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.15 (#762) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 9de626d28..ab23609ac 100755 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.14", + "@snapshot-labs/snapshot.js": "^0.4.15", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", "copyfiles": "^2.4.1", diff --git a/yarn.lock b/yarn.lock index c509ae213..752cd9f75 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.14": - version "0.4.14" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.14.tgz#838057afa61eac92bde8b82f1b79241baf7e2e37" - integrity sha512-JX2TwYUWkldMeqcXIevDHXCyuqV27VaarbgdBaV/MmG2PXOxC/+A5CAutxC79WRMAjQNcAsKifh00mOeACqWbg== +"@snapshot-labs/snapshot.js@^0.4.15": + version "0.4.15" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.15.tgz#8311ade22a3fdc1c884e2db585eb87d64824ff02" + integrity sha512-5SDaOyfbLOrJAmYbKJ5EwIuMR1kLQVBGfV2gzCznboE4hJEpDwFkT8U9ZEdUn9fBAPU7jr6x2a9w5zr9J8yO7Q== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 140100b56bae85cace35e859611312dbcf08e83e Mon Sep 17 00:00:00 2001 From: Chris Ling <81092286+chrisling-dev@users.noreply.github.com> Date: Fri, 5 Aug 2022 20:54:04 +0800 Subject: [PATCH 062/815] feat: prepo vesting contract weighted voting [prepo-vesting] (#755) * feat: prepo vesting contract weighted voting * refactor: move prepo vesting to middle of list * feat: add schema * feat: added readme.md * refactor: adjust parameters * feat: update README.md * feat: add symbol example to README.md * feat: testing command * feat: rearrange * feat: update README.md * feat: finalize README.md * feat: capitalize Contract Address in schema.json * fix: edited wrong file * feat: capitalize Contract Address in schema.json * feat: update README.md * feat: update default symbol * fix: symbol should not be required * feat: rename variables to match formula in readme * feat: resolve conflict * feat: readme.md --- src/strategies/index.ts | 2 + src/strategies/prepo-vesting/README.md | 44 ++++++++++++++++++ src/strategies/prepo-vesting/examples.json | 36 +++++++++++++++ src/strategies/prepo-vesting/index.ts | 54 ++++++++++++++++++++++ src/strategies/prepo-vesting/schema.json | 33 +++++++++++++ 5 files changed, 169 insertions(+) create mode 100644 src/strategies/prepo-vesting/README.md create mode 100644 src/strategies/prepo-vesting/examples.json create mode 100644 src/strategies/prepo-vesting/index.ts create mode 100644 src/strategies/prepo-vesting/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 8963ed8c3..f613d5e99 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -27,6 +27,7 @@ import * as erc20WithBalance from './erc20-with-balance'; import * as erc20BalanceOfDelegation from './erc20-balance-of-delegation'; import * as erc20BalanceOfQuadraticDelegation from './erc20-balance-of-quadratic-delegation'; import * as erc20BalanceOfWeighted from './erc20-balance-of-weighted'; +import * as prepoVesting from './prepo-vesting'; import * as mintoBalanceAll from './minto-balance-of-all'; import * as erc20BalanceOfIndexed from './erc20-balance-of-indexed'; import * as revest from './revest'; @@ -411,6 +412,7 @@ const strategies = { 'erc721-multi-registry': erc721MultiRegistry, 'erc1155-balance-of': erc1155BalanceOf, 'erc1155-balance-of-cv': erc1155BalanceOfCv, + 'prepo-vesting': prepoVesting, multichain, uni, 'frax-finance': fraxFinance, diff --git a/src/strategies/prepo-vesting/README.md b/src/strategies/prepo-vesting/README.md new file mode 100644 index 000000000..fcb528df5 --- /dev/null +++ b/src/strategies/prepo-vesting/README.md @@ -0,0 +1,44 @@ +# prePO Vesting Snapshot Strategy + +This strategy returns a voting score based on PPO under vesting from the [prePO Vesting contract](https://github.com/prepo-io/prepo-monorepo/blob/main/apps/smart-contracts/token/contracts/vesting/Vesting.sol). + +To use this strategy, your contract must contain 3 methods from the prePO [Vesting interface](https://github.com/prepo-io/prepo-monorepo/blob/main/apps/smart-contracts/token/contracts/vesting/interfaces/IVesting.sol): `getAmountAllocated`, `getClaimableAmount` and `getVestedAmount`. + +This strategy assumes that the vesting token has 18 decimals. + +### Calculation + +`score = unclaimedVestedBalance + unvestedBalance * multiplier` + +where: + +- `unclaimedVestedBalance = getClaimableAmount` +- `unvestedBalance = getAmountAllocated - getVestedAmount` + +### Parameters + +The strategy takes three parameters: + +- `symbol`: Symbol of the strategy +- `address`: Address of contract that has all the methods mentioned above +- `multiplier`: A multiplier applied to the unvested balance + +Here is an example of parameters: + +```json +{ + "symbol": "PPO (Vesting)", + "address": "0xB1B74EA823bAd9AFb5e2caC578235EeeB329A245", + "multiplier": 0.5 +} +``` + +### Tests + +To test the strategy, run `yarn test --strategy=prepo-vesting --more=500` + +### Links + +- [prePO's Website](https://prepo.io/) +- [prePO's GitHub](https://github.com/prepo-io/prepo-monorepo/) +- [prePO's Snapshot Space](https://vote.prepo.io/) diff --git a/src/strategies/prepo-vesting/examples.json b/src/strategies/prepo-vesting/examples.json new file mode 100644 index 000000000..bb81fcafa --- /dev/null +++ b/src/strategies/prepo-vesting/examples.json @@ -0,0 +1,36 @@ +[ + { + "name": "Example Goerli query", + "strategy": { + "name": "prepo-vesting", + "params": { + "symbol": "PPO (Vesting)", + "address": "0xB1B74EA823bAd9AFb5e2caC578235EeeB329A245", + "multiplier": 0.5 + } + }, + "network": "5", + "addresses": [ + "0x1549920373edB37AE3a9Cffe1bE02844Df3127D0", + "0xa478c2975ab1ea89e8196811f51a7b7ade33eb11", + "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", + "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", + "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", + "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e", + "0x1d5E65a087eBc3d03a294412E46CE5D6882969f4", + "0x1f254336E5c46639A851b9CfC165697150a6c327", + "0x2ec3F80BeDA63Ede96BA20375032CDD3aAfb3030", + "0x4AcBcA6BE2f8D2540bBF4CA77E45dA0A4a095Fa2", + "0x4F3D348a6D09837Ae7961B1E0cEe2cc118cec777", + "0x6D7f23A509E212Ba7773EC1b2505d1A134f54fbe", + "0x07a1f6fc89223c5ebD4e4ddaE89Ac97629856A0f", + "0x8d5F05270da470e015b67Ab5042BDbE2D2FEFB48", + "0x8d07D225a769b7Af3A923481E1FdF49180e6A265", + "0x8f60501dE5b9b01F9EAf1214dbE1924aA97F7fd0", + "0x9B8e8dD9151260c21CB6D7cc59067cd8DF306D58", + "0x17ea92D6FfbAA1c7F6B117c1E9D0c88ABdc8b84C", + "0x38C0039247A31F3939baE65e953612125cB88268" + ], + "snapshot": 7343530 + } +] diff --git a/src/strategies/prepo-vesting/index.ts b/src/strategies/prepo-vesting/index.ts new file mode 100644 index 000000000..640c0e2b6 --- /dev/null +++ b/src/strategies/prepo-vesting/index.ts @@ -0,0 +1,54 @@ +import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'prepo-io'; +export const version = '1.0.0'; + +const abi = [ + 'function getAmountAllocated(address _recipient) external view override returns (uint256)', + 'function getClaimableAmount(address _recipient) public view override returns (uint256)', + 'function getVestedAmount(address _recipient) public view override returns (uint256)' +]; + +type MulticallOutput = Record>; + +const convertBN = (amount: BigNumberish, unitName?: BigNumberish) => + parseFloat(formatUnits(amount, unitName)); + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const { address, multiplier } = options; + + const multi = new Multicaller(network, provider, abi, { blockTag }); + + addresses.forEach((addr) => { + multi.call(`allocated.${addr}`, address, 'getAmountAllocated', [addr]); + multi.call(`claimable.${addr}`, address, 'getClaimableAmount', [addr]); + multi.call(`vested.${addr}`, address, 'getVestedAmount', [addr]); + }); + + const { allocated, claimable, vested }: MulticallOutput = + await multi.execute(); + + const output = Object.fromEntries( + Object.entries(allocated).map(([address, amountAllocated]) => { + const unclaimedVestedBalance = convertBN(claimable[address], 18); + const unvestedBalance = convertBN( + BigNumber.from(amountAllocated).sub(vested[address]), + 18 + ); + const score = unclaimedVestedBalance + unvestedBalance * multiplier; + return [address, score]; + }) + ); + return output; +} diff --git a/src/strategies/prepo-vesting/schema.json b/src/strategies/prepo-vesting/schema.json new file mode 100644 index 000000000..fa8fcf9a5 --- /dev/null +++ b/src/strategies/prepo-vesting/schema.json @@ -0,0 +1,33 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "prePO Vesting Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. PPO (Vesting)"], + "maxLength": 16 + }, + "address": { + "type": "string", + "title": "Contract Address", + "examples": ["e.g. 0xB1B74EA823bAd9AFb5e2caC578235EeeB329A245"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "multiplier": { + "type": "number", + "title": "Multiplier", + "examples": ["e.g. 0.5"] + } + }, + "required": ["address", "multiplier"], + "additionalProperties": false + } + } +} From b08b4edac2689c2feb3228391d36e76392223c01 Mon Sep 17 00:00:00 2001 From: Weizard Date: Sun, 7 Aug 2022 20:43:39 +0800 Subject: [PATCH 063/815] feat: add a strategy to calc blance with subgraph (#748) Co-authored-by: Chaitanya --- src/strategies/balance-of-subgraph/README.md | 24 ++++++++ .../balance-of-subgraph/examples.json | 17 ++++++ src/strategies/balance-of-subgraph/index.ts | 55 +++++++++++++++++++ src/strategies/index.ts | 2 + 4 files changed, 98 insertions(+) create mode 100644 src/strategies/balance-of-subgraph/README.md create mode 100644 src/strategies/balance-of-subgraph/examples.json create mode 100644 src/strategies/balance-of-subgraph/index.ts diff --git a/src/strategies/balance-of-subgraph/README.md b/src/strategies/balance-of-subgraph/README.md new file mode 100644 index 000000000..86275dbce --- /dev/null +++ b/src/strategies/balance-of-subgraph/README.md @@ -0,0 +1,24 @@ +# Balance of subgraph + +To calculate the token balance including user's EOA and smart wallet, we developed this strategy. Developers can create their own subparagraphs using the below scheme, and the score will be calculated as a result. + +``` +users{ + id + amount +} +``` + + +## Example + +The space config will look like this: + +```JSON +{ + // subgraphURL for the request + "subGraphURL": "https://api.thegraph.com/subgraphs/name/dinngodev/furucombo-tokenomics-mainnet", + // scoreMultiplier can be used to increase users' scores by a certain magnitude + "scoreMultiplier": 1, +} +``` diff --git a/src/strategies/balance-of-subgraph/examples.json b/src/strategies/balance-of-subgraph/examples.json new file mode 100644 index 000000000..c97beb9c8 --- /dev/null +++ b/src/strategies/balance-of-subgraph/examples.json @@ -0,0 +1,17 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "balance-of-subgraph", + "params": { + "subGraphURL": "https://api.thegraph.com/subgraphs/name/dinngodev/furucombo-tokenomics-mainnet" + } + }, + "network": "1", + "addresses": [ + "0xe4ef29545db14e252AeC1c660A004e2408Dc62d2", + "0xa3c1c91403f0026b9dd086882adbc8cdbc3b3cfb" + ], + "snapshot": 14716396 + } +] diff --git a/src/strategies/balance-of-subgraph/index.ts b/src/strategies/balance-of-subgraph/index.ts new file mode 100644 index 000000000..0761ec0d3 --- /dev/null +++ b/src/strategies/balance-of-subgraph/index.ts @@ -0,0 +1,55 @@ +import { getAddress } from '@ethersproject/address'; +import { subgraphRequest } from '../../utils'; + +const SUBGRAPH_URL = { + '1': 'https://api.thegraph.com/subgraphs/name/dinngodev/furucombo-tokenomics-mainnet', + '137': + 'https://api.thegraph.com/subgraphs/name/dinngodev/furucombo-tokenomics-polygon' +}; + +export const author = 'weizard'; +export const version = '0.1.0'; + +export async function strategy( + _space, + network, + _provider, + addresses, + options, + snapshot +) { + const params = { + users: { + __args: { + where: { + id_in: addresses.map((address) => address.toLowerCase()), + amount_gt: 0 + } + }, + id: true, + amount: true + } + }; + if (snapshot !== 'latest') { + // @ts-ignore + params.users.__args.block = { number: snapshot }; + } + const result = await subgraphRequest( + options.subGraphURL ? options.subGraphURL : SUBGRAPH_URL[network], + params + ); + const score = {}; + if (result && result.users) { + result.users.forEach((user) => { + const userAddress = getAddress(user.id); + let userScore = Number(user.amount); + + if (options.scoreMultiplier) { + userScore = userScore * options.scoreMultiplier; + } + if (!score[userAddress]) score[userAddress] = 0; + score[userAddress] = score[userAddress] + userScore; + }); + } + return score || {}; +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index f613d5e99..f4535d324 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -344,6 +344,7 @@ import * as selfswap from './selfswap'; import * as xrookBalanceOfUnderlyingWeighted from './xrook-balance-of-underlying-weighted'; import * as bancorPoolTokenUnderlyingBalance from './bancor-pool-token-underlying-balance'; import * as orbsNetworkDelegation from './orbs-network-delegation'; +import * as balanceOfSubgraph from './balance-of-subgraph'; import * as erc3525FlexibleVoucher from './erc3525-flexible-voucher'; import * as erc721PairWeights from './erc721-pair-weights'; import * as harmonyStaking from './harmony-staking'; @@ -696,6 +697,7 @@ const strategies = { 'erc3525-vesting-voucher': erc3525VestingVoucher, 'xrook-balance-of-underlying-weighted': xrookBalanceOfUnderlyingWeighted, 'orbs-network-delegation': orbsNetworkDelegation, + 'balance-of-subgraph': balanceOfSubgraph, 'erc721-pair-weights': erc721PairWeights, 'harmony-staking': harmonyStaking, 'echelon-cached-erc1155-decay': echelonCachedErc1155Decay, From fa28d719c61aa3db9d0a807b20a5f76b7aacc54e Mon Sep 17 00:00:00 2001 From: charq <73696209+buchaoqun@users.noreply.github.com> Date: Mon, 8 Aug 2022 19:32:47 +0800 Subject: [PATCH 064/815] erc3525 vesting voucher claim coefficient updated [erc3525-vesting-voucher] (#763) * add vesting voucher strategies * vesting-voucher rename erc3525-vesting-voucher * Update src/strategies/erc3525-vesting-voucher/index.ts Co-authored-by: Chaitanya * Update src/strategies/erc3525-vesting-voucher/index.ts Co-authored-by: Chaitanya * optimization * erc3525 vesting voucher logical change * added flexible voucher strategies * erc3525 vesting voucher change amount value * restore * restore * erc3525 vesting voucher change amount take value * Restore accidentally deleted code * erc3525 vesting voucher claim coefficient updated Co-authored-by: Chaitanya --- src/strategies/erc3525-vesting-voucher/index.ts | 2 +- src/strategies/erc3525-vesting-voucher/utils.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/strategies/erc3525-vesting-voucher/index.ts b/src/strategies/erc3525-vesting-voucher/index.ts index dac056bec..edf5d5ca0 100644 --- a/src/strategies/erc3525-vesting-voucher/index.ts +++ b/src/strategies/erc3525-vesting-voucher/index.ts @@ -5,7 +5,7 @@ import { Multicaller } from '../../utils'; import { claimCoefficient, maturitiesCoefficient } from './utils'; export const author = 'buchaoqun'; -export const version = '0.1.2'; +export const version = '0.1.3'; const abi = [ 'function getSnapshot(uint256 tokenId_) view returns (uint8 claimType_, uint64 term_, uint256 vestingAmount_, uint256 principal_, uint64[] maturities_, uint32[] percentages_, uint256 availableWithdrawAmount_, string originalInvestor_, bool isValid_)', diff --git a/src/strategies/erc3525-vesting-voucher/utils.ts b/src/strategies/erc3525-vesting-voucher/utils.ts index 62e52265c..417785e1c 100644 --- a/src/strategies/erc3525-vesting-voucher/utils.ts +++ b/src/strategies/erc3525-vesting-voucher/utils.ts @@ -25,9 +25,9 @@ export const maturitiesCoefficient = (maturities: Array) => { export const claimCoefficient = (claimType: number) => { if (claimType == 0) { - return 2; - } else if (claimType == 1) { return 1.2; + } else if (claimType == 1) { + return 2; } else if (claimType == 2) { return 1.5; } else { From ef8dae9d373aeb68c3c279aa0ff6033127a67215 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 8 Aug 2022 18:08:36 +0530 Subject: [PATCH 065/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.16 (#764) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index ab23609ac..684cd5a60 100755 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.15", + "@snapshot-labs/snapshot.js": "^0.4.16", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", "copyfiles": "^2.4.1", diff --git a/yarn.lock b/yarn.lock index 752cd9f75..9d8c4cafb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.15": - version "0.4.15" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.15.tgz#8311ade22a3fdc1c884e2db585eb87d64824ff02" - integrity sha512-5SDaOyfbLOrJAmYbKJ5EwIuMR1kLQVBGfV2gzCznboE4hJEpDwFkT8U9ZEdUn9fBAPU7jr6x2a9w5zr9J8yO7Q== +"@snapshot-labs/snapshot.js@^0.4.16": + version "0.4.16" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.16.tgz#1329e7534f3b9b7f11a70529364534cc19d904ee" + integrity sha512-ffibFOgPcne4r1g1pV8q88IyYamruvY/ThwtkPtj+2W6pxT1AlriBZRiTqbj9xHY2Oybau5ke+icZQjjRKT3mA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 3228dfd57e32442db7894d8947a9426a860abbf3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 10 Aug 2022 23:22:25 +0530 Subject: [PATCH 066/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.18 (#767) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 684cd5a60..bac873333 100755 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.16", + "@snapshot-labs/snapshot.js": "^0.4.18", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", "copyfiles": "^2.4.1", diff --git a/yarn.lock b/yarn.lock index 9d8c4cafb..8184ace68 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.16": - version "0.4.16" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.16.tgz#1329e7534f3b9b7f11a70529364534cc19d904ee" - integrity sha512-ffibFOgPcne4r1g1pV8q88IyYamruvY/ThwtkPtj+2W6pxT1AlriBZRiTqbj9xHY2Oybau5ke+icZQjjRKT3mA== +"@snapshot-labs/snapshot.js@^0.4.18": + version "0.4.18" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.18.tgz#ed1a06219780cae128878f9a002d6eabf4bf3421" + integrity sha512-C3qoXeTXEqDsEGdq3eNgJ/YTPCyBUHURKorkJnFhcar0QqB5zg99cqbkXbHNlIjZv9qBJFNWl5JomEqdmwERDw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From a67ad2af53f99cf9eacca46952e6d0e928abde4b Mon Sep 17 00:00:00 2001 From: charq <73696209+buchaoqun@users.noreply.github.com> Date: Thu, 11 Aug 2022 01:53:57 +0800 Subject: [PATCH 067/815] erc3525 flexible voucher claim coefficient updated [erc3525-flexible-voucher] (#766) * add vesting voucher strategies * vesting-voucher rename erc3525-vesting-voucher * Update src/strategies/erc3525-vesting-voucher/index.ts Co-authored-by: Chaitanya * Update src/strategies/erc3525-vesting-voucher/index.ts Co-authored-by: Chaitanya * optimization * erc3525 vesting voucher logical change * added flexible voucher strategies * erc3525 vesting voucher change amount value * restore * restore * erc3525 vesting voucher change amount take value * Restore accidentally deleted code * erc3525 vesting voucher claim coefficient updated * erc3525 flexible voucher claim coefficient updated Co-authored-by: Chaitanya --- src/strategies/erc3525-flexible-voucher/index.ts | 2 +- src/strategies/erc3525-flexible-voucher/utils.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/strategies/erc3525-flexible-voucher/index.ts b/src/strategies/erc3525-flexible-voucher/index.ts index 153d97c20..f32e4e67e 100644 --- a/src/strategies/erc3525-flexible-voucher/index.ts +++ b/src/strategies/erc3525-flexible-voucher/index.ts @@ -5,7 +5,7 @@ import { Multicaller } from '../../utils'; import { claimCoefficient, maturitiesCoefficient } from './utils'; export const author = 'buchaoqun'; -export const version = '0.1.0'; +export const version = '0.1.1'; const abi = [ 'function getSnapshot(uint256 tokenId) view returns (tuple(tuple(address issuer, uint8 claimType, uint64 startTime, uint64 latestStartTime, uint64[] terms, uint32[] percentages, bool isValid), uint256 tokenId, uint256 vestingAmount))', diff --git a/src/strategies/erc3525-flexible-voucher/utils.ts b/src/strategies/erc3525-flexible-voucher/utils.ts index 6a949a610..4dbb64212 100644 --- a/src/strategies/erc3525-flexible-voucher/utils.ts +++ b/src/strategies/erc3525-flexible-voucher/utils.ts @@ -29,9 +29,9 @@ export const maturitiesCoefficient = ( export const claimCoefficient = (claimType: number) => { if (claimType == 0) { - return 2; - } else if (claimType == 1) { return 1.2; + } else if (claimType == 1) { + return 2; } else if (claimType == 2) { return 1.5; } else { From a0084cf55dac60d598e9c05a01ecf54ce00a0363 Mon Sep 17 00:00:00 2001 From: 0xButterfield <100517047+0xButterfield@users.noreply.github.com> Date: Tue, 16 Aug 2022 08:34:35 +0200 Subject: [PATCH 068/815] feat: Add vlAURA to veBAL balanceOf strategy [aura-balance-of-vlaura-vebal] (#777) * feat: Add vlAURA to veBAL balanceOf strategy * feat: Add vlAURA to veBAL balanceOf strategy --- .../aura-balance-of-vlaura-vebal/README.md | 30 ++++++++++ .../examples.json | 20 +++++++ .../aura-balance-of-vlaura-vebal/index.ts | 58 +++++++++++++++++++ .../aura-balance-of-vlaura-vebal/schema.json | 38 ++++++++++++ src/strategies/index.ts | 2 + 5 files changed, 148 insertions(+) create mode 100644 src/strategies/aura-balance-of-vlaura-vebal/README.md create mode 100644 src/strategies/aura-balance-of-vlaura-vebal/examples.json create mode 100644 src/strategies/aura-balance-of-vlaura-vebal/index.ts create mode 100644 src/strategies/aura-balance-of-vlaura-vebal/schema.json diff --git a/src/strategies/aura-balance-of-vlaura-vebal/README.md b/src/strategies/aura-balance-of-vlaura-vebal/README.md new file mode 100644 index 000000000..aa1838dd7 --- /dev/null +++ b/src/strategies/aura-balance-of-vlaura-vebal/README.md @@ -0,0 +1,30 @@ +# aura-balance-of-vlaura-vebal + +This strategy returns proportional voting power for vlAURA holders based on system owned veBAL. + +The voting power is based on the raw balance, rather than delegated voting power. + +For example: +- there are 10000 vlAURA total supply +- a user has 2000 vlAURA (raw balance) +- Aura's voterProxy owns 100k veBAL + +In this example, the user has 20k veBAL balance as they own 20% of the vlAURA voting power. + +_Note: When depositing to the auraLocker, a user does not receive vlAURA until the next epoch has begun (Thursday at 00:00 UTC)_ + +## Params + +- `auraLocker` - (**Required**, `string`) Address of AuraLocker (vlAURA) contract +- `auraVoterProxy` - (**Required**, `string`) Address of Aura VoterProxy contract +- `votingEscrow` - (**Required**, `string`) Address of Balancer VotingEscrow contract + +Here is an example of parameters: + +```json +{ + "auraLocker": "0x3Fa73f1E5d8A792C80F426fc8F84FBF7Ce9bBCAC", + "auraVoterProxy": "0xaF52695E1bB01A16D33D7194C28C42b10e0Dbec2", + "votingEscrow": "0xC128a9954e6c874eA3d62ce62B468bA073093F25" +} +``` diff --git a/src/strategies/aura-balance-of-vlaura-vebal/examples.json b/src/strategies/aura-balance-of-vlaura-vebal/examples.json new file mode 100644 index 000000000..648742d98 --- /dev/null +++ b/src/strategies/aura-balance-of-vlaura-vebal/examples.json @@ -0,0 +1,20 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "aura-balance-of-vlaura-vebal", + "params": { + "auraLocker": "0x3Fa73f1E5d8A792C80F426fc8F84FBF7Ce9bBCAC", + "auraVoterProxy": "0xaF52695E1bB01A16D33D7194C28C42b10e0Dbec2", + "votingEscrow": "0xC128a9954e6c874eA3d62ce62B468bA073093F25" + } + }, + "network": "1", + "addresses": [ + "0x512fce9B07Ce64590849115EE6B32fd40eC0f5F3", + "0x808af82545A721C06D1FcCEbea915a6F5128BeF9", + "0x0CAd1d5ea8b4EeE26959cC00B4A3677f7A11e40F" + ], + "snapshot": 15276577 + } +] diff --git a/src/strategies/aura-balance-of-vlaura-vebal/index.ts b/src/strategies/aura-balance-of-vlaura-vebal/index.ts new file mode 100644 index 000000000..d294c271a --- /dev/null +++ b/src/strategies/aura-balance-of-vlaura-vebal/index.ts @@ -0,0 +1,58 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = '0xButterfield'; +export const version = '0.1.0'; + +const abi = [ + 'function balanceOf(address account) public view returns (uint256)', + 'function totalSupply() public view returns (uint256)' +]; + +interface Params { + auraLocker: string; + auraVoterProxy: string; + votingEscrow: string; +} + +interface Response { + vlAuraTotalSupply: BigNumber; + vlAuraBalance: Record; + veBalOwnedByAura: BigNumber; +} + +export async function strategy( + space, + network, + provider, + addresses, + options: Params, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multi = new Multicaller(network, provider, abi, { blockTag }); + multi.call('vlAuraTotalSupply', options.auraLocker, 'totalSupply', []); + addresses.forEach((address) => + multi.call(`vlAuraBalance.${address}`, options.auraLocker, 'balanceOf', [ + address + ]) + ); + multi.call('veBalOwnedByAura', options.votingEscrow, 'balanceOf', [ + options.auraVoterProxy + ]); + const res: Response = await multi.execute(); + + return Object.fromEntries( + Object.entries(res.vlAuraBalance).map(([address, balance]) => [ + address, + parseFloat( + formatUnits( + res.veBalOwnedByAura.mul(balance).div(res.vlAuraTotalSupply), + 18 + ) + ) + ]) + ); +} diff --git a/src/strategies/aura-balance-of-vlaura-vebal/schema.json b/src/strategies/aura-balance-of-vlaura-vebal/schema.json new file mode 100644 index 000000000..85b8c6d26 --- /dev/null +++ b/src/strategies/aura-balance-of-vlaura-vebal/schema.json @@ -0,0 +1,38 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "auraLocker": { + "type": "string", + "title": "auraLocker", + "examples": ["e.g. 0x3Fa73f1E5d8A792C80F426fc8F84FBF7Ce9bBCAC"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "auraVoterProxy": { + "type": "string", + "title": "auraVoterProxy", + "examples": ["e.g. 0xaF52695E1bB01A16D33D7194C28C42b10e0Dbec2"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "votingEscrow": { + "type": "string", + "title": "votingEscrow", + "examples": ["e.g. 0xC128a9954e6c874eA3d62ce62B468bA073093F25"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } + }, + "required": ["auraLocker", "auraVoterProxy", "votingEscrow"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index f4535d324..8ebc53cce 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -328,6 +328,7 @@ import * as helix from './helix'; import * as arrakisFinance from './arrakis-finance'; import * as auraFinance from './aura-vlaura-vebal'; import * as auraFinanceWithOverrides from './aura-vlaura-vebal-with-overrides'; +import * as auraBalanceOfVlauraVebal from './aura-balance-of-vlaura-vebal'; import * as rocketpoolNodeOperator from './rocketpool-node-operator'; import * as earthfundChildDaoStakingBalance from './earthfund-child-dao-staking-balance'; import * as unipilotVaultPilotBalance from './unipilot-vault-pilot-balance'; @@ -681,6 +682,7 @@ const strategies = { 'arrakis-finance': arrakisFinance, 'aura-vlaura-vebal': auraFinance, 'aura-vlaura-vebal-with-overrides': auraFinanceWithOverrides, + 'aura-balance-of-vlaura-vebal': auraBalanceOfVlauraVebal, 'rocketpool-node-operator': rocketpoolNodeOperator, 'earthfund-child-dao-staking-balance': earthfundChildDaoStakingBalance, 'sd-boost-twavp': sdBoostTWAVP, From 8f8b39f13762ea90400b278d09b51906fd131bc7 Mon Sep 17 00:00:00 2001 From: charq <73696209+buchaoqun@users.noreply.github.com> Date: Tue, 16 Aug 2022 14:51:57 +0800 Subject: [PATCH 069/815] maturities coefficient parameter type change [erc3525-flexible-voucher] (#773) * add vesting voucher strategies * vesting-voucher rename erc3525-vesting-voucher * Update src/strategies/erc3525-vesting-voucher/index.ts Co-authored-by: Chaitanya * Update src/strategies/erc3525-vesting-voucher/index.ts Co-authored-by: Chaitanya * optimization * erc3525 vesting voucher logical change * added flexible voucher strategies * erc3525 vesting voucher change amount value * restore * restore * erc3525 vesting voucher change amount take value * Restore accidentally deleted code * erc3525 vesting voucher claim coefficient updated * erc3525 flexible voucher claim coefficient updated * erc3525 flexible voucher maturities coefficient parameter type change Co-authored-by: Chaitanya --- src/strategies/erc3525-flexible-voucher/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/strategies/erc3525-flexible-voucher/index.ts b/src/strategies/erc3525-flexible-voucher/index.ts index f32e4e67e..9ab7e231d 100644 --- a/src/strategies/erc3525-flexible-voucher/index.ts +++ b/src/strategies/erc3525-flexible-voucher/index.ts @@ -5,7 +5,7 @@ import { Multicaller } from '../../utils'; import { claimCoefficient, maturitiesCoefficient } from './utils'; export const author = 'buchaoqun'; -export const version = '0.1.1'; +export const version = '0.1.2'; const abi = [ 'function getSnapshot(uint256 tokenId) view returns (tuple(tuple(address issuer, uint8 claimType, uint64 startTime, uint64 latestStartTime, uint64[] terms, uint32[] percentages, bool isValid), uint256 tokenId, uint256 vestingAmount))', @@ -87,7 +87,7 @@ export async function strategy( parseFloat(formatUnits(snapshot[2].toString(), options.decimals)) * claimCoefficient(snapshot[0][1]) * maturitiesCoefficient( - snapshot[0][2] == 0 ? snapshot[0][3] : snapshot[0][2], + snapshot[0][2] == 0 ? snapshot[0][3].toNumber() : snapshot[0][2].toNumber(), snapshot[0][4] ); walletToWeights[address] = walletToWeights[address] From 10db92eb9e9923f2bcfc43425347846fbdbac532 Mon Sep 17 00:00:00 2001 From: Justin Huang Date: Tue, 16 Aug 2022 19:47:05 +0200 Subject: [PATCH 070/815] Proxy Protocol ERC1155 [proxyprotocol-erc1155-balance-of] (#774) * Proxy Protocol ERC1155 * ABI/version number suggestions from code review Co-authored-by: Chaitanya * Call ERC1155 balance of Co-authored-by: Chaitanya --- src/strategies/index.ts | 4 +- .../README.md | 5 ++ .../examples.json | 20 ++++++ .../proxyprotocol-erc1155-balance-of/index.ts | 64 +++++++++++++++++++ 4 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 src/strategies/proxyprotocol-erc1155-balance-of/README.md create mode 100644 src/strategies/proxyprotocol-erc1155-balance-of/examples.json create mode 100644 src/strategies/proxyprotocol-erc1155-balance-of/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 8ebc53cce..744bd7bbb 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -350,6 +350,7 @@ import * as erc3525FlexibleVoucher from './erc3525-flexible-voucher'; import * as erc721PairWeights from './erc721-pair-weights'; import * as harmonyStaking from './harmony-staking'; import * as echelonCachedErc1155Decay from './echelon-cached-erc1155-decay'; +import * as proxyProtocolErc1155BalanceOf from './proxyprotocol-erc1155-balance-of'; const strategies = { 'forta-shares': fortaShares, @@ -703,7 +704,8 @@ const strategies = { 'erc721-pair-weights': erc721PairWeights, 'harmony-staking': harmonyStaking, 'echelon-cached-erc1155-decay': echelonCachedErc1155Decay, - 'erc3525-flexible-voucher': erc3525FlexibleVoucher + 'erc3525-flexible-voucher': erc3525FlexibleVoucher, + 'proxyprotocol-erc1155-balance-of': proxyProtocolErc1155BalanceOf }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/proxyprotocol-erc1155-balance-of/README.md b/src/strategies/proxyprotocol-erc1155-balance-of/README.md new file mode 100644 index 000000000..af84210fc --- /dev/null +++ b/src/strategies/proxyprotocol-erc1155-balance-of/README.md @@ -0,0 +1,5 @@ +# Proxy ERC1155 + +This allows for a Proxy wallet to map to multiple wallets owned by the user. + +You would use the exact same parameters as erc1155-balance-of, but the signing wallet is now the proxy wallet. diff --git a/src/strategies/proxyprotocol-erc1155-balance-of/examples.json b/src/strategies/proxyprotocol-erc1155-balance-of/examples.json new file mode 100644 index 000000000..dd62f2028 --- /dev/null +++ b/src/strategies/proxyprotocol-erc1155-balance-of/examples.json @@ -0,0 +1,20 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "proxyprotocol-erc1155-balance-of", + "params": { + "symbol": "ADI", + "address": "0x28472a58a490c5e09a238847f66a68a47cc76f0f", + "tokenId": "1", + "decimals": 0 + } + }, + "network": "1", + "addresses": [ + "0x346f1c338b38ef9cf18964695dd68e9956ca5d37", + "0xa164591f695b11e1c6b77925e326e20754521200" + ], + "snapshot": 15304592 + } +] diff --git a/src/strategies/proxyprotocol-erc1155-balance-of/index.ts b/src/strategies/proxyprotocol-erc1155-balance-of/index.ts new file mode 100644 index 000000000..b45aeb490 --- /dev/null +++ b/src/strategies/proxyprotocol-erc1155-balance-of/index.ts @@ -0,0 +1,64 @@ +import fetch from 'cross-fetch'; +import { strategy as erc1155BalanceOfStrategy } from '../erc1155-balance-of'; + +export const author = 'rawrjustin'; +export const version = '0.1.0'; + +const calculateVotingPower = (inputAddresses, addressScores, walletMap) => { + let userVotingPower = {}; + inputAddresses.forEach(input => { + let count = 0.0 + walletMap[input.toLowerCase()].forEach(address => { + count += addressScores[address] + }); + userVotingPower[input] = count + }); + return userVotingPower +}; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + // Get the wallet mapping from proxy wallets to actual wallets + const url = 'https://api.proxychat.xyz/external/v0/getProxyWalletMappings'; + const params = { + proxyAddresses: addresses + }; + const apiResponse = await fetch(url, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify(params) + }); + const data = await apiResponse.json(); + + // Flatten the wallet mapping so it's an array of real wallets to query for tokens + var arrayOfProxyWallets = Object.keys(data).map(function(key){ + return data[key]; + }); + var flattenedWalletAddresses = [].concat.apply([], arrayOfProxyWallets); + + // Query for token holdings + const addressScores = await erc1155BalanceOfStrategy( + space, + network, + provider, + flattenedWalletAddresses, + options, + snapshot + ); + + // Calculate the voting power across all wallets and map it back to original Proxy wallets. + return calculateVotingPower( + addresses, + addressScores, + data + ); +} From ca7190cee531e646ba8cce8199932a38f9574a40 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 16 Aug 2022 23:31:14 +0530 Subject: [PATCH 071/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.19 (#778) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index bac873333..08e7bb651 100755 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.18", + "@snapshot-labs/snapshot.js": "^0.4.19", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", "copyfiles": "^2.4.1", diff --git a/yarn.lock b/yarn.lock index 8184ace68..65e13f774 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.18": - version "0.4.18" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.18.tgz#ed1a06219780cae128878f9a002d6eabf4bf3421" - integrity sha512-C3qoXeTXEqDsEGdq3eNgJ/YTPCyBUHURKorkJnFhcar0QqB5zg99cqbkXbHNlIjZv9qBJFNWl5JomEqdmwERDw== +"@snapshot-labs/snapshot.js@^0.4.19": + version "0.4.19" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.19.tgz#e5e1b58624fcd6aff8dc954d9b6ae8b2b1ae3fd8" + integrity sha512-Wrm0AKoDhr6lYiDj32SEoVs5QxE8rZk08zz8tdM415frvHwiynMbGz47BDCPXEVESuyjM0CeVes/nIjgYyfzcA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From cbf1b5137430cdf1951df65b6956078869ad4441 Mon Sep 17 00:00:00 2001 From: Justin Huang Date: Tue, 16 Aug 2022 20:44:30 +0200 Subject: [PATCH 072/815] Proxy Protocol ERC721 [proxyprotocol-erc721-balance-of] (#775) * Proxy Protocol Erc721 * Call ERC721 balance of and change example NFT --- src/strategies/index.ts | 2 + .../proxyprotocol-erc721-balance-of/README.md | 5 ++ .../examples.json | 18 ++++++ .../proxyprotocol-erc721-balance-of/index.ts | 64 +++++++++++++++++++ .../schema.json | 28 ++++++++ 5 files changed, 117 insertions(+) create mode 100644 src/strategies/proxyprotocol-erc721-balance-of/README.md create mode 100644 src/strategies/proxyprotocol-erc721-balance-of/examples.json create mode 100644 src/strategies/proxyprotocol-erc721-balance-of/index.ts create mode 100644 src/strategies/proxyprotocol-erc721-balance-of/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 744bd7bbb..d9f96019b 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -350,6 +350,7 @@ import * as erc3525FlexibleVoucher from './erc3525-flexible-voucher'; import * as erc721PairWeights from './erc721-pair-weights'; import * as harmonyStaking from './harmony-staking'; import * as echelonCachedErc1155Decay from './echelon-cached-erc1155-decay'; +import * as proxyProtocolErc721BalanceOf from './proxyprotocol-erc721-balance-of'; import * as proxyProtocolErc1155BalanceOf from './proxyprotocol-erc1155-balance-of'; const strategies = { @@ -705,6 +706,7 @@ const strategies = { 'harmony-staking': harmonyStaking, 'echelon-cached-erc1155-decay': echelonCachedErc1155Decay, 'erc3525-flexible-voucher': erc3525FlexibleVoucher, + 'proxyprotocol-erc721-balance-of': proxyProtocolErc721BalanceOf, 'proxyprotocol-erc1155-balance-of': proxyProtocolErc1155BalanceOf }; diff --git a/src/strategies/proxyprotocol-erc721-balance-of/README.md b/src/strategies/proxyprotocol-erc721-balance-of/README.md new file mode 100644 index 000000000..bbe65e12d --- /dev/null +++ b/src/strategies/proxyprotocol-erc721-balance-of/README.md @@ -0,0 +1,5 @@ +# Proxy ERC-721 + +This allows for a Proxy wallet to map to multiple wallets owned by the user. + +You would use the exact same parameters as erc721-balance-of, but the signing wallet is now the proxy wallet. diff --git a/src/strategies/proxyprotocol-erc721-balance-of/examples.json b/src/strategies/proxyprotocol-erc721-balance-of/examples.json new file mode 100644 index 000000000..991cf3820 --- /dev/null +++ b/src/strategies/proxyprotocol-erc721-balance-of/examples.json @@ -0,0 +1,18 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "proxyprotocol-erc721-balance-of", + "params": { + "address": "0x6826c4c51f4855d0280e99f646c5ef43edb3848e", + "symbol": "TYXMK" + } + }, + "network": "1", + "addresses": [ + "0x346f1c338b38ef9cf18964695dd68e9956ca5d37", + "0xa164591f695b11e1c6b77925e326e20754521200" + ], + "snapshot": 15304592 + } +] diff --git a/src/strategies/proxyprotocol-erc721-balance-of/index.ts b/src/strategies/proxyprotocol-erc721-balance-of/index.ts new file mode 100644 index 000000000..6b369314d --- /dev/null +++ b/src/strategies/proxyprotocol-erc721-balance-of/index.ts @@ -0,0 +1,64 @@ +import fetch from 'cross-fetch'; +import { strategy as erc721BalanceOfStrategy } from '../erc721'; + +export const author = 'rawrjustin'; +export const version = '0.1.0'; + +const calculateVotingPower = (inputAddresses, addressScores, walletMap) => { + let userVotingPower = {}; + inputAddresses.forEach(input => { + let count = 0.0 + walletMap[input.toLowerCase()].forEach(address => { + count += addressScores[address] + }); + userVotingPower[input] = count + }); + return userVotingPower +}; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + // Get the wallet mapping from proxy wallets to actual wallets + const url = 'https://api.proxychat.xyz/external/v0/getProxyWalletMappings'; + const params = { + proxyAddresses: addresses + }; + const apiResponse = await fetch(url, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify(params) + }); + const data = await apiResponse.json(); + + // Flatten the wallet mapping so it's an array of real wallets to query for tokens + var arrayOfProxyWallets = Object.keys(data).map(function(key){ + return data[key]; + }); + var flattenedWalletAddresses = [].concat.apply([], arrayOfProxyWallets); + + // Query for token holdings + const addressScores = await erc721BalanceOfStrategy( + space, + network, + provider, + flattenedWalletAddresses, + options, + snapshot + ) + + // Calculate the voting power across all wallets and map it back to original Proxy wallets. + return calculateVotingPower( + addresses, + addressScores, + data + ); +} diff --git a/src/strategies/proxyprotocol-erc721-balance-of/schema.json b/src/strategies/proxyprotocol-erc721-balance-of/schema.json new file mode 100644 index 000000000..a63b9e004 --- /dev/null +++ b/src/strategies/proxyprotocol-erc721-balance-of/schema.json @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. DOODLE"], + "maxLength": 16 + }, + "address": { + "type": "string", + "title": "Contract address", + "examples": ["e.g. 0x1f9840a85d5af5bf1d1762f925bdaddc4201f984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } + }, + "required": ["address"], + "additionalProperties": false + } + } +} From a33d2a5b886a2228206f6152c1f42f3b5b22c5b7 Mon Sep 17 00:00:00 2001 From: Justin Huang Date: Tue, 16 Aug 2022 21:05:15 +0200 Subject: [PATCH 073/815] Proxy Protocol ERC20 [proxyprotocol-erc20-balance-of] (#776) * Proxy Protocol ERC20 * Call erc-20 --- src/strategies/index.ts | 2 + .../proxyprotocol-erc20-balance-of/README.md | 5 ++ .../examples.json | 19 ++++++ .../proxyprotocol-erc20-balance-of/index.ts | 64 +++++++++++++++++++ .../schema.json | 33 ++++++++++ 5 files changed, 123 insertions(+) create mode 100644 src/strategies/proxyprotocol-erc20-balance-of/README.md create mode 100644 src/strategies/proxyprotocol-erc20-balance-of/examples.json create mode 100644 src/strategies/proxyprotocol-erc20-balance-of/index.ts create mode 100644 src/strategies/proxyprotocol-erc20-balance-of/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index d9f96019b..7acc5af81 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -350,6 +350,7 @@ import * as erc3525FlexibleVoucher from './erc3525-flexible-voucher'; import * as erc721PairWeights from './erc721-pair-weights'; import * as harmonyStaking from './harmony-staking'; import * as echelonCachedErc1155Decay from './echelon-cached-erc1155-decay'; +import * as proxyProtocolErc20BalanceOf from './proxyprotocol-erc20-balance-of'; import * as proxyProtocolErc721BalanceOf from './proxyprotocol-erc721-balance-of'; import * as proxyProtocolErc1155BalanceOf from './proxyprotocol-erc1155-balance-of'; @@ -706,6 +707,7 @@ const strategies = { 'harmony-staking': harmonyStaking, 'echelon-cached-erc1155-decay': echelonCachedErc1155Decay, 'erc3525-flexible-voucher': erc3525FlexibleVoucher, + 'proxyprotocol-erc20-balance-of': proxyProtocolErc20BalanceOf, 'proxyprotocol-erc721-balance-of': proxyProtocolErc721BalanceOf, 'proxyprotocol-erc1155-balance-of': proxyProtocolErc1155BalanceOf }; diff --git a/src/strategies/proxyprotocol-erc20-balance-of/README.md b/src/strategies/proxyprotocol-erc20-balance-of/README.md new file mode 100644 index 000000000..12ea50a13 --- /dev/null +++ b/src/strategies/proxyprotocol-erc20-balance-of/README.md @@ -0,0 +1,5 @@ +# Proxy ERC-20 + +This allows for a Proxy wallet to map to multiple wallets owned by the user. + +You would use the exact same parameters as erc20-balance-of, but the signing wallet is now the proxy wallet. diff --git a/src/strategies/proxyprotocol-erc20-balance-of/examples.json b/src/strategies/proxyprotocol-erc20-balance-of/examples.json new file mode 100644 index 000000000..89db17a96 --- /dev/null +++ b/src/strategies/proxyprotocol-erc20-balance-of/examples.json @@ -0,0 +1,19 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "proxyprotocol-erc20-balance-of", + "params": { + "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "symbol": "WETH", + "decimals": 18 + } + }, + "network": "1", + "addresses": [ + "0x346f1c338b38ef9cf18964695dd68e9956ca5d37", + "0xa164591f695b11e1c6b77925e326e20754521200" + ], + "snapshot": 15304592 + } +] diff --git a/src/strategies/proxyprotocol-erc20-balance-of/index.ts b/src/strategies/proxyprotocol-erc20-balance-of/index.ts new file mode 100644 index 000000000..d522a15b8 --- /dev/null +++ b/src/strategies/proxyprotocol-erc20-balance-of/index.ts @@ -0,0 +1,64 @@ +import fetch from 'cross-fetch'; +import { strategy as erc20BalanceOfStrategy } from '../erc20-balance-of'; + +export const author = 'rawrjustin'; +export const version = '0.1.0'; + +const calculateVotingPower = (inputAddresses, addressScores, walletMap) => { + let userVotingPower = {}; + inputAddresses.forEach(input => { + let count = 0.0 + walletMap[input.toLowerCase()].forEach(address => { + count += addressScores[address] + }); + userVotingPower[input] = count + }); + return userVotingPower +}; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + // Get the wallet mapping from proxy wallets to actual wallets + const url = 'https://api.proxychat.xyz/external/v0/getProxyWalletMappings'; + const params = { + proxyAddresses: addresses + }; + const response = await fetch(url, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify(params) + }); + const data = await response.json(); + + // Flatten the wallet mapping so it's an array of real wallets to query for tokens + var arrayOfProxyWallets = Object.keys(data).map(function(key){ + return data[key]; + }); + var flattenedWalletAddresses = [].concat.apply([], arrayOfProxyWallets); + + // Query for token holdings + const addressScores = await erc20BalanceOfStrategy( + space, + network, + provider, + flattenedWalletAddresses, + options, + snapshot + ) + + // Calculate the voting power across all wallets and map it back to original Proxy wallets. + return calculateVotingPower( + addresses, + addressScores, + data + ); +} diff --git a/src/strategies/proxyprotocol-erc20-balance-of/schema.json b/src/strategies/proxyprotocol-erc20-balance-of/schema.json new file mode 100644 index 000000000..2113da8b8 --- /dev/null +++ b/src/strategies/proxyprotocol-erc20-balance-of/schema.json @@ -0,0 +1,33 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. UNI"], + "maxLength": 16 + }, + "address": { + "type": "string", + "title": "Contract address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 18"] + } + }, + "required": ["address", "decimals"], + "additionalProperties": false + } + } +} From dba3bed6a9c0196a1f16566939462b00e56f01bf Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Wed, 17 Aug 2022 00:48:33 +0530 Subject: [PATCH 074/815] Remove delegation.json (#779) --- src/utils/delegations.json | 9 --------- src/utils/vp.ts | 2 +- test/__snapshots__/vp.test.ts.snap | 4 ++-- test/vp.test.ts | 2 +- 4 files changed, 4 insertions(+), 13 deletions(-) delete mode 100644 src/utils/delegations.json diff --git a/src/utils/delegations.json b/src/utils/delegations.json deleted file mode 100644 index 545cfb58e..000000000 --- a/src/utils/delegations.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "1": "https://gateway.thegraph.com/api/0f15b42bdeff7a063a4e1757d7e2f99e/deployments/id/QmXvEzRJXby7KFuTr7NJsM47hGefM5VckEXZrQyZzL9eJd", - "4": "https://api.thegraph.com/subgraphs/name/snapshot-labs/snapshot-rinkeby", - "42": "https://api.thegraph.com/subgraphs/name/snapshot-labs/snapshot-kovan", - "56": "https://api.thegraph.com/subgraphs/name/snapshot-labs/snapshot-binance-smart-chain", - "100": "https://api.thegraph.com/subgraphs/name/snapshot-labs/snapshot-gnosis-chain", - "137": "https://api.thegraph.com/subgraphs/name/snapshot-labs/snapshot-polygon", - "250": "https://api.thegraph.com/subgraphs/name/snapshot-labs/snapshot-fantom" -} diff --git a/src/utils/vp.ts b/src/utils/vp.ts index 404d4f65d..ad61e31da 100644 --- a/src/utils/vp.ts +++ b/src/utils/vp.ts @@ -7,7 +7,7 @@ import { subgraphRequest } from '../utils'; import _strategies from '../strategies'; -import subgraphs from './delegations.json'; +import subgraphs from '@snapshot-labs/snapshot.js/src/delegationSubgraphs.json'; const DELEGATION_CONTRACT = '0x469788fE6E9E9681C6ebF3bF78e7Fd26Fc015446'; const EMPTY_ADDRESS = '0x0000000000000000000000000000000000000000'; diff --git a/test/__snapshots__/vp.test.ts.snap b/test/__snapshots__/vp.test.ts.snap index 25b20c6de..80a296baa 100644 --- a/test/__snapshots__/vp.test.ts.snap +++ b/test/__snapshots__/vp.test.ts.snap @@ -15,11 +15,11 @@ Object { exports[` getVp without delegation 1`] = ` Object { - "vp": 20.491128299590727, + "vp": 21.55404462002206, "vp_by_strategy": Array [ 0, 9.998985610441185, - 10.443718706159482, + 11.506635026590818, 0.04842398299005922, ], "vp_state": "final", diff --git a/test/vp.test.ts b/test/vp.test.ts index 000e48147..205a3d91c 100644 --- a/test/vp.test.ts +++ b/test/vp.test.ts @@ -3,7 +3,7 @@ import { getVp } from '../src/utils/vp'; const address = '0xeF8305E140ac520225DAf050e2f71d5fBcC543e7'; const space = 'cvx.eth'; const network = '1'; -const snapshot = 15109700; +const snapshot = 15354134; const strategies = [ { name: 'erc20-balance-of', From 17f214f72446e78b2280a2702d944be8d7a6cad1 Mon Sep 17 00:00:00 2001 From: Fabien Date: Thu, 18 Aug 2022 00:23:44 +0700 Subject: [PATCH 075/815] Add validations strategies (#772) * Add getVp and getDelegations functions * Update dependencies * Export functions getVp and getDelegations * Remove unused file * Add validations strategies * Add test for validation * Add pkg script for validation test --- package.json | 1 + src/index.ts | 2 + src/validations/aave/examples.json | 107 +++++++++++++++++++++ src/validations/aave/index.ts | 55 +++++++++++ src/validations/basic/examples.json | 11 +++ src/validations/basic/index.ts | 33 +++++++ src/validations/index.ts | 11 +++ src/validations/nouns/examples.json | 50 ++++++++++ src/validations/nouns/index.ts | 52 ++++++++++ src/validations/timeperiod/examples.json | 14 +++ src/validations/timeperiod/index.ts | 26 +++++ test/__snapshots__/validation.test.ts.snap | 3 + test/validation.test.ts | 20 ++++ 13 files changed, 385 insertions(+) create mode 100644 src/validations/aave/examples.json create mode 100644 src/validations/aave/index.ts create mode 100644 src/validations/basic/examples.json create mode 100644 src/validations/basic/index.ts create mode 100644 src/validations/index.ts create mode 100644 src/validations/nouns/examples.json create mode 100644 src/validations/nouns/index.ts create mode 100644 src/validations/timeperiod/examples.json create mode 100644 src/validations/timeperiod/index.ts create mode 100644 test/__snapshots__/validation.test.ts.snap create mode 100644 test/validation.test.ts diff --git a/package.json b/package.json index 08e7bb651..7fb709e89 100755 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "test": "jest -i strategy.test.ts", "test:vp": "jest -i vp.test.ts", "test:delegation": "jest -i delegation.test.ts", + "test:validation": "jest -i validation.test.ts", "prepublishOnly": "npm run build", "postinstall": "npm run build", "postbuild": "copyfiles -u 1 \"src/**/*.md\" dist/ && copyfiles -u 1 \"src/**/*.json\" dist/", diff --git a/src/index.ts b/src/index.ts index 020b86563..f12e35b07 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,9 @@ import strategies from './strategies'; +import validations from './validations'; import utils from './utils'; export default { strategies, + validations, utils }; diff --git a/src/validations/aave/examples.json b/src/validations/aave/examples.json new file mode 100644 index 000000000..4a1322ec2 --- /dev/null +++ b/src/validations/aave/examples.json @@ -0,0 +1,107 @@ +[ + { + "name": "Example of Aave Proposition Power proposal validation", + "validation": { + "name": "aave", + "params": {} + }, + "network": "1", + "userAddress": "0x5BC928BF0DAb1e4A2ddd9e347b0F22e88026D76c", + "space": { + "name": "Aave", + "skin": "aave", + "admins": [ + "0x8d07D225a769b7Af3A923481E1FdF49180e6A265", + "0xc8E0345596D7196941E61D3aB607E57Fe61F85E7" + ], + "avatar": "ipfs://QmRKgfxSiCU3EmkN52ZaxgKvDyPFUR5DdPvnKxwyLRncKS", + "domain": "signal.aave.com", + "github": "aave", + "symbol": "AAVE", + "filters": { + "minScore": 1, + "onlyMembers": false + }, + "members": [], + "network": "1", + "plugins": {}, + "twitter": "AaveAave", + "strategies": [ + { + "name": "erc20-balance-of", + "params": { + "symbol": "aAAVE", + "address": "0xffc97d72e13e01096502cb8eb52dee56f74dad7b", + "decimals": 18 + } + }, + { + "name": "aave-governance-power", + "params": { + "symbol": "AAVE+stkAAVE", + "decimals": 18, + "powerType": "vote", + "governanceStrategy": "0xb7e383ef9b1e9189fc0f71fb30af8aa14377429e" + } + }, + { + "name": "multichain", + "params": { + "graphs": { + "137": "https://api.thegraph.com/subgraphs/name/sameepsi/maticblocks" + }, + "symbol": "Matic AAVE+amAAVE", + "strategies": [ + { + "name": "erc20-balance-of", + "params": { + "symbol": "AAVE", + "address": "0xD6DF932A45C0f255f85145f286eA0b292B21C90B", + "decimals": 18 + }, + "network": "137" + }, + { + "name": "erc20-balance-of", + "params": { + "symbol": "amAAVE", + "address": "0x1d2a0E5EC8E5bBDCA5CB219e649B565d8e5c3360", + "decimals": 18 + }, + "network": 137 + } + ] + } + }, + { + "name": "contract-call", + "params": { + "args": ["%{address}"], + "symbol": "AAVE in stkBPT", + "address": "0xC0259c59D9f980E3b5e2574cD78C9A9Bc6A8E3fc", + "decimals": 18, + "methodABI": { + "name": "balanceOf", + "type": "function", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + } + } + } + ] + } + } +] diff --git a/src/validations/aave/index.ts b/src/validations/aave/index.ts new file mode 100644 index 000000000..8408a2bdf --- /dev/null +++ b/src/validations/aave/index.ts @@ -0,0 +1,55 @@ +import { getProvider, getScoresDirect } from '../../utils'; + +export const author = 'kartojal'; +export const version = '0.1.0'; + +/** + * Aave Space Validation proposal validation uses: + * - Proposition power of GovernanceStrategy contract + * - Other active Aave Snapshot voting strategies + * + * The current validation implementation mutates the "strategies" field of the space + * to be able to use proposition power instead of voting power for "aave-governance-power". + * + */ + +export default async function validate( + author: string, + space, + proposal, + options +): Promise { + const onlyMembers = options.onlyMembers || space.filters?.onlyMembers; + const minScore = options.minScore || space.filters?.minScore; + const members = (space.members || []).map((address) => address.toLowerCase()); + const strategies = [...space.strategies]; + + const aaveGovernanceStrategyIndex = strategies.findIndex( + ({ name }) => name === 'aave-governance-power' + ); + + // Use the proposition power instead of voting power + if (aaveGovernanceStrategyIndex >= 0) { + strategies[aaveGovernanceStrategyIndex].params.powerType = 'proposition'; + } + + if (members.includes(author.toLowerCase())) return true; + + if (onlyMembers) return false; + + if (minScore) { + const scores = await getScoresDirect( + space.id || space.key, + strategies, + space.network, + getProvider(space.network), + [author] + ); + const totalScore: any = scores + .map((score: any) => Object.values(score).reduce((a, b: any) => a + b, 0)) + .reduce((a, b: any) => a + b, 0); + if (totalScore < minScore) return false; + } + + return true; +} diff --git a/src/validations/basic/examples.json b/src/validations/basic/examples.json new file mode 100644 index 000000000..0dcf2b063 --- /dev/null +++ b/src/validations/basic/examples.json @@ -0,0 +1,11 @@ +[ + { + "name": "Example of a basic proposal validation", + "validation": { + "name": "basic", + "params": {} + }, + "network": "1", + "userAddress": "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7" + } +] diff --git a/src/validations/basic/index.ts b/src/validations/basic/index.ts new file mode 100644 index 000000000..92104f866 --- /dev/null +++ b/src/validations/basic/index.ts @@ -0,0 +1,33 @@ +import { getProvider, getScoresDirect } from '../../utils'; + +export default async function validate( + author: string, + space, + proposal, + options +): Promise { + const strategies = options.strategies || space.strategies; + const onlyMembers = options.onlyMembers || space.filters?.onlyMembers; + const minScore = options.minScore || space.filters?.minScore; + const members = (space.members || []).map((address) => address.toLowerCase()); + + if (members.includes(author.toLowerCase())) return true; + + if (onlyMembers) return false; + + if (minScore) { + const scores = await getScoresDirect( + space.id || space.key, + strategies, + space.network, + getProvider(space.network), + [author] + ); + const totalScore: any = scores + .map((score: any) => Object.values(score).reduce((a, b: any) => a + b, 0)) + .reduce((a, b: any) => a + b, 0); + if (totalScore < minScore) return false; + } + + return true; +} diff --git a/src/validations/index.ts b/src/validations/index.ts new file mode 100644 index 000000000..419465fb8 --- /dev/null +++ b/src/validations/index.ts @@ -0,0 +1,11 @@ +import basic from './basic'; +import aave from './aave'; +import nouns from './nouns'; +import timeperiod from './timeperiod'; + +export default { + basic, + aave, + nouns, + timeperiod +}; diff --git a/src/validations/nouns/examples.json b/src/validations/nouns/examples.json new file mode 100644 index 000000000..0e9a3c96d --- /dev/null +++ b/src/validations/nouns/examples.json @@ -0,0 +1,50 @@ +[ + { + "name": "Example of Nouns Proposition Power proposal validation", + "validation": { + "name": "nouns", + "params": {} + }, + "network": "4", + "userAddress": "0x03CD30Ab7b6eFaDfdc5D49Ec2B83DDD6a898e054", + "space": { + "name": "Nouns", + "skin": "nouns", + "admins": [ + "0xe6bcaacdca149114446612255cc4721bf7261b5b", + "0xC4D2f3231879A26A2cAB5F1783D8a65f6B7191bE" + ], + "avatar": "ipfs://QmRKdsssCU3EmkN52ZaxgKvDyPFUR5DdPvnKxwyLRncKS", + "domain": "signal.nouns.com", + "github": "nouns", + "symbol": "NOUNS", + "filters": { + "minScore": 1, + "onlyMembers": false + }, + "members": [], + "network": "4", + "plugins": {}, + "twitter": "NounishNounlet", + "strategies": [ + { + "name": "erc20-balance-of", + "params": { + "symbol": "LINK", + "address": "0x01BE23585060835E02B77ef475b0Cc51aA1e0709", + "decimals": 18 + } + }, + { + "name": "nouns-rfp-power", + "params": { + "symbol": "NOUNS", + "decimals": 1, + "powerType": "vote", + "governanceStrategy": "0x50Acc1831E954fB5bB407d7A3CFe1e7769A41ab0" + } + } + ] + } + } +] diff --git a/src/validations/nouns/index.ts b/src/validations/nouns/index.ts new file mode 100644 index 000000000..df395cf23 --- /dev/null +++ b/src/validations/nouns/index.ts @@ -0,0 +1,52 @@ +import { getProvider, getScoresDirect } from '../../utils'; + +export const author = 'waterdrops'; +export const version = '0.1.0'; + +/** + * Nouns Space Validation proposal validation uses: + * + * The current validation implementation mutates the "strategies" field of the space + * to be able to use proposition power instead of voting power for "nouns-rfp-power". + * + */ + +export default async function validate( + author: string, + space, + proposal, + options +): Promise { + const onlyMembers = options.onlyMembers || space.filters?.onlyMembers; + const minScore = options.minScore || space.filters?.minScore; + const members = (space.members || []).map((address) => address.toLowerCase()); + const strategies = [...space.strategies]; + + const nounsRFPStrategyIndex = strategies.findIndex( + ({ name }) => name === 'nouns-rfp-power' + ); + + // Use the proposition power instead of the voting power + if (nounsRFPStrategyIndex >= 0) + strategies[nounsRFPStrategyIndex].params.powerType = 'proposition'; + + if (members.includes(author.toLowerCase())) return true; + + if (onlyMembers) return false; + + if (minScore) { + const scores = await getScoresDirect( + space.id || space.key, + strategies, + space.network, + getProvider(space.network), + [author] + ); + const totalScore: any = scores + .map((score: any) => Object.values(score).reduce((a, b: any) => a + b, 0)) + .reduce((a, b: any) => a + b, 0); + if (totalScore < minScore) return false; + } + + return true; +} diff --git a/src/validations/timeperiod/examples.json b/src/validations/timeperiod/examples.json new file mode 100644 index 000000000..02381e38e --- /dev/null +++ b/src/validations/timeperiod/examples.json @@ -0,0 +1,14 @@ +[ + { + "name": "Example of a prop entry time constrained validation", + "validation": { + "name": "timeperiod", + "params": { + "propEntryStart": 1659108444521, + "propEntryEnd": 1659194844521 + } + }, + "network": "1", + "userAddress": "" + } +] diff --git a/src/validations/timeperiod/index.ts b/src/validations/timeperiod/index.ts new file mode 100644 index 000000000..91f69e86d --- /dev/null +++ b/src/validations/timeperiod/index.ts @@ -0,0 +1,26 @@ +export default async function validate( + author: string, + space, + proposal, + options +): Promise { + const onlyMembers = options.onlyMembers || space.filters?.onlyMembers; + const members = (space.members || []).map((address) => address.toLowerCase()); + const { propEntryStart = 0, propEntryEnd = 0 } = options; + + if (!propEntryStart || !propEntryEnd || propEntryStart >= propEntryEnd) + return false; + + if (members.includes(author.toLowerCase())) return true; + + if (onlyMembers) return false; + + const now = new Date().getTime(); + const startTime = new Date(propEntryStart).getTime(); + const endTime = new Date(propEntryEnd).getTime(); + + // Only allow proposals being submitted in this time window. + if (now >= startTime && now <= endTime) return true; + + return false; +} diff --git a/test/__snapshots__/validation.test.ts.snap b/test/__snapshots__/validation.test.ts.snap new file mode 100644 index 000000000..1aed0f601 --- /dev/null +++ b/test/__snapshots__/validation.test.ts.snap @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` validation 1`] = `true`; diff --git a/test/validation.test.ts b/test/validation.test.ts new file mode 100644 index 000000000..1a5729717 --- /dev/null +++ b/test/validation.test.ts @@ -0,0 +1,20 @@ +import snapshot from '../src'; +import examples from '../src/validations/aave/examples.json'; + +const name = examples[0].validation.name; +const params = examples[0].validation.params || {}; +const author = examples[0].userAddress; +const space = examples[0].space; +const proposal = {}; + +describe('', () => { + it('validation', async () => { + const validation = await snapshot.validations[name]( + author, + space, + proposal, + params + ); + expect(validation).toMatchSnapshot(); + }, 20e3); +}); From 84e24bf97ef4954adde16f55b6b69e7c43154fae Mon Sep 17 00:00:00 2001 From: sirpy Date: Thu, 18 Aug 2022 11:21:42 +0300 Subject: [PATCH 076/815] [gooddollar-multichain] New strategy (#683) * feat:multichain-max strategy * feat: math strategy to support multichains * add: limit to 1,122 and two strategies * Revert "feat: math strategy to support multichains" This reverts commit 77bb89acfe0fdb99211c0ab637b16a5e9160fb5b. * fix: index * add: apply code review changes * fix: index * fix: index * fix: lint --- .../gooddollar-multichain/README.md | 73 ++++++++++++++++++ .../gooddollar-multichain/examples.json | 75 +++++++++++++++++++ src/strategies/gooddollar-multichain/index.ts | 57 ++++++++++++++ src/strategies/index.ts | 2 + 4 files changed, 207 insertions(+) create mode 100644 src/strategies/gooddollar-multichain/README.md create mode 100644 src/strategies/gooddollar-multichain/examples.json create mode 100644 src/strategies/gooddollar-multichain/index.ts diff --git a/src/strategies/gooddollar-multichain/README.md b/src/strategies/gooddollar-multichain/README.md new file mode 100644 index 000000000..47658c503 --- /dev/null +++ b/src/strategies/gooddollar-multichain/README.md @@ -0,0 +1,73 @@ +# max eth fuse + +** This strategy is limited to networks 1 and 122 and allows at most 2 sub strategies** + +This is similar to the multichain strategy only that it chooses the chain with max voting power. + +Here is an example of parameters: + +In the below example, the tokens on etherem and fuse are queried and the max value denotes the voting power + +```json +{ + "symbol": "GOOD", + "strategies": [ + { + "name": "contract-call", + "network": "122", + "params": { + "symbol": "GOOD", + "address": "0x603b8c0f110e037b51a381cbcacabb8d6c6e4543", + "decimals": 18, + "methodABI": { + "name": "getVotes", + "type": "function", + "inputs": [ + { + "name": "voter", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + } + } + }, + { + "name": "contract-call", + "network": "1", + "params": { + "symbol": "GOOD", + "address": "0x603b8c0f110e037b51a381cbcacabb8d6c6e4543", + "decimals": 18, + "methodABI": { + "name": "getVotes", + "type": "function", + "inputs": [ + { + "name": "voter", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + } + } + } + ] +} +``` diff --git a/src/strategies/gooddollar-multichain/examples.json b/src/strategies/gooddollar-multichain/examples.json new file mode 100644 index 000000000..c047a1c90 --- /dev/null +++ b/src/strategies/gooddollar-multichain/examples.json @@ -0,0 +1,75 @@ +[ + { + "name": "GoodDolalr Multichain", + "strategy": { + "name": "gooddollar-multichain", + "params": { + "symbol": "GOOD", + "strategies": [ + { + "name": "contract-call", + "network": "122", + "params": { + "symbol": "GOOD", + "address": "0x603b8c0f110e037b51a381cbcacabb8d6c6e4543", + "decimals": 18, + "methodABI": { + "name": "getVotes", + "type": "function", + "inputs": [ + { + "name": "voter", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + } + } + }, + { + "name": "contract-call", + "network": "1", + "params": { + "symbol": "GOOD", + "address": "0x603b8c0f110e037b51a381cbcacabb8d6c6e4543", + "decimals": 18, + "methodABI": { + "name": "getVotes", + "type": "function", + "inputs": [ + { + "name": "voter", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + } + } + } + ] + } + }, + "network": "1", + "addresses": [ + "0x66582D24FEaD72555adaC681Cc621caCbB208324", + "0xA48840D89a761502A4a7d995c74f3864D651A87F" + ], + "snapshot": 15000000 + } +] \ No newline at end of file diff --git a/src/strategies/gooddollar-multichain/index.ts b/src/strategies/gooddollar-multichain/index.ts new file mode 100644 index 000000000..649642f46 --- /dev/null +++ b/src/strategies/gooddollar-multichain/index.ts @@ -0,0 +1,57 @@ +import { getProvider, getSnapshots } from '../../utils'; +import strategies from '..'; + +export const author = 'sirpy'; +export const version = '1.0.0'; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const promises: any = []; + const validStrategies = options.strategies + .filter((s) => s.network === '122' || s.network === '1') + .slice(0, 2); + const blocks = await getSnapshots( + network, + snapshot, + provider, + validStrategies.map((s) => s.network || network) + ); + + for (const strategy of validStrategies) { + // If snapshot is taken before a network is activated then ignore its strategies + if ( + options.startBlocks && + blocks[strategy.network] < options.startBlocks[strategy.network] + ) { + continue; + } + + promises.push( + strategies[strategy.name].strategy( + space, + strategy.network, + getProvider(strategy.network), + addresses, + strategy.params, + blocks[strategy.network] + ) + ); + } + + const results = await Promise.all(promises); + return results.reduce((finalResults: any, strategyResult: any) => { + for (const [address, value] of Object.entries(strategyResult)) { + if (!finalResults[address]) { + finalResults[address] = 0; + } + finalResults[address] = Math.max(finalResults[address], value as number); + } + return finalResults; + }, {}); +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 7acc5af81..d5ce3f6da 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -40,6 +40,7 @@ import * as ethBalance from './eth-balance'; import * as ethWithBalance from './eth-with-balance'; import * as ethWalletAge from './eth-wallet-age'; import * as multichain from './multichain'; +import * as gooddollarMultichain from './gooddollar-multichain'; import * as makerDsChief from './maker-ds-chief'; import * as uni from './uni'; import * as yearnVault from './yearn-vault'; @@ -419,6 +420,7 @@ const strategies = { 'erc1155-balance-of-cv': erc1155BalanceOfCv, 'prepo-vesting': prepoVesting, multichain, + 'gooddollar-multichain': gooddollarMultichain, uni, 'frax-finance': fraxFinance, 'yearn-vault': yearnVault, From f048b69a94228bb887e299e04fd0aca45cc112c2 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Thu, 18 Aug 2022 14:04:25 +0530 Subject: [PATCH 077/815] Update multichain documentation (#780) * Remove block subgraph documentation from multichain Readme * Update --- src/strategies/multichain/README.md | 86 +---------------------------- 1 file changed, 3 insertions(+), 83 deletions(-) diff --git a/src/strategies/multichain/README.md b/src/strategies/multichain/README.md index f9cd6f934..2cfec8c9a 100644 --- a/src/strategies/multichain/README.md +++ b/src/strategies/multichain/README.md @@ -4,43 +4,11 @@ If you want to calculate the balance from various chains like Ethereum, Binance In multichain strategy, the params should define sub strategies which would use different networks mentioned in the field to combine the voting power. -In order to provide multichain functionality, this strategy requires a way for calculating which block number should be used on additional chains: If a snapshot was created on block 125 on mainnet, it needs to find the timestamp for that block and go find which block number corresponds to that same timestamp on every other wanted chain. This way it can accurately represent an address' voting power at a given point in time. In order to do this, it supports 2 different mechanisms: - -- [DEFAULT] Querying a block subgraph. If a working block info subgraph is found for that chain, it can be passed into the strategy's options in the "graphs" object. This will allow the strategy to query that subgraph for the given chain and fetch the block number from there. An example of a graphs object could be: -```json - "graphs": { - "56": "https://api.thegraph.com/subgraphs/name/apyvision/block-info", - "137": "https://api.thegraph.com/subgraphs/name/sameepsi/maticblocks" - } - ``` - -- Integrating with a custom API (overrides subgraph option if present). TheGraph doesn't support every existing chains on their hosting services, therefor finding a subgraph for them can be challenging without launching and maintaining an independant graph-node. This option comes in as an alternative for developers who wish to integrate even on chains without a subgraph. In order to integrate an API must be created to fulfill the block fetching functionality on every chain that wants to be supported. A single HTTP receiving a timestamp should return the block number for every desired chain. -The setting that should be set is `blockApi` and it should be an url pointing to an endpoint that: - - Supports GET calls passing timestamp as a query parameter. (Ex: If blockApi is "https://myCustomApi.com/blocks", it should support a GET to https://myCustomApi.com/blocks?timestamp=xxxxxx) - - Return a json object containing at least 1 key named "blocks" with a map from chainId to block number for *every chain* desired. An example of a valid api response could be: -```json - { - "timestamp":"1640185827", - "blocks":{ - "25":678246, - "56":13700191, - "128":11097265, - "137":22832200, - "250":25715540, - "1285":1141104, - "42161":4021906, - "42220":10521555, - "43114":8573779, - "1666600000":20812976 - } - } -``` - +In order to provide multichain functionality, this strategy provides a way to calculate which block number should be used on additional chains: If a snapshot was created on block 125 on mainnet, it will find the timestamp for that block and go find which block number corresponds to that same timestamp on every other wanted chain. This way it can accurately represent an address' voting power at a given point in time. Here is an example of parameters: -In the below example, the tokens on the three networks namely ethereum, polygon and bsc denotes combined voting power and block numbers on each chain are searched from a subgraph query. - +In the below example, the tokens on the three networks namely ethereum, polygon and bsc denotes combined voting power ```json { @@ -78,55 +46,7 @@ In the below example, the tokens on the three networks namely ethereum, polygon "decimals": 18 } } - ], - "graphs": { - "56": "https://api.thegraph.com/subgraphs/name/apyvision/block-info", - "137": "https://api.thegraph.com/subgraphs/name/sameepsi/maticblocks" - } + ] } ``` - -In the below example, the custom API block fetching alternative is used. Note that the api url isn't a working one and should be replaced - - -```json -{ - "symbol": "MULTI", - "strategies": [ - { - "name": "erc20-balance-of", - "network": "1", - "params": { - "address": "0x579cea1889991f68acc35ff5c3dd0621ff29b0c9", - "decimals": 18 - } - }, - { - "name": "erc20-balance-of", - "network": "137", - "params": { - "address": "0xB9638272aD6998708de56BBC0A290a1dE534a578", - "decimals": 18 - } - }, - { - "name": "erc20-balance-of", - "network": "56", - "params": { - "address": "0x0e37d70b51ffa2b98b4d34a5712c5291115464e3", - "decimals": 18 - } - }, - { - "name": "erc20-balance-of", - "network": 137, - "params": { - "address": "0xfC0fA725E8fB4D87c38EcE56e8852258219C64Ee", - "decimals": 18 - } - } - ], - "blockApi": "https://api.custom/blocks" -} -``` \ No newline at end of file From 6430e277335f57a6db24fc93905e31cd4ec7b35e Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Thu, 18 Aug 2022 16:01:52 +0530 Subject: [PATCH 078/815] [orca-pod] Orca pods strategy (#770) * [orca-pods] Orca pods strategy * Rename and fixes --- src/strategies/index.ts | 2 ++ src/strategies/orca-pod/README.md | 20 ++++++++++++++++++ src/strategies/orca-pod/examples.json | 16 ++++++++++++++ src/strategies/orca-pod/index.ts | 28 +++++++++++++++++++++++++ src/strategies/orca-pod/schema.json | 30 +++++++++++++++++++++++++++ 5 files changed, 96 insertions(+) create mode 100644 src/strategies/orca-pod/README.md create mode 100644 src/strategies/orca-pod/examples.json create mode 100644 src/strategies/orca-pod/index.ts create mode 100644 src/strategies/orca-pod/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index d5ce3f6da..6e724433e 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -351,6 +351,7 @@ import * as erc3525FlexibleVoucher from './erc3525-flexible-voucher'; import * as erc721PairWeights from './erc721-pair-weights'; import * as harmonyStaking from './harmony-staking'; import * as echelonCachedErc1155Decay from './echelon-cached-erc1155-decay'; +import * as orcaPod from './orca-pod'; import * as proxyProtocolErc20BalanceOf from './proxyprotocol-erc20-balance-of'; import * as proxyProtocolErc721BalanceOf from './proxyprotocol-erc721-balance-of'; import * as proxyProtocolErc1155BalanceOf from './proxyprotocol-erc1155-balance-of'; @@ -709,6 +710,7 @@ const strategies = { 'harmony-staking': harmonyStaking, 'echelon-cached-erc1155-decay': echelonCachedErc1155Decay, 'erc3525-flexible-voucher': erc3525FlexibleVoucher, + 'orca-pod': orcaPod, 'proxyprotocol-erc20-balance-of': proxyProtocolErc20BalanceOf, 'proxyprotocol-erc721-balance-of': proxyProtocolErc721BalanceOf, 'proxyprotocol-erc1155-balance-of': proxyProtocolErc1155BalanceOf diff --git a/src/strategies/orca-pod/README.md b/src/strategies/orca-pod/README.md new file mode 100644 index 000000000..02b3f5be2 --- /dev/null +++ b/src/strategies/orca-pod/README.md @@ -0,0 +1,20 @@ +# orca-pod + +This strategy give 1 voting power for each holder of a specific tokenId of orca's ERC1155 + +## Parameters + +| Param Name | Description | +| ----------- | ----------- | +| id | TokenId of the pod | +| weight (optional) | Multiplier of the voting power - Default is `1` | + +Here is an example of the parameters: + +```json +{ + "symbol": "ORCA", + "id": "1", + "weight": 100 +} +``` diff --git a/src/strategies/orca-pod/examples.json b/src/strategies/orca-pod/examples.json new file mode 100644 index 000000000..106705a21 --- /dev/null +++ b/src/strategies/orca-pod/examples.json @@ -0,0 +1,16 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "orca-pod", + "params": { + "symbol": "ORCA", + "id": "1", + "weight": 100 + } + }, + "network": "1", + "addresses": ["0x094a473985464098b59660b37162a284b5132753"], + "snapshot": 15188155 + } +] diff --git a/src/strategies/orca-pod/index.ts b/src/strategies/orca-pod/index.ts new file mode 100644 index 000000000..d8320488e --- /dev/null +++ b/src/strategies/orca-pod/index.ts @@ -0,0 +1,28 @@ +import { strategy as erc1155BalanceOfIdsWeightedStrategy } from '../erc1155-balance-of-ids-weighted'; + +export const author = 'snapshot-labs'; +export const version = '0.1.0'; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const score = await erc1155BalanceOfIdsWeightedStrategy( + space, + network, + provider, + addresses, + { + address: '0x0762aa185b6ed2dca77945ebe92de705e0c37ae3', + ids: [options.id], + weight: parseFloat(options.weight || 1) + }, + snapshot + ); + + return Object.fromEntries(Object.entries(score).map((a) => [a[0], a[1]])); +} diff --git a/src/strategies/orca-pod/schema.json b/src/strategies/orca-pod/schema.json new file mode 100644 index 000000000..5c3787a45 --- /dev/null +++ b/src/strategies/orca-pod/schema.json @@ -0,0 +1,30 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. ORCA"], + "maxLength": 16 + }, + "id": { + "type": "string", + "title": "Token id", + "examples": ["1"] + }, + "weight": { + "type": "number", + "title": "Weight", + "examples": ["e.g. 100"] + } + }, + "required": ["id"], + "additionalProperties": false + } + } +} From 9c1fa32fb0366684b090f6ab521090aa3648b761 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 18 Aug 2022 16:04:42 +0530 Subject: [PATCH 079/815] Automated lint (#781) Co-authored-by: ChaituVR --- .../erc3525-flexible-voucher/index.ts | 4 ++- .../gooddollar-multichain/examples.json | 2 +- .../proxyprotocol-erc1155-balance-of/index.ts | 24 +++++++---------- .../proxyprotocol-erc20-balance-of/index.ts | 26 ++++++++----------- .../proxyprotocol-erc721-balance-of/index.ts | 26 ++++++++----------- 5 files changed, 36 insertions(+), 46 deletions(-) diff --git a/src/strategies/erc3525-flexible-voucher/index.ts b/src/strategies/erc3525-flexible-voucher/index.ts index 9ab7e231d..b40c54de8 100644 --- a/src/strategies/erc3525-flexible-voucher/index.ts +++ b/src/strategies/erc3525-flexible-voucher/index.ts @@ -87,7 +87,9 @@ export async function strategy( parseFloat(formatUnits(snapshot[2].toString(), options.decimals)) * claimCoefficient(snapshot[0][1]) * maturitiesCoefficient( - snapshot[0][2] == 0 ? snapshot[0][3].toNumber() : snapshot[0][2].toNumber(), + snapshot[0][2] == 0 + ? snapshot[0][3].toNumber() + : snapshot[0][2].toNumber(), snapshot[0][4] ); walletToWeights[address] = walletToWeights[address] diff --git a/src/strategies/gooddollar-multichain/examples.json b/src/strategies/gooddollar-multichain/examples.json index c047a1c90..d24cd1389 100644 --- a/src/strategies/gooddollar-multichain/examples.json +++ b/src/strategies/gooddollar-multichain/examples.json @@ -72,4 +72,4 @@ ], "snapshot": 15000000 } -] \ No newline at end of file +] diff --git a/src/strategies/proxyprotocol-erc1155-balance-of/index.ts b/src/strategies/proxyprotocol-erc1155-balance-of/index.ts index b45aeb490..38a211f6c 100644 --- a/src/strategies/proxyprotocol-erc1155-balance-of/index.ts +++ b/src/strategies/proxyprotocol-erc1155-balance-of/index.ts @@ -5,15 +5,15 @@ export const author = 'rawrjustin'; export const version = '0.1.0'; const calculateVotingPower = (inputAddresses, addressScores, walletMap) => { - let userVotingPower = {}; - inputAddresses.forEach(input => { - let count = 0.0 - walletMap[input.toLowerCase()].forEach(address => { - count += addressScores[address] + const userVotingPower = {}; + inputAddresses.forEach((input) => { + let count = 0.0; + walletMap[input.toLowerCase()].forEach((address) => { + count += addressScores[address]; }); - userVotingPower[input] = count + userVotingPower[input] = count; }); - return userVotingPower + return userVotingPower; }; export async function strategy( @@ -40,10 +40,10 @@ export async function strategy( const data = await apiResponse.json(); // Flatten the wallet mapping so it's an array of real wallets to query for tokens - var arrayOfProxyWallets = Object.keys(data).map(function(key){ + const arrayOfProxyWallets = Object.keys(data).map(function (key) { return data[key]; }); - var flattenedWalletAddresses = [].concat.apply([], arrayOfProxyWallets); + const flattenedWalletAddresses = [].concat.apply([], arrayOfProxyWallets); // Query for token holdings const addressScores = await erc1155BalanceOfStrategy( @@ -56,9 +56,5 @@ export async function strategy( ); // Calculate the voting power across all wallets and map it back to original Proxy wallets. - return calculateVotingPower( - addresses, - addressScores, - data - ); + return calculateVotingPower(addresses, addressScores, data); } diff --git a/src/strategies/proxyprotocol-erc20-balance-of/index.ts b/src/strategies/proxyprotocol-erc20-balance-of/index.ts index d522a15b8..ba3fabe34 100644 --- a/src/strategies/proxyprotocol-erc20-balance-of/index.ts +++ b/src/strategies/proxyprotocol-erc20-balance-of/index.ts @@ -5,15 +5,15 @@ export const author = 'rawrjustin'; export const version = '0.1.0'; const calculateVotingPower = (inputAddresses, addressScores, walletMap) => { - let userVotingPower = {}; - inputAddresses.forEach(input => { - let count = 0.0 - walletMap[input.toLowerCase()].forEach(address => { - count += addressScores[address] + const userVotingPower = {}; + inputAddresses.forEach((input) => { + let count = 0.0; + walletMap[input.toLowerCase()].forEach((address) => { + count += addressScores[address]; }); - userVotingPower[input] = count + userVotingPower[input] = count; }); - return userVotingPower + return userVotingPower; }; export async function strategy( @@ -40,10 +40,10 @@ export async function strategy( const data = await response.json(); // Flatten the wallet mapping so it's an array of real wallets to query for tokens - var arrayOfProxyWallets = Object.keys(data).map(function(key){ + const arrayOfProxyWallets = Object.keys(data).map(function (key) { return data[key]; }); - var flattenedWalletAddresses = [].concat.apply([], arrayOfProxyWallets); + const flattenedWalletAddresses = [].concat.apply([], arrayOfProxyWallets); // Query for token holdings const addressScores = await erc20BalanceOfStrategy( @@ -53,12 +53,8 @@ export async function strategy( flattenedWalletAddresses, options, snapshot - ) + ); // Calculate the voting power across all wallets and map it back to original Proxy wallets. - return calculateVotingPower( - addresses, - addressScores, - data - ); + return calculateVotingPower(addresses, addressScores, data); } diff --git a/src/strategies/proxyprotocol-erc721-balance-of/index.ts b/src/strategies/proxyprotocol-erc721-balance-of/index.ts index 6b369314d..4a87c7037 100644 --- a/src/strategies/proxyprotocol-erc721-balance-of/index.ts +++ b/src/strategies/proxyprotocol-erc721-balance-of/index.ts @@ -5,15 +5,15 @@ export const author = 'rawrjustin'; export const version = '0.1.0'; const calculateVotingPower = (inputAddresses, addressScores, walletMap) => { - let userVotingPower = {}; - inputAddresses.forEach(input => { - let count = 0.0 - walletMap[input.toLowerCase()].forEach(address => { - count += addressScores[address] + const userVotingPower = {}; + inputAddresses.forEach((input) => { + let count = 0.0; + walletMap[input.toLowerCase()].forEach((address) => { + count += addressScores[address]; }); - userVotingPower[input] = count + userVotingPower[input] = count; }); - return userVotingPower + return userVotingPower; }; export async function strategy( @@ -40,10 +40,10 @@ export async function strategy( const data = await apiResponse.json(); // Flatten the wallet mapping so it's an array of real wallets to query for tokens - var arrayOfProxyWallets = Object.keys(data).map(function(key){ + const arrayOfProxyWallets = Object.keys(data).map(function (key) { return data[key]; }); - var flattenedWalletAddresses = [].concat.apply([], arrayOfProxyWallets); + const flattenedWalletAddresses = [].concat.apply([], arrayOfProxyWallets); // Query for token holdings const addressScores = await erc721BalanceOfStrategy( @@ -53,12 +53,8 @@ export async function strategy( flattenedWalletAddresses, options, snapshot - ) + ); // Calculate the voting power across all wallets and map it back to original Proxy wallets. - return calculateVotingPower( - addresses, - addressScores, - data - ); + return calculateVotingPower(addresses, addressScores, data); } From c8e4d88c5193cc2084f9d8f5bc2107184fbec1fa Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Thu, 18 Aug 2022 23:58:51 +0530 Subject: [PATCH 080/815] Documentaion update for erc20-with-balance and holds-tokens (#783) * Documentaion update for erc20-with-balance and holds-tokens * Documentaion update for erc20-with-balance and holds-tokens --- src/strategies/erc20-with-balance/README.md | 25 ++++++++++++++++++++ src/strategies/holds-tokens/README.md | 26 +++++++++++++++++---- 2 files changed, 46 insertions(+), 5 deletions(-) create mode 100644 src/strategies/erc20-with-balance/README.md diff --git a/src/strategies/erc20-with-balance/README.md b/src/strategies/erc20-with-balance/README.md new file mode 100644 index 000000000..ab0715780 --- /dev/null +++ b/src/strategies/erc20-with-balance/README.md @@ -0,0 +1,25 @@ +# with-balance + +> Important Note: This strategy works for ERC721 contract too. + +This strategy checks if the voter has a balance of the token in the contract. returns `1` if the voter has a balance of the token in the contract. else returns `0`. + +## Parameters + +| Param Name | Description | +| ----------- | ----------- | +| address | Address of the contract | +| symbol (optional) | symbol | +| decimals (optional) | decimals | +| minBalance (optional) | Minimum balance check (Note that this value is exclusive, For example if you pass `1`, balance should be more than `1`) Default is `0` | + +Here is an example of parameters: + +```json +{ + "address": "0x84cA8bc7997272c7CfB4D0Cd3D55cd942B3c9419", + "symbol": "DIA", + "decimals": 18, + "minBalance": 10 +} +``` diff --git a/src/strategies/holds-tokens/README.md b/src/strategies/holds-tokens/README.md index 8289b9e56..0b1833bc2 100644 --- a/src/strategies/holds-tokens/README.md +++ b/src/strategies/holds-tokens/README.md @@ -1,14 +1,30 @@ # holds-tokens -This strategy return the balances of the voters for a specific ERC20 or ERC721 and maps them to the number of votes that voter gets based on holding a set of tokens. +This strategy return the balances of the voters for a specific ERC20 or ERC721 and maps them to the number of votes that voter gets based on holding a set of tokens. on multiple networks + +## Parameters + +Same as [erc20-with-balance](https://snapshot.org/#/strategy/erc20-with-balance) strategy. except that we have to pass the `network` parameter. This is the network that the contract is deployed on. also can pass multiple params into `tokenAddresses` array (Check the example below). + +> Note: minBalance is exclusive. For example if you pass `1`, balance should be more than `1` Here is an example of parameters: ```json { - "tokenAddresses": [ - {"address": "0x7Bd29408f11D2bFC23c34f18275bBf23bB716Bc7", "network": "1", "decimals": 0, "minBalance": 1}, - {"address": "0xc34cbca32e355636c7f52dd8beab0af2396ebd79", "network": "137", "decimals": 0, "minBalance": 1} - ] + "tokenAddresses": [ + { + "address": "0x7Bd29408f11D2bFC23c34f18275bBf23bB716Bc7", + "network": "1", + "decimals": 0, + "minBalance": 1 + }, + { + "address": "0xc34cbca32e355636c7f52dd8beab0af2396ebd79", + "network": "137", + "decimals": 0, + "minBalance": 1 + } + ] } ``` From 0402897190c31247e9506200d6827c529136e866 Mon Sep 17 00:00:00 2001 From: BrassLion Date: Fri, 19 Aug 2022 07:52:40 +0100 Subject: [PATCH 081/815] Add Arrow vesting contract strategy (#784) --- src/strategies/arrow-vesting/README.md | 24 ++++++ src/strategies/arrow-vesting/examples.json | 23 ++++++ src/strategies/arrow-vesting/index.ts | 85 ++++++++++++++++++++++ src/strategies/index.ts | 4 +- 4 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 src/strategies/arrow-vesting/README.md create mode 100644 src/strategies/arrow-vesting/examples.json create mode 100644 src/strategies/arrow-vesting/index.ts diff --git a/src/strategies/arrow-vesting/README.md b/src/strategies/arrow-vesting/README.md new file mode 100644 index 000000000..345855312 --- /dev/null +++ b/src/strategies/arrow-vesting/README.md @@ -0,0 +1,24 @@ +# arrow-vesting + +This strategy returns voters underlying token balance for a given Arrow vesting contract factory. + +Token balance for is address is equal to the sum of the locked balance in all vesting contracts holding it +as a beneficiary. + +## Params + +- `address` - (**Required**, `string`) Address of ERC20 token contract +- `symbol` - (**Optional**, `string`) Symbol of ERC20 token +- `decimals` - (**Required**, `number`) Decimal precision for ERC20 token +- `vestingFactory` - (**Required**, `string`) Address of Vesting Escrow Factory that creates vesting contracts holding ERC20 tokens + +Here is an example of parameters: + +```json +{ + "address": "0x78b3C724A2F663D11373C4a1978689271895256f", + "symbol": "ARROW", + "decimals": 18, + "vestingFactory": "0xB93427b83573C8F27a08A909045c3e809610411a" +} +``` diff --git a/src/strategies/arrow-vesting/examples.json b/src/strategies/arrow-vesting/examples.json new file mode 100644 index 000000000..c862e4d7b --- /dev/null +++ b/src/strategies/arrow-vesting/examples.json @@ -0,0 +1,23 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "arrow-vesting", + "params": { + "address": "0x78b3C724A2F663D11373C4a1978689271895256f", + "symbol": "ARROW", + "decimals": 18, + "vestingFactory": "0xB93427b83573C8F27a08A909045c3e809610411a" + } + }, + "network": "10", + "addresses": [ + "0xaDc17e5f0e9F755C717B2beE43B590260034b852", + "0xB66f08DBd7A59B32e98033b9A1da08B5793DAb79", + "0x5b8eD2A2CfFCD474B2E688fdeA21CB5c4350E575", + "0x03b5Dc2CE78a7bEe9F66DD619b291595a2E166BB", + "0x06A61f56de8c6a2735D1Dea68340D201ddEd7348" + ], + "snapshot": 18879362 + } +] diff --git a/src/strategies/arrow-vesting/index.ts b/src/strategies/arrow-vesting/index.ts new file mode 100644 index 000000000..83cb11438 --- /dev/null +++ b/src/strategies/arrow-vesting/index.ts @@ -0,0 +1,85 @@ +import { BigNumberish, BigNumber } from '@ethersproject/bignumber'; +import { Contract } from '@ethersproject/contracts'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'BrassLion'; +export const version = '0.1.0'; + +const vestingFactoryAbi = [ + "function escrows_length() public view returns (uint256)", + "function escrows(uint256 index) public view returns (address)", +]; + +const vestingContractAbi = [ + "function recipient() public view returns (address)", +] + +const tokenAbi = [ + "function balanceOf(address account) external view returns (uint256)", +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot + ): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + // Get all vesting contract addresses. + const vestingFactory = new Contract(options.vestingFactory, vestingFactoryAbi, provider); + + const vestingContractCount = await vestingFactory.escrows_length(); + + const vestingFactoryMulti = new Multicaller(network, provider, vestingFactoryAbi, { blockTag }); + + [...Array(vestingContractCount.toNumber()).keys()].forEach((contractIdx) => { + vestingFactoryMulti.call(contractIdx, options.vestingFactory, "escrows", [contractIdx]) + }); + + const vestingContracts: Record = await vestingFactoryMulti.execute(); + + // Get all beneficiaries of vesting contracts. + const vestingContractMulti = new Multicaller(network, provider, vestingContractAbi, { blockTag }); + + Object.values(vestingContracts).forEach((vestingContractAddress) => { + vestingContractMulti.call(vestingContractAddress, vestingContractAddress, "recipient", []) + }); + + const vestingContractRecipients: Record = await vestingContractMulti.execute(); + + // Get all balances of vesting contracts. + const tokenMulti = new Multicaller(network, provider, tokenAbi, { blockTag }); + + Object.values(vestingContracts).forEach((vestingContractAddress) => { + tokenMulti.call(vestingContractAddress, options.address, "balanceOf", [vestingContractAddress]) + }); + + const vestingContractBalances: Record = await tokenMulti.execute(); + + // Sum all vesting contract balances by recipient over requested addresses. + let addressBalances: Record = {}; + + addresses.forEach(address => { + addressBalances[address] = BigNumber.from(0); + }); + + Object.values(vestingContracts).forEach((vestingContractAddress) => { + const recipient = vestingContractRecipients[vestingContractAddress]; + + if (recipient in addressBalances) { + addressBalances[recipient] = addressBalances[recipient].add(vestingContractBalances[vestingContractAddress]); + } + }); + + return Object.fromEntries( + Object.entries(addressBalances).map(([address, balance]) => [ + address, + parseFloat(formatUnits(balance, options.decimals)) + ]) + ); + } + \ No newline at end of file diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 6e724433e..44f9705a8 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -355,6 +355,7 @@ import * as orcaPod from './orca-pod'; import * as proxyProtocolErc20BalanceOf from './proxyprotocol-erc20-balance-of'; import * as proxyProtocolErc721BalanceOf from './proxyprotocol-erc721-balance-of'; import * as proxyProtocolErc1155BalanceOf from './proxyprotocol-erc1155-balance-of'; +import * as arrowVesting from "./arrow-vesting"; const strategies = { 'forta-shares': fortaShares, @@ -713,7 +714,8 @@ const strategies = { 'orca-pod': orcaPod, 'proxyprotocol-erc20-balance-of': proxyProtocolErc20BalanceOf, 'proxyprotocol-erc721-balance-of': proxyProtocolErc721BalanceOf, - 'proxyprotocol-erc1155-balance-of': proxyProtocolErc1155BalanceOf + 'proxyprotocol-erc1155-balance-of': proxyProtocolErc1155BalanceOf, + "arrow-vesting": arrowVesting }; Object.keys(strategies).forEach(function (strategyName) { From 785d35dcac64a0daecef320b5bede10e7c41e5a3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 21 Aug 2022 12:29:10 +0530 Subject: [PATCH 082/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.20 (#785) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 7fb709e89..d3cdcf03c 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.19", + "@snapshot-labs/snapshot.js": "^0.4.20", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", "copyfiles": "^2.4.1", diff --git a/yarn.lock b/yarn.lock index 65e13f774..54159ed69 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.19": - version "0.4.19" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.19.tgz#e5e1b58624fcd6aff8dc954d9b6ae8b2b1ae3fd8" - integrity sha512-Wrm0AKoDhr6lYiDj32SEoVs5QxE8rZk08zz8tdM415frvHwiynMbGz47BDCPXEVESuyjM0CeVes/nIjgYyfzcA== +"@snapshot-labs/snapshot.js@^0.4.20": + version "0.4.20" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.20.tgz#ddb9c5ac9b900eb35e6e34bc19f07f181072c951" + integrity sha512-CSOyTODppuMKDCG69tc9PpFsxTG5D8PqDrNQxExIYvANBHlTGQEWawoGdfWvhDysxcVFOJkp/bStYGm0OcZW6g== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 7bfe2e478e6dff017b057405e9e6f51c36c761e8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 21 Aug 2022 22:55:21 +0530 Subject: [PATCH 083/815] Automated lint (#786) Co-authored-by: ChaituVR --- src/strategies/arrow-vesting/index.ts | 151 +++++++++++++++----------- src/strategies/index.ts | 4 +- 2 files changed, 91 insertions(+), 64 deletions(-) diff --git a/src/strategies/arrow-vesting/index.ts b/src/strategies/arrow-vesting/index.ts index 83cb11438..b1085b66e 100644 --- a/src/strategies/arrow-vesting/index.ts +++ b/src/strategies/arrow-vesting/index.ts @@ -7,79 +7,106 @@ export const author = 'BrassLion'; export const version = '0.1.0'; const vestingFactoryAbi = [ - "function escrows_length() public view returns (uint256)", - "function escrows(uint256 index) public view returns (address)", + 'function escrows_length() public view returns (uint256)', + 'function escrows(uint256 index) public view returns (address)' ]; const vestingContractAbi = [ - "function recipient() public view returns (address)", -] + 'function recipient() public view returns (address)' +]; const tokenAbi = [ - "function balanceOf(address account) external view returns (uint256)", + 'function balanceOf(address account) external view returns (uint256)' ]; export async function strategy( - space, + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + // Get all vesting contract addresses. + const vestingFactory = new Contract( + options.vestingFactory, + vestingFactoryAbi, + provider + ); + + const vestingContractCount = await vestingFactory.escrows_length(); + + const vestingFactoryMulti = new Multicaller( network, provider, - addresses, - options, - snapshot - ): Promise> { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - // Get all vesting contract addresses. - const vestingFactory = new Contract(options.vestingFactory, vestingFactoryAbi, provider); - - const vestingContractCount = await vestingFactory.escrows_length(); - - const vestingFactoryMulti = new Multicaller(network, provider, vestingFactoryAbi, { blockTag }); - - [...Array(vestingContractCount.toNumber()).keys()].forEach((contractIdx) => { - vestingFactoryMulti.call(contractIdx, options.vestingFactory, "escrows", [contractIdx]) - }); - - const vestingContracts: Record = await vestingFactoryMulti.execute(); - - // Get all beneficiaries of vesting contracts. - const vestingContractMulti = new Multicaller(network, provider, vestingContractAbi, { blockTag }); + vestingFactoryAbi, + { blockTag } + ); - Object.values(vestingContracts).forEach((vestingContractAddress) => { - vestingContractMulti.call(vestingContractAddress, vestingContractAddress, "recipient", []) - }); + [...Array(vestingContractCount.toNumber()).keys()].forEach((contractIdx) => { + vestingFactoryMulti.call(contractIdx, options.vestingFactory, 'escrows', [ + contractIdx + ]); + }); - const vestingContractRecipients: Record = await vestingContractMulti.execute(); + const vestingContracts: Record = + await vestingFactoryMulti.execute(); - // Get all balances of vesting contracts. - const tokenMulti = new Multicaller(network, provider, tokenAbi, { blockTag }); - - Object.values(vestingContracts).forEach((vestingContractAddress) => { - tokenMulti.call(vestingContractAddress, options.address, "balanceOf", [vestingContractAddress]) - }); - - const vestingContractBalances: Record = await tokenMulti.execute(); - - // Sum all vesting contract balances by recipient over requested addresses. - let addressBalances: Record = {}; - - addresses.forEach(address => { - addressBalances[address] = BigNumber.from(0); - }); - - Object.values(vestingContracts).forEach((vestingContractAddress) => { - const recipient = vestingContractRecipients[vestingContractAddress]; - - if (recipient in addressBalances) { - addressBalances[recipient] = addressBalances[recipient].add(vestingContractBalances[vestingContractAddress]); - } - }); - - return Object.fromEntries( - Object.entries(addressBalances).map(([address, balance]) => [ - address, - parseFloat(formatUnits(balance, options.decimals)) - ]) + // Get all beneficiaries of vesting contracts. + const vestingContractMulti = new Multicaller( + network, + provider, + vestingContractAbi, + { blockTag } + ); + + Object.values(vestingContracts).forEach((vestingContractAddress) => { + vestingContractMulti.call( + vestingContractAddress, + vestingContractAddress, + 'recipient', + [] ); - } - \ No newline at end of file + }); + + const vestingContractRecipients: Record = + await vestingContractMulti.execute(); + + // Get all balances of vesting contracts. + const tokenMulti = new Multicaller(network, provider, tokenAbi, { blockTag }); + + Object.values(vestingContracts).forEach((vestingContractAddress) => { + tokenMulti.call(vestingContractAddress, options.address, 'balanceOf', [ + vestingContractAddress + ]); + }); + + const vestingContractBalances: Record = + await tokenMulti.execute(); + + // Sum all vesting contract balances by recipient over requested addresses. + const addressBalances: Record = {}; + + addresses.forEach((address) => { + addressBalances[address] = BigNumber.from(0); + }); + + Object.values(vestingContracts).forEach((vestingContractAddress) => { + const recipient = vestingContractRecipients[vestingContractAddress]; + + if (recipient in addressBalances) { + addressBalances[recipient] = addressBalances[recipient].add( + vestingContractBalances[vestingContractAddress] + ); + } + }); + + return Object.fromEntries( + Object.entries(addressBalances).map(([address, balance]) => [ + address, + parseFloat(formatUnits(balance, options.decimals)) + ]) + ); +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 44f9705a8..ae1e875e4 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -355,7 +355,7 @@ import * as orcaPod from './orca-pod'; import * as proxyProtocolErc20BalanceOf from './proxyprotocol-erc20-balance-of'; import * as proxyProtocolErc721BalanceOf from './proxyprotocol-erc721-balance-of'; import * as proxyProtocolErc1155BalanceOf from './proxyprotocol-erc1155-balance-of'; -import * as arrowVesting from "./arrow-vesting"; +import * as arrowVesting from './arrow-vesting'; const strategies = { 'forta-shares': fortaShares, @@ -715,7 +715,7 @@ const strategies = { 'proxyprotocol-erc20-balance-of': proxyProtocolErc20BalanceOf, 'proxyprotocol-erc721-balance-of': proxyProtocolErc721BalanceOf, 'proxyprotocol-erc1155-balance-of': proxyProtocolErc1155BalanceOf, - "arrow-vesting": arrowVesting + 'arrow-vesting': arrowVesting }; Object.keys(strategies).forEach(function (strategyName) { From 4a416a59310f8788d5280ab2d9a338c327129bb5 Mon Sep 17 00:00:00 2001 From: Chris Ling <81092286+chrisling-dev@users.noreply.github.com> Date: Mon, 22 Aug 2022 18:45:33 +0800 Subject: [PATCH 084/815] Feat/update strategy [prepo-vesting] (#787) * feat: use multiplier on everything when contract is paused * feat: update readme * feat: update readme.md * feat: remove override * feat: replace public with external in abi Co-authored-by: Chris Ling --- src/strategies/prepo-vesting/README.md | 4 ++++ src/strategies/prepo-vesting/index.ts | 14 +++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/strategies/prepo-vesting/README.md b/src/strategies/prepo-vesting/README.md index fcb528df5..f090b9772 100644 --- a/src/strategies/prepo-vesting/README.md +++ b/src/strategies/prepo-vesting/README.md @@ -8,6 +8,10 @@ This strategy assumes that the vesting token has 18 decimals. ### Calculation +When contract is paused (as a proxy for a cliff): +`score = (unclaimedVestedBalance + unvestedBalance) * multiplier` + +Else: `score = unclaimedVestedBalance + unvestedBalance * multiplier` where: diff --git a/src/strategies/prepo-vesting/index.ts b/src/strategies/prepo-vesting/index.ts index 640c0e2b6..cb0f0766b 100644 --- a/src/strategies/prepo-vesting/index.ts +++ b/src/strategies/prepo-vesting/index.ts @@ -6,9 +6,10 @@ export const author = 'prepo-io'; export const version = '1.0.0'; const abi = [ - 'function getAmountAllocated(address _recipient) external view override returns (uint256)', - 'function getClaimableAmount(address _recipient) public view override returns (uint256)', - 'function getVestedAmount(address _recipient) public view override returns (uint256)' + 'function getAmountAllocated(address _recipient) external view returns (uint256)', + 'function getClaimableAmount(address _recipient) external view returns (uint256)', + 'function getVestedAmount(address _recipient) external view returns (uint256)', + 'function isPaused() external view returns (bool)' ]; type MulticallOutput = Record>; @@ -34,9 +35,10 @@ export async function strategy( multi.call(`allocated.${addr}`, address, 'getAmountAllocated', [addr]); multi.call(`claimable.${addr}`, address, 'getClaimableAmount', [addr]); multi.call(`vested.${addr}`, address, 'getVestedAmount', [addr]); + multi.call(`isPaused`, address, 'isPaused', []); }); - const { allocated, claimable, vested }: MulticallOutput = + const { allocated, claimable, vested, isPaused }: MulticallOutput = await multi.execute(); const output = Object.fromEntries( @@ -46,7 +48,9 @@ export async function strategy( BigNumber.from(amountAllocated).sub(vested[address]), 18 ); - const score = unclaimedVestedBalance + unvestedBalance * multiplier; + const score = isPaused + ? (unclaimedVestedBalance + unvestedBalance) * multiplier + : unclaimedVestedBalance + unvestedBalance * multiplier; return [address, score]; }) ); From 10e96bbaa652f01a9bc0b6158fd32f2c761b7aac Mon Sep 17 00:00:00 2001 From: Victor Merino <38182181+victormer@users.noreply.github.com> Date: Mon, 22 Aug 2022 15:24:21 +0200 Subject: [PATCH 085/815] Tutellus DAO protocol strategy [tutellus-protocol] (#788) * tutellus-protocol strategy * modified readme Co-authored-by: Chaitanya --- src/strategies/index.ts | 4 +- src/strategies/tutellus-protocol/README.md | 3 + .../tutellus-protocol/examples.json | 19 +++++ src/strategies/tutellus-protocol/index.ts | 77 +++++++++++++++++++ src/strategies/tutellus-protocol/schema.json | 13 ++++ 5 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 src/strategies/tutellus-protocol/README.md create mode 100644 src/strategies/tutellus-protocol/examples.json create mode 100644 src/strategies/tutellus-protocol/index.ts create mode 100644 src/strategies/tutellus-protocol/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index ae1e875e4..f32120f51 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -356,6 +356,7 @@ import * as proxyProtocolErc20BalanceOf from './proxyprotocol-erc20-balance-of'; import * as proxyProtocolErc721BalanceOf from './proxyprotocol-erc721-balance-of'; import * as proxyProtocolErc1155BalanceOf from './proxyprotocol-erc1155-balance-of'; import * as arrowVesting from './arrow-vesting'; +import * as tutellusProtocol from './tutellus-protocol'; const strategies = { 'forta-shares': fortaShares, @@ -715,7 +716,8 @@ const strategies = { 'proxyprotocol-erc20-balance-of': proxyProtocolErc20BalanceOf, 'proxyprotocol-erc721-balance-of': proxyProtocolErc721BalanceOf, 'proxyprotocol-erc1155-balance-of': proxyProtocolErc1155BalanceOf, - 'arrow-vesting': arrowVesting + 'arrow-vesting': arrowVesting, + 'tutellus-protocol': tutellusProtocol }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/tutellus-protocol/README.md b/src/strategies/tutellus-protocol/README.md new file mode 100644 index 000000000..41e476c64 --- /dev/null +++ b/src/strategies/tutellus-protocol/README.md @@ -0,0 +1,3 @@ +# tutellus-protocol + +It returns the voting power in the Tutellus Protocol for proposals of Tutellus DAO, this includes holding $TUT, staking $TUT in the Staking contract and staking LP tokens from Sushi Pool against $WBTC in the Farming contract. diff --git a/src/strategies/tutellus-protocol/examples.json b/src/strategies/tutellus-protocol/examples.json new file mode 100644 index 000000000..4016b9385 --- /dev/null +++ b/src/strategies/tutellus-protocol/examples.json @@ -0,0 +1,19 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "tutellus-protocol", + "params": {} + }, + "network": "137", + "addresses": [ + "0xf3adfDFdB3f9f3151db8595C4e850C11a2b1b70E", + "0x18f43A59D698Ea7a4f5A0c11E7AA50973F5B396B", + "0x81EC959A48756984C2c94DB1BF9D4BB18746Ee2A", + "0x66e2495AEbCa70c141F3936Cb6F6d2e6464a5D99", + "0x0F22A52D6Ee30abEc311fd67C998Ab4B5e00382C", + "0xf79f703A6C80a427E826866cF91BC7c5B249187C" + ], + "snapshot": 32188493 + } +] diff --git a/src/strategies/tutellus-protocol/index.ts b/src/strategies/tutellus-protocol/index.ts new file mode 100644 index 000000000..f9d1d82ee --- /dev/null +++ b/src/strategies/tutellus-protocol/index.ts @@ -0,0 +1,77 @@ +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits, parseEther } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'victormer'; +export const version = '0.0.1'; + +const tokenABI = [ + 'function balanceOf(address account) external view returns (uint256)' +]; + +const stakingABI = [ + 'function getUserBalance(address user_) external view returns (uint256)' +]; + +const poolABI = [ + 'function totalSupply() external view returns (uint256)', + 'function getReserves() external view returns (uint112, uint112, uint32)' +] + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multiToken = new Multicaller(network, provider, tokenABI, { blockTag }); + const multiStaking = new Multicaller(network, provider, stakingABI, { blockTag }); + const multiFarming = new Multicaller(network, provider, stakingABI, { blockTag }); + const multiPool = new Multicaller(network, provider, poolABI, { blockTag }); + + addresses.forEach((address) => + multiToken.call(address, '0x12a34A6759c871C4C1E8A0A42CFc97e4D7Aaf68d', 'balanceOf', [address]) + ); + + addresses.forEach((address) => + multiStaking.call(address, '0x28Caa843cB577d892A8B6eC3F24Aa682ED22Be68', 'getUserBalance', [address]) + ); + + addresses.forEach((address) => + multiFarming.call(address, '0x57eB1b68F2ae0F77bf54F5EE6133bE80d6381d1B', 'getUserBalance', [address]) + ); + + multiPool.call('totalSupply', '0x5d9AC8993B714df01D079d1B5b0b592e579Ca099', 'totalSupply', []); + multiPool.call('reserves', '0x5d9AC8993B714df01D079d1B5b0b592e579Ca099', 'getReserves', []); + + const [ + resultToken, + resultStaking, + resultFarming, + resultPool + ] = await Promise.all([ + multiToken.execute(), + multiStaking.execute(), + multiFarming.execute(), + multiPool.execute() + ]); + + const poolRatio = resultPool.reserves[0].mul(parseEther('1')).div(resultPool.totalSupply); + + const result: Record = {}; + + addresses.forEach((address) => { + result[address] = resultToken[address].add(resultStaking[address]).add(resultFarming[address].mul(poolRatio).div(parseEther('1'))).toString(); + }) + + return Object.fromEntries( + Object.entries(result).map(([address, balance]) => [ + address, + parseFloat(formatUnits(balance, 18)) + ]) + ); +} diff --git a/src/strategies/tutellus-protocol/schema.json b/src/strategies/tutellus-protocol/schema.json new file mode 100644 index 000000000..8eb7ce143 --- /dev/null +++ b/src/strategies/tutellus-protocol/schema.json @@ -0,0 +1,13 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + } + } +} From b99dcc43cfd9d42f936c5be5e0b636500aff6d5a Mon Sep 17 00:00:00 2001 From: MantisClone Date: Mon, 22 Aug 2022 13:05:11 -0400 Subject: [PATCH 086/815] Add fight-club strategy [fight-club] (#782) * Copy erc20-balance-of and rename to fight-club/ * Fix tests * Empty commit to re-run CI - CI depends on PR_TITLE, I just updated it so tests should run * Update author and version * Update examples.json * Update schema.json * Start hacking on fight-club index.ts * console log debug: TypeError: options.gloves.forEach is not a function * Tweak console log. prints object. Why doesn't forEach work? * Only look at 1 "glove" NFT * Test on Mumbai * Try to console.log the result of glove balanceOf multicall * Remove unneeded console.log and forEach captured arg * Increase glove weight to 8 * Remove unused captured arg * Add calls to weightClass erc-1155 balanceOf - Fails with error: unexpected tokens (argument="value", value="balanceOf (address account, uint256 id) external view returns (uint256) ;", code=INVALID_ARGUMENT, version=abi/5.6.4) - Maybe can't specify ERC721 balanceOf in same ABI array as ERC1155 balanceOf?? * Update example weightClass weights * Use a much more recent block * Use addresses.forEach and addresses.map * Fix abi to differentiate ERC721 balanceOf and ERC1155 balanceOf * Modify results in place, applying weights * Observe that editing in place doesn't persist * Try changing from const to let. Didn't work * Revert "Try changing from const to let. Didn't work" This reverts commit 1857ffc7603f849d82ddc81904f7b4816e8f4fb5. * Build weightedResult object withour errors, but structure isn't right. * Make weightedResult look more like result * Use toNumber() in preparation for using Math.max() * Add logic to multiply max glove with max weight class Kudo. * fix errors in weightedResult type BigNumber -> number * fix weightClass key (was "weightedClassess") * Remove commented lines. formatUnits not needed * Use checksum addresses in examples.json * Rename weightClassTokenIds to weightClassIds * yarn lint * Improve logging. Remove unnecessary logging * weight class multiplier = 1 if voter has no weight class kudos * Improve fight-club README * Rename options.gloves to options.gloveAddresses * fixup! Rename options.gloves to options.gloveAddresses * Switch to using NFTs and 1155s on ethereum mainnet for testing. - Mumbai RPC doesn't support archive node queries. * If a user has >=1 nft or kudo, then only 1 is counted. * Improve comments * Adjust console logs * Change title to match parameter name * Delete fight-club schema.json - "type": "object" parameters don't render in snapshot playground, evidenced by safety-module-bpt-power. * Update README to match examples.json * yarn lint * Change equation to use `score` instead of `power` * Fix formatting * Comment out console logging * Limit gloves and weight class ids to 10. --- src/strategies/fight-club/README.md | 57 ++++++++++++ src/strategies/fight-club/examples.json | 27 ++++++ src/strategies/fight-club/index.ts | 117 ++++++++++++++++++++++++ src/strategies/index.ts | 4 +- 4 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 src/strategies/fight-club/README.md create mode 100644 src/strategies/fight-club/examples.json create mode 100644 src/strategies/fight-club/index.ts diff --git a/src/strategies/fight-club/README.md b/src/strategies/fight-club/README.md new file mode 100644 index 000000000..b3057c2b3 --- /dev/null +++ b/src/strategies/fight-club/README.md @@ -0,0 +1,57 @@ +# fight-club + +This strategy calculates a fight-club member's voting score. + +## Params + +- `gloveAddresses` - (**Required**, `object`) Up to 10 Fight Club Glove NFT + addresses and weights +- `weightClassAddress` - (**Required**, `string`) Weight Class Kudo (ERC-1155) + Address +- `weightClassIds` - (**Required**, `object`) Up to 10 Weight Class Kudo IDs and + weights +- `symbol` - (**Optional**, `string`) Symbol of the strategy + + +Here is an example of parameters: + +```json +{ + "gloveAddresses": { + "0x25ed58c027921E14D86380eA2646E3a1B5C55A8b": 3 + }, + "weightClassAddress": "0xF1F3ca6268f330fDa08418db12171c3173eE39C9", + "weightClassIds": { + "8": 4, + "26": 5, + "33": 6 + }, + "symbol": "FC" +} +``` + +## Details + +This strategy uses a Multicall to query `balanceOf` fight club glove NFTs and +`balanceOf` weight class kudos (ERC-1155). A voter's score is calculated via the +following equation: + +``` +score = gloveWeight * weightClassMultiplier +``` + +* If a user has more than 1 fight club glove NFT, only the one with the highest + associated weight is counted. +* If a user has more than 1 weight class Kudo, only the one with the highest + associated weight is counted. +* If a user has 0 fight club glove NFTs, then their vote score is 0, regardless + of their weight class Kudos. +* If a user has a fight club glove NFT, but 0 weight class Kudos, the weight + class multiplier defaults to 1. +* To avoid memory issues, the strategy is limited to 10 distinct glove NFT + addresses and 10 distinct weight class kudo IDs. + +> **Warning**: This strategy uses `ethers.utils.BigNumber.toNumber()` and will + fail if a voter's `gloveWeight` or `weightClassMultiplier` is is greater than + or equal to `Number.MAX_SAFE_INTEGER` or less than or equal to + `Number.MIN_SAFE_INTEGER` diff --git a/src/strategies/fight-club/examples.json b/src/strategies/fight-club/examples.json new file mode 100644 index 000000000..b58d8737b --- /dev/null +++ b/src/strategies/fight-club/examples.json @@ -0,0 +1,27 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "fight-club", + "params": { + "gloveAddresses": { + "0x25ed58c027921E14D86380eA2646E3a1B5C55A8b": 3 + }, + "weightClassAddress": "0xF1F3ca6268f330fDa08418db12171c3173eE39C9", + "weightClassIds": { + "8": 4, + "26": 5, + "33": 6 + }, + "symbol": "FC" + } + }, + "network": "1", + "addresses": [ + "0x1EC1CcEF3e1735bdA3F4BA698e8a524AA7c93274", + "0x3eEFAa9d6e2ab7972C1001D41C82BB4881389257", + "0x7911670881A81F8410d06053d7B3c237cE77b9B4" + ], + "snapshot": 13921307 + } +] diff --git a/src/strategies/fight-club/index.ts b/src/strategies/fight-club/index.ts new file mode 100644 index 000000000..8225f8a16 --- /dev/null +++ b/src/strategies/fight-club/index.ts @@ -0,0 +1,117 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import { Multicaller } from '../../utils'; + +export const author = 'MantisClone'; +export const version = '0.1.0'; + +const abi = [ + 'function balanceOf(address account) external view returns (uint256)', + 'function balanceOf(address account, uint256 id) external view returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + // Arbitrary limit to avoid memory issues + const limit = 10; + if (options.gloveAddresses.length > limit) { + throw new Error( + `Number of glove addresses ${options.gloveAddresses.length} exceeds limit ${limit}` + ); + } + if (options.weightClassIds.length > limit) { + throw new Error( + `Number of weight class IDs ${options.weightClassIds.length} exceeds limit ${limit}` + ); + } + + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multi = new Multicaller(network, provider, abi, { blockTag }); + + Object.entries(options.gloveAddresses).forEach(([gloveAddress]) => { + addresses.forEach((address: string) => { + multi.call( + `${address}.gloves.${gloveAddress}`, + gloveAddress, + 'balanceOf(address)', + [address] + ); + }); + }); + + Object.entries(options.weightClassIds).forEach(([weightClassId]) => { + addresses.forEach((address: string) => { + multi.call( + `${address}.weightClasses.${weightClassId}`, + options.weightClassAddress, + 'balanceOf(address, uint256)', + [address, weightClassId] + ); + }); + }); + + const result: Record< + string, + Record> + > = await multi.execute(); + + // console.log('Multicall result'); + // console.dir(result, { depth: null }); + + const weightedResult: Record< + string, + Record> + > = Object.fromEntries( + addresses.map((address: string) => [ + address, + { + gloves: Object.fromEntries( + Object.entries(result[address].gloves).map( + ([gloveAddress, numGloves]) => { + const hasGlove = numGloves.gte(1) ? 1 : 0; + return [ + gloveAddress, + hasGlove * options.gloveAddresses[gloveAddress] + ]; + } + ) + ), + weightClasses: Object.fromEntries( + Object.entries(result[address].weightClasses).map( + ([weightClassId, numKudos]) => { + const hasKudo = numKudos.gte(1) ? 1 : 0; + return [ + weightClassId, + hasKudo * options.weightClassIds[weightClassId] + ]; + } + ) + ) + } + ]) + ); + + // console.log('Weighted result'); + // console.dir(weightedResult, { depth: null }); + + return Object.fromEntries( + addresses.map((address: string) => { + // Only the glove with the highest associated weight is counted. + // Total vote score is 0 if voter has no gloves. + const maxGlove = Math.max( + ...Object.values(weightedResult[address].gloves) + ); + // Only the weight class Kudo with the highest associated weight is counted. + // Weight class multiplier defaults to 1 if voter has no weight class Kudos. + const maxWeightClass = + Math.max(...Object.values(weightedResult[address].weightClasses)) || 1; + return [address, maxGlove * maxWeightClass]; + }) + ); +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index f32120f51..4172124ff 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -357,6 +357,7 @@ import * as proxyProtocolErc721BalanceOf from './proxyprotocol-erc721-balance-of import * as proxyProtocolErc1155BalanceOf from './proxyprotocol-erc1155-balance-of'; import * as arrowVesting from './arrow-vesting'; import * as tutellusProtocol from './tutellus-protocol'; +import * as fightClub from './fight-club'; const strategies = { 'forta-shares': fortaShares, @@ -717,7 +718,8 @@ const strategies = { 'proxyprotocol-erc721-balance-of': proxyProtocolErc721BalanceOf, 'proxyprotocol-erc1155-balance-of': proxyProtocolErc1155BalanceOf, 'arrow-vesting': arrowVesting, - 'tutellus-protocol': tutellusProtocol + 'tutellus-protocol': tutellusProtocol, + 'fight-club': fightClub }; Object.keys(strategies).forEach(function (strategyName) { From 60e921897a1c30a7293efdd06d71dcae80530cc5 Mon Sep 17 00:00:00 2001 From: DanielZlotin <6660239+DanielZlotin@users.noreply.github.com> Date: Mon, 22 Aug 2022 20:08:20 +0300 Subject: [PATCH 087/815] [orbs-network-delegation] fix address sanitation (#790) Co-authored-by: Chaitanya --- src/strategies/orbs-network-delegation/examples.json | 12 ++++++------ src/strategies/orbs-network-delegation/index.ts | 7 ++++--- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/strategies/orbs-network-delegation/examples.json b/src/strategies/orbs-network-delegation/examples.json index 6f28581fa..9e91df8a7 100644 --- a/src/strategies/orbs-network-delegation/examples.json +++ b/src/strategies/orbs-network-delegation/examples.json @@ -12,13 +12,13 @@ "network": "1", "addresses": [ "0xc5e624d6824e626a6f14457810e794e4603cfee2", - "0x63aef7616882f488bca97361d1c24f05b4657ae5", - "0x3d726623456e34e8a7f5567f6249ec4d72cc3595", - "0x8ddb908c77ccc9cfde28ddf84311cb6fdf3f3125", + "0x63AEf7616882F488BCa97361d1c24F05B4657ae5", + "0x3D726623456e34e8a7F5567F6249EC4D72Cc3595", + "0x8DdB908c77ccc9cfde28dDF84311CB6fDF3f3125", "0xca565ccb6434e0adf49b2d66df12b0046b013d7f", - "0x9520f53fd81c668e8088ae194c40e3f977b73d28", - "0x588c28c19e4185a2442c4c3dd9ebd592c61eccb9", - "0xa478c2975ab1ea89e8196811f51a7b7ade33eb11" + "0x9520F53FD81C668E8088AE194C40E3F977B73D28", + "0x588C28C19E4185A2442C4C3DD9EBD592C61ECCB9", + "0xA478C2975AB1EA89E8196811F51A7B7ADE33EB11" ], "snapshot": 15210123 }, diff --git a/src/strategies/orbs-network-delegation/index.ts b/src/strategies/orbs-network-delegation/index.ts index a875dbd5e..4d84f5242 100644 --- a/src/strategies/orbs-network-delegation/index.ts +++ b/src/strategies/orbs-network-delegation/index.ts @@ -1,6 +1,7 @@ import { BigNumberish, BigNumber } from '@ethersproject/bignumber'; import { formatUnits } from '@ethersproject/units'; import { Multicaller } from '../../utils'; +import { getAddress } from "@ethersproject/address"; export const author = 'gadcl'; export const version = '0.1.1'; @@ -36,8 +37,8 @@ export async function strategy( Object.entries(override).forEach( ([address, [delegation, delegatorStake]]) => { - const from = address.toLowerCase(); - const to = delegation.toLocaleLowerCase(); + const from = getAddress(address); + const to = getAddress(delegation); delegations[from] = delegatorStake; if (delegations[to]) { delegations[to] = BigNumber.from(delegations[to]).sub(delegatorStake); @@ -47,7 +48,7 @@ export async function strategy( return Object.fromEntries( Object.entries(delegations).map(([address, delegatedStake]) => [ - address, + getAddress(address), parseFloat(formatUnits(delegatedStake, options.decimals)) ]) ); From 979e5dcc98a892a95cfe5efc7c71c56383f4765c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 23 Aug 2022 12:11:24 +0530 Subject: [PATCH 088/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.21 (#793) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index d3cdcf03c..3d7b1022e 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.20", + "@snapshot-labs/snapshot.js": "^0.4.21", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", "copyfiles": "^2.4.1", diff --git a/yarn.lock b/yarn.lock index 54159ed69..15c055b1d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.20": - version "0.4.20" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.20.tgz#ddb9c5ac9b900eb35e6e34bc19f07f181072c951" - integrity sha512-CSOyTODppuMKDCG69tc9PpFsxTG5D8PqDrNQxExIYvANBHlTGQEWawoGdfWvhDysxcVFOJkp/bStYGm0OcZW6g== +"@snapshot-labs/snapshot.js@^0.4.21": + version "0.4.21" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.21.tgz#68cd57496d8ea54a01dcca5bda24030d7245aa5d" + integrity sha512-HNSNAZqMYEpD5ep2UIGBHtBZoLxjZkepWe9PMtNAKLzmJyJKo9N2Ktt6n1/eiewomRXQSD1bE8kQJPCJ9U+G/w== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 412c2966c84f23e8b80372b648412c1a7d1248ca Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 23 Aug 2022 17:02:17 +0530 Subject: [PATCH 089/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.22 (#794) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 3d7b1022e..c454a8caf 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.21", + "@snapshot-labs/snapshot.js": "^0.4.22", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", "copyfiles": "^2.4.1", diff --git a/yarn.lock b/yarn.lock index 15c055b1d..01f69f844 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.21": - version "0.4.21" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.21.tgz#68cd57496d8ea54a01dcca5bda24030d7245aa5d" - integrity sha512-HNSNAZqMYEpD5ep2UIGBHtBZoLxjZkepWe9PMtNAKLzmJyJKo9N2Ktt6n1/eiewomRXQSD1bE8kQJPCJ9U+G/w== +"@snapshot-labs/snapshot.js@^0.4.22": + version "0.4.22" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.22.tgz#731b6f947395dfc4eb0d52cf646f3e270d0ca59d" + integrity sha512-hbWPqayBLCmZ+vQdVdDFdjqOyD/H2ER0prRk/rRX38uQ4mXLklNKdRTyyN1uZCID4bNQ9upH+tJ5hy8nOIgvxw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 0a0816d2cc5223cedd66ecf3689be06a4339c9c0 Mon Sep 17 00:00:00 2001 From: MantisClone Date: Wed, 24 Aug 2022 08:18:37 -0400 Subject: [PATCH 090/815] Disambiguate "voting weight" and "weight class" [fight-club] (#792) * Disambiguate "voting weight" and "weight class" * Update src/strategies/fight-club/README.md Co-authored-by: iSpeakNerd <96841384+iSpeakNerd@users.noreply.github.com> Co-authored-by: iSpeakNerd <96841384+iSpeakNerd@users.noreply.github.com> --- src/strategies/fight-club/README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/strategies/fight-club/README.md b/src/strategies/fight-club/README.md index b3057c2b3..a9d4eb281 100644 --- a/src/strategies/fight-club/README.md +++ b/src/strategies/fight-club/README.md @@ -5,11 +5,11 @@ This strategy calculates a fight-club member's voting score. ## Params - `gloveAddresses` - (**Required**, `object`) Up to 10 Fight Club Glove NFT - addresses and weights + addresses and their associated voting power. - `weightClassAddress` - (**Required**, `string`) Weight Class Kudo (ERC-1155) Address - `weightClassIds` - (**Required**, `object`) Up to 10 Weight Class Kudo IDs and - weights + their associated voting multiplier. - `symbol` - (**Optional**, `string`) Symbol of the strategy @@ -33,25 +33,25 @@ Here is an example of parameters: ## Details This strategy uses a Multicall to query `balanceOf` fight club glove NFTs and -`balanceOf` weight class kudos (ERC-1155). A voter's score is calculated via the -following equation: +`balanceOf` weight class kudos (ERC-1155). A voter's total voting score is +calculated via the following equation: ``` -score = gloveWeight * weightClassMultiplier +score = glovePower * weightClassMultiplier ``` * If a user has more than 1 fight club glove NFT, only the one with the highest - associated weight is counted. + associated voting power is counted. * If a user has more than 1 weight class Kudo, only the one with the highest - associated weight is counted. -* If a user has 0 fight club glove NFTs, then their vote score is 0, regardless - of their weight class Kudos. + associated voting multiplier is counted. +* If a user has 0 fight club glove NFTs, then their total vote score is 0, + regardless of their weight class Kudos. * If a user has a fight club glove NFT, but 0 weight class Kudos, the weight class multiplier defaults to 1. * To avoid memory issues, the strategy is limited to 10 distinct glove NFT addresses and 10 distinct weight class kudo IDs. > **Warning**: This strategy uses `ethers.utils.BigNumber.toNumber()` and will - fail if a voter's `gloveWeight` or `weightClassMultiplier` is is greater than + fail if a voter's `glovePower` or `weightClassMultiplier` is is greater than or equal to `Number.MAX_SAFE_INTEGER` or less than or equal to `Number.MIN_SAFE_INTEGER` From b0297e55c297cb3945989959144a026c9a9c2423 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 24 Aug 2022 17:50:01 +0530 Subject: [PATCH 091/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.24 (#796) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index c454a8caf..1fdcee223 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.22", + "@snapshot-labs/snapshot.js": "^0.4.24", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", "copyfiles": "^2.4.1", diff --git a/yarn.lock b/yarn.lock index 01f69f844..1480bd6b2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.22": - version "0.4.22" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.22.tgz#731b6f947395dfc4eb0d52cf646f3e270d0ca59d" - integrity sha512-hbWPqayBLCmZ+vQdVdDFdjqOyD/H2ER0prRk/rRX38uQ4mXLklNKdRTyyN1uZCID4bNQ9upH+tJ5hy8nOIgvxw== +"@snapshot-labs/snapshot.js@^0.4.24": + version "0.4.24" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.24.tgz#61f40267e1b7455d990cab86cd534c606500ccc0" + integrity sha512-b0mLZJRIqPfojirpOhltndeKDraH0I+wlne72TGJkxMcxPLQsYFXbaDWao5+X/+fAJgqCcOM/Z+zBdAx8bkNIQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From a9b1eeeeb6626255eecd59015ad230df50db0bf2 Mon Sep 17 00:00:00 2001 From: AKochanski <50527866+AdrianKochanski@users.noreply.github.com> Date: Thu, 25 Aug 2022 15:17:20 +0200 Subject: [PATCH 092/815] tpro-staking v1.0.0 [tpro-staking] (#798) * tpro-staking v1.0.0 * Update src/strategies/tpro-staking/index.ts Co-authored-by: Chaitanya Co-authored-by: Chaitanya --- src/strategies/index.ts | 4 +- src/strategies/tpro-staking/examples.json | 38 +++++++++++ src/strategies/tpro-staking/index.ts | 78 +++++++++++++++++++++++ 3 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 src/strategies/tpro-staking/examples.json create mode 100644 src/strategies/tpro-staking/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 4172124ff..d553b47a4 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -358,6 +358,7 @@ import * as proxyProtocolErc1155BalanceOf from './proxyprotocol-erc1155-balance- import * as arrowVesting from './arrow-vesting'; import * as tutellusProtocol from './tutellus-protocol'; import * as fightClub from './fight-club'; +import * as tproStaking from './tpro-staking'; const strategies = { 'forta-shares': fortaShares, @@ -719,7 +720,8 @@ const strategies = { 'proxyprotocol-erc1155-balance-of': proxyProtocolErc1155BalanceOf, 'arrow-vesting': arrowVesting, 'tutellus-protocol': tutellusProtocol, - 'fight-club': fightClub + 'fight-club': fightClub, + 'tpro-staking': tproStaking }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/tpro-staking/examples.json b/src/strategies/tpro-staking/examples.json new file mode 100644 index 000000000..55bedbabe --- /dev/null +++ b/src/strategies/tpro-staking/examples.json @@ -0,0 +1,38 @@ +[ + { + "name": "tpro-staking", + "strategy": { + "name": "tpro-staking", + "params": { + "address": "0x3540abe4f288b280a0740ad5121aec337c404d15", + "symbol": "TPRO", + "decimals": 18, + "smartContracts": [ + "0x5c9977cA74Be8028a2715229A4ce1e7cABd6eFC6", + "0x764C205a50Ef89A55b2E8FE13B0e06E50391716e", + "0xa3c6dfaDF1ABA174e54406e692b09F61c4bFD689", + "0x674EeEF1Da64b9e398210621A61d1d2a8Bf27387", + "0x1C2AC88532f54A046f842B0651f0C2F6A80E729D" + ], + "contractFactor": [ + 0.03125, + 0.0625, + 0.125, + 0.25, + 1 + ], + "powerFactor": 2 + } + }, + "network": "1", + "addresses": [ + "0x9D424a91A4D47ccb858436CE006492D61C8dBA76", + "0x8fc8405d41114D6F8271C44902464Ca1325Ac692", + "0x87Dddb39a02755c8Bfc567e30080b006DaD93Bf6", + "0xB5C8BB51A4cf229ced4cBA3fE352BF0D47088813", + "0xAC02A175594010228AC9dDCa9584b894386f7b27", + "0x8db0c967E6F8c6D8dA1a74147614Fd66c437bF45" + ], + "snapshot": 15402131 + } +] diff --git a/src/strategies/tpro-staking/index.ts b/src/strategies/tpro-staking/index.ts new file mode 100644 index 000000000..7ea31f71f --- /dev/null +++ b/src/strategies/tpro-staking/index.ts @@ -0,0 +1,78 @@ +import { multicall } from '../../utils'; +import { formatEther } from '@ethersproject/units'; + +export const author = 'tokenomia-pro'; +export const version = '1.0.0'; + +const abi = [ + 'function userInfo(uint256, address) view returns (uint256 amount, uint256 rewardDebt, uint256 pendingRewards, uint256 lockedTimestamp, uint256 lockupTimestamp, uint256 lockupTimerange, uint256 virtAmount)' +]; + +interface StrategyOptions { + address: string; + symbol: string; + decimals: number; + smartContracts: Array; + contractFactor: Array; + powerFactor: number; +} + +interface VotingPower { + [key: string]: number; +} + +export async function strategy( + space: string, + network: string, + provider, + addresses: string[], + options: StrategyOptions, + snapshot: number +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const promises: any[] = []; + + options.smartContracts.forEach(contract => { + promises.push(multicall( + network, + provider, + abi, + addresses.map((address: any) => [ + contract, + 'userInfo', + [0, address] + ]), + { blockTag } + )); + }); + + const resolvedPromises = await Promise.all(promises); + const votingPowers: Array = []; + + resolvedPromises.forEach((response, contractIdx) => { + const contractFactor = options.contractFactor[contractIdx]; + const currentTimestamp = Math.floor(Date.now() / 1000); + + for (let i = 0; i < response.length; i++) { + const user = addresses[i]; + const endTimestamp = Number(response[i].lockedTimestamp); + const tokensAmount = Number(formatEther(response[i].amount)); + const remainMonths = Number(endTimestamp - currentTimestamp)/(60 * 60 * 24 * 30); + + if(tokensAmount <= 0 || remainMonths <= 0) { + continue; + } + + const votePower = Math.floor(tokensAmount * Math.pow(remainMonths, options.powerFactor) * contractFactor); + + if(votePower && votingPowers[user]) { + votingPowers[user] += votePower; + } + else if(votePower) { + votingPowers[user] = votePower; + } + } + }); + + return votingPowers || []; +} From 00469bc462cbea3db02ee12486a7fbd90d3a182e Mon Sep 17 00:00:00 2001 From: Mitesh Mutha Date: Thu, 25 Aug 2022 19:49:29 +0200 Subject: [PATCH 093/815] feat: Add gysr-pending-rewards strategy (#799) Co-authored-by: Chaitanya --- src/strategies/gysr-pending-rewards/README.md | 16 ++++ .../gysr-pending-rewards/examples.json | 20 +++++ src/strategies/gysr-pending-rewards/index.ts | 89 +++++++++++++++++++ .../gysr-pending-rewards/schema.json | 36 ++++++++ src/strategies/index.ts | 2 + 5 files changed, 163 insertions(+) create mode 100644 src/strategies/gysr-pending-rewards/README.md create mode 100644 src/strategies/gysr-pending-rewards/examples.json create mode 100644 src/strategies/gysr-pending-rewards/index.ts create mode 100644 src/strategies/gysr-pending-rewards/schema.json diff --git a/src/strategies/gysr-pending-rewards/README.md b/src/strategies/gysr-pending-rewards/README.md new file mode 100644 index 000000000..ce3b200ba --- /dev/null +++ b/src/strategies/gysr-pending-rewards/README.md @@ -0,0 +1,16 @@ +# GYSR Pending Rewards + +This strategy returns the pending rewards for each user in a specified GYSR pool. It supports the networks the GYSR Pool Info is available. + +Here is an example of parameters: + +```json +{ + // Required + "pool": "0xE48eddbBcA614be5416f20dE57D858562b72479d", + + // Optional + "rewardToken": "0xb521022EeaD7E7eEe95D30BA1A1f0aB657F83a61", + "symbol": "REX" +} +``` diff --git a/src/strategies/gysr-pending-rewards/examples.json b/src/strategies/gysr-pending-rewards/examples.json new file mode 100644 index 000000000..8c004fe83 --- /dev/null +++ b/src/strategies/gysr-pending-rewards/examples.json @@ -0,0 +1,20 @@ +[ + { + "name": "Example GYSR Pending Rewards query", + "strategy": { + "name": "gysr-pending-rewards", + "params": { + "pool": "0xE48eddbBcA614be5416f20dE57D858562b72479d", + "rewardToken": "0xb521022EeaD7E7eEe95D30BA1A1f0aB657F83a61", + "symbol": "REX" + } + }, + "network": 137, + "addresses": [ + "0x62a3ebf2acfcb209804faa5f5c52138c505d7ef6", + "0x29e3d28f1111d68ea4036eea466a922b7cd02311", + "0xE9DE5d8AD37d9514f3c452BA8CE780bf2100Da10" + ], + "snapshot": 32189416 + } +] \ No newline at end of file diff --git a/src/strategies/gysr-pending-rewards/index.ts b/src/strategies/gysr-pending-rewards/index.ts new file mode 100644 index 000000000..1e8f17904 --- /dev/null +++ b/src/strategies/gysr-pending-rewards/index.ts @@ -0,0 +1,89 @@ +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { multicall, Multicaller } from '../../utils'; + +export const author = 'mitesh-mutha'; +export const version = '0.1.0'; + +const poolInfoAddressForNetwork = { + 1: '0x01356d78c770840166C1654691D19Bd33C52EaAd', + 10: '0x3cAA041d1a0a78d141703C0E95408c1801Ed74dd', + 42: '0x91EB59690526b748FE1046D27BdB1B3dadeaf958', + 137: '0x53590f017d73bAb31A6CbCBF6500A66D92fecFbE' +}; + +const poolInfoABI = [ + 'function rewards(address pool, address addr) external view returns (uint256[])' +]; + +const poolABI = ['function rewardTokens() external view returns (address[])']; + +const tokenABI = ['function decimals() external view returns (uint8)']; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + // Network specific pool info contract address + const poolInfoContractAddress = poolInfoAddressForNetwork[network]; + + + // Determine which token rewards to count for voting power + let tokenIndex = 0; + + let tokenCallResult = await multicall( + network, + provider, + poolABI, + [[options.pool, 'rewardTokens', []]], + { blockTag } + ); + + const rewardTokens = tokenCallResult[0].map((tokenAddress) => [ + tokenAddress.toString().toLowerCase() + ]); + + if (!(options.rewardToken == null)) { + tokenIndex = Math.max( + rewardTokens.indexOf(options.rewardToken.toLowerCase()), + 0 + ); + } + + + // Determine decimals + const rewardTokenAddress = tokenCallResult[0][tokenIndex].toString(); + let decimalCallResult = await multicall( + network, + provider, + tokenABI, + [[rewardTokenAddress, 'decimals', []]], + { blockTag } + ); + const decimals = decimalCallResult[0]; + + + // Get the pending rewards for addresses + const multi = new Multicaller(network, provider, poolInfoABI, { blockTag }); + addresses.forEach((address) => + multi.call(address, poolInfoContractAddress, 'rewards', [ + options.pool, + address + ]) + ); + const result: Record = await multi.execute(); + + + return Object.fromEntries( + Object.entries(result).map(([address, balances]) => [ + address, + parseFloat(formatUnits(balances[tokenIndex], decimals)) + ]) + ); +} diff --git a/src/strategies/gysr-pending-rewards/schema.json b/src/strategies/gysr-pending-rewards/schema.json new file mode 100644 index 000000000..468a4eb77 --- /dev/null +++ b/src/strategies/gysr-pending-rewards/schema.json @@ -0,0 +1,36 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. UNI"], + "maxLength": 16 + }, + "pool": { + "type": "string", + "title": "Pool Address", + "examples": ["e.g. 0xE48eddbBcA614be5416f20dE57D858562b72479d"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "rewardToken": { + "type": "string", + "title": "Reward Token Address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } + }, + "required": ["pool"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index d553b47a4..6ce71d31a 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -290,6 +290,7 @@ import * as landDaoTiers from './landdao-token-tiers'; import * as defiplaza from './defiplaza'; import * as stakingClaimedUnclaimed from './staking-claimed-unclaimed'; import * as gysrStakingBalance from './gysr-staking-balance'; +import * as gysrPendingRewards from './gysr-pending-rewards'; import * as wanakafarmStaking from './wanakafarm-staking'; import * as starsharks from './starsharks'; import * as printerFinancial from './printer-financial'; @@ -654,6 +655,7 @@ const strategies = { revest: revest, 'staking-claimed-unclaimed': stakingClaimedUnclaimed, 'gysr-staking-balance': gysrStakingBalance, + 'gysr-pending-rewards': gysrPendingRewards, 'wanakafarm-staking': wanakafarmStaking, starsharks, 'printer-financial': printerFinancial, From d99cd02413a4ebf74cdf4b95c23f894b5010f0ad Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Sun, 28 Aug 2022 01:04:32 +0530 Subject: [PATCH 094/815] Run tests for all examples in examples.json (#804) --- test/strategy.test.ts | 270 +++++++++++++++++++++++------------------- 1 file changed, 146 insertions(+), 124 deletions(-) diff --git a/test/strategy.test.ts b/test/strategy.test.ts index 263d2273c..f950ecee7 100644 --- a/test/strategy.test.ts +++ b/test/strategy.test.ts @@ -23,7 +23,9 @@ const moreArg: string | undefined = const strategy = Object.keys(snapshot.strategies).find((s) => strategyArg == s); if (!strategy) throw 'Strategy not found'; -const example = require(`../src/strategies/${strategy}/examples.json`)[0]; +const examples = require(`../src/strategies/${strategy}/examples.json`).map( + (example, index) => ({ index, example }) +); function callGetScores(example) { const provider = snapshot.utils.getProvider(example.network); @@ -37,113 +39,127 @@ function callGetScores(example) { ); } -describe(`\nTest strategy "${strategy}"`, () => { - let scores: any = null; - let getScoresTime: number | null = null; +describe.each(examples)( + `\nTest strategy "${strategy}" with example index $index`, + // @ts-ignore + ({ example }) => { + let scores: any = null; + let getScoresTime: number | null = null; - it('Strategy name should be lowercase and should not contain any special char expect hyphen', () => { - expect(strategy).toMatch(/^[a-z0-9\-]+$/); - }); + it('Strategy name should be lowercase and should not contain any special char expect hyphen', () => { + expect(strategy).toMatch(/^[a-z0-9\-]+$/); + }); - it('Strategy name should be same as in examples.json', () => { - expect(example.strategy.name).toBe(strategy); - }); + it('Strategy name should be same as in examples.json', () => { + expect(example.strategy.name).toBe(strategy); + }); - it('Strategy should run without any errors', async () => { - const getScoresStart = performance.now(); - scores = await callGetScores(example); - const getScoresEnd = performance.now(); - getScoresTime = getScoresEnd - getScoresStart; - console.log(scores); - console.log(`Resolved in ${(getScoresTime / 1e3).toFixed(2)} sec.`); - }, 2e4); - - it('Should return an array of object with addresses', () => { - expect(scores).toBeTruthy(); - // Check array - expect(Array.isArray(scores)).toBe(true); - // Check array contains a object - expect(typeof scores[0]).toBe('object'); - // Check object contains at least one address from example.json - expect(Object.keys(scores[0]).length).toBeGreaterThanOrEqual(1); - expect( - Object.keys(scores[0]).some((address) => - example.addresses - .map((v) => v.toLowerCase()) - .includes(address.toLowerCase()) - ) - ).toBe(true); - // Check if all scores are numbers - expect( - Object.values(scores[0]).every((val) => typeof val === 'number') - ).toBe(true); - }); + it('Strategy should run without any errors', async () => { + const getScoresStart = performance.now(); + scores = await callGetScores(example); + const getScoresEnd = performance.now(); + getScoresTime = getScoresEnd - getScoresStart; + console.log(scores); + console.log(`Resolved in ${(getScoresTime / 1e3).toFixed(2)} sec.`); + }, 2e4); + + it('Should return an array of object with addresses', () => { + expect(scores).toBeTruthy(); + // Check array + expect(Array.isArray(scores)).toBe(true); + // Check array contains a object + expect(typeof scores[0]).toBe('object'); + // Check object contains at least one address from example.json + expect(Object.keys(scores[0]).length).toBeGreaterThanOrEqual(1); + expect( + Object.keys(scores[0]).some((address) => + example.addresses + .map((v) => v.toLowerCase()) + .includes(address.toLowerCase()) + ) + ).toBe(true); + // Check if all scores are numbers + expect( + Object.values(scores[0]).every((val) => typeof val === 'number') + ).toBe(true); + }); - it('Should take less than 10 sec. to resolve', () => { - expect(getScoresTime).toBeLessThanOrEqual(10000); - }); + it('Should take less than 10 sec. to resolve', () => { + expect(getScoresTime).toBeLessThanOrEqual(10000); + }); - it('File examples.json should include at least 1 address with a positive score', () => { - expect(Object.values(scores[0]).some((score: any) => score > 0)).toBe(true); - }); + it('File examples.json should include at least 1 address with a positive score', () => { + expect(Object.values(scores[0]).some((score: any) => score > 0)).toBe( + true + ); + }); - it('File examples.json must use a snapshot block number in the past', async () => { - expect(typeof example.snapshot).toBe('number'); - const provider = snapshot.utils.getProvider(example.network); - const blockNumber = await snapshot.utils.getBlockNumber(provider); - expect(example.snapshot).toBeLessThanOrEqual(blockNumber); - }); + it('File examples.json must use a snapshot block number in the past', async () => { + expect(typeof example.snapshot).toBe('number'); + const provider = snapshot.utils.getProvider(example.network); + const blockNumber = await snapshot.utils.getBlockNumber(provider); + expect(example.snapshot).toBeLessThanOrEqual(blockNumber); + }); - it('Returned addresses should be either same case as input addresses or checksum addresses', () => { - expect( - Object.keys(scores[0]).every( - (address) => - example.addresses.includes(address) || getAddress(address) === address - ) - ).toBe(true); - }); -}); + it('Returned addresses should be either same case as input addresses or checksum addresses', () => { + expect( + Object.keys(scores[0]).every( + (address) => + example.addresses.includes(address) || + getAddress(address) === address + ) + ).toBe(true); + }); + } +); -describe(`\nTest strategy "${strategy}" with latest snapshot`, () => { - let scores: any = null; - let getScoresTime: number | null = null; - it('Strategy should run without any errors', async () => { - const getScoresStart = performance.now(); - scores = await callGetScores({ ...example, snapshot: 'latest' }); - const getScoresEnd = performance.now(); - getScoresTime = getScoresEnd - getScoresStart; - console.log('Scores with latest snapshot', scores); - console.log(`Resolved in ${(getScoresTime / 1e3).toFixed(2)} sec.`); - // wait for all logs to be printed (bug: printed after results) - await new Promise((r) => setTimeout(r, 500)); - }, 2e4); - - it('Should return an array of object with addresses', () => { - expect(scores).toBeTruthy(); - // Check array - expect(Array.isArray(scores)).toBe(true); - // Check array contains a object - expect(typeof scores[0]).toBe('object'); - // Check object contains atleast one address from example.json - expect(Object.keys(scores[0]).length).toBeGreaterThanOrEqual(1); - expect( - Object.keys(scores[0]).some((address) => - example.addresses - .map((v) => v.toLowerCase()) - .includes(address.toLowerCase()) - ) - ).toBe(true); - - // Check if all scores are numbers - expect( - Object.values(scores[0]).every((val) => typeof val === 'number') - ).toBe(true); - }); -}); +describe.each(examples)( + `\nTest strategy "${strategy}" with example index $index (latest snapshot)`, + // @ts-ignore + ({ example }) => { + let scores: any = null; + let getScoresTime: number | null = null; + it('Strategy should run without any errors', async () => { + const getScoresStart = performance.now(); + scores = await callGetScores({ ...example, snapshot: 'latest' }); + const getScoresEnd = performance.now(); + getScoresTime = getScoresEnd - getScoresStart; + console.log('Scores with latest snapshot', scores); + console.log(`Resolved in ${(getScoresTime / 1e3).toFixed(2)} sec.`); + // wait for all logs to be printed (bug: printed after results) + await new Promise((r) => setTimeout(r, 500)); + }, 2e4); + + it('Should return an array of object with addresses', () => { + expect(scores).toBeTruthy(); + // Check array + expect(Array.isArray(scores)).toBe(true); + // Check array contains a object + expect(typeof scores[0]).toBe('object'); + // Check object contains atleast one address from example.json + expect(Object.keys(scores[0]).length).toBeGreaterThanOrEqual(1); + expect( + Object.keys(scores[0]).some((address) => + example.addresses + .map((v) => v.toLowerCase()) + .includes(address.toLowerCase()) + ) + ).toBe(true); + + // Check if all scores are numbers + expect( + Object.values(scores[0]).every((val) => typeof val === 'number') + ).toBe(true); + }); + } +); -(moreArg ? describe : describe.skip)( - `\nTest strategy "${strategy}" (with ${moreArg || 500} addresses)`, - () => { +(moreArg ? describe.each(examples) : describe.skip.each(examples))( + `\nTest strategy "${strategy}" with example index $index (with ${ + moreArg || 500 + } addresses)`, + // @ts-ignore + ({ example }) => { let scoresMore: any = null; let getScoresTimeMore: number | null = null; @@ -167,6 +183,37 @@ describe(`\nTest strategy "${strategy}" with latest snapshot`, () => { } ); +describe.each(examples)( + `\nOther tests with example index $index`, + // @ts-ignore + ({ example }) => { + let schema; + try { + schema = require(`../src/strategies/${strategy}/schema.json`); + } catch (error) { + schema = null; + } + (schema ? it : it.skip)( + 'Check schema (if available) is valid with examples.json', + async () => { + expect(typeof schema).toBe('object'); + expect( + snapshotjs.utils.validateSchema(schema, example.strategy.params) + ).toBe(true); + } + ); + (schema ? it : it.skip)( + 'Strategy should work even when strategy symbol is null', + async () => { + delete example.strategy.params.symbol; + expect( + snapshotjs.utils.validateSchema(schema, example.strategy.params) + ).toBe(true); + } + ); + } +); + describe(`\nOthers:`, () => { it('Author in strategy should be a valid github username', async () => { const author = snapshot.strategies[strategy].author; @@ -181,29 +228,4 @@ describe(`\nOthers:`, () => { const version = snapshot.strategies[strategy].author; expect(typeof version).toBe('string'); }); - - let schema; - try { - schema = require(`../src/strategies/${strategy}/schema.json`); - } catch (error) { - schema = null; - } - (schema ? it : it.skip)( - 'Check schema (if available) is valid with examples.json', - async () => { - expect(typeof schema).toBe('object'); - expect( - snapshotjs.utils.validateSchema(schema, example.strategy.params) - ).toBe(true); - } - ); - (schema ? it : it.skip)( - 'Strategy should work even when strategy symbol is null', - async () => { - delete example.strategy.params.symbol; - expect( - snapshotjs.utils.validateSchema(schema, example.strategy.params) - ).toBe(true); - } - ); }); From ed74ad73c9daaf2cac6af71ef1b74496de4b68f6 Mon Sep 17 00:00:00 2001 From: Max <82761650+MaxMustermann2@users.noreply.github.com> Date: Sat, 27 Aug 2022 19:37:35 +0000 Subject: [PATCH 095/815] [harmony-staking] add testnet example (#802) Co-authored-by: Chaitanya --- src/strategies/harmony-staking/examples.json | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/strategies/harmony-staking/examples.json b/src/strategies/harmony-staking/examples.json index fb0832e66..b1d6be8a8 100644 --- a/src/strategies/harmony-staking/examples.json +++ b/src/strategies/harmony-staking/examples.json @@ -14,5 +14,21 @@ "0xA5241513DA9F4463F1d4874b548dFBAC29D91f34" ], "snapshot": 10937992 + }, + { + "name": "Example query", + "strategy": { + "name": "harmony-staking", + "params": { + "symbol": "ONE" + } + }, + "network": "1666700000", + "addresses": [ + "0x29c2eC57803f8b695f02613E5FA1749c165c5057", + "0xd143988234dF9117f4Baa00b5f8D4A56d64e56eA", + "0xA5241513DA9F4463F1d4874b548dFBAC29D91f34" + ], + "snapshot": 192690 } ] From 7447728e1328b89d46064199c8ac42b9b1f2a9c0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 28 Aug 2022 01:32:33 +0530 Subject: [PATCH 096/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.25 (#805) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 1fdcee223..8e50aaba6 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.24", + "@snapshot-labs/snapshot.js": "^0.4.25", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", "copyfiles": "^2.4.1", diff --git a/yarn.lock b/yarn.lock index 1480bd6b2..fc0951111 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.24": - version "0.4.24" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.24.tgz#61f40267e1b7455d990cab86cd534c606500ccc0" - integrity sha512-b0mLZJRIqPfojirpOhltndeKDraH0I+wlne72TGJkxMcxPLQsYFXbaDWao5+X/+fAJgqCcOM/Z+zBdAx8bkNIQ== +"@snapshot-labs/snapshot.js@^0.4.25": + version "0.4.25" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.25.tgz#c2a3a994a8eb2c7f3506463b5c9e7ab7b3e81f35" + integrity sha512-5rWC7eSDibmx38dlKiDaZNJ+Z2FAQovYilr7xQfpOwz1wkcx4ruZJoD95Rj0/SlWy2MMoEFVsuSs7pCnNBb5JA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From d3a15a37dcb093ff31696edf08be0145600f3ee0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 29 Aug 2022 12:22:10 +0530 Subject: [PATCH 097/815] Automated lint (#806) Co-authored-by: ChaituVR --- .../gysr-pending-rewards/examples.json | 2 +- src/strategies/gysr-pending-rewards/index.ts | 8 +- .../orbs-network-delegation/index.ts | 2 +- src/strategies/tpro-staking/examples.json | 8 +- src/strategies/tpro-staking/index.ts | 38 +++++----- src/strategies/tutellus-protocol/index.ts | 74 +++++++++++++------ 6 files changed, 77 insertions(+), 55 deletions(-) diff --git a/src/strategies/gysr-pending-rewards/examples.json b/src/strategies/gysr-pending-rewards/examples.json index 8c004fe83..fc3ac7bb8 100644 --- a/src/strategies/gysr-pending-rewards/examples.json +++ b/src/strategies/gysr-pending-rewards/examples.json @@ -17,4 +17,4 @@ ], "snapshot": 32189416 } -] \ No newline at end of file +] diff --git a/src/strategies/gysr-pending-rewards/index.ts b/src/strategies/gysr-pending-rewards/index.ts index 1e8f17904..9b4d59b19 100644 --- a/src/strategies/gysr-pending-rewards/index.ts +++ b/src/strategies/gysr-pending-rewards/index.ts @@ -33,11 +33,10 @@ export async function strategy( // Network specific pool info contract address const poolInfoContractAddress = poolInfoAddressForNetwork[network]; - // Determine which token rewards to count for voting power let tokenIndex = 0; - let tokenCallResult = await multicall( + const tokenCallResult = await multicall( network, provider, poolABI, @@ -56,10 +55,9 @@ export async function strategy( ); } - // Determine decimals const rewardTokenAddress = tokenCallResult[0][tokenIndex].toString(); - let decimalCallResult = await multicall( + const decimalCallResult = await multicall( network, provider, tokenABI, @@ -68,7 +66,6 @@ export async function strategy( ); const decimals = decimalCallResult[0]; - // Get the pending rewards for addresses const multi = new Multicaller(network, provider, poolInfoABI, { blockTag }); addresses.forEach((address) => @@ -79,7 +76,6 @@ export async function strategy( ); const result: Record = await multi.execute(); - return Object.fromEntries( Object.entries(result).map(([address, balances]) => [ address, diff --git a/src/strategies/orbs-network-delegation/index.ts b/src/strategies/orbs-network-delegation/index.ts index 4d84f5242..ccb7bc200 100644 --- a/src/strategies/orbs-network-delegation/index.ts +++ b/src/strategies/orbs-network-delegation/index.ts @@ -1,7 +1,7 @@ import { BigNumberish, BigNumber } from '@ethersproject/bignumber'; import { formatUnits } from '@ethersproject/units'; import { Multicaller } from '../../utils'; -import { getAddress } from "@ethersproject/address"; +import { getAddress } from '@ethersproject/address'; export const author = 'gadcl'; export const version = '0.1.1'; diff --git a/src/strategies/tpro-staking/examples.json b/src/strategies/tpro-staking/examples.json index 55bedbabe..230274dc1 100644 --- a/src/strategies/tpro-staking/examples.json +++ b/src/strategies/tpro-staking/examples.json @@ -14,13 +14,7 @@ "0x674EeEF1Da64b9e398210621A61d1d2a8Bf27387", "0x1C2AC88532f54A046f842B0651f0C2F6A80E729D" ], - "contractFactor": [ - 0.03125, - 0.0625, - 0.125, - 0.25, - 1 - ], + "contractFactor": [0.03125, 0.0625, 0.125, 0.25, 1], "powerFactor": 2 } }, diff --git a/src/strategies/tpro-staking/index.ts b/src/strategies/tpro-staking/index.ts index 7ea31f71f..63f53cb05 100644 --- a/src/strategies/tpro-staking/index.ts +++ b/src/strategies/tpro-staking/index.ts @@ -32,18 +32,16 @@ export async function strategy( const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; const promises: any[] = []; - options.smartContracts.forEach(contract => { - promises.push(multicall( - network, - provider, - abi, - addresses.map((address: any) => [ - contract, - 'userInfo', - [0, address] - ]), - { blockTag } - )); + options.smartContracts.forEach((contract) => { + promises.push( + multicall( + network, + provider, + abi, + addresses.map((address: any) => [contract, 'userInfo', [0, address]]), + { blockTag } + ) + ); }); const resolvedPromises = await Promise.all(promises); @@ -57,18 +55,22 @@ export async function strategy( const user = addresses[i]; const endTimestamp = Number(response[i].lockedTimestamp); const tokensAmount = Number(formatEther(response[i].amount)); - const remainMonths = Number(endTimestamp - currentTimestamp)/(60 * 60 * 24 * 30); + const remainMonths = + Number(endTimestamp - currentTimestamp) / (60 * 60 * 24 * 30); - if(tokensAmount <= 0 || remainMonths <= 0) { + if (tokensAmount <= 0 || remainMonths <= 0) { continue; } - const votePower = Math.floor(tokensAmount * Math.pow(remainMonths, options.powerFactor) * contractFactor); + const votePower = Math.floor( + tokensAmount * + Math.pow(remainMonths, options.powerFactor) * + contractFactor + ); - if(votePower && votingPowers[user]) { + if (votePower && votingPowers[user]) { votingPowers[user] += votePower; - } - else if(votePower) { + } else if (votePower) { votingPowers[user] = votePower; } } diff --git a/src/strategies/tutellus-protocol/index.ts b/src/strategies/tutellus-protocol/index.ts index f9d1d82ee..2b384a5b9 100644 --- a/src/strategies/tutellus-protocol/index.ts +++ b/src/strategies/tutellus-protocol/index.ts @@ -16,7 +16,7 @@ const stakingABI = [ const poolABI = [ 'function totalSupply() external view returns (uint256)', 'function getReserves() external view returns (uint112, uint112, uint32)' -] +]; export async function strategy( space, @@ -29,44 +29,74 @@ export async function strategy( const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; const multiToken = new Multicaller(network, provider, tokenABI, { blockTag }); - const multiStaking = new Multicaller(network, provider, stakingABI, { blockTag }); - const multiFarming = new Multicaller(network, provider, stakingABI, { blockTag }); + const multiStaking = new Multicaller(network, provider, stakingABI, { + blockTag + }); + const multiFarming = new Multicaller(network, provider, stakingABI, { + blockTag + }); const multiPool = new Multicaller(network, provider, poolABI, { blockTag }); addresses.forEach((address) => - multiToken.call(address, '0x12a34A6759c871C4C1E8A0A42CFc97e4D7Aaf68d', 'balanceOf', [address]) + multiToken.call( + address, + '0x12a34A6759c871C4C1E8A0A42CFc97e4D7Aaf68d', + 'balanceOf', + [address] + ) ); addresses.forEach((address) => - multiStaking.call(address, '0x28Caa843cB577d892A8B6eC3F24Aa682ED22Be68', 'getUserBalance', [address]) + multiStaking.call( + address, + '0x28Caa843cB577d892A8B6eC3F24Aa682ED22Be68', + 'getUserBalance', + [address] + ) ); addresses.forEach((address) => - multiFarming.call(address, '0x57eB1b68F2ae0F77bf54F5EE6133bE80d6381d1B', 'getUserBalance', [address]) + multiFarming.call( + address, + '0x57eB1b68F2ae0F77bf54F5EE6133bE80d6381d1B', + 'getUserBalance', + [address] + ) ); - multiPool.call('totalSupply', '0x5d9AC8993B714df01D079d1B5b0b592e579Ca099', 'totalSupply', []); - multiPool.call('reserves', '0x5d9AC8993B714df01D079d1B5b0b592e579Ca099', 'getReserves', []); + multiPool.call( + 'totalSupply', + '0x5d9AC8993B714df01D079d1B5b0b592e579Ca099', + 'totalSupply', + [] + ); + multiPool.call( + 'reserves', + '0x5d9AC8993B714df01D079d1B5b0b592e579Ca099', + 'getReserves', + [] + ); - const [ - resultToken, - resultStaking, - resultFarming, - resultPool - ] = await Promise.all([ - multiToken.execute(), - multiStaking.execute(), - multiFarming.execute(), - multiPool.execute() - ]); + const [resultToken, resultStaking, resultFarming, resultPool] = + await Promise.all([ + multiToken.execute(), + multiStaking.execute(), + multiFarming.execute(), + multiPool.execute() + ]); - const poolRatio = resultPool.reserves[0].mul(parseEther('1')).div(resultPool.totalSupply); + const poolRatio = resultPool.reserves[0] + .mul(parseEther('1')) + .div(resultPool.totalSupply); const result: Record = {}; addresses.forEach((address) => { - result[address] = resultToken[address].add(resultStaking[address]).add(resultFarming[address].mul(poolRatio).div(parseEther('1'))).toString(); - }) + result[address] = resultToken[address] + .add(resultStaking[address]) + .add(resultFarming[address].mul(poolRatio).div(parseEther('1'))) + .toString(); + }); return Object.fromEntries( Object.entries(result).map(([address, balance]) => [ From 1123938ef3f64bdfbac6b68e743638cdeef6197a Mon Sep 17 00:00:00 2001 From: Mitesh Mutha Date: Tue, 30 Aug 2022 13:24:05 +0200 Subject: [PATCH 098/815] feat: add gysr-lp-staking-balance (#807) --- .../gysr-lp-staking-balance/README.md | 14 ++++ .../gysr-lp-staking-balance/examples.json | 22 ++++++ .../gysr-lp-staking-balance/index.ts | 72 +++++++++++++++++++ .../gysr-lp-staking-balance/schema.json | 41 +++++++++++ src/strategies/index.ts | 2 + 5 files changed, 151 insertions(+) create mode 100644 src/strategies/gysr-lp-staking-balance/README.md create mode 100644 src/strategies/gysr-lp-staking-balance/examples.json create mode 100644 src/strategies/gysr-lp-staking-balance/index.ts create mode 100644 src/strategies/gysr-lp-staking-balance/schema.json diff --git a/src/strategies/gysr-lp-staking-balance/README.md b/src/strategies/gysr-lp-staking-balance/README.md new file mode 100644 index 000000000..e55ca50d0 --- /dev/null +++ b/src/strategies/gysr-lp-staking-balance/README.md @@ -0,0 +1,14 @@ +# gysr-lp-staking-balance + +This strategy returns the LP staking balance for each user in a specified GYSR pool with a given token. + +Here is an example of the parameters: + +```json +{ + "pool": "0x05dff8d71cd222e09bb71e44e0be7cc8f03a07c9", + "tokenAddress": "0xa92e7c82b11d10716ab534051b271d2f6aef7df5", + "symbol": "ARA", + "decimals": 18 +} +``` diff --git a/src/strategies/gysr-lp-staking-balance/examples.json b/src/strategies/gysr-lp-staking-balance/examples.json new file mode 100644 index 000000000..807040a2d --- /dev/null +++ b/src/strategies/gysr-lp-staking-balance/examples.json @@ -0,0 +1,22 @@ +[ + { + "name": "Example GYSR LP Staking Query", + "strategy": { + "name": "gysr-lp-staking-balance", + "params": { + "pool": "0x05dff8d71cd222e09bb71e44e0be7cc8f03a07c9", + "tokenAddress": "0xa92e7c82b11d10716ab534051b271d2f6aef7df5", + "symbol": "ARA", + "decimals": 18 + } + }, + "network": "1", + "addresses": [ + "0x29c0b49931A18CB8F343b8474D2fb103DBa1e294", + "0xecfecf375160d2e3d1ab27a31a161d955c7650cb", + "0x75f1771f278b064a6f09242ad8a8a5d1da1cc9bd", + "0x001292f42f0ec85636f652f618fefd94bcc3ac6e" + ], + "snapshot": 15364930 + } +] diff --git a/src/strategies/gysr-lp-staking-balance/index.ts b/src/strategies/gysr-lp-staking-balance/index.ts new file mode 100644 index 000000000..9cf9e736b --- /dev/null +++ b/src/strategies/gysr-lp-staking-balance/index.ts @@ -0,0 +1,72 @@ +import { multicall } from '../../utils'; + +export const author = 'mitesh-mutha'; +export const version = '0.0.1'; + +const tokenABI = [ + 'function balanceOf(address account) view returns (uint256)', + 'function totalSupply() view returns (uint256)' +]; + +const poolABI = [ + 'function stakingBalances(address user) external view returns (uint256[])', + 'function stakingTokens() external view returns (address[])' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + // Fetch pool -> get lp token address + const poolCallResult = await multicall( + network, + provider, + poolABI, + [[options.pool, 'stakingTokens', []]], + { blockTag } + ); + const lpTokenAddress = poolCallResult[0][0][0]; + + // Fetch balances from lp token + const callResult = await multicall( + network, + provider, + tokenABI, + [ + [lpTokenAddress, 'totalSupply', []], + [options.tokenAddress, 'balanceOf', [lpTokenAddress]] + ], + { blockTag } + ); + const totalSupply = callResult[0]; + const rewardTokenBalance = callResult[1]; + const rewardTokensPerLP = + rewardTokenBalance / 10 ** options.decimals / (totalSupply / 1e18); + + // Fetch balances + const balanceResult = await multicall( + network, + provider, + poolABI, + addresses.map((address: any) => [ + options.pool, + 'stakingBalances', + [address] + ]), + { blockTag } + ); + + // Final result + return Object.fromEntries( + balanceResult.map((value, i) => [ + addresses[i], + (value / 10 ** options.decimals) * rewardTokensPerLP + ]) + ); +} diff --git a/src/strategies/gysr-lp-staking-balance/schema.json b/src/strategies/gysr-lp-staking-balance/schema.json new file mode 100644 index 000000000..4923eb86f --- /dev/null +++ b/src/strategies/gysr-lp-staking-balance/schema.json @@ -0,0 +1,41 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. UNI"], + "maxLength": 16 + }, + "pool": { + "type": "string", + "title": "Pool Address", + "examples": ["e.g. 0x05dff8d71cd222e09bb71e44e0be7cc8f03a07c9"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "tokenAddress": { + "type": "string", + "title": "Token Address", + "examples": ["e.g. 0xa92e7c82b11d10716ab534051b271d2f6aef7df5"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 18"] + } + }, + "required": ["pool", "tokenAddress", "decimals"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 6ce71d31a..a58c9276c 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -291,6 +291,7 @@ import * as defiplaza from './defiplaza'; import * as stakingClaimedUnclaimed from './staking-claimed-unclaimed'; import * as gysrStakingBalance from './gysr-staking-balance'; import * as gysrPendingRewards from './gysr-pending-rewards'; +import * as gysrLPStakingBalance from './gysr-lp-staking-balance'; import * as wanakafarmStaking from './wanakafarm-staking'; import * as starsharks from './starsharks'; import * as printerFinancial from './printer-financial'; @@ -656,6 +657,7 @@ const strategies = { 'staking-claimed-unclaimed': stakingClaimedUnclaimed, 'gysr-staking-balance': gysrStakingBalance, 'gysr-pending-rewards': gysrPendingRewards, + 'gysr-lp-staking-balance': gysrLPStakingBalance, 'wanakafarm-staking': wanakafarmStaking, starsharks, 'printer-financial': printerFinancial, From 92ae4ceb2428d76b7f391554fe5563dc322f19f0 Mon Sep 17 00:00:00 2001 From: Daniel Sanchez Date: Tue, 30 Aug 2022 19:20:13 +0200 Subject: [PATCH 099/815] [safe-vested] Add safe vested strategy (#801) * safe-vested strategy proposal * Improve performance using flat outside reduce * Add example file * Fix issues detected by tests * Add reference to the vesting contract * Fix example data to current commit --- src/strategies/index.ts | 4 +- src/strategies/safe-vested/README.md | 16 +++++ src/strategies/safe-vested/examples.json | 24 +++++++ src/strategies/safe-vested/index.ts | 86 ++++++++++++++++++++++++ 4 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 src/strategies/safe-vested/README.md create mode 100755 src/strategies/safe-vested/examples.json create mode 100755 src/strategies/safe-vested/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index a58c9276c..e32a289b5 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -361,6 +361,7 @@ import * as arrowVesting from './arrow-vesting'; import * as tutellusProtocol from './tutellus-protocol'; import * as fightClub from './fight-club'; import * as tproStaking from './tpro-staking'; +import * as safeVested from './safe-vested'; const strategies = { 'forta-shares': fortaShares, @@ -725,7 +726,8 @@ const strategies = { 'arrow-vesting': arrowVesting, 'tutellus-protocol': tutellusProtocol, 'fight-club': fightClub, - 'tpro-staking': tproStaking + 'tpro-staking': tproStaking, + 'safe-vested': safeVested }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/safe-vested/README.md b/src/strategies/safe-vested/README.md new file mode 100644 index 000000000..027d9718b --- /dev/null +++ b/src/strategies/safe-vested/README.md @@ -0,0 +1,16 @@ +# safe-vested + +Custom strategy to compute voting power from vested tokens. Strategy is configurable accepting a JSON using the following structure. +```json +[ + [ + { + "account": "ACCOUNT_ADDRESS", + "contract": "ALLOCATIONS_CONTRACT", + "vestingId": "VESTING_HASH", + "amount": "VESTED_AMOUNT" + } + ] +] +``` + diff --git a/src/strategies/safe-vested/examples.json b/src/strategies/safe-vested/examples.json new file mode 100755 index 000000000..843b63ad0 --- /dev/null +++ b/src/strategies/safe-vested/examples.json @@ -0,0 +1,24 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "safe-vested", + "params": { + "allocationsSource": "https://raw.githubusercontent.com/5afe/claiming-app-data/7942c2b6757c02fadb32d58dde09a12a35f5a462/resources/data/snapshot-allocations-test.json" + } + }, + "network": "4", + "snapshot": 11250000, + "addresses": [ + "0x9970dcab40e29a84D1020DeaEa443dCE1d8471b7", + "0x1230B3d59858296A31053C1b8562Ecf89A2f888b", + "0x121Cf7457171bD7a93232807CBa65f7Bd7a48a2d", + "0xda2242a6DbDa924bf7D7DB8aC9482d4763EB211C", + "0xf2565317F3Ae8Ae9EA98E9Fe1e7FADC77F823cbD", + "0x37b828802FAeA4244d176Da386CF632F5Bbc414F", + "0xA8FFD6B87388F8d5FACfDa0147d9B0Da511539b6", + "0xd7539FCdC0aB79a7B688b04387cb128E75cb77Dc" + ] + } + ] + \ No newline at end of file diff --git a/src/strategies/safe-vested/index.ts b/src/strategies/safe-vested/index.ts new file mode 100755 index 000000000..8ebd80211 --- /dev/null +++ b/src/strategies/safe-vested/index.ts @@ -0,0 +1,86 @@ +import fetch from 'cross-fetch'; +import { formatUnits, parseUnits } from '@ethersproject/units'; + +import { Multicaller } from '../../utils'; + +export const author = 'dasanra'; +export const version = '0.1.0'; + +// https://github.com/safe-global/safe-token/blob/main/contracts/VestingPool.sol +const abi = [ + 'function vestings(bytes32) view returns (address account, uint8 curveType, bool managed, uint16 durationWeeks, uint64 startDate, uint128 amount, uint128 amountClaimed, uint64 pausingDate, bool cancelled)' +]; + +type AllocationDetails = { + account: string; + contract: string; + vestingId: string; + amount: string; +}; + +type Options = { + allocationsSource: string; +}; + +export async function strategy( + space: string, + network: string, + provider, + addresses: string[], + options: Options, + snapshot: number | string = 'latest' +) { + const response = await fetch(options.allocationsSource, { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + } + }); + const allocationsList: [[AllocationDetails]] = await response.json(); + + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const multi = new Multicaller(network, provider, abi, { blockTag }); + + // Get current vesting state from smart contract using the vestingId + addresses.forEach((address) => { + const addressAllocations = allocationsList.find( + (allocations: AllocationDetails[]) => allocations[0].account === address + ); + + if (addressAllocations) { + addressAllocations.forEach(({ contract, vestingId }) => { + multi.call(vestingId, contract, 'vestings', [vestingId]); + }); + } + }); + + const vestings = await multi.execute(); + + const flatAllocationsList = allocationsList.flat(); + // Check vesting state, consider only unclaimed amounts and group allocations to the same account + return Object.keys(vestings).reduce((acc, key) => { + const { account, amount } = flatAllocationsList.find( + ({ vestingId }) => vestingId === key + ) as AllocationDetails; + + const hasAlreadyClaimed = vestings[key].account === account; + // If account already claimed only count the pending amount + // Else nothing claimed yet so consider the full allocation + const currentVestingAmount = hasAlreadyClaimed + ? vestings[key].amount.sub(vestings[key].amountClaimed) + : amount; + + const previousAmount = acc[account]; + // If account received multiple allocations sum them + // Else we just return the currentAmount + const pendingVestedAmount = previousAmount + ? parseUnits(previousAmount.toString()).add(currentVestingAmount) + : currentVestingAmount; + + return { + ...acc, + [account]: parseFloat(formatUnits(pendingVestedAmount)) + }; + }, {}); +} From f29dda929194c64bbd49e81a7208e7e2125c1e3c Mon Sep 17 00:00:00 2001 From: Mitesh Mutha Date: Wed, 31 Aug 2022 20:42:13 +0200 Subject: [PATCH 100/815] [gysr-pending-rewards] change example to eth mainnet (#809) --- .../gysr-pending-rewards/examples.json | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/strategies/gysr-pending-rewards/examples.json b/src/strategies/gysr-pending-rewards/examples.json index fc3ac7bb8..6d42e5dbc 100644 --- a/src/strategies/gysr-pending-rewards/examples.json +++ b/src/strategies/gysr-pending-rewards/examples.json @@ -4,17 +4,18 @@ "strategy": { "name": "gysr-pending-rewards", "params": { - "pool": "0xE48eddbBcA614be5416f20dE57D858562b72479d", - "rewardToken": "0xb521022EeaD7E7eEe95D30BA1A1f0aB657F83a61", - "symbol": "REX" + "pool": "0x30c0f65d9b27ebe2cc2a49cbcb4133230b3fb381", + "rewardToken": "0xbEa98c05eEAe2f3bC8c3565Db7551Eb738c8CCAb", + "symbol": "GYSR" } }, - "network": 137, + "network": 1, "addresses": [ - "0x62a3ebf2acfcb209804faa5f5c52138c505d7ef6", - "0x29e3d28f1111d68ea4036eea466a922b7cd02311", - "0xE9DE5d8AD37d9514f3c452BA8CE780bf2100Da10" + "0xc56e357599de4418c3a33ad611130d2b2b36b19a", + "0x3a5a5ed68b3eea83df82fbd3d16b16562e205ffb", + "0x6c2448c22a7947bd4fd886b719618b913cd09538", + "0x30c0f65d9b27ebe2cc2a49cbcb4133230b3fb381" ], - "snapshot": 32189416 + "snapshot": 15410000 } ] From 2f6547079997e604d008d3038575013f6893bb75 Mon Sep 17 00:00:00 2001 From: Drew <89287674+dewpe@users.noreply.github.com> Date: Thu, 1 Sep 2022 01:05:57 -0500 Subject: [PATCH 101/815] Underwriter ERC721 Strategy [riskharbor-underwriter] (#810) * added underwriter strategy * Update src/strategies/riskharbor-underwriter/index.ts Co-authored-by: Chaitanya --- src/strategies/index.ts | 4 +- .../riskharbor-underwriter/README.md | 10 +++ .../riskharbor-underwriter/examples.json | 23 ++++++ .../riskharbor-underwriter/index.ts | 78 +++++++++++++++++++ .../riskharbor-underwriter/schema.json | 29 +++++++ 5 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 src/strategies/riskharbor-underwriter/README.md create mode 100644 src/strategies/riskharbor-underwriter/examples.json create mode 100644 src/strategies/riskharbor-underwriter/index.ts create mode 100644 src/strategies/riskharbor-underwriter/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index e32a289b5..b43c7d3b0 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -362,6 +362,7 @@ import * as tutellusProtocol from './tutellus-protocol'; import * as fightClub from './fight-club'; import * as tproStaking from './tpro-staking'; import * as safeVested from './safe-vested'; +import * as riskharborUnderwriter from './riskharbor-underwriter'; const strategies = { 'forta-shares': fortaShares, @@ -727,7 +728,8 @@ const strategies = { 'tutellus-protocol': tutellusProtocol, 'fight-club': fightClub, 'tpro-staking': tproStaking, - 'safe-vested': safeVested + 'safe-vested': safeVested, + 'riskharbor-underwriter': riskharborUnderwriter }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/riskharbor-underwriter/README.md b/src/strategies/riskharbor-underwriter/README.md new file mode 100644 index 000000000..ebd323100 --- /dev/null +++ b/src/strategies/riskharbor-underwriter/README.md @@ -0,0 +1,10 @@ +# riskharbor-underwriter + +This strategy allows underwriters in a given Risk Harbor vault to vote based on the shares issued to them across their various positions in that vault. This strategy works by querying the vault's subgraph to compute how many shares each user holds and divides that amount by the decimals in the underwriting asset. + +```json +{ + "SUBGRAPH_URL": "https://api.thegraph.com/subgraphs/name/some-protocol/v1-protocol", + "VAULT_ADDR": "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984" +} +``` diff --git a/src/strategies/riskharbor-underwriter/examples.json b/src/strategies/riskharbor-underwriter/examples.json new file mode 100644 index 000000000..f5d6fbf43 --- /dev/null +++ b/src/strategies/riskharbor-underwriter/examples.json @@ -0,0 +1,23 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "riskharbor-underwriter", + "params": { + "SUBGRAPH_URL": "https://api.thegraph.com/subgraphs/name/risk-harbor/v2-arbitrum", + "VAULT_ADDR": "0xbcA81A2118982182d897845571BE950aE94C619c" + } + }, + "network": "42161", + "addresses": [ + "0x02a41565811ad5fe8f21d738c8ce2995d224fee4", + "0xd4d4e905d7f1eb095769face2c2be516865e4981", + "0xd401c5b54a079420c6c7d9405fafc9a10cd8a4ed", + "0x010dab3779810cf08ac213b9efa915821bb43e26", + "0x0dcdd4f4a70ebb2eaffd5a01bd6cacde14dae4f0", + "0xfc9bffa77c2b725add71f4ad88bbe228d5601eb3", + "0xc2e63f57958d5ad5ced8fc18a7b763d9c8327237" + ], + "snapshot": 22260293 + } +] diff --git a/src/strategies/riskharbor-underwriter/index.ts b/src/strategies/riskharbor-underwriter/index.ts new file mode 100644 index 000000000..32099b437 --- /dev/null +++ b/src/strategies/riskharbor-underwriter/index.ts @@ -0,0 +1,78 @@ +import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { subgraphRequest } from '../../utils'; + +export const author = 'dewpe'; +export const version = '0.1.0'; + +export async function strategy( + _space, + _network, + _provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const positionsQuery = { + underwriterPositions: { + __args: { + where: { + shares_not: '0', + vault: options.VAULT_ADDR.toLowerCase(), + user_in: addresses.map((addr: string) => addr.toLowerCase()) + }, + block: blockTag != 'latest' ? { number: blockTag } : null, + first: 1000 + }, + shares: true, + user: { + id: true + } + } + }; + + const decimalsQuery = { + vault: { + __args: { + id: options.VAULT_ADDR.toLowerCase(), + block: blockTag != 'latest' ? { number: blockTag } : null + }, + underwritingToken: { + decimals: true + } + } + }; + + const decimals = (await subgraphRequest(options.SUBGRAPH_URL, decimalsQuery)) + .vault.underwritingToken.decimals; + + const positions = ( + await subgraphRequest(options.SUBGRAPH_URL, positionsQuery) + ).underwriterPositions; + + // Go through each position and reduce it down to the form: + // userAddr: balance + const agUserBals: Record = {}; + positions.forEach((position) => { + const shares = BigNumber.from(position.shares); + if (shares.isZero()) return; + // If key already has a value, then increase it + if (agUserBals[position.user.id]) { + agUserBals[position.user.id] = ( + agUserBals[position.user.id] as BigNumber + ).add(shares); + } else { + agUserBals[position.user.id] = shares; + } + }); + + return Object.fromEntries( + Object.entries(agUserBals).map(([address, balance]) => [ + address, + // Divide each bal by 1eDecimals + parseFloat(formatUnits(balance, decimals)) + ]) + ); +} diff --git a/src/strategies/riskharbor-underwriter/schema.json b/src/strategies/riskharbor-underwriter/schema.json new file mode 100644 index 000000000..78f56d803 --- /dev/null +++ b/src/strategies/riskharbor-underwriter/schema.json @@ -0,0 +1,29 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "SUBGRAPH_URL": { + "type": "string", + "title": "Subgraph url", + "examples": [ + "https://api.thegraph.com/subgraphs/name/some-protocol/v1-protocol" + ] + }, + "VAULT_ADDR": { + "type": "string", + "title": "Vault address", + "examples": ["e.g. 0xbcA81A2118982182d897845571BE950aE94C619c"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } + }, + "required": ["SUBGRAPH_URL", "VAULT_ADDR"], + "additionalProperties": false + } + } +} From 4669f8fa612ee92e8201d115f602de8325b5bde0 Mon Sep 17 00:00:00 2001 From: gadcl Date: Thu, 1 Sep 2022 15:52:11 +0300 Subject: [PATCH 102/815] [orbs-network-delegation] support deprecated edge case cascade delegations a->b->c (#795) * support deprecated edge case cascade delegations a->b->c * Update index.ts Co-authored-by: Chaitanya --- src/strategies/orbs-network-delegation/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/strategies/orbs-network-delegation/index.ts b/src/strategies/orbs-network-delegation/index.ts index ccb7bc200..b0a9915fc 100644 --- a/src/strategies/orbs-network-delegation/index.ts +++ b/src/strategies/orbs-network-delegation/index.ts @@ -4,7 +4,7 @@ import { Multicaller } from '../../utils'; import { getAddress } from '@ethersproject/address'; export const author = 'gadcl'; -export const version = '0.1.1'; +export const version = '0.1.2'; const abi = [ 'function getDelegatedStake(address addr) external view returns (uint256)', @@ -40,7 +40,7 @@ export async function strategy( const from = getAddress(address); const to = getAddress(delegation); delegations[from] = delegatorStake; - if (delegations[to]) { + if (delegations[to] && !override[to]) { delegations[to] = BigNumber.from(delegations[to]).sub(delegatorStake); } } From b04fe43587fb52c487359075b204fc64494e9bb5 Mon Sep 17 00:00:00 2001 From: rsquare Date: Thu, 1 Sep 2022 15:11:23 +0200 Subject: [PATCH 103/815] Otterspace badges [otterspace-badges] (#808) * Adding the otterspace bagdes strategy * Adding optimism network * Refactoring * Typo fixes * Removed optimism network * Adding rafts urn prefix in query * Added optimism config * Updating author name * Fetching by specs when specified in config * Added blocktag to graphql query --- src/strategies/index.ts | 4 +- src/strategies/otterspace-badges/README.md | 33 ++++++ .../otterspace-badges/examples.json | 94 ++++++++++++++++ src/strategies/otterspace-badges/index.ts | 106 ++++++++++++++++++ 4 files changed, 236 insertions(+), 1 deletion(-) create mode 100644 src/strategies/otterspace-badges/README.md create mode 100644 src/strategies/otterspace-badges/examples.json create mode 100644 src/strategies/otterspace-badges/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index b43c7d3b0..92dcadb3f 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -363,6 +363,7 @@ import * as fightClub from './fight-club'; import * as tproStaking from './tpro-staking'; import * as safeVested from './safe-vested'; import * as riskharborUnderwriter from './riskharbor-underwriter'; +import * as otterspaceBadges from './otterspace-badges'; const strategies = { 'forta-shares': fortaShares, @@ -729,7 +730,8 @@ const strategies = { 'fight-club': fightClub, 'tpro-staking': tproStaking, 'safe-vested': safeVested, - 'riskharbor-underwriter': riskharborUnderwriter + 'riskharbor-underwriter': riskharborUnderwriter, + 'otterspace-badges': otterspaceBadges }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/otterspace-badges/README.md b/src/strategies/otterspace-badges/README.md new file mode 100644 index 000000000..c4221dd9e --- /dev/null +++ b/src/strategies/otterspace-badges/README.md @@ -0,0 +1,33 @@ +# Otterspace Badges + +- A RAFT is an NFT that represents a community (or a DAO) within Otterspace. +- A RAFT has several badge specs under it. A badge spec is the design of a badge, which is essentially described as ERC721 metadata standard. +- Each BADGE is a non-transferable token built with [ERC4973]("https://github.com/otterspace-xyz/ERC4973") spec and maximally backwards compatible with ERC721. Each badge spec may have several badges associated which indicate the badges minted for that spec that is associated to a raft + +The parameters that must be specified when using this strategy are as follows + +- A RAFT token ID +- The RAFT's contract address +- An array of weights associated to the badge specs + +If no specs are specified, all badges under the RAFT are considered equal with the weight of 1 + +Here is an example of its usage: + +```json +{ + "symbol": "BADGES", + "raftTokenId": "1", + "raftAddress": "0xbb8997048e5f0bfe6c9d6bee63ede53bd0236bb2", + "specs": [ + { + "id": "bafyreicmofif36f2s4d2iv37gy532epnw7rwjf5rygdhzzh2iw6nmbunrq", + "weight": 5 + }, + { + "id": "bafyreihj2e3mxqwk24auglrfckk3eh2hzsq7eyghjpcprmopvok5wxz3bu", + "weight": 10 + } + ] +} +``` diff --git a/src/strategies/otterspace-badges/examples.json b/src/strategies/otterspace-badges/examples.json new file mode 100644 index 000000000..04e0dc26e --- /dev/null +++ b/src/strategies/otterspace-badges/examples.json @@ -0,0 +1,94 @@ +[ + { + "name": "Example query with specific badge specs", + "strategy": { + "name": "otterspace-badges", + "params": { + "symbol": "BADGES", + "raftTokenId": "1", + "raftAddress": "0xbb8997048e5f0bfe6c9d6bee63ede53bd0236bb2", + "specs": [ + { + "id": "bafyreicmofif36f2s4d2iv37gy532epnw7rwjf5rygdhzzh2iw6nmbunrq", + "weight": 5 + }, + { + "id": "bafyreihj2e3mxqwk24auglrfckk3eh2hzsq7eyghjpcprmopvok5wxz3bu", + "weight": 10 + } + ] + } + }, + "network": "5", + "addresses": [ + "0xbb9ecfd5685502977b5b7c1ac0cdff8c136a4da8", + "0x33d0bbd05cf3c7e040d33bc1f338585a087e5dd9", + "0x0F1c502d4EF5b1940a7A77062e51353D8B366547" + ], + "snapshot": 7509588 + }, + { + "name": "Example query for all badge specs", + "strategy": { + "name": "otterspace-badges", + "params": { + "symbol": "BADGES", + "raftTokenId": "1", + "raftAddress": "0xbb8997048e5f0bfe6c9d6bee63ede53bd0236bb2", + "specs": [] + } + }, + "network": "5", + "addresses": [ + "0xbb9ecfd5685502977b5b7c1ac0cdff8c136a4da8", + "0x33d0bbd05cf3c7e040d33bc1f338585a087e5dd9", + "0x0F1c502d4EF5b1940a7A77062e51353D8B366547" + ], + "snapshot": 7509588 + }, + { + "name": "Example query with specific badge specs", + "strategy": { + "name": "otterspace-badges", + "params": { + "symbol": "BADGES", + "raftTokenId": "1", + "specs": [ + { + "id": "bafyreibvclrxnfm5nrchvdqfog6t2usvlqiozwgxynrxwlgftl3ln7uxqe", + "weight": 5 + }, + { + "id": "bafyreicl3unvw6tvzjfduvrhxbfi74gsob6mpf6ekn3s2nkopqz2phtx7e", + "weight": 10 + } + ] + } + }, + "network": "10", + "addresses": [ + "0x76d84163bc0bbf58d6d3f2332f8a9c5b339df983", + "0x73677662f66088236ddfc95da42e405cf3f4ce13", + "0x0F1c502d4EF5b1940a7A77062e51353D8B366547" + ], + "snapshot": 21528802 + }, + { + "name": "Example query for all badge specs", + "strategy": { + "name": "otterspace-badges", + "params": { + "symbol": "BADGES", + "raftTokenId": "1", + "specs": [] + } + }, + "network": "10", + "addresses": [ + "0x76d84163bc0bbf58d6d3f2332f8a9c5b339df983", + "0x73677662f66088236ddfc95da42e405cf3f4ce13", + "0x0F1c502d4EF5b1940a7A77062e51353D8B366547" + ], + "snapshot": 21528802 + } +] diff --git a/src/strategies/otterspace-badges/index.ts b/src/strategies/otterspace-badges/index.ts new file mode 100644 index 000000000..834673216 --- /dev/null +++ b/src/strategies/otterspace-badges/index.ts @@ -0,0 +1,106 @@ +import { error } from 'console'; +import { subgraphRequest } from '../../utils'; + +export const author = 'otterspace-xyz'; +export const version = '1.0.0'; + +const OTTERSPACE_SUBGRAPH_API_URLS_BY_CHAIN_ID = { + '5': 'https://api.thegraph.com/subgraphs/name/otterspace-xyz/badges-goerli', + '10': 'https://api.thegraph.com/subgraphs/name/otterspace-xyz/badges-optimism' +}; + +function fetchBadgesForRaft( + network: string, + raftTokenId: string, + specIds: string[], + blockTag: number | string +): Promise { + const url = OTTERSPACE_SUBGRAPH_API_URLS_BY_CHAIN_ID[network]; + + if (url == undefined) { + throw new error(`Unsupported network with id: ${network}`); + } + + let specFilter: any = { + raft: `rafts:${raftTokenId}` + }; + if (specIds && specIds.length > 0) { + specFilter.id_in = specIds; + } + + let query = { + badges: { + __args: { + where: { + spec_: specFilter + }, + block: blockTag != 'latest' ? { number: blockTag } : null + }, + owner: true, + spec: { + id: true + } + } + }; + + return subgraphRequest(url, query); +} + +function getBadgeWeight(specs: any[], badgeSpecID: string): number { + let badgeWeight = 0; + + if (specs && specs.length > 0) { + const specConfig = specs.find((spec: any) => spec.id === badgeSpecID); + badgeWeight = specConfig ? specConfig.weight : 0; + } else { + badgeWeight = 1; + } + + return badgeWeight; +} + +function applyBadgeWeights(badges: [], options: any) { + let badgeWeights = {}; + + badges.forEach((badge: any) => { + const badgeAddress = badge.owner.toLowerCase(); + + if (badgeWeights[badgeAddress]) return; + + badgeWeights[badgeAddress] = getBadgeWeight(options.specs, badge.spec.id); + }); + + return badgeWeights; +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const getBadgesResponse = await fetchBadgesForRaft( + network, + options.raftTokenId, + options.specs.map((spec) => spec.id), + blockTag + ); + + let badgeWeights = {}; + let badges = getBadgesResponse?.badges; + if (!badges) return badgeWeights; + + badgeWeights = applyBadgeWeights(badges, options); + + return Object.fromEntries( + addresses.map((address: string) => [ + address, + badgeWeights[address.toLowerCase()] || 0 + ]) + ); +} From bc721f5b6731369cff279ee4a1fd6d3bf761016d Mon Sep 17 00:00:00 2001 From: Stephan <5469870+stephancill@users.noreply.github.com> Date: Fri, 2 Sep 2022 09:33:07 +0200 Subject: [PATCH 104/815] Add synthetic nouns claimer strategy (#812) --- src/strategies/index.ts | 4 +- .../synthetic-nouns-with-claimer/README.md | 14 ++++ .../examples.json | 19 +++++ .../synthetic-nouns-with-claimer/index.ts | 71 +++++++++++++++++++ 4 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 src/strategies/synthetic-nouns-with-claimer/README.md create mode 100644 src/strategies/synthetic-nouns-with-claimer/examples.json create mode 100644 src/strategies/synthetic-nouns-with-claimer/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 92dcadb3f..ae8e8f83b 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -364,6 +364,7 @@ import * as tproStaking from './tpro-staking'; import * as safeVested from './safe-vested'; import * as riskharborUnderwriter from './riskharbor-underwriter'; import * as otterspaceBadges from './otterspace-badges'; +import * as syntheticNounsClaimerOwner from './synthetic-nouns-with-claimer'; const strategies = { 'forta-shares': fortaShares, @@ -731,7 +732,8 @@ const strategies = { 'tpro-staking': tproStaking, 'safe-vested': safeVested, 'riskharbor-underwriter': riskharborUnderwriter, - 'otterspace-badges': otterspaceBadges + 'otterspace-badges': otterspaceBadges, + 'synthetic-nouns-with-claimer': syntheticNounsClaimerOwner }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/synthetic-nouns-with-claimer/README.md b/src/strategies/synthetic-nouns-with-claimer/README.md new file mode 100644 index 000000000..943484211 --- /dev/null +++ b/src/strategies/synthetic-nouns-with-claimer/README.md @@ -0,0 +1,14 @@ +# Synthetic Nouns + +This strategy allows you to determine if an address is eligible to vote by checking if it holds the unique NFT claimed by it originally. + +It uses the Zora API to find the minting event associated with the user address on the Synthetic Nouns contract and then checks if the NFT is still owned by the user. + +Here is an example of parameters: + +```json +{ + "address": "0x8761b55af5a703d5855f1865db8fe4dd18e94c53", + "symbol": "sNOUN" +} +``` diff --git a/src/strategies/synthetic-nouns-with-claimer/examples.json b/src/strategies/synthetic-nouns-with-claimer/examples.json new file mode 100644 index 000000000..12b4e66dd --- /dev/null +++ b/src/strategies/synthetic-nouns-with-claimer/examples.json @@ -0,0 +1,19 @@ +[ + { + "name": "Example query for Synthetic Nouns that are owned by the original claiming address", + "strategy": { + "name": "synthetic-nouns-with-claimer", + "params": { + "address": "0x8761b55af5a703d5855f1865db8fe4dd18e94c53", + "symbol": "sNOUN" + } + }, + "network": "1", + "addresses": [ + "0x8d25687829d6b85d9e0020b8c89e3ca24de20a89", + "0x368f593244f04c599b3328a23493680b23818fa6", + "0x7f16D5c969380E3420E17B4c3456A3844745A578" + ], + "snapshot": 15454334 + } +] diff --git a/src/strategies/synthetic-nouns-with-claimer/index.ts b/src/strategies/synthetic-nouns-with-claimer/index.ts new file mode 100644 index 000000000..ab5e1e5f6 --- /dev/null +++ b/src/strategies/synthetic-nouns-with-claimer/index.ts @@ -0,0 +1,71 @@ +import { Multicaller } from '../../utils'; +import fetch from 'cross-fetch'; + +export const author = 'stephancill'; +export const version = '0.1.0'; + +const abi = ['function ownerOf(uint256 index) external view returns (address)']; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + // Get the minter from zora api + const mints = await fetch('https://api.zora.co/graphql', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + query: `{ + mints(where: {collectionAddresses: "${ + options.address + }", minterAddresses: ${JSON.stringify( + addresses + )}}, pagination: {limit: 500}) { + nodes { + mint { + tokenId, + toAddress + } + } + } + }` + }) + }).then((res) => res.json()); + + const mintsByAddress = mints.data.mints.nodes.reduce((acc, node) => { + const address = node.mint.toAddress; + const tokenId = node.mint.tokenId; + if (!acc[address]) { + acc[address] = undefined; + } + acc[address] = tokenId; + return acc; + }, {}); + + // Use multicall to check if the token is owned by the address + const multicaller = new Multicaller(network, provider, abi, { + blockTag + }); + addresses.forEach((address) => { + if (mintsByAddress[address]) { + multicaller.call(address, options.address, 'ownerOf', [ + mintsByAddress[address] + ]); + } + }); + + const response = await multicaller.execute(); + + return Object.fromEntries( + addresses.map((address) => [ + address, + response[address] && response[address].toLowerCase() === address ? 1 : 0 + ]) + ); +} From bd84bd03789898e9b5d4b1beca1a69855152c2cd Mon Sep 17 00:00:00 2001 From: Syed Mohib Uddin <36672373+syedMohib44@users.noreply.github.com> Date: Fri, 2 Sep 2022 13:11:25 +0500 Subject: [PATCH 105/815] Ethermon-ERC721 Changes for calculating vote power [ethermon-erc721] (#813) * ckear * Version 0.0.1 [ethermon-erc721] * Version 0.0.1 [ethermon-erc721] * Update src/strategies/ethermon-erc721/index.ts Co-authored-by: Chaitanya * Commit before Pull * Update address.json Removed additional addresses * Update delegation.ts Reverted address and snapshot block number back to original * Update index.spec.ts Removed log and reverted test cases to original * Updated Score.ts Removed additional addresses and changed chain id back to 1 from 137 * Update Score.ts Removed null address * Update index.spec.ts Reverted changes on test * Update index.ts Removed ethermon-erc721 import * Update index.ts Fetching weight from IPFS file instead of params * Update example.json Replaced weights objects with IPFS hash * Delete package-lock.json Removed package-lock.json * Strategy added to index.ts * Commit before pull * Changed default ipfs gateway to fleek * Changed default IPFS gateway to fleek * Fixed string concat issue instead of addition of number * Removing invalid file This file may be created mistakenly * Removing Package.json Co-authored-by: Syed Mohib Co-authored-by: Chaitanya --- src/strategies/ethermon-erc721/examples.json | 16 ++++++++------ src/strategies/ethermon-erc721/index.ts | 23 ++++++++++---------- test/addresses.json | 2 +- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/strategies/ethermon-erc721/examples.json b/src/strategies/ethermon-erc721/examples.json index 0bced1cfa..7bfd4baa2 100644 --- a/src/strategies/ethermon-erc721/examples.json +++ b/src/strategies/ethermon-erc721/examples.json @@ -4,14 +4,16 @@ "strategy": { "name": "ethermon-erc721", "params": { - "EMON_DATA_ADDRESS": "0x5d00d312e171be5342067c09bae883f9bcb2003b", - "EMONA_ADDRESS": "0xabc1c404424bdf24c19a5cc5ef8f47781d18eb3e", - "symbol": "EMONA", - "tokenWeightIPFS": "abb6cbba-f8e6-4fce-89a8-7360cda5daf9-bucket/weights.json" + "EMONA_ADDRESS": "0x9928a8ea82d86290dfd1920e126b3872890525b3", + "tokenWeightIPFS": "abb6cbba-f8e6-4fce-89a8-7360cda5daf9-bucket/weights.json", + "EMON_DATA_ADDRESS": "0x0f05607e51d5224300520a710898a8467d8d1117", + "symbol": "EMONA" } }, - "network": "1", - "addresses": ["0x038ae33f4bbfd9e0489abd7e622f014244433f72"], - "snapshot": 13847063 + "network": "137", + "addresses": [ + "0x111c26A02ca4050684D4083d72E2A7C1dCbA853f" + ], + "snapshot": 14101222 } ] diff --git a/src/strategies/ethermon-erc721/index.ts b/src/strategies/ethermon-erc721/index.ts index 25159fdc2..b2cd5fe2d 100644 --- a/src/strategies/ethermon-erc721/index.ts +++ b/src/strategies/ethermon-erc721/index.ts @@ -3,7 +3,7 @@ import { BigNumber } from '@ethersproject/bignumber'; import { Multicaller } from '../../utils'; export const author = 'syedMohib44'; -export const version = '0.0.1'; +export const version = '0.0.2'; const abi1 = [ 'function getMonsterObj(uint64 _objId) external view returns(uint64 objId, uint32 classId, address trainer, uint32 exp, uint32 createIndex, uint32 lastClaimIndex, uint createTime)', @@ -26,7 +26,7 @@ export async function strategy( Math.min(Math.max(num, min), max); addresses.map((address) => { - multi.call(address, options.EMON_DATA_ADDRESS, 'balanceOf', [address]); + multi.call(address, options.EMONA_ADDRESS, 'balanceOf', [address]); }); const player_addresses: Record = await multi.execute(); @@ -37,7 +37,7 @@ export async function strategy( for (let i = 0; i < balance; i++) { multi1.call( address[0].toString() + '-' + i.toString(), - options.EMON_DATA_ADDRESS, + options.EMONA_ADDRESS, 'tokenOfOwnerByIndex', [address[0], i] ); @@ -49,7 +49,7 @@ export async function strategy( Object.entries(address_tokens).forEach((address_token) => { const address = address_token[0].split('-')[0].toString(); const token = +address_token[1].toString(); - multi2.call(address + '-' + token, options.EMONA_ADDRESS, 'getMonsterObj', [ + multi2.call(address + '-' + token, options.EMON_DATA_ADDRESS, 'getMonsterObj', [ token ]); }); @@ -80,15 +80,14 @@ export async function strategy( } result[address] += - +player_addresses[address].toString() > 200 - ? (classIdWeight[classId] - ? (classIdWeight[classId].weight / 200) * - +player_addresses[address].toString() - : 0 - ).toFixed(0) + Number((+player_addresses[address].toString() > 200) + ? Number(classIdWeight[classId] + ? ((classIdWeight[classId].weight / 200) * Number(player_addresses[address])) + : 0 + ).toFixed(0) : classIdWeight[classId] - ? classIdWeight[classId].weight - : 0; + ? classIdWeight[classId].weight + : 0); } return Object.fromEntries( Object.entries(result).map(([address, balance]) => [address, balance]) diff --git a/test/addresses.json b/test/addresses.json index d490cc630..8d2f88206 100644 --- a/test/addresses.json +++ b/test/addresses.json @@ -3349,4 +3349,4 @@ "0x3dDEA4021C4956a5347B01C05BE72cCa2dfE5653", "0x6271aDd46DCbb4B4EF5b32F18704bDd716BD9be9", "0xF12504E1d4917A2eBa3c27794186be17C0f02033" -] +] \ No newline at end of file From e75a242cda66e387fdd0f69f6d27e437833cb58c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 4 Sep 2022 21:56:40 +0530 Subject: [PATCH 106/815] Automated lint (#814) Co-authored-by: ChaituVR --- src/strategies/ethermon-erc721/examples.json | 4 +- src/strategies/ethermon-erc721/index.ts | 28 +++++++----- .../gysr-lp-staking-balance/schema.json | 2 +- src/strategies/otterspace-badges/index.ts | 8 ++-- src/strategies/safe-vested/examples.json | 45 +++++++++---------- test/addresses.json | 2 +- 6 files changed, 46 insertions(+), 43 deletions(-) diff --git a/src/strategies/ethermon-erc721/examples.json b/src/strategies/ethermon-erc721/examples.json index 7bfd4baa2..17fc08ee3 100644 --- a/src/strategies/ethermon-erc721/examples.json +++ b/src/strategies/ethermon-erc721/examples.json @@ -11,9 +11,7 @@ } }, "network": "137", - "addresses": [ - "0x111c26A02ca4050684D4083d72E2A7C1dCbA853f" - ], + "addresses": ["0x111c26A02ca4050684D4083d72E2A7C1dCbA853f"], "snapshot": 14101222 } ] diff --git a/src/strategies/ethermon-erc721/index.ts b/src/strategies/ethermon-erc721/index.ts index b2cd5fe2d..1fa0bfc18 100644 --- a/src/strategies/ethermon-erc721/index.ts +++ b/src/strategies/ethermon-erc721/index.ts @@ -49,9 +49,12 @@ export async function strategy( Object.entries(address_tokens).forEach((address_token) => { const address = address_token[0].split('-')[0].toString(); const token = +address_token[1].toString(); - multi2.call(address + '-' + token, options.EMON_DATA_ADDRESS, 'getMonsterObj', [ - token - ]); + multi2.call( + address + '-' + token, + options.EMON_DATA_ADDRESS, + 'getMonsterObj', + [token] + ); }); const monObject: Record = await multi2.execute(); @@ -79,15 +82,18 @@ export async function strategy( continue; } - result[address] += - Number((+player_addresses[address].toString() > 200) - ? Number(classIdWeight[classId] - ? ((classIdWeight[classId].weight / 200) * Number(player_addresses[address])) - : 0 - ).toFixed(0) + result[address] += Number( + +player_addresses[address].toString() > 200 + ? Number( + classIdWeight[classId] + ? (classIdWeight[classId].weight / 200) * + Number(player_addresses[address]) + : 0 + ).toFixed(0) : classIdWeight[classId] - ? classIdWeight[classId].weight - : 0); + ? classIdWeight[classId].weight + : 0 + ); } return Object.fromEntries( Object.entries(result).map(([address, balance]) => [address, balance]) diff --git a/src/strategies/gysr-lp-staking-balance/schema.json b/src/strategies/gysr-lp-staking-balance/schema.json index 4923eb86f..4aef4cbb9 100644 --- a/src/strategies/gysr-lp-staking-balance/schema.json +++ b/src/strategies/gysr-lp-staking-balance/schema.json @@ -32,7 +32,7 @@ "type": "number", "title": "Decimals", "examples": ["e.g. 18"] - } + } }, "required": ["pool", "tokenAddress", "decimals"], "additionalProperties": false diff --git a/src/strategies/otterspace-badges/index.ts b/src/strategies/otterspace-badges/index.ts index 834673216..c805d0b53 100644 --- a/src/strategies/otterspace-badges/index.ts +++ b/src/strategies/otterspace-badges/index.ts @@ -21,14 +21,14 @@ function fetchBadgesForRaft( throw new error(`Unsupported network with id: ${network}`); } - let specFilter: any = { + const specFilter: any = { raft: `rafts:${raftTokenId}` }; if (specIds && specIds.length > 0) { specFilter.id_in = specIds; } - let query = { + const query = { badges: { __args: { where: { @@ -60,7 +60,7 @@ function getBadgeWeight(specs: any[], badgeSpecID: string): number { } function applyBadgeWeights(badges: [], options: any) { - let badgeWeights = {}; + const badgeWeights = {}; badges.forEach((badge: any) => { const badgeAddress = badge.owner.toLowerCase(); @@ -92,7 +92,7 @@ export async function strategy( ); let badgeWeights = {}; - let badges = getBadgesResponse?.badges; + const badges = getBadgesResponse?.badges; if (!badges) return badgeWeights; badgeWeights = applyBadgeWeights(badges, options); diff --git a/src/strategies/safe-vested/examples.json b/src/strategies/safe-vested/examples.json index 843b63ad0..ce9e3659f 100755 --- a/src/strategies/safe-vested/examples.json +++ b/src/strategies/safe-vested/examples.json @@ -1,24 +1,23 @@ [ - { - "name": "Example query", - "strategy": { - "name": "safe-vested", - "params": { - "allocationsSource": "https://raw.githubusercontent.com/5afe/claiming-app-data/7942c2b6757c02fadb32d58dde09a12a35f5a462/resources/data/snapshot-allocations-test.json" - } - }, - "network": "4", - "snapshot": 11250000, - "addresses": [ - "0x9970dcab40e29a84D1020DeaEa443dCE1d8471b7", - "0x1230B3d59858296A31053C1b8562Ecf89A2f888b", - "0x121Cf7457171bD7a93232807CBa65f7Bd7a48a2d", - "0xda2242a6DbDa924bf7D7DB8aC9482d4763EB211C", - "0xf2565317F3Ae8Ae9EA98E9Fe1e7FADC77F823cbD", - "0x37b828802FAeA4244d176Da386CF632F5Bbc414F", - "0xA8FFD6B87388F8d5FACfDa0147d9B0Da511539b6", - "0xd7539FCdC0aB79a7B688b04387cb128E75cb77Dc" - ] - } - ] - \ No newline at end of file + { + "name": "Example query", + "strategy": { + "name": "safe-vested", + "params": { + "allocationsSource": "https://raw.githubusercontent.com/5afe/claiming-app-data/7942c2b6757c02fadb32d58dde09a12a35f5a462/resources/data/snapshot-allocations-test.json" + } + }, + "network": "4", + "snapshot": 11250000, + "addresses": [ + "0x9970dcab40e29a84D1020DeaEa443dCE1d8471b7", + "0x1230B3d59858296A31053C1b8562Ecf89A2f888b", + "0x121Cf7457171bD7a93232807CBa65f7Bd7a48a2d", + "0xda2242a6DbDa924bf7D7DB8aC9482d4763EB211C", + "0xf2565317F3Ae8Ae9EA98E9Fe1e7FADC77F823cbD", + "0x37b828802FAeA4244d176Da386CF632F5Bbc414F", + "0xA8FFD6B87388F8d5FACfDa0147d9B0Da511539b6", + "0xd7539FCdC0aB79a7B688b04387cb128E75cb77Dc" + ] + } +] diff --git a/test/addresses.json b/test/addresses.json index 8d2f88206..d490cc630 100644 --- a/test/addresses.json +++ b/test/addresses.json @@ -3349,4 +3349,4 @@ "0x3dDEA4021C4956a5347B01C05BE72cCa2dfE5653", "0x6271aDd46DCbb4B4EF5b32F18704bDd716BD9be9", "0xF12504E1d4917A2eBa3c27794186be17C0f02033" -] \ No newline at end of file +] From 47692d4c5d99021dc786db81dd904ebb54fe2c22 Mon Sep 17 00:00:00 2001 From: Drew <89287674+dewpe@users.noreply.github.com> Date: Mon, 5 Sep 2022 02:51:34 -0500 Subject: [PATCH 107/815] [riskharbor-underwriter] returned checksum address instead (#815) * added underwriter strategy * Update src/strategies/riskharbor-underwriter/index.ts * returned checksum address * bumped version Co-authored-by: Chaitanya --- src/strategies/riskharbor-underwriter/examples.json | 5 ++--- src/strategies/riskharbor-underwriter/index.ts | 5 +++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/strategies/riskharbor-underwriter/examples.json b/src/strategies/riskharbor-underwriter/examples.json index f5d6fbf43..154fe0f76 100644 --- a/src/strategies/riskharbor-underwriter/examples.json +++ b/src/strategies/riskharbor-underwriter/examples.json @@ -10,9 +10,8 @@ }, "network": "42161", "addresses": [ - "0x02a41565811ad5fe8f21d738c8ce2995d224fee4", - "0xd4d4e905d7f1eb095769face2c2be516865e4981", - "0xd401c5b54a079420c6c7d9405fafc9a10cd8a4ed", + "0xD4D4e905d7F1Eb095769fAce2C2bE516865E4981", + "0xd401c5B54A079420C6C7D9405faFc9a10CD8a4ed", "0x010dab3779810cf08ac213b9efa915821bb43e26", "0x0dcdd4f4a70ebb2eaffd5a01bd6cacde14dae4f0", "0xfc9bffa77c2b725add71f4ad88bbe228d5601eb3", diff --git a/src/strategies/riskharbor-underwriter/index.ts b/src/strategies/riskharbor-underwriter/index.ts index 32099b437..a615a771f 100644 --- a/src/strategies/riskharbor-underwriter/index.ts +++ b/src/strategies/riskharbor-underwriter/index.ts @@ -1,9 +1,10 @@ +import { getAddress } from '@ethersproject/address'; import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; import { formatUnits } from '@ethersproject/units'; import { subgraphRequest } from '../../utils'; export const author = 'dewpe'; -export const version = '0.1.0'; +export const version = '0.1.1'; export async function strategy( _space, @@ -70,7 +71,7 @@ export async function strategy( return Object.fromEntries( Object.entries(agUserBals).map(([address, balance]) => [ - address, + getAddress(address), // Divide each bal by 1eDecimals parseFloat(formatUnits(balance, decimals)) ]) From 1c2bb6fc338e1ea713ba06cb665c1c28deedd899 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 5 Sep 2022 20:13:02 +0530 Subject: [PATCH 108/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.26 (#816) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 8e50aaba6..aae4fbc38 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.25", + "@snapshot-labs/snapshot.js": "^0.4.26", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", "copyfiles": "^2.4.1", diff --git a/yarn.lock b/yarn.lock index fc0951111..5d39e6a79 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.25": - version "0.4.25" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.25.tgz#c2a3a994a8eb2c7f3506463b5c9e7ab7b3e81f35" - integrity sha512-5rWC7eSDibmx38dlKiDaZNJ+Z2FAQovYilr7xQfpOwz1wkcx4ruZJoD95Rj0/SlWy2MMoEFVsuSs7pCnNBb5JA== +"@snapshot-labs/snapshot.js@^0.4.26": + version "0.4.26" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.26.tgz#831701f109814f479a0e8b5a00f9689abf57b770" + integrity sha512-0BYJX8eo9A0SJBr4fRSoXlNTONn+WfyJLzimybjpqrAV+dk6BmKxuhGDaIEb+QoDfnpU2N2XSC2BW97JyLvb/A== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 778d8310430e3552ecdabc93314032c291c1a219 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 5 Sep 2022 22:20:41 +0530 Subject: [PATCH 109/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.27 (#817) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index aae4fbc38..75f7a175a 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.26", + "@snapshot-labs/snapshot.js": "^0.4.27", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", "copyfiles": "^2.4.1", diff --git a/yarn.lock b/yarn.lock index 5d39e6a79..58cc9cada 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.26": - version "0.4.26" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.26.tgz#831701f109814f479a0e8b5a00f9689abf57b770" - integrity sha512-0BYJX8eo9A0SJBr4fRSoXlNTONn+WfyJLzimybjpqrAV+dk6BmKxuhGDaIEb+QoDfnpU2N2XSC2BW97JyLvb/A== +"@snapshot-labs/snapshot.js@^0.4.27": + version "0.4.27" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.27.tgz#f1b98134da9f02f9e07b3a7af67d366ef879a5d7" + integrity sha512-lIfo+74a5BCiRDCILgUqCiNcvR4n1ypFDyVECp6wCdnU7pV/vMKUb4db+fpzBGrIpjfWCQw+MhOJzsJUv4MHwg== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From b11d2fb1612f9a0217df4688858b2a7f7d3f5588 Mon Sep 17 00:00:00 2001 From: Shadab Khan Date: Tue, 6 Sep 2022 14:44:14 +0530 Subject: [PATCH 110/815] feat: add lrc lp subgraph balance strategy [lrc-lp-subgraph-balance-of] (#818) * feat: add lrc lp subgraph balance strategy [lrc-lp-subgraph-balance-of] * Update src/strategies/lrc-lp-subgraph-balance-of/index.ts * fix: add address with positive balance to examples.json Co-authored-by: Chaitanya --- src/strategies/index.ts | 2 + .../lrc-lp-subgraph-balance-of/README.md | 19 ++ .../lrc-lp-subgraph-balance-of/examples.json | 42 ++++ .../lrc-lp-subgraph-balance-of/index.ts | 214 ++++++++++++++++++ 4 files changed, 277 insertions(+) create mode 100644 src/strategies/lrc-lp-subgraph-balance-of/README.md create mode 100644 src/strategies/lrc-lp-subgraph-balance-of/examples.json create mode 100644 src/strategies/lrc-lp-subgraph-balance-of/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index ae8e8f83b..dd1686a82 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -342,6 +342,7 @@ import * as solvVoucherClaimable from './solv-voucher-claimable'; import * as h2o from './h2o'; import * as dopamine from './dopamine'; import * as lrcL2SubgraphBalanceOf from './lrc-l2-subgraph-balance-of'; +import * as lrcLPSubgraphBalanceOf from './lrc-lp-subgraph-balance-of'; import * as erc3525VestingVoucher from './erc3525-vesting-voucher'; import * as rariFuse from './rari-fuse'; import * as selfswap from './selfswap'; @@ -711,6 +712,7 @@ const strategies = { h2o, dopamine, 'lrc-l2-subgraph-balance-of': lrcL2SubgraphBalanceOf, + 'lrc-lp-subgraph-balance-of': lrcLPSubgraphBalanceOf, 'rari-fuse': rariFuse, 'bancor-pool-token-underlying-balance': bancorPoolTokenUnderlyingBalance, selfswap, diff --git a/src/strategies/lrc-lp-subgraph-balance-of/README.md b/src/strategies/lrc-lp-subgraph-balance-of/README.md new file mode 100644 index 000000000..de7226542 --- /dev/null +++ b/src/strategies/lrc-lp-subgraph-balance-of/README.md @@ -0,0 +1,19 @@ +# lrc-l2-subgraph-balance-of + +Strategy to read account LRC LP balance from LoopringV2 subgraph. + +Here is an example of parameters: + +```json +{ + "symbol": "LRC", + "tokenIdToPoolMap": { + "235": "0x194db39e4c99f6c8dd81b4647465f7599f3c215a", + "102": "0xe6cc0d45c4e4f81be340f4d176e6ce0d63ad5743", + "83": "0x18920d6e6fb7ebe057a4dd9260d6d95845c95036", + "168": "0xfa6680779dc9168600bcdcaff28b41c8fa568d98", + "200": "0xc8f242b2ac6069ebdc876ba0ef42efbf03c5ba4b" + }, + "graph": "https://api.thegraph.com/subgraphs/name/juanmardefago/loopring36" +} +``` diff --git a/src/strategies/lrc-lp-subgraph-balance-of/examples.json b/src/strategies/lrc-lp-subgraph-balance-of/examples.json new file mode 100644 index 000000000..280a05787 --- /dev/null +++ b/src/strategies/lrc-lp-subgraph-balance-of/examples.json @@ -0,0 +1,42 @@ +[ + { + "name": "LoopringV2 LP Balance", + "strategy": { + "name": "lrc-lp-subgraph-balance-of", + "params": { + "symbol": "LRC", + "tokenIdToPoolMap": { + "235": "0x194db39e4c99f6c8dd81b4647465f7599f3c215a", + "102": "0xe6cc0d45c4e4f81be340f4d176e6ce0d63ad5743", + "83": "0x18920d6e6fb7ebe057a4dd9260d6d95845c95036", + "168": "0xfa6680779dc9168600bcdcaff28b41c8fa568d98", + "200": "0xc8f242b2ac6069ebdc876ba0ef42efbf03c5ba4b" + }, + "graph": "https://api.thegraph.com/subgraphs/name/juanmardefago/loopring36" + } + }, + "network": "1", + "addresses": [ + "0xa478c2975ab1ea89e8196811f51a7b7ade33eb11", + "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", + "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", + "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", + "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e", + "0x1d5E65a087eBc3d03a294412E46CE5D6882969f4", + "0x1f254336E5c46639A851b9CfC165697150a6c327", + "0x2ec3F80BeDA63Ede96BA20375032CDD3aAfb3030", + "0x4AcBcA6BE2f8D2540bBF4CA77E45dA0A4a095Fa2", + "0x4F3D348a6D09837Ae7961B1E0cEe2cc118cec777", + "0x6D7f23A509E212Ba7773EC1b2505d1A134f54fbe", + "0x07a1f6fc89223c5ebD4e4ddaE89Ac97629856A0f", + "0x8d5F05270da470e015b67Ab5042BDbE2D2FEFB48", + "0x8d07D225a769b7Af3A923481E1FdF49180e6A265", + "0x8f60501dE5b9b01F9EAf1214dbE1924aA97F7fd0", + "0x9B8e8dD9151260c21CB6D7cc59067cd8DF306D58", + "0x17ea92D6FfbAA1c7F6B117c1E9D0c88ABdc8b84C", + "0x38C0039247A31F3939baE65e953612125cB88268", + "0x2b1284fa49af4f7b1a6563e1ec7f88767f2a3900" + ], + "snapshot": 15482770 + } +] diff --git a/src/strategies/lrc-lp-subgraph-balance-of/index.ts b/src/strategies/lrc-lp-subgraph-balance-of/index.ts new file mode 100644 index 000000000..89ccfb990 --- /dev/null +++ b/src/strategies/lrc-lp-subgraph-balance-of/index.ts @@ -0,0 +1,214 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import { subgraphRequest } from '../../utils'; + +export const author = 'shad-k'; +export const version = '0.1.1'; + +const LIMIT = 500; + +function makeUserQuery(snapshot, addresses, tokenIds) { + const query: any = { + accounts: { + __args: { + where: { + address_in: addresses + }, + first: LIMIT + }, + balances: { + __args: { + where: { + token_in: tokenIds + } + }, + balance: true, + token: { + id: true, + decimals: true + } + }, + address: true + } + }; + + if (snapshot !== 'latest') { + query.accounts.__args = { + ...query.accounts.__args, + block: { + number: snapshot + } + }; + } + + return query; +} + +function makePoolQuery(snapshot, addresses, tokenIds) { + const query: any = { + pools: { + __args: { + where: { + address_in: addresses + } + }, + address: true, + balances: { + __args: { + where: { + token_in: ['1', ...tokenIds] + } + }, + balance: true, + token: { + id: true, + decimals: true + } + } + } + }; + + if (snapshot !== 'latest') { + query.pools.__args = { + ...query.pools.__args, + block: { + number: snapshot + } + }; + } + + return query; +} + +function calculateUserScore( + addressToBalancesMap, + calculatedPoolMultipliers, + tokenIdToPoolMap +): number { + let score = 0; + + addressToBalancesMap.forEach(({ balance, token }) => { + const tokenBalance = BigNumber.from(balance); + + const lpTokenScore = tokenBalance + .mul( + calculatedPoolMultipliers[tokenIdToPoolMap[token?.id]].numOfLRCInPool + ) + .div( + calculatedPoolMultipliers[tokenIdToPoolMap[token?.id]].totalLPTokens + ); + + score += lpTokenScore.toNumber(); + }); + + return score; +} + +function calculatePoolMultipliers( + poolToBalancesMap +): Record> { + return Object.fromEntries( + Object.keys(poolToBalancesMap).map((poolAddress) => { + let numOfLRCInPool = BigNumber.from(0); + let totalLPTokens = BigNumber.from(0); + + poolToBalancesMap[poolAddress].forEach(({ balance, token }) => { + if (parseInt(token.id) === 1) { + const lrcTokenBalance = BigNumber.from(balance).div( + BigNumber.from(10).pow(token?.decimals ?? 18) + ); + numOfLRCInPool = lrcTokenBalance; + } else { + const lpTokenBalance = BigNumber.from(balance); + totalLPTokens = BigNumber.from(2).pow(96).sub(lpTokenBalance); + } + }); + + return [poolAddress, { numOfLRCInPool, totalLPTokens }]; + }) + ); +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const _addresses = addresses.map((address) => address.toLowerCase()); + const addressSubsets = Array.apply( + null, + Array(Math.ceil(_addresses.length / LIMIT)) + ).map((_e, i) => _addresses.slice(i * LIMIT, (i + 1) * LIMIT)); + + const tokenIds: Array = []; + const poolAddresses: Array = []; + + // get tokenIds and poolAddresses from tokenIdToPoolMap + for (const [tokenId, poolAddress] of Object.entries( + options.tokenIdToPoolMap + )) { + tokenIds.push(tokenId); + poolAddresses.push(poolAddress as string); + } + + // fetch user LP token balances + const response = await Promise.all( + addressSubsets.map((subset) => + subgraphRequest(options.graph, makeUserQuery(snapshot, subset, tokenIds)) + ) + ); + + const accounts = response.map((data) => data.accounts).flat(); + const addressToLPBalancesMap = Object.fromEntries( + accounts.map((account) => { + if (account.balances.length > 0) { + return [account.address, account.balances]; + } + + return [account.address, []]; + }) + ); + + // fetch pool LP and LRC token balances + const poolAccountBalances = await subgraphRequest( + options.graph, + makePoolQuery(snapshot, poolAddresses, tokenIds) + ); + + const poolToBalancesMap = Object.fromEntries( + poolAccountBalances.pools.map((pool) => { + if (pool.balances.length > 0) { + return [pool.address, pool.balances]; + } + + return [pool.address, 0]; + }) + ); + + // calculate numOfLRCInPool and totalLPTokens for each pool + const calculatedPoolMultipliers = calculatePoolMultipliers(poolToBalancesMap); + + // calculate user score + const addressToScoreMap = Object.fromEntries( + Object.keys(addressToLPBalancesMap).map((userAddress) => { + const userScore = calculateUserScore( + addressToLPBalancesMap[userAddress], + calculatedPoolMultipliers, + options.tokenIdToPoolMap + ); + + return [userAddress.toLowerCase(), userScore]; + }) + ); + + const scores = Object.fromEntries( + addresses.map((address) => [ + address, + addressToScoreMap[address.toLowerCase()] + ]) + ); + + return scores; +} From 847c9894c1f9d7970e6c0743a9b2a47c2c732a6b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 6 Sep 2022 16:51:01 +0530 Subject: [PATCH 111/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.28 (#819) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 75f7a175a..fd723ea34 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.27", + "@snapshot-labs/snapshot.js": "^0.4.28", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", "copyfiles": "^2.4.1", diff --git a/yarn.lock b/yarn.lock index 58cc9cada..f6e0f5aa6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.27": - version "0.4.27" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.27.tgz#f1b98134da9f02f9e07b3a7af67d366ef879a5d7" - integrity sha512-lIfo+74a5BCiRDCILgUqCiNcvR4n1ypFDyVECp6wCdnU7pV/vMKUb4db+fpzBGrIpjfWCQw+MhOJzsJUv4MHwg== +"@snapshot-labs/snapshot.js@^0.4.28": + version "0.4.28" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.28.tgz#503a460473fce28b3ef52717077753cb65d230a7" + integrity sha512-zP/XtR6gzoF5KjD8q9PdlN7HMQGC1yX9pT1hK185xqfdwB57Ut+Jk3Sk7Sr6bRygSSTlSSyg12zZ1EdHwZMGyw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 18262847ee404a68c89fcac46ac36b84ab1cf135 Mon Sep 17 00:00:00 2001 From: Stephan <5469870+stephancill@users.noreply.github.com> Date: Wed, 7 Sep 2022 07:08:34 +0200 Subject: [PATCH 112/815] Fix inconsistent address cases (#821) --- .../synthetic-nouns-with-claimer/examples.json | 3 ++- .../synthetic-nouns-with-claimer/index.ts | 16 ++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/strategies/synthetic-nouns-with-claimer/examples.json b/src/strategies/synthetic-nouns-with-claimer/examples.json index 12b4e66dd..b72dc492f 100644 --- a/src/strategies/synthetic-nouns-with-claimer/examples.json +++ b/src/strategies/synthetic-nouns-with-claimer/examples.json @@ -12,8 +12,9 @@ "addresses": [ "0x8d25687829d6b85d9e0020b8c89e3ca24de20a89", "0x368f593244f04c599b3328a23493680b23818fa6", + "0x6ab075abfA7cdD7B19FA83663b1f2a83e4A957e3", "0x7f16D5c969380E3420E17B4c3456A3844745A578" ], - "snapshot": 15454334 + "snapshot": 15486783 } ] diff --git a/src/strategies/synthetic-nouns-with-claimer/index.ts b/src/strategies/synthetic-nouns-with-claimer/index.ts index ab5e1e5f6..914cf3023 100644 --- a/src/strategies/synthetic-nouns-with-claimer/index.ts +++ b/src/strategies/synthetic-nouns-with-claimer/index.ts @@ -1,6 +1,6 @@ import { Multicaller } from '../../utils'; import fetch from 'cross-fetch'; - +import { getAddress } from '@ethersproject/address'; export const author = 'stephancill'; export const version = '0.1.0'; @@ -16,6 +16,8 @@ export async function strategy( ) { const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const checksummedAddresses = addresses.map((address) => getAddress(address)); + // Get the minter from zora api const mints = await fetch('https://api.zora.co/graphql', { method: 'POST', @@ -39,7 +41,7 @@ export async function strategy( }).then((res) => res.json()); const mintsByAddress = mints.data.mints.nodes.reduce((acc, node) => { - const address = node.mint.toAddress; + const address = getAddress(node.mint.toAddress); const tokenId = node.mint.tokenId; if (!acc[address]) { acc[address] = undefined; @@ -52,7 +54,7 @@ export async function strategy( const multicaller = new Multicaller(network, provider, abi, { blockTag }); - addresses.forEach((address) => { + checksummedAddresses.forEach((address) => { if (mintsByAddress[address]) { multicaller.call(address, options.address, 'ownerOf', [ mintsByAddress[address] @@ -62,10 +64,12 @@ export async function strategy( const response = await multicaller.execute(); - return Object.fromEntries( - addresses.map((address) => [ + const scores = Object.fromEntries( + checksummedAddresses.map((address) => [ address, - response[address] && response[address].toLowerCase() === address ? 1 : 0 + response[address] && getAddress(response[address]) === address ? 1 : 0 ]) ); + + return scores; } From 7166262e39ae834b71189de31ee9cb0e0e9e39da Mon Sep 17 00:00:00 2001 From: pepperstepper <86356812+pepperstepper@users.noreply.github.com> Date: Fri, 9 Sep 2022 07:58:39 +0100 Subject: [PATCH 113/815] Update MinotaurMoney voting strategy [minotaur-money] (#820) * Update MinotaurMoney voting strategy * Fix inconsistent address cases (#821) * update to latest cronos blocknumber * refactor * refactor 2 * bump version * fix ws scaling * remove 1 call * refactor 3 * remove a second call * add some comments Co-authored-by: Stephan <5469870+stephancill@users.noreply.github.com> --- src/strategies/minotaur-money/examples.json | 2 +- src/strategies/minotaur-money/index.ts | 89 +++++++++++---------- 2 files changed, 48 insertions(+), 43 deletions(-) diff --git a/src/strategies/minotaur-money/examples.json b/src/strategies/minotaur-money/examples.json index 2c5beb5c6..409e47d27 100644 --- a/src/strategies/minotaur-money/examples.json +++ b/src/strategies/minotaur-money/examples.json @@ -12,6 +12,6 @@ "0x4E5D385E44DCD0b7adf5fBe03A6BB867A8A90E7B", "0x86Fdd9980aCD3e2C8e7959Db344Ff6D5FD5743F5" ], - "snapshot": 2917145 + "snapshot": 4521240 } ] diff --git a/src/strategies/minotaur-money/index.ts b/src/strategies/minotaur-money/index.ts index d3a2cb089..942453486 100644 --- a/src/strategies/minotaur-money/index.ts +++ b/src/strategies/minotaur-money/index.ts @@ -2,14 +2,16 @@ import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; import { Multicaller, call } from '../../utils'; export const author = 'pepperstepper'; -export const version = '0.0.3'; +export const version = '0.0.4'; const minoContractAddress = '0x3A1138075bd97a33F23A87824b811146FA44288E'; const sMinoContractAddress = '0xB46fe6791A30d51970EA3B840C9fa5F1F107b86F'; +const wsMinoContractAddress = '0x1066c6753FFaf8540F691643A6D683e23599c4ab'; //const mmfPoolAddressOld = '0x57E8f8F7447D8d02fe4D291378D37E67D393257A'; -const mmfPoolAddressOld = '0x849f97c5452cc4bad1069b8efe2b3561b06694c3'; -const mmfPoolAddressNew = '0xf6a96e753dec01acb659acbe75deba46d53ebc5e'; +//const mmfPoolAddressOld = '0x849f97c5452cc4bad1069b8efe2b3561b06694c3'; +//const mmfPoolAddressNew = '0xf6a96e753dec01acb659acbe75deba46d53ebc5e'; +const mmfPoolAddressNewNew = '0x687a0275aE620FB7868b09f16d3FeF862824317d' const erc20ContractAbi = [ 'function balanceOf(address account) external view returns (uint256)', @@ -41,81 +43,84 @@ export async function strategy( ]); }; - const makeMulticaller = (abi, contractAddress, functionSignature) => { - const multiCaller = new Multicaller(network, provider, abi, { - blockTag - }); + const makeMulticaller = (abi, contractAddress, functionSignature, multicaller, callBatchIdx = "0") => { + let multiCaller = new Multicaller(network, provider, abi, {blockTag}) + if (callBatchIdx !== "0") { + multiCaller = multicaller + } addresses.forEach((address) => - multiCaller.call(address, contractAddress, functionSignature, [address]) + multiCaller.call(address+callBatchIdx, contractAddress, functionSignature, [address]) ); return multiCaller; }; - const minoMulti = makeMulticaller( - erc20ContractAbi, - minoContractAddress, - 'balanceOf' - ); - const sMinoMulti = makeMulticaller( erc20ContractAbi, sMinoContractAddress, - 'balanceOf' + 'balanceOf', + null, + "0" ); - const wsMinoInMMFMultiOld = makeMulticaller( - mmfPoolAbi, - mmfPoolAddressOld, - 'userInfo' + const wsMinoMulti = makeMulticaller( + erc20ContractAbi, + wsMinoContractAddress, + 'balanceOf', + sMinoMulti, + "1" ); - const wsMinoInMMFMultiNew = makeMulticaller( + const minoMulti = makeMulticaller( + erc20ContractAbi, + minoContractAddress, + 'balanceOf', + wsMinoMulti, + "2" + ); + const wsMinoInMMFMulti = makeMulticaller( mmfPoolAbi, - mmfPoolAddressNew, - 'userInfo' + mmfPoolAddressNewNew, + 'userInfo', + null, + "0" ); - const [index, minoBalances, sMinoBalances, mmfUserInfosOld, mmfUserInfoNew]: [ + const [index]: [ BigNumber, + ] = await Promise.all([ + callIndex(), + ]); + + const [minoBalances, mmfUserInfo]: [ MultiCallResult, - MultiCallResult, - MultiCallObjectResult, MultiCallObjectResult ] = await Promise.all([ - callIndex(), - sMinoMulti.execute(), minoMulti.execute(), - wsMinoInMMFMultiOld.execute(), - wsMinoInMMFMultiNew.execute() + wsMinoInMMFMulti.execute() ]); const scores: Record = {}; for (const address of addresses) { const wsMinoScore = BigNumber.from( - mmfUserInfosOld[address] - ? BigNumber.from(mmfUserInfosOld[address]['amount']) + mmfUserInfo[address+"0"] //from mmf pool + ? mmfUserInfo[address+"0"]['amount'] : 0 ) - .add( - mmfUserInfoNew[address] - ? BigNumber.from(mmfUserInfoNew[address]['amount']) - : 0 - ) - .mul(index) - .div(BigNumber.from(10).pow(18)); + .add(minoBalances[address+"1"] || 0) // wsMinoBalances + .mul(index) // timeses by 10^9 effectively const minoScore = wsMinoScore - .add(sMinoBalances[address] || 0) - .add(minoBalances[address] || 0); - + .add(BigNumber.from(minoBalances[address+"0"] || 0).mul(BigNumber.from(10).pow(18))) // mino balances + .add(BigNumber.from(minoBalances[address+"2"] || 0).mul(BigNumber.from(10).pow(18))) // sMino balances + scores[address] = minoScore; } const scoresNumber = Object.fromEntries( Object.entries(scores).map(([address, balance]) => [ address, - balance.toNumber() / 1000000000 + balance.div(BigNumber.from(10).pow(18)).toNumber() / 1000000000 ]) ); From 677537c6eecf9478ca13b0527ad5522e195b0387 Mon Sep 17 00:00:00 2001 From: Karamorf Date: Fri, 9 Sep 2022 00:05:44 -0700 Subject: [PATCH 114/815] Add strategy LRC NFT balances by minter account [lrc-l2-nft-balance-of] (#823) * first attempt at custom strategy. * fixing parsing of NFT ownership and doing it by slot. * updating readme. * return balances with case made input on addreses. * fixing how snapshot filtering works. Co-authored-by: karamorf Co-authored-by: Chaitanya --- src/strategies/index.ts | 2 + .../lrc-l2-nft-balance-of/README.md | 17 ++++ .../lrc-l2-nft-balance-of/examples.json | 25 ++++++ src/strategies/lrc-l2-nft-balance-of/index.ts | 80 +++++++++++++++++++ 4 files changed, 124 insertions(+) create mode 100644 src/strategies/lrc-l2-nft-balance-of/README.md create mode 100644 src/strategies/lrc-l2-nft-balance-of/examples.json create mode 100644 src/strategies/lrc-l2-nft-balance-of/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index dd1686a82..47e6bcadf 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -342,6 +342,7 @@ import * as solvVoucherClaimable from './solv-voucher-claimable'; import * as h2o from './h2o'; import * as dopamine from './dopamine'; import * as lrcL2SubgraphBalanceOf from './lrc-l2-subgraph-balance-of'; +import * as lrcL2NftBalanceOf from './lrc-l2-nft-balance-of'; import * as lrcLPSubgraphBalanceOf from './lrc-lp-subgraph-balance-of'; import * as erc3525VestingVoucher from './erc3525-vesting-voucher'; import * as rariFuse from './rari-fuse'; @@ -712,6 +713,7 @@ const strategies = { h2o, dopamine, 'lrc-l2-subgraph-balance-of': lrcL2SubgraphBalanceOf, + 'lrc-l2-nft-balance-of': lrcL2NftBalanceOf, 'lrc-lp-subgraph-balance-of': lrcLPSubgraphBalanceOf, 'rari-fuse': rariFuse, 'bancor-pool-token-underlying-balance': bancorPoolTokenUnderlyingBalance, diff --git a/src/strategies/lrc-l2-nft-balance-of/README.md b/src/strategies/lrc-l2-nft-balance-of/README.md new file mode 100644 index 000000000..492433c97 --- /dev/null +++ b/src/strategies/lrc-l2-nft-balance-of/README.md @@ -0,0 +1,17 @@ +# lrc-l2-nft-balance-of + +Strategy to read account balances for NFTs (72 or 1155) from LoopringV2 subgraph. Assumes we only want tokens minted by a specific account id. + +Here is an example of parameters: + +```json +{ + "graph": "https://api.thegraph.com/subgraphs/name/juanmardefago/loopring36", + "minter_account_id": "74447", + "blacklisted_account_ids": ["38482"] +} +``` + +Use explorer.loopring.io to look up addresses and find account id's. + +Account id `38482` maps to `0x000000000000000000000000000000000000dead` and is used for burning tokens. diff --git a/src/strategies/lrc-l2-nft-balance-of/examples.json b/src/strategies/lrc-l2-nft-balance-of/examples.json new file mode 100644 index 000000000..844ec65d8 --- /dev/null +++ b/src/strategies/lrc-l2-nft-balance-of/examples.json @@ -0,0 +1,25 @@ +[ + { + "name": "LoopringV2NFT", + "strategy": { + "name": "lrc-l2-nft-balance-of", + "params": { + "graph": "https://api.thegraph.com/subgraphs/name/juanmardefago/loopring36", + "minter_account_id": "74447", + "blacklisted_account_ids": ["38482"] + } + }, + "network": "1", + "addresses": [ + "0xad29249bd6d203b3c824d2514b8221c83eb608d1", + "0x3c41f4e24e52f624fd4bf00dfe90d63c64cf964c", + "0xe4c9487dbef67405d4469ae27837e5f42197af21", + "0xacf9c4d62f00ed3e47e3d8aabfc80300be02cb4d", + "0x6efd66a92a22561c3b2e08b5253a2bbd64c3edcc", + "0x197f6515eb864133ce1d689f50a912620f3953ac", + "0xecd5d7ca36538174c977b42c08e924b4341ffbf0", + "0x0a437c0caeda1e081ba413229da0bf132fe74584" + ], + "snapshot": 15175152 + } +] diff --git a/src/strategies/lrc-l2-nft-balance-of/index.ts b/src/strategies/lrc-l2-nft-balance-of/index.ts new file mode 100644 index 000000000..70195e929 --- /dev/null +++ b/src/strategies/lrc-l2-nft-balance-of/index.ts @@ -0,0 +1,80 @@ +import { subgraphRequest } from '../../utils'; + +export const author = 'karamorf'; +export const version = '0.1.0'; + +const LIMIT = 1000; + +function makeQuery(snapshot, minter, lastUpdatedAt, blacklisted_accounts) { + const query: any = { + accountNFTSlots: { + __args: { + where: { + nft_: { minter: minter }, + account_not_in: blacklisted_accounts, + lastUpdatedAt_gt: lastUpdatedAt + }, + first: LIMIT + }, + account: { address: true }, + balance: true, + lastUpdatedAt: true + } + }; + + if (snapshot !== 'latest') { + query.accountNFTSlots.__args = { + ...query.accountNFTSlots.__args, + block: { + number: snapshot + } + }; + } + + return query; +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + let blacklisted_ids = options.blacklisted_account_ids; + let balances = {}; + let lastUpdatedAt = 0; + let response_size = 0; + + if(! blacklisted_ids || blacklisted_ids.length === 0) { + blacklisted_ids = [""]; + } + + + do { + const response = await subgraphRequest( + options.graph, + makeQuery(snapshot, options.minter_account_id, lastUpdatedAt, blacklisted_ids) + ); + + response.accountNFTSlots.forEach((slot) => { + if(! balances.hasOwnProperty(slot.account.address)) { + balances[slot.account.address] = 0; + } + balances[slot.account.address] += parseInt(slot.balance); + lastUpdatedAt = slot.lastUpdatedAt; + }); + response_size = response.accountNFTSlots.length; + + } while(response_size == LIMIT); + + const scores = Object.fromEntries( + addresses.map((address) => [ + address, + balances[address.toLowerCase()] + ]) + ); + + return scores; +} From c6256b000803b68887cbd50bf1d7bf0bfd77159b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 11 Sep 2022 22:41:50 +0530 Subject: [PATCH 115/815] Automated lint (#827) Co-authored-by: ChaituVR --- src/strategies/lrc-l2-nft-balance-of/index.ts | 24 +++---- src/strategies/minotaur-money/index.ts | 68 +++++++++++-------- 2 files changed, 51 insertions(+), 41 deletions(-) diff --git a/src/strategies/lrc-l2-nft-balance-of/index.ts b/src/strategies/lrc-l2-nft-balance-of/index.ts index 70195e929..f16e24155 100644 --- a/src/strategies/lrc-l2-nft-balance-of/index.ts +++ b/src/strategies/lrc-l2-nft-balance-of/index.ts @@ -43,37 +43,37 @@ export async function strategy( snapshot ): Promise> { let blacklisted_ids = options.blacklisted_account_ids; - let balances = {}; + const balances = {}; let lastUpdatedAt = 0; let response_size = 0; - if(! blacklisted_ids || blacklisted_ids.length === 0) { - blacklisted_ids = [""]; + if (!blacklisted_ids || blacklisted_ids.length === 0) { + blacklisted_ids = ['']; } - do { const response = await subgraphRequest( options.graph, - makeQuery(snapshot, options.minter_account_id, lastUpdatedAt, blacklisted_ids) + makeQuery( + snapshot, + options.minter_account_id, + lastUpdatedAt, + blacklisted_ids + ) ); response.accountNFTSlots.forEach((slot) => { - if(! balances.hasOwnProperty(slot.account.address)) { + if (!balances.hasOwnProperty(slot.account.address)) { balances[slot.account.address] = 0; } balances[slot.account.address] += parseInt(slot.balance); lastUpdatedAt = slot.lastUpdatedAt; }); response_size = response.accountNFTSlots.length; - - } while(response_size == LIMIT); + } while (response_size == LIMIT); const scores = Object.fromEntries( - addresses.map((address) => [ - address, - balances[address.toLowerCase()] - ]) + addresses.map((address) => [address, balances[address.toLowerCase()]]) ); return scores; diff --git a/src/strategies/minotaur-money/index.ts b/src/strategies/minotaur-money/index.ts index 942453486..7bf88da3f 100644 --- a/src/strategies/minotaur-money/index.ts +++ b/src/strategies/minotaur-money/index.ts @@ -11,7 +11,7 @@ const wsMinoContractAddress = '0x1066c6753FFaf8540F691643A6D683e23599c4ab'; //const mmfPoolAddressOld = '0x57E8f8F7447D8d02fe4D291378D37E67D393257A'; //const mmfPoolAddressOld = '0x849f97c5452cc4bad1069b8efe2b3561b06694c3'; //const mmfPoolAddressNew = '0xf6a96e753dec01acb659acbe75deba46d53ebc5e'; -const mmfPoolAddressNewNew = '0x687a0275aE620FB7868b09f16d3FeF862824317d' +const mmfPoolAddressNewNew = '0x687a0275aE620FB7868b09f16d3FeF862824317d'; const erc20ContractAbi = [ 'function balanceOf(address account) external view returns (uint256)', @@ -43,13 +43,24 @@ export async function strategy( ]); }; - const makeMulticaller = (abi, contractAddress, functionSignature, multicaller, callBatchIdx = "0") => { - let multiCaller = new Multicaller(network, provider, abi, {blockTag}) - if (callBatchIdx !== "0") { - multiCaller = multicaller + const makeMulticaller = ( + abi, + contractAddress, + functionSignature, + multicaller, + callBatchIdx = '0' + ) => { + let multiCaller = new Multicaller(network, provider, abi, { blockTag }); + if (callBatchIdx !== '0') { + multiCaller = multicaller; } addresses.forEach((address) => - multiCaller.call(address+callBatchIdx, contractAddress, functionSignature, [address]) + multiCaller.call( + address + callBatchIdx, + contractAddress, + functionSignature, + [address] + ) ); return multiCaller; }; @@ -59,7 +70,7 @@ export async function strategy( sMinoContractAddress, 'balanceOf', null, - "0" + '0' ); const wsMinoMulti = makeMulticaller( @@ -67,7 +78,7 @@ export async function strategy( wsMinoContractAddress, 'balanceOf', sMinoMulti, - "1" + '1' ); const minoMulti = makeMulticaller( @@ -75,45 +86,44 @@ export async function strategy( minoContractAddress, 'balanceOf', wsMinoMulti, - "2" + '2' ); const wsMinoInMMFMulti = makeMulticaller( mmfPoolAbi, mmfPoolAddressNewNew, 'userInfo', null, - "0" + '0' ); - const [index]: [ - BigNumber, - ] = await Promise.all([ - callIndex(), - ]); + const [index]: [BigNumber] = await Promise.all([callIndex()]); - const [minoBalances, mmfUserInfo]: [ - MultiCallResult, - MultiCallObjectResult - ] = await Promise.all([ - minoMulti.execute(), - wsMinoInMMFMulti.execute() - ]); + const [minoBalances, mmfUserInfo]: [MultiCallResult, MultiCallObjectResult] = + await Promise.all([minoMulti.execute(), wsMinoInMMFMulti.execute()]); const scores: Record = {}; for (const address of addresses) { const wsMinoScore = BigNumber.from( - mmfUserInfo[address+"0"] //from mmf pool - ? mmfUserInfo[address+"0"]['amount'] + mmfUserInfo[address + '0'] //from mmf pool + ? mmfUserInfo[address + '0']['amount'] : 0 ) - .add(minoBalances[address+"1"] || 0) // wsMinoBalances - .mul(index) // timeses by 10^9 effectively + .add(minoBalances[address + '1'] || 0) // wsMinoBalances + .mul(index); // timeses by 10^9 effectively const minoScore = wsMinoScore - .add(BigNumber.from(minoBalances[address+"0"] || 0).mul(BigNumber.from(10).pow(18))) // mino balances - .add(BigNumber.from(minoBalances[address+"2"] || 0).mul(BigNumber.from(10).pow(18))) // sMino balances - + .add( + BigNumber.from(minoBalances[address + '0'] || 0).mul( + BigNumber.from(10).pow(18) + ) + ) // mino balances + .add( + BigNumber.from(minoBalances[address + '2'] || 0).mul( + BigNumber.from(10).pow(18) + ) + ); // sMino balances + scores[address] = minoScore; } From fac6ab825bb6123680d770910e800cc8b9fadb2c Mon Sep 17 00:00:00 2001 From: Dan OneTree Date: Sun, 11 Sep 2022 23:26:16 +0530 Subject: [PATCH 116/815] add strategy deposit-in-sablier-stream [deposit-in-sablier-stream] (#828) * feat: added strategy deposit-in-sablier-stream * feat: support more networks for deposit-in-sablier-stream Co-authored-by: Chaitanya --- .../deposit-in-sablier-stream/README.md | 12 ++++ .../deposit-in-sablier-stream/examples.json | 35 ++++++++++ .../deposit-in-sablier-stream/index.ts | 69 +++++++++++++++++++ .../deposit-in-sablier-stream/schema.json | 35 ++++++++++ src/strategies/index.ts | 4 +- 5 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 src/strategies/deposit-in-sablier-stream/README.md create mode 100644 src/strategies/deposit-in-sablier-stream/examples.json create mode 100644 src/strategies/deposit-in-sablier-stream/index.ts create mode 100644 src/strategies/deposit-in-sablier-stream/schema.json diff --git a/src/strategies/deposit-in-sablier-stream/README.md b/src/strategies/deposit-in-sablier-stream/README.md new file mode 100644 index 000000000..9c60aac49 --- /dev/null +++ b/src/strategies/deposit-in-sablier-stream/README.md @@ -0,0 +1,12 @@ +# Deposit in Sablier Stream + +This strategy returns the score for any voter as the sum of all deposits made by a sender towards the voters for a specific ERC20 token; + +Here is an example of parameters: + +```JSON +{ + "sender": "0xC9F2D9adfa6C24ce0D5a999F2BA3c6b06E36F75E", + "token": "0x7f8F6E42C169B294A384F5667c303fd8Eedb3CF3" +} +``` diff --git a/src/strategies/deposit-in-sablier-stream/examples.json b/src/strategies/deposit-in-sablier-stream/examples.json new file mode 100644 index 000000000..e0eea6f0d --- /dev/null +++ b/src/strategies/deposit-in-sablier-stream/examples.json @@ -0,0 +1,35 @@ +[ + { + "name": "Example query 0", + "strategy": { + "name": "deposit-in-sablier-stream", + "params": { + "sender": "0xC9F2D9adfa6C24ce0D5a999F2BA3c6b06E36F75E", + "token": "0x7f8F6E42C169B294A384F5667c303fd8Eedb3CF3" + } + }, + "network": "5", + "addresses": [ + "0x3f9b2fea60325d733e61bc76598725c5430cd751", + "0x7f8F6E42C169B294A384F5667c303fd8Eedb3CF3" + ], + "snapshot": 7572600 + }, + { + "name": "Example query 1", + "strategy": { + "name": "deposit-in-sablier-stream", + "params": { + "sender": "0xC9F2D9adfa6C24ce0D5a999F2BA3c6b06E36F75E", + "token": "0x7f8F6E42C169B294A384F5667c303fd8Eedb3CF3", + "subGraphURL": "https://api.thegraph.com/subgraphs/name/sablierhq/sablier-goerli" + } + }, + "network": "5", + "addresses": [ + "0x1206b51217271FC3ffCa57d0678121983ce0390E", + "0x7f8F6E42C169B294A384F5667c303fd8Eedb3CF3" + ], + "snapshot": 7572688 + } +] diff --git a/src/strategies/deposit-in-sablier-stream/index.ts b/src/strategies/deposit-in-sablier-stream/index.ts new file mode 100644 index 000000000..afad5ab87 --- /dev/null +++ b/src/strategies/deposit-in-sablier-stream/index.ts @@ -0,0 +1,69 @@ +import { getAddress } from '@ethersproject/address'; +import { formatUnits } from '@ethersproject/units'; +import { subgraphRequest } from '../../utils'; + +const SUBGRAPH_URL = { + '1': 'https://api.thegraph.com/subgraphs/name/sablierhq/sablier', // mainnet + '3': 'https://api.thegraph.com/subgraphs/name/sablierhq/sablier-ropsten', // ropsten + '4': 'https://api.thegraph.com/subgraphs/name/sablierhq/sablier-rinkeby', // rinkeby + '5': 'https://api.thegraph.com/subgraphs/name/sablierhq/sablier-goerli', // goerli + '10': 'https://api.thegraph.com/subgraphs/name/sablierhq/sablier-optimism', // optimism + '42': 'https://api.thegraph.com/subgraphs/name/sablierhq/sablier-kovan', // kovan + '56': 'https://api.thegraph.com/subgraphs/name/sablierhq/sablier-bsc', // bsc + '137': 'https://api.thegraph.com/subgraphs/name/sablierhq/sablier-matic', // polygon + '42161': 'https://api.thegraph.com/subgraphs/name/sablierhq/sablier-arbitrum', // arbitrum + '43114': 'https://api.thegraph.com/subgraphs/name/sablierhq/sablier-avalanche' // avalanche +}; + +export const author = 'dan13ram'; +export const version = '0.1.0'; + +export async function strategy( + _space, + network, + _provider, + addresses, + options, + snapshot +) { + const params = { + streams: { + __args: { + limit: 1000, + where: { + recipient_in: addresses.map((address) => address.toLowerCase()), + sender: options.sender.toLowerCase(), + token: options.token.toLowerCase(), + cancellation: null + } + }, + recipient: true, + deposit: true, + token: { + decimals: true + } + } + }; + if (snapshot !== 'latest') { + // @ts-ignore + params.streams.__args.block = { number: snapshot }; + } + const result = await subgraphRequest( + options.subGraphURL ? options.subGraphURL : SUBGRAPH_URL[network], + params + ); + const score = Object.fromEntries( + addresses.map((address) => [getAddress(address), 0]) + ); + if (result && result.streams) { + result.streams.forEach((stream) => { + const userAddress = getAddress(stream.recipient); + const userScore = parseFloat( + formatUnits(stream.deposit, stream.token.decimals) + ); + + score[userAddress] = score[userAddress] + userScore; + }); + } + return score; +} diff --git a/src/strategies/deposit-in-sablier-stream/schema.json b/src/strategies/deposit-in-sablier-stream/schema.json new file mode 100644 index 000000000..583a6148d --- /dev/null +++ b/src/strategies/deposit-in-sablier-stream/schema.json @@ -0,0 +1,35 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "sender": { + "type": "string", + "title": "Sender address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "token": { + "type": "string", + "title": "ERC20 token address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "subGraphURL": { + "type": "string", + "title": "Optional subgraph url", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"] + } + }, + "required": ["sender", "token"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 47e6bcadf..153fa00f3 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -367,6 +367,7 @@ import * as safeVested from './safe-vested'; import * as riskharborUnderwriter from './riskharbor-underwriter'; import * as otterspaceBadges from './otterspace-badges'; import * as syntheticNounsClaimerOwner from './synthetic-nouns-with-claimer'; +import * as depositInSablierStream from './deposit-in-sablier-stream'; const strategies = { 'forta-shares': fortaShares, @@ -737,7 +738,8 @@ const strategies = { 'safe-vested': safeVested, 'riskharbor-underwriter': riskharborUnderwriter, 'otterspace-badges': otterspaceBadges, - 'synthetic-nouns-with-claimer': syntheticNounsClaimerOwner + 'synthetic-nouns-with-claimer': syntheticNounsClaimerOwner, + 'deposit-in-sablier-stream': depositInSablierStream }; Object.keys(strategies).forEach(function (strategyName) { From 0d8a33ae8ef71d27a2f76a03721afa3ee6cfc7bc Mon Sep 17 00:00:00 2001 From: Curtis MacDuff <97050098+curtis741@users.noreply.github.com> Date: Sun, 11 Sep 2022 11:34:15 -0700 Subject: [PATCH 117/815] Improvement and more options to LRC L2 NFT balance strategy [lrc-l2-nft-balance-of] (#829) * adding options for blacklisting nft id's and filter by token id(s) instead of minter account id * use skip instead of lastUpdateAt Co-authored-by: karamorf --- .../lrc-l2-nft-balance-of/README.md | 6 ++- .../lrc-l2-nft-balance-of/examples.json | 4 +- src/strategies/lrc-l2-nft-balance-of/index.ts | 46 +++++++++++++------ 3 files changed, 39 insertions(+), 17 deletions(-) diff --git a/src/strategies/lrc-l2-nft-balance-of/README.md b/src/strategies/lrc-l2-nft-balance-of/README.md index 492433c97..121c5c972 100644 --- a/src/strategies/lrc-l2-nft-balance-of/README.md +++ b/src/strategies/lrc-l2-nft-balance-of/README.md @@ -8,10 +8,14 @@ Here is an example of parameters: { "graph": "https://api.thegraph.com/subgraphs/name/juanmardefago/loopring36", "minter_account_id": "74447", - "blacklisted_account_ids": ["38482"] + "tokens": ["token (Collection) id's to include"], + "blacklisted_account_ids": ["38482"], + "blacklisted_nft_ids": ["... nft id's to exclude ..."] } ``` Use explorer.loopring.io to look up addresses and find account id's. Account id `38482` maps to `0x000000000000000000000000000000000000dead` and is used for burning tokens. + +to note: either the `minter_account_id` or the `tokens` parameter must be provided for this query to work. You do not need to specify both, just one of them. diff --git a/src/strategies/lrc-l2-nft-balance-of/examples.json b/src/strategies/lrc-l2-nft-balance-of/examples.json index 844ec65d8..24321667d 100644 --- a/src/strategies/lrc-l2-nft-balance-of/examples.json +++ b/src/strategies/lrc-l2-nft-balance-of/examples.json @@ -6,7 +6,9 @@ "params": { "graph": "https://api.thegraph.com/subgraphs/name/juanmardefago/loopring36", "minter_account_id": "74447", - "blacklisted_account_ids": ["38482"] + "tokens": ["0xc76eca2937b006606ebe717621409e4c2df906f1"], + "blacklisted_account_ids": ["38482"], + "blacklisted_nft_ids": ["0x94743548ba8d82a4ee8ea3dfad589ea501ad2738-0-0xc76eca2937b006606ebe717621409e4c2df906f1-0x15f13a1431906d9ca5b24df9de0b443690bf822d012e5da30b18d36ffad545aa-5"] } }, "network": "1", diff --git a/src/strategies/lrc-l2-nft-balance-of/index.ts b/src/strategies/lrc-l2-nft-balance-of/index.ts index f16e24155..b8348b0a1 100644 --- a/src/strategies/lrc-l2-nft-balance-of/index.ts +++ b/src/strategies/lrc-l2-nft-balance-of/index.ts @@ -1,27 +1,36 @@ import { subgraphRequest } from '../../utils'; - export const author = 'karamorf'; -export const version = '0.1.0'; +export const version = '0.1.1'; const LIMIT = 1000; -function makeQuery(snapshot, minter, lastUpdatedAt, blacklisted_accounts) { +function makeQuery(snapshot, minter, tokens, skip, blacklisted_account_ids, blacklisted_nft_ids) { const query: any = { accountNFTSlots: { __args: { where: { - nft_: { minter: minter }, - account_not_in: blacklisted_accounts, - lastUpdatedAt_gt: lastUpdatedAt + nft_: { + id_not_in: blacklisted_nft_ids + }, + account_not_in: blacklisted_account_ids, }, - first: LIMIT + first: LIMIT, + skip: skip }, account: { address: true }, balance: true, - lastUpdatedAt: true } }; + if(minter && minter !== "") { + query.accountNFTSlots.__args.where.nft_.minter = minter; + } + + if(tokens && tokens.length > 0) { + query.accountNFTSlots.__args.where.nft_.token_in = tokens + } + + if (snapshot !== 'latest') { query.accountNFTSlots.__args = { ...query.accountNFTSlots.__args, @@ -42,13 +51,18 @@ export async function strategy( options, snapshot ): Promise> { - let blacklisted_ids = options.blacklisted_account_ids; + let blacklisted_account_ids = options.blacklisted_account_ids; + let blacklisted_nft_ids = options.blacklisted_nft_ids; const balances = {}; - let lastUpdatedAt = 0; + let skip = 0; let response_size = 0; - if (!blacklisted_ids || blacklisted_ids.length === 0) { - blacklisted_ids = ['']; + if(! blacklisted_account_ids || blacklisted_account_ids.length === 0) { + blacklisted_account_ids = ['']; + } + + if(! blacklisted_nft_ids || blacklisted_nft_ids.length === 0) { + blacklisted_nft_ids = ['']; } do { @@ -57,8 +71,10 @@ export async function strategy( makeQuery( snapshot, options.minter_account_id, - lastUpdatedAt, - blacklisted_ids + options.tokens, + skip, + blacklisted_account_ids, + blacklisted_nft_ids ) ); @@ -67,9 +83,9 @@ export async function strategy( balances[slot.account.address] = 0; } balances[slot.account.address] += parseInt(slot.balance); - lastUpdatedAt = slot.lastUpdatedAt; }); response_size = response.accountNFTSlots.length; + skip += response_size; } while (response_size == LIMIT); const scores = Object.fromEntries( From 8a4744c7515dd50ba37a04225b19336aaaa1f96a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 12 Sep 2022 00:06:36 +0530 Subject: [PATCH 118/815] Automated lint (#830) Co-authored-by: ChaituVR --- .../lrc-l2-nft-balance-of/examples.json | 4 +++- src/strategies/lrc-l2-nft-balance-of/index.ts | 24 ++++++++++++------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/strategies/lrc-l2-nft-balance-of/examples.json b/src/strategies/lrc-l2-nft-balance-of/examples.json index 24321667d..0f2c7cec1 100644 --- a/src/strategies/lrc-l2-nft-balance-of/examples.json +++ b/src/strategies/lrc-l2-nft-balance-of/examples.json @@ -8,7 +8,9 @@ "minter_account_id": "74447", "tokens": ["0xc76eca2937b006606ebe717621409e4c2df906f1"], "blacklisted_account_ids": ["38482"], - "blacklisted_nft_ids": ["0x94743548ba8d82a4ee8ea3dfad589ea501ad2738-0-0xc76eca2937b006606ebe717621409e4c2df906f1-0x15f13a1431906d9ca5b24df9de0b443690bf822d012e5da30b18d36ffad545aa-5"] + "blacklisted_nft_ids": [ + "0x94743548ba8d82a4ee8ea3dfad589ea501ad2738-0-0xc76eca2937b006606ebe717621409e4c2df906f1-0x15f13a1431906d9ca5b24df9de0b443690bf822d012e5da30b18d36ffad545aa-5" + ] } }, "network": "1", diff --git a/src/strategies/lrc-l2-nft-balance-of/index.ts b/src/strategies/lrc-l2-nft-balance-of/index.ts index b8348b0a1..e2820c1a6 100644 --- a/src/strategies/lrc-l2-nft-balance-of/index.ts +++ b/src/strategies/lrc-l2-nft-balance-of/index.ts @@ -4,7 +4,14 @@ export const version = '0.1.1'; const LIMIT = 1000; -function makeQuery(snapshot, minter, tokens, skip, blacklisted_account_ids, blacklisted_nft_ids) { +function makeQuery( + snapshot, + minter, + tokens, + skip, + blacklisted_account_ids, + blacklisted_nft_ids +) { const query: any = { accountNFTSlots: { __args: { @@ -12,25 +19,24 @@ function makeQuery(snapshot, minter, tokens, skip, blacklisted_account_ids, blac nft_: { id_not_in: blacklisted_nft_ids }, - account_not_in: blacklisted_account_ids, + account_not_in: blacklisted_account_ids }, first: LIMIT, skip: skip }, account: { address: true }, - balance: true, + balance: true } }; - if(minter && minter !== "") { + if (minter && minter !== '') { query.accountNFTSlots.__args.where.nft_.minter = minter; } - if(tokens && tokens.length > 0) { - query.accountNFTSlots.__args.where.nft_.token_in = tokens + if (tokens && tokens.length > 0) { + query.accountNFTSlots.__args.where.nft_.token_in = tokens; } - if (snapshot !== 'latest') { query.accountNFTSlots.__args = { ...query.accountNFTSlots.__args, @@ -57,11 +63,11 @@ export async function strategy( let skip = 0; let response_size = 0; - if(! blacklisted_account_ids || blacklisted_account_ids.length === 0) { + if (!blacklisted_account_ids || blacklisted_account_ids.length === 0) { blacklisted_account_ids = ['']; } - if(! blacklisted_nft_ids || blacklisted_nft_ids.length === 0) { + if (!blacklisted_nft_ids || blacklisted_nft_ids.length === 0) { blacklisted_nft_ids = ['']; } From 22fb72190c78e24a8969ca72ecb246acbf7182e4 Mon Sep 17 00:00:00 2001 From: Guillermo Campanudo <61250854+guillermoriv@users.noreply.github.com> Date: Tue, 13 Sep 2022 18:27:37 +0100 Subject: [PATCH 119/815] [ethalend-balance-of] Adding the ethalend strategy :sparkles: (#825) * :sparkles: Adding the ethalend strategy * :pencil2: Fixing example number of addresses --- src/strategies/ethalend-balance-of/README.md | 16 ++++++ .../ethalend-balance-of/examples.json | 32 +++++++++++ src/strategies/ethalend-balance-of/index.ts | 56 +++++++++++++++++++ .../ethalend-balance-of/schema.json | 41 ++++++++++++++ src/strategies/index.ts | 2 + 5 files changed, 147 insertions(+) create mode 100644 src/strategies/ethalend-balance-of/README.md create mode 100644 src/strategies/ethalend-balance-of/examples.json create mode 100644 src/strategies/ethalend-balance-of/index.ts create mode 100644 src/strategies/ethalend-balance-of/schema.json diff --git a/src/strategies/ethalend-balance-of/README.md b/src/strategies/ethalend-balance-of/README.md new file mode 100644 index 000000000..9ef4a55aa --- /dev/null +++ b/src/strategies/ethalend-balance-of/README.md @@ -0,0 +1,16 @@ +# ethalend-balance-of + +This is a strategy made for the protocol ETHALend where we have smartWallets and we need to somehow check +directly the balanceOf in the smartWallet instead of the web3 wallet, it returns the balanceOf the specified ERC20 token +as the web3 wallet key and the value as the balanceOf the smartWallet. + +Here is an example of parameters: + +```json +{ + "address": "0x6b175474e89094c44da98b954eedeac495271d0f", + "symbol": "DAI", + "decimals": 18, + "registry": "0x583B965462e11Da63D1d4bC6D2d43d391F79af1f" +} +``` diff --git a/src/strategies/ethalend-balance-of/examples.json b/src/strategies/ethalend-balance-of/examples.json new file mode 100644 index 000000000..122cfa0d2 --- /dev/null +++ b/src/strategies/ethalend-balance-of/examples.json @@ -0,0 +1,32 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "ethalend-balance-of", + "params": { + "registry": "0x583B965462e11Da63D1d4bC6D2d43d391F79af1f", + "address": "0x56bA9a2f00A4F581a05bfE9Fd0b16277eD130349", + "symbol": "veETHA", + "decimals": 18 + } + }, + "network": "137", + "addresses": [ + "0xd7539FCdC0aB79a7B688b04387cb128E75cb77Dc", + "0x6E33e22f7aC5A4b58A93C7f6D8Da8b46c50A3E20", + "0xC9dA7343583fA8Bb380A6F04A208C612F86C7701", + "0x4e46cd691b0a159fbe5e2d08a3951a324e2fb4c0", + "0x1de9184f070627a33eab44e329c699b3068c073d", + "0x77c66d0457b6bd390c1824b3e44d6f9c31fa4166", + "0x358271f5578868e8051441677fbaacbd5d80ae39", + "0xae80dcf8109e2774d38884ece6c11191c7a1c583", + "0xe07d2caf3be9447ee71ed721ac2730b8e8e985f0", + "0xf758e816b602feb404948626b2f7f16e948a578c", + "0xb7f5566100751c64b06280b1cb5a9286b08ae161", + "0x647f3d7f8d513bdf67bd407f2f98b90a84e8edb5", + "0xd3670fd0e5bbdc6c04634c66c1b94e9788d71473", + "0x642FC634b8a0809D4d591A9A5367424E52a698C4" + ], + "snapshot": 32843708 + } +] diff --git a/src/strategies/ethalend-balance-of/index.ts b/src/strategies/ethalend-balance-of/index.ts new file mode 100644 index 000000000..369ab12f4 --- /dev/null +++ b/src/strategies/ethalend-balance-of/index.ts @@ -0,0 +1,56 @@ +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'ethalend'; +export const version = '0.1.0'; + +const abi = [ + 'function balanceOf(address account) external view returns (uint256)', + 'function wallets(address account) external view returns (address)' +]; + +function swapKeys(obj: { [key: string]: string }) { + const newObj = {}; + + for (const key in obj) { + newObj[obj[key]] = key; + } + + return newObj; +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const multi = new Multicaller(network, provider, abi, { blockTag }); + + addresses.forEach((address) => + multi.call(address, options.registry, 'wallets', [address]) + ); + + const resultSmartWallets: Record = await multi.execute(); + + addresses.forEach((address) => + multi.call(resultSmartWallets[address], options.address, 'balanceOf', [ + resultSmartWallets[address] + ]) + ); + + const invertedSmartWallets = swapKeys(resultSmartWallets); + + const resultAccounts: Record = await multi.execute(); + + return Object.fromEntries( + Object.entries(resultAccounts).map(([address, balance]) => [ + invertedSmartWallets[address], + parseFloat(formatUnits(balance, options.decimals)) + ]) + ); +} diff --git a/src/strategies/ethalend-balance-of/schema.json b/src/strategies/ethalend-balance-of/schema.json new file mode 100644 index 000000000..2ee463c5c --- /dev/null +++ b/src/strategies/ethalend-balance-of/schema.json @@ -0,0 +1,41 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. UNI"], + "maxLength": 16 + }, + "registry": { + "type": "string", + "title": "Contract address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "address": { + "type": "string", + "title": "Contract address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 18"] + } + }, + "required": ["address", "decimals"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 153fa00f3..34b7b804e 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -27,6 +27,7 @@ import * as erc20WithBalance from './erc20-with-balance'; import * as erc20BalanceOfDelegation from './erc20-balance-of-delegation'; import * as erc20BalanceOfQuadraticDelegation from './erc20-balance-of-quadratic-delegation'; import * as erc20BalanceOfWeighted from './erc20-balance-of-weighted'; +import * as ethalendBalanceOf from './ethalend-balance-of'; import * as prepoVesting from './prepo-vesting'; import * as mintoBalanceAll from './minto-balance-of-all'; import * as erc20BalanceOfIndexed from './erc20-balance-of-indexed'; @@ -411,6 +412,7 @@ const strategies = { 'minto-balance-of-all': mintoBalanceAll, 'erc20-balance-of-indexed': erc20BalanceOfIndexed, 'erc20-price': erc20Price, + 'ethalend-balance-of': ethalendBalanceOf, 'balance-of-with-min': balanceOfWithMin, 'balance-of-with-thresholds': balanceOfWithThresholds, thresholds, From 92534645a2d4edd2d7b73dc0d8ecfbaa9ecd0d74 Mon Sep 17 00:00:00 2001 From: millken Date: Wed, 14 Sep 2022 17:18:53 +0800 Subject: [PATCH 120/815] Update iotex API, add iotex test address to default list[iotex-staked-balance] (#831) * update iotex api endpoints * add iotex test address * update json * update iotex staked test address * update iotex staked test address * update iotex staked test address Co-authored-by: guo --- src/strategies/iotex-balance/examples.json | 2 +- src/strategies/iotex-balance/index.ts | 10 +++++----- src/strategies/iotex-staked-balance/examples.json | 4 ++-- src/strategies/iotex-staked-balance/index.ts | 8 ++++---- test/addresses.json | 3 +++ 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/strategies/iotex-balance/examples.json b/src/strategies/iotex-balance/examples.json index 1eb23cc05..7fa6bbe80 100644 --- a/src/strategies/iotex-balance/examples.json +++ b/src/strategies/iotex-balance/examples.json @@ -1,6 +1,6 @@ [ { - "name": "iotex query", + "name": "iotex balance query", "strategy": { "name": "iotex-balance", "params": { diff --git a/src/strategies/iotex-balance/index.ts b/src/strategies/iotex-balance/index.ts index 5f6184686..0ecf21b25 100644 --- a/src/strategies/iotex-balance/index.ts +++ b/src/strategies/iotex-balance/index.ts @@ -4,11 +4,11 @@ interface ApiReturn { balance: string[]; } -export const author = 'iotex'; -export const version = '0.0.1'; +export const author = 'iotexproject'; +export const version = '0.0.2'; -const testNetUrl = 'https://iotex-analyser-api-testnet.chainanalytics.org'; -const mainNetUrl = 'https://iotex-analyser-api-mainnet.chainanalytics.org'; +const testNetUrl = 'https://analyser-api.testnet.iotex.io'; +const mainNetUrl = 'https://analyser-api.iotex.io'; function getUrl(network) { return network == 4689 ? mainNetUrl : testNetUrl; @@ -35,7 +35,7 @@ export async function strategy( const apiUrl = getUrl(network); const response = await fetch( - `${apiUrl}/api.AccountService.GetIotexBalanceByHeight`, + `${apiUrl}/api.AccountService.IotexBalanceByHeight`, { method: 'POST', headers: { diff --git a/src/strategies/iotex-staked-balance/examples.json b/src/strategies/iotex-staked-balance/examples.json index 65f283937..baf2669cc 100644 --- a/src/strategies/iotex-staked-balance/examples.json +++ b/src/strategies/iotex-staked-balance/examples.json @@ -11,8 +11,8 @@ }, "network": "4689", "addresses": [ - "0xb04FDF8c53baBBf67dB1cC6bd700fDb73DFF8252", - "0x49E4DbfF86a2E5DA27c540c9A9E8D2C3726E278F" + "0x49e4dbff86a2e5da27c540c9a9e8d2c3726e278f", + "0x4757ce43dc5429b8f1a132dc29ef970e55ae722b" ], "snapshot": 5161495 } diff --git a/src/strategies/iotex-staked-balance/index.ts b/src/strategies/iotex-staked-balance/index.ts index 8a56ba592..b0c364af8 100644 --- a/src/strategies/iotex-staked-balance/index.ts +++ b/src/strategies/iotex-staked-balance/index.ts @@ -4,10 +4,10 @@ interface ApiReturn { } export const author = 'iotex'; -export const version = '0.0.1'; +export const version = '0.0.2'; -const testNetUrl = 'https://iotex-analyser-api-testnet.chainanalytics.org'; -const mainNetUrl = 'https://iotex-analyser-api-mainnet.chainanalytics.org'; +const testNetUrl = 'https://analyser-api.testnet.iotex.io'; +const mainNetUrl = 'https://analyser-api.iotex.io'; function getUrl(network) { return network == 4689 ? mainNetUrl : testNetUrl; @@ -23,7 +23,7 @@ export async function strategy( ) { const height = typeof snapshot === 'number' ? snapshot : 10000000000; const apiUrl = getUrl(network); - const response = await fetch(`${apiUrl}/api.StakingService.GetVoteByHeight`, { + const response = await fetch(`${apiUrl}/api.StakingService.VoteByHeight`, { method: 'POST', headers: { Accept: 'application/json', diff --git a/test/addresses.json b/test/addresses.json index d490cc630..286c709d8 100644 --- a/test/addresses.json +++ b/test/addresses.json @@ -1,4 +1,7 @@ [ + "0x56d0b5ed3d525332f00c9bc938f93598ab16aaa7", + "0x49e4dbff86a2e5da27c540c9a9e8d2c3726e278f", + "0x4757ce43dc5429b8f1a132dc29ef970e55ae722b", "0xd7539FCdC0aB79a7B688b04387cb128E75cb77Dc", "0x6E33e22f7aC5A4b58A93C7f6D8Da8b46c50A3E20", "0xC9dA7343583fA8Bb380A6F04A208C612F86C7701", From dfc4d8f9eb3bfe1860ae3143db0bf6cdfadc31e0 Mon Sep 17 00:00:00 2001 From: rsquare Date: Wed, 14 Sep 2022 16:45:33 +0400 Subject: [PATCH 121/815] Updates example with address from optimism (#832) --- src/strategies/otterspace-badges/README.md | 2 +- src/strategies/otterspace-badges/examples.json | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/strategies/otterspace-badges/README.md b/src/strategies/otterspace-badges/README.md index c4221dd9e..828f3ef00 100644 --- a/src/strategies/otterspace-badges/README.md +++ b/src/strategies/otterspace-badges/README.md @@ -18,7 +18,7 @@ Here is an example of its usage: { "symbol": "BADGES", "raftTokenId": "1", - "raftAddress": "0xbb8997048e5f0bfe6c9d6bee63ede53bd0236bb2", + "raftAddress": "0xa6773847d3D2c8012C9cF62818b320eE278Ff722", "specs": [ { "id": "bafyreicmofif36f2s4d2iv37gy532epnw7rwjf5rygdhzzh2iw6nmbunrq", diff --git a/src/strategies/otterspace-badges/examples.json b/src/strategies/otterspace-badges/examples.json index 04e0dc26e..df3be78f7 100644 --- a/src/strategies/otterspace-badges/examples.json +++ b/src/strategies/otterspace-badges/examples.json @@ -6,7 +6,6 @@ "params": { "symbol": "BADGES", "raftTokenId": "1", - "raftAddress": "0xbb8997048e5f0bfe6c9d6bee63ede53bd0236bb2", "specs": [ { "id": "bafyreicmofif36f2s4d2iv37gy532epnw7rwjf5rygdhzzh2iw6nmbunrq", @@ -34,7 +33,6 @@ "params": { "symbol": "BADGES", "raftTokenId": "1", - "raftAddress": "0xbb8997048e5f0bfe6c9d6bee63ede53bd0236bb2", "specs": [] } }, From 5fd157b1e3b93835399c5e6e3d7c7af7d1c3f33c Mon Sep 17 00:00:00 2001 From: Brandon Date: Fri, 16 Sep 2022 13:42:40 -0400 Subject: [PATCH 122/815] new echelon voting strategy (#833) --- .../README.md | 28 +++++++ .../examples.json | 30 ++++++++ .../index.ts | 77 +++++++++++++++++++ src/strategies/index.ts | 4 +- 4 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 src/strategies/echelon-wallet-prime-and-cached-key/README.md create mode 100644 src/strategies/echelon-wallet-prime-and-cached-key/examples.json create mode 100644 src/strategies/echelon-wallet-prime-and-cached-key/index.ts diff --git a/src/strategies/echelon-wallet-prime-and-cached-key/README.md b/src/strategies/echelon-wallet-prime-and-cached-key/README.md new file mode 100644 index 000000000..8b2962215 --- /dev/null +++ b/src/strategies/echelon-wallet-prime-and-cached-key/README.md @@ -0,0 +1,28 @@ +# echelon-wallet-prime-cached-key + +This strategy looks at an ERC1155 caching (staking) contract and assigns a linearly decaying amount of voting power. The business context behind this is that each cached asset is eligible to claim a set amount of ERC20s over the same period; and thus can use those tokens to vote as well. + +For example, at block 0, the voting should have equivalent to 4000 units of voting power. A year later, they should have 0 units. + +As parameters, we pass in the base amount of voting power (e.g. 4000), starting block where there's no decay, and number of months until complete decay (e.g. 12). + +At a high level, the strategy grabs the UNIX timestamp in seconds for starting block, current block, and project timestamp of final block. It then queries the contract for the amount of cached ERC1155s. A simple slope formula is then applied to calculate the decay rate; which is then applied to determine the voting power per asset at current block. + +This strategy also makes use of the `erc20-balance-of` strategy. The erc20 balance is added to the equivalent value of the cached NFT. + +The final value is square rooted. + +Example of parameters: + +```json + "params": { + "symbol": "PRIME VOTE", + "address": "0xb23d80f5FefcDDaa212212F028021B41DEd428CF", + "decimals": 18, + "stakingAddress": "0x3399eff96D4b6Bae8a56F4852EB55736c9C2b041", + "baseValue": 4000, + "startingBlock": 15166749, + "monthsToDecay": 12 + } +``` + diff --git a/src/strategies/echelon-wallet-prime-and-cached-key/examples.json b/src/strategies/echelon-wallet-prime-and-cached-key/examples.json new file mode 100644 index 000000000..7e868e06e --- /dev/null +++ b/src/strategies/echelon-wallet-prime-and-cached-key/examples.json @@ -0,0 +1,30 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "echelon-wallet-prime-and-cached-key", + "params": { + "symbol": "PRIME VOTE", + "address": "0xb23d80f5FefcDDaa212212F028021B41DEd428CF", + "decimals": 18, + "stakingAddress": "0x3399eff96D4b6Bae8a56F4852EB55736c9C2b041", + "baseValue": 4000, + "startingBlock": 15166749, + "monthsToDecay": 12 + } + }, + "network": "1", + "addresses": [ + "0xE6be99cbC7796F90baff870a2ffE838a540E27C9", + "0xf98A4A42853cC611eED664627087d4ae19740ED8", + "0xbdc3C931387e2c6647b0D7237Ed30c702260fa80", + "0x5566eec3684F3ED896740590cc372758f25f056f", + "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", + "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e", + "0x1d5E65a087eBc3d03a294412E46CE5D6882969f4", + "0x1f254336E5c46639A851b9CfC165697150a6c327", + "0x2ec3F80BeDA63Ede96BA20375032CDD3aAfb3030" + ], + "snapshot": 15540462 + } +] diff --git a/src/strategies/echelon-wallet-prime-and-cached-key/index.ts b/src/strategies/echelon-wallet-prime-and-cached-key/index.ts new file mode 100644 index 000000000..e6268362f --- /dev/null +++ b/src/strategies/echelon-wallet-prime-and-cached-key/index.ts @@ -0,0 +1,77 @@ +import { Multicaller } from '../../utils'; +import { strategy as erc20BalanceOfStrategy } from '../erc20-balance-of'; + +export const author = 'brandonleung'; +export const version = '1.0.0'; + +const cachingAbi = [ + 'function cacheInfo(uint256, address) view returns (uint256 amount, int256 rewardDebt)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const stakingPool = new Multicaller(network, provider, cachingAbi, { + blockTag + }); + + const startingBlockTimestamp = ( + await provider.getBlock(options.startingBlock) + ).timestamp; + const endingBlockTimestamp = + startingBlockTimestamp + 2628288 * options.monthsToDecay; + const currentBlockTimestamp = (await provider.getBlock(snapshot)).timestamp; + + const decayRate = + (0 - options.baseValue) / (endingBlockTimestamp - startingBlockTimestamp); + + const votingPowerPerKey = + options.baseValue + + decayRate * (currentBlockTimestamp - startingBlockTimestamp); + + addresses.forEach((address) => { + stakingPool.call(address, options.stakingAddress, 'cacheInfo', [ + 0, + address + ]); + }); + const contractResponse = await stakingPool.execute(); + + const cachedKeyScore = Object.fromEntries( + addresses.map((address) => { + return [ + address, + contractResponse[address][0].toNumber() * votingPowerPerKey + ]; + }) + ); + + const walletScore = await erc20BalanceOfStrategy( + space, + network, + provider, + addresses, + options, + snapshot + ); + const votingPower = Object.entries(walletScore).reduce( + (address, [key, value]) => ({ + ...address, + [key]: (address[key] || 0) + value + }), + { ...cachedKeyScore } + ); + + Object.keys(votingPower).forEach((key) => { + votingPower[key] = Math.sqrt(votingPower[key]); + }); + + return votingPower; +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 34b7b804e..fa92b80f3 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -369,6 +369,7 @@ import * as riskharborUnderwriter from './riskharbor-underwriter'; import * as otterspaceBadges from './otterspace-badges'; import * as syntheticNounsClaimerOwner from './synthetic-nouns-with-claimer'; import * as depositInSablierStream from './deposit-in-sablier-stream'; +import * as echelonWalletPrimeAndCachedKey from './echelon-wallet-prime-and-cached-key'; const strategies = { 'forta-shares': fortaShares, @@ -741,7 +742,8 @@ const strategies = { 'riskharbor-underwriter': riskharborUnderwriter, 'otterspace-badges': otterspaceBadges, 'synthetic-nouns-with-claimer': syntheticNounsClaimerOwner, - 'deposit-in-sablier-stream': depositInSablierStream + 'deposit-in-sablier-stream': depositInSablierStream, + 'echelon-wallet-prime-and-cached-key': echelonWalletPrimeAndCachedKey }; Object.keys(strategies).forEach(function (strategyName) { From 6704c72717e5939710040a1196b062ab2f96ea48 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 19 Sep 2022 18:12:22 +0530 Subject: [PATCH 123/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.29 (#835) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index fd723ea34..2c6cd7555 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.28", + "@snapshot-labs/snapshot.js": "^0.4.29", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", "copyfiles": "^2.4.1", diff --git a/yarn.lock b/yarn.lock index f6e0f5aa6..ec270ad0a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.28": - version "0.4.28" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.28.tgz#503a460473fce28b3ef52717077753cb65d230a7" - integrity sha512-zP/XtR6gzoF5KjD8q9PdlN7HMQGC1yX9pT1hK185xqfdwB57Ut+Jk3Sk7Sr6bRygSSTlSSyg12zZ1EdHwZMGyw== +"@snapshot-labs/snapshot.js@^0.4.29": + version "0.4.29" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.29.tgz#ea19fe6b11282dbd88554add52086b696697cc65" + integrity sha512-CKBPe4SkL/b89uQtp9TQ2VObqVkZKCpd5wjqxdxMHumoVNMpSd+UAndYL72Bq/eiSIIhYnOacRtgxzCbDL1mjg== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 8808b4e2531dea237286d5d21d2e01d99c272c62 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Tue, 20 Sep 2022 00:46:49 +0530 Subject: [PATCH 124/815] Fix uniswap dep issue (#836) --- package.json | 3 +++ yarn.lock | 14 +------------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 2c6cd7555..6359db9ce 100755 --- a/package.json +++ b/package.json @@ -58,5 +58,8 @@ }, "engines": { "node": ">=16.10.0" + }, + "resolutions": { + "@uniswap/v3-periphery": "1.4.1" } } diff --git a/yarn.lock b/yarn.lock index ec270ad0a..60e23cd5e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1409,7 +1409,7 @@ resolved "https://registry.yarnpkg.com/@uniswap/v3-core/-/v3-core-1.0.0.tgz#6c24adacc4c25dceee0ba3ca142b35adbd7e359d" integrity sha512-kSC4djMGKMHj7sLMYVnn61k9nu+lHjMIxgg9CDQT+s2QYLoA56GbSK9Oxr+qJXzzygbkrmuY6cwgP6cW2JXPFA== -"@uniswap/v3-periphery@1.4.1": +"@uniswap/v3-periphery@1.4.1", "@uniswap/v3-periphery@^1.0.1", "@uniswap/v3-periphery@^1.1.1": version "1.4.1" resolved "https://registry.yarnpkg.com/@uniswap/v3-periphery/-/v3-periphery-1.4.1.tgz#b90f08b7386163c0abfd7258831caef6339c7862" integrity sha512-Ab0ZCKOQrQMKIcpBTezTsEhWfQjItd0TtkCG8mPhoQu+wC67nPaf4hYUhM6wGHeFUmDiYY5MpEQuokB0ENvoTg== @@ -1421,18 +1421,6 @@ base64-sol "1.0.1" hardhat-watcher "^2.1.1" -"@uniswap/v3-periphery@^1.0.1", "@uniswap/v3-periphery@^1.1.1": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@uniswap/v3-periphery/-/v3-periphery-1.4.0.tgz#9abb733fc596916718070c688b5f426fd8d01fe3" - integrity sha512-OXikenS40UIEa2XxQ+TyGpFFcTOfSW8eH3Ngy7sGOYp+7yr6uGU2UzomeTsqzagBEAXUDTwxqkk9oUS1KtWTUw== - dependencies: - "@openzeppelin/contracts" "3.4.1-solc-0.7-2" - "@uniswap/lib" "^4.0.1-alpha" - "@uniswap/v2-core" "1.0.1" - "@uniswap/v3-core" "1.0.0" - base64-sol "1.0.1" - hardhat-watcher "^2.1.1" - "@uniswap/v3-sdk@^3.9.0": version "3.9.0" resolved "https://registry.yarnpkg.com/@uniswap/v3-sdk/-/v3-sdk-3.9.0.tgz#de93fa19f89c29d460996aa4d0b4bb6531641105" From 5c2b5c50ffb5c171cbc0059ba9d8079f23420d6f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 20 Sep 2022 23:22:46 +0530 Subject: [PATCH 125/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.30 (#838) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 6359db9ce..9ed4e9c4e 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.29", + "@snapshot-labs/snapshot.js": "^0.4.30", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", "copyfiles": "^2.4.1", diff --git a/yarn.lock b/yarn.lock index 60e23cd5e..74468e856 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.29": - version "0.4.29" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.29.tgz#ea19fe6b11282dbd88554add52086b696697cc65" - integrity sha512-CKBPe4SkL/b89uQtp9TQ2VObqVkZKCpd5wjqxdxMHumoVNMpSd+UAndYL72Bq/eiSIIhYnOacRtgxzCbDL1mjg== +"@snapshot-labs/snapshot.js@^0.4.30": + version "0.4.30" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.30.tgz#99cae65b688841cfb476010a587e0b09d8256c6a" + integrity sha512-731jvTKpzq16ADFBGOzNxcRo9dXZWIJ3/6jf3X3N6UJmsBVde49JgvWYFrKKGImUQ21dVvRjQnd61EzcET5IsQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 9ac720d354e018e513e35e64a2cdb917d9f0aae2 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Thu, 22 Sep 2022 00:09:19 +0530 Subject: [PATCH 126/815] Lint for eval and rename workflow files (#841) * Lint for eval * Rename github actions --- .eslintrc | 1 + .github/workflows/{nodejs.yml => build.yml} | 7 +++---- .github/workflows/{main.yml => lint.yml} | 0 3 files changed, 4 insertions(+), 4 deletions(-) rename .github/workflows/{nodejs.yml => build.yml} (86%) rename .github/workflows/{main.yml => lint.yml} (100%) diff --git a/.eslintrc b/.eslintrc index 6118d728d..38a2ad992 100644 --- a/.eslintrc +++ b/.eslintrc @@ -13,6 +13,7 @@ }, "rules": { "no-console": "off", + "no-eval": "error", "prettier/prettier": "error", "@typescript-eslint/explicit-function-return-type": "off", "@typescript-eslint/ban-ts-ignore": "off", diff --git a/.github/workflows/nodejs.yml b/.github/workflows/build.yml similarity index 86% rename from .github/workflows/nodejs.yml rename to .github/workflows/build.yml index d83b782f3..cbe485b91 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/build.yml @@ -1,10 +1,9 @@ -name: Node CI +name: Build CI on: [push, pull_request] jobs: - build: - + build_lint: runs-on: ubuntu-latest strategy: @@ -12,7 +11,7 @@ jobs: node-version: [16.10.x] steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2.3.4 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v1 with: diff --git a/.github/workflows/main.yml b/.github/workflows/lint.yml similarity index 100% rename from .github/workflows/main.yml rename to .github/workflows/lint.yml From 5e56f890d9b07810a3ab5884dc349c45f321ac55 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 22 Sep 2022 17:34:11 +0530 Subject: [PATCH 127/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.31 (#842) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 9ed4e9c4e..38fe88238 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.30", + "@snapshot-labs/snapshot.js": "^0.4.31", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", "copyfiles": "^2.4.1", diff --git a/yarn.lock b/yarn.lock index 74468e856..e42d4dc12 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.30": - version "0.4.30" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.30.tgz#99cae65b688841cfb476010a587e0b09d8256c6a" - integrity sha512-731jvTKpzq16ADFBGOzNxcRo9dXZWIJ3/6jf3X3N6UJmsBVde49JgvWYFrKKGImUQ21dVvRjQnd61EzcET5IsQ== +"@snapshot-labs/snapshot.js@^0.4.31": + version "0.4.31" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.31.tgz#b9ac5a2805e4b76377f344a748d8631d60b362b2" + integrity sha512-lhejgMHHR0rPrEcH8XUufZc7zRM4wLcXEd2MBMEHvR3n5USSTEgrh1LwN5urjAISjKyMVdByU6H5Gz96G4Jxjw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From cfda117a1d841b6a335a8f16f6056f3304852118 Mon Sep 17 00:00:00 2001 From: Caranell Date: Fri, 23 Sep 2022 21:59:26 +0400 Subject: [PATCH 128/815] Add strategy for nation3 [nation3-votes-with-delegations] (#822) * Add strategy for nation3 * Fix condition * Add readme * Update src/strategies/nation3-votes-with-delegations/examples.json * Calculate sum of votes in case there're multiple delegations to the same acc Co-authored-by: Chaitanya --- src/strategies/index.ts | 4 +- .../nation3-votes-with-delegations/README.md | 13 ++ .../examples.json | 21 +++ .../nation3-votes-with-delegations/index.ts | 126 ++++++++++++++++++ .../schema.json | 30 +++++ 5 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 src/strategies/nation3-votes-with-delegations/README.md create mode 100644 src/strategies/nation3-votes-with-delegations/examples.json create mode 100644 src/strategies/nation3-votes-with-delegations/index.ts create mode 100644 src/strategies/nation3-votes-with-delegations/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index fa92b80f3..6028843f1 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -370,6 +370,7 @@ import * as otterspaceBadges from './otterspace-badges'; import * as syntheticNounsClaimerOwner from './synthetic-nouns-with-claimer'; import * as depositInSablierStream from './deposit-in-sablier-stream'; import * as echelonWalletPrimeAndCachedKey from './echelon-wallet-prime-and-cached-key'; +import * as nation3VotesWIthDelegations from './nation3-votes-with-delegations'; const strategies = { 'forta-shares': fortaShares, @@ -743,7 +744,8 @@ const strategies = { 'otterspace-badges': otterspaceBadges, 'synthetic-nouns-with-claimer': syntheticNounsClaimerOwner, 'deposit-in-sablier-stream': depositInSablierStream, - 'echelon-wallet-prime-and-cached-key': echelonWalletPrimeAndCachedKey + 'echelon-wallet-prime-and-cached-key': echelonWalletPrimeAndCachedKey, + 'nation3-votes-with-delegations': nation3VotesWIthDelegations }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/nation3-votes-with-delegations/README.md b/src/strategies/nation3-votes-with-delegations/README.md new file mode 100644 index 000000000..467ae2dd5 --- /dev/null +++ b/src/strategies/nation3-votes-with-delegations/README.md @@ -0,0 +1,13 @@ +# Nation3 voting power strategy + +Calculates voting power based on a user's staked tokens and 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 2 input parameters: + +**erc20** + +The address of veNation tokens contract + +**erc721** + +The address of nation3 passport tokens contract \ No newline at end of file diff --git a/src/strategies/nation3-votes-with-delegations/examples.json b/src/strategies/nation3-votes-with-delegations/examples.json new file mode 100644 index 000000000..507976620 --- /dev/null +++ b/src/strategies/nation3-votes-with-delegations/examples.json @@ -0,0 +1,21 @@ +[ + { + "name": "Voting Power with ERC20 Balances (only for ERC721 Holders) ", + "strategy": { + "name": "nation3-votes-with-delegations", + "params": { + "erc721": "0x3337dac9f251d4e403d6030e18e3cfb6a2cb1333", + "erc20": "0xf7def1d2fbda6b74bee7452fdf7894da9201065d" + } + }, + "network": "1", + "addresses": [ + "0xE4BE9b821f84Ec062865372914c8392CA8F31464", + "0x05a4448597935c508e4ad0D2CF56d56beDb246Ce", + "0x69A5c0Db191697D11b0Ac5637c3445D38AF4b15b", + "0x443d40B2AA10cb01884A97281Dc8ac3cCb0eef2a", + "0x6412517845128C289e111Ad9dA26100f78e529d8" + ], + "snapshot": 15491432 + } +] diff --git a/src/strategies/nation3-votes-with-delegations/index.ts b/src/strategies/nation3-votes-with-delegations/index.ts new file mode 100644 index 000000000..02653c59d --- /dev/null +++ b/src/strategies/nation3-votes-with-delegations/index.ts @@ -0,0 +1,126 @@ +import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'caranell'; +export const version = '0.1.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)' +]; + +const lastTokenIdAbi = ['function getNextId() external view returns (uint256)']; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const erc721OwnerCaller = new Multicaller(network, provider, ownerAbi, { + blockTag + }); + const erc721SignerCaller = new Multicaller(network, provider, signerAbi, { + blockTag + }); + const erc721LastTokenIdCaller = new Multicaller( + network, + provider, + lastTokenIdAbi, + { blockTag } + ); + + const erc20BalanceCaller = new Multicaller(network, provider, balanceAbi, { + blockTag + }); + + erc721LastTokenIdCaller.call('lastTokenId', options.erc721, 'getNextId'); + + addresses.forEach((address) => { + erc20BalanceCaller.call(address, options.erc20, 'balanceOf', [address]); + }); + + const [erc20Balances, lastIndex]: [ + Record, + Record + ] = await Promise.all([ + erc20BalanceCaller.execute(), + erc721LastTokenIdCaller.execute() + ]); + + const lastTokenId = BigNumber.from(lastIndex.lastTokenId).toNumber(); + + for (let i = 0; i < lastTokenId; i++) { + erc721SignerCaller.call(i, options.erc721, 'signerOf', [i]); + erc721OwnerCaller.call(i, options.erc721, 'ownerOf', [i]); + } + + const [erc721Signers, erc721Owners]: [ + Record, + Record + ] = await Promise.all([ + erc721SignerCaller.execute(), + erc721OwnerCaller.execute() + ]); + + const erc721OwnersArr = Object.entries(erc721Owners); + const delegatedTokens = erc721OwnersArr.filter( + ([id, address]) => address != erc721Signers[id] + ); + + const result = Object.fromEntries( + addresses.map((address) => { + const tokenDelegations = delegatedTokens.find( + ([, addr]) => addr === address + ); + + if (tokenDelegations?.length) { + const realOwners = erc721OwnersArr.find(([id]) => + tokenDelegations.includes(id) + ); + + if (!realOwners?.length) { + return [address, 0.0]; + } + + const ownerAddresses = realOwners.map(([, addr]) => addr); + const erc20Balance = ownerAddresses.reduce((sum, addr) => { + return sum + parseFloat(formatUnits(erc20Balances[addr], DECIMALS)); + }, 0); + + return [address, parseFloat(formatUnits(erc20Balance, DECIMALS))]; + } else { + const erc20Balance = erc20Balances[address]; + const erc721Token = erc721OwnersArr.find( + ([, addr]) => addr === address + ); + + if (!erc721Token) { + return [address, 0.0]; + } + + const isUsersTokenDelegated = delegatedTokens.find( + ([id]) => id === erc721Token[0] + ); + + if (erc721Token && !isUsersTokenDelegated) { + return [address, parseFloat(formatUnits(erc20Balance, DECIMALS))]; + } + + return [address, 0.0]; + } + }) + ); + return result; +} diff --git a/src/strategies/nation3-votes-with-delegations/schema.json b/src/strategies/nation3-votes-with-delegations/schema.json new file mode 100644 index 000000000..8318dcad9 --- /dev/null +++ b/src/strategies/nation3-votes-with-delegations/schema.json @@ -0,0 +1,30 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "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", + "examples": ["e.g. 0x3337dac9f251d4e403d6030e18e3cfb6a2cb1333"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } + }, + "required": ["erc20", "erc721"], + "additionalProperties": false + } + } +} From 63cf9fc9ebcd63533093ed9750de6d5b3108c3ab Mon Sep 17 00:00:00 2001 From: rsquare Date: Fri, 23 Sep 2022 20:01:43 +0200 Subject: [PATCH 129/815] Added logic for considering expiring badges (#844) --- src/strategies/otterspace-badges/index.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/strategies/otterspace-badges/index.ts b/src/strategies/otterspace-badges/index.ts index c805d0b53..bedf4f2ac 100644 --- a/src/strategies/otterspace-badges/index.ts +++ b/src/strategies/otterspace-badges/index.ts @@ -51,7 +51,8 @@ function getBadgeWeight(specs: any[], badgeSpecID: string): number { if (specs && specs.length > 0) { const specConfig = specs.find((spec: any) => spec.id === badgeSpecID); - badgeWeight = specConfig ? specConfig.weight : 0; + badgeWeight = + specConfig && !isBadgeExpired(specConfig.expiresAt) ? specConfig.weight : 0; } else { badgeWeight = 1; } @@ -59,6 +60,10 @@ function getBadgeWeight(specs: any[], badgeSpecID: string): number { return badgeWeight; } +function isBadgeExpired(expiresAt: string | null): boolean { + return expiresAt ? Date.now() - Number(new Date(expiresAt)) > 0 : false; +} + function applyBadgeWeights(badges: [], options: any) { const badgeWeights = {}; From 8d0b0632a42a2ad065c410c3f72c3a9c0d41db6a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 24 Sep 2022 13:15:05 +0530 Subject: [PATCH 130/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.33 (#843) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 38fe88238..c3e7aa7a9 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.31", + "@snapshot-labs/snapshot.js": "^0.4.33", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", "copyfiles": "^2.4.1", diff --git a/yarn.lock b/yarn.lock index e42d4dc12..b2317a290 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.31": - version "0.4.31" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.31.tgz#b9ac5a2805e4b76377f344a748d8631d60b362b2" - integrity sha512-lhejgMHHR0rPrEcH8XUufZc7zRM4wLcXEd2MBMEHvR3n5USSTEgrh1LwN5urjAISjKyMVdByU6H5Gz96G4Jxjw== +"@snapshot-labs/snapshot.js@^0.4.33": + version "0.4.33" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.33.tgz#28174da010d25eae6028d8a6bdb793071dd90a47" + integrity sha512-I2ocNOUsEQH4BTmtRNrpqnwz14mp31itgsOKFdD0ATJh/SlVbkcVvjmdvGdmBPSinuBz5E3zWbfuT38jbUkf7A== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 18c8a01302a0e08e68b354afe8e303aa7726f7e4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 25 Sep 2022 17:37:30 +0530 Subject: [PATCH 131/815] Automated lint (#845) Co-authored-by: ChaituVR --- src/strategies/otterspace-badges/index.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/strategies/otterspace-badges/index.ts b/src/strategies/otterspace-badges/index.ts index bedf4f2ac..1ba8314a5 100644 --- a/src/strategies/otterspace-badges/index.ts +++ b/src/strategies/otterspace-badges/index.ts @@ -52,7 +52,9 @@ function getBadgeWeight(specs: any[], badgeSpecID: string): number { if (specs && specs.length > 0) { const specConfig = specs.find((spec: any) => spec.id === badgeSpecID); badgeWeight = - specConfig && !isBadgeExpired(specConfig.expiresAt) ? specConfig.weight : 0; + specConfig && !isBadgeExpired(specConfig.expiresAt) + ? specConfig.weight + : 0; } else { badgeWeight = 1; } From 1572dfc3d46a81d7af361e544a6de39865aa54d7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 25 Sep 2022 22:51:45 +0530 Subject: [PATCH 132/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.34 (#846) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index c3e7aa7a9..c6ca772d6 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.33", + "@snapshot-labs/snapshot.js": "^0.4.34", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", "copyfiles": "^2.4.1", diff --git a/yarn.lock b/yarn.lock index b2317a290..360d1ac17 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.33": - version "0.4.33" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.33.tgz#28174da010d25eae6028d8a6bdb793071dd90a47" - integrity sha512-I2ocNOUsEQH4BTmtRNrpqnwz14mp31itgsOKFdD0ATJh/SlVbkcVvjmdvGdmBPSinuBz5E3zWbfuT38jbUkf7A== +"@snapshot-labs/snapshot.js@^0.4.34": + version "0.4.34" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.34.tgz#7f7480dcef2098f22695c11815e8ffa684beac88" + integrity sha512-RDWVQFsKYJKjvvU8nuxrKdsnxfANMoeeE6CDZyZPaQKIkpwzOXdBsmajpwYMUZsUav1XZidiqZa56Xz+3mVlHA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 9d277f4f2cb8b3bb7c2b706cff8fc2df1f7005c4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 27 Sep 2022 12:10:45 +0530 Subject: [PATCH 133/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.35 (#853) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index c6ca772d6..c4ee683dc 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.34", + "@snapshot-labs/snapshot.js": "^0.4.35", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", "copyfiles": "^2.4.1", diff --git a/yarn.lock b/yarn.lock index 360d1ac17..e6c86bd04 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.34": - version "0.4.34" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.34.tgz#7f7480dcef2098f22695c11815e8ffa684beac88" - integrity sha512-RDWVQFsKYJKjvvU8nuxrKdsnxfANMoeeE6CDZyZPaQKIkpwzOXdBsmajpwYMUZsUav1XZidiqZa56Xz+3mVlHA== +"@snapshot-labs/snapshot.js@^0.4.35": + version "0.4.35" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.35.tgz#9137f40916f6c4054dee1bd18586dc2a0e9a1eb2" + integrity sha512-3AIw536Z7HgeM/7PIwqNKGPffiEL/c0VsYPT+18Z7wEHFgI/UMilhCYcHpZxbnE6AYhlPLowRSFtNwHjwvwRww== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 0920edf9aa062bd559517b0718300cc38285d132 Mon Sep 17 00:00:00 2001 From: programmablewealth <68889286+programmablewealth@users.noreply.github.com> Date: Wed, 28 Sep 2022 21:40:25 +1000 Subject: [PATCH 134/815] erc20-tokens-per-uni strat (#848) Co-authored-by: Chaitanya --- src/strategies/erc20-tokens-per-uni/README.md | 7 +++ .../erc20-tokens-per-uni/examples.json | 15 ++++++ src/strategies/erc20-tokens-per-uni/index.ts | 51 +++++++++++++++++++ src/strategies/index.ts | 4 +- 4 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 src/strategies/erc20-tokens-per-uni/README.md create mode 100644 src/strategies/erc20-tokens-per-uni/examples.json create mode 100644 src/strategies/erc20-tokens-per-uni/index.ts diff --git a/src/strategies/erc20-tokens-per-uni/README.md b/src/strategies/erc20-tokens-per-uni/README.md new file mode 100644 index 000000000..e28c312f5 --- /dev/null +++ b/src/strategies/erc20-tokens-per-uni/README.md @@ -0,0 +1,7 @@ +# ERC20 Tokens Per Uni + +## Description + +This snapshot strategy provides one voting power unit for each unit of a given ERC20 token included in the LP. + +It is a generic strategy that can be re-used for any ERC20 token and LP token. \ No newline at end of file diff --git a/src/strategies/erc20-tokens-per-uni/examples.json b/src/strategies/erc20-tokens-per-uni/examples.json new file mode 100644 index 000000000..eb95a76eb --- /dev/null +++ b/src/strategies/erc20-tokens-per-uni/examples.json @@ -0,0 +1,15 @@ +[ + { + "name": "Strategy provides one voting power unit for each unit of a given ERC20 token included in the LP.", + "strategy": { + "name": "erc20-tokens-per-uni", + "params": { + "erc20TokenAddress": "0x385Eeac5cB85A38A9a07A70c73e0a3271CfB54A7", + "poolTokenAddress": "0xb0E35478a389dD20050D66a67FB761678af99678" + } + }, + "network": "137", + "addresses": ["0x26cf02F892B04aF4Cf350539CE2C77FCF79Ec172", "0x027Ffd3c119567e85998f4E6B9c3d83D5702660c"], + "snapshot": 33423178 + } +] diff --git a/src/strategies/erc20-tokens-per-uni/index.ts b/src/strategies/erc20-tokens-per-uni/index.ts new file mode 100644 index 000000000..8de513b0b --- /dev/null +++ b/src/strategies/erc20-tokens-per-uni/index.ts @@ -0,0 +1,51 @@ +import { multicall } from '../../utils'; + +export const author = 'programmablewealth'; +export const version = '0.0.1'; + +const tokenAbi = [ + 'function balanceOf(address account) view returns (uint256)', + 'function totalSupply() view returns (uint256)', +]; + +export async function strategy( + _space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const poolTokensBalanceQueries = addresses.map((address: string) => [ + options.poolTokenAddress, + 'balanceOf', + [address] + ]); + + const res = await multicall( + network, + provider, + tokenAbi, + [ + ...poolTokensBalanceQueries, + [options.poolTokenAddress, 'totalSupply', []], + [options.erc20TokenAddress, 'balanceOf', [options.poolTokenAddress]], + ], + { blockTag } + ); + + const tokensPerUni = (balanceInUni: number, totalSupply: number) => { + return balanceInUni / 1e18 / (totalSupply / 1e18); + }; + + let entries = {}; + for (let addressIndex = 0; addressIndex < addresses.length; addressIndex++) { + let address = addresses[addressIndex]; + let result = res[addressIndex] * tokensPerUni(res[poolTokensBalanceQueries.length + 1], res[poolTokensBalanceQueries.length]); + entries[address] = Number(result.toString()) / 1e18; + } + + return entries; +} \ No newline at end of file diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 6028843f1..e6d6d1f30 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -371,6 +371,7 @@ import * as syntheticNounsClaimerOwner from './synthetic-nouns-with-claimer'; import * as depositInSablierStream from './deposit-in-sablier-stream'; import * as echelonWalletPrimeAndCachedKey from './echelon-wallet-prime-and-cached-key'; import * as nation3VotesWIthDelegations from './nation3-votes-with-delegations'; +import * as erc20TokensPerUni from './erc20-tokens-per-uni'; const strategies = { 'forta-shares': fortaShares, @@ -745,7 +746,8 @@ const strategies = { 'synthetic-nouns-with-claimer': syntheticNounsClaimerOwner, 'deposit-in-sablier-stream': depositInSablierStream, 'echelon-wallet-prime-and-cached-key': echelonWalletPrimeAndCachedKey, - 'nation3-votes-with-delegations': nation3VotesWIthDelegations + 'nation3-votes-with-delegations': nation3VotesWIthDelegations, + 'erc20-tokens-per-uni': erc20TokensPerUni }; Object.keys(strategies).forEach(function (strategyName) { From d42ed21c666ba79ca99dd009d2c0923c0f34e178 Mon Sep 17 00:00:00 2001 From: programmablewealth <68889286+programmablewealth@users.noreply.github.com> Date: Wed, 28 Sep 2022 21:50:01 +1000 Subject: [PATCH 135/815] gltr-staked-lp strat (#850) Co-authored-by: Chaitanya --- .../README.md | 22 +++ .../examples.json | 34 ++++ .../index.ts | 166 ++++++++++++++++++ src/strategies/index.ts | 2 + 4 files changed, 224 insertions(+) create mode 100644 src/strategies/aavegotchi-agip-37-gltr-staked-lp/README.md create mode 100644 src/strategies/aavegotchi-agip-37-gltr-staked-lp/examples.json create mode 100644 src/strategies/aavegotchi-agip-37-gltr-staked-lp/index.ts diff --git a/src/strategies/aavegotchi-agip-37-gltr-staked-lp/README.md b/src/strategies/aavegotchi-agip-37-gltr-staked-lp/README.md new file mode 100644 index 000000000..81369b718 --- /dev/null +++ b/src/strategies/aavegotchi-agip-37-gltr-staked-lp/README.md @@ -0,0 +1,22 @@ +# Aavegotchi AGIP 37 GLTR Staked LP Strategy + +## Description + +This snapshot strategy enables voting power for the following assets staked in GLTR staking pools + +- GHST-FUD LP +- GHST-FOMO LP +- GHST-ALPHA LP +- GHST-KEK LP +- GHST-GLTR LP +- GHST-USDC LP +- GHST-WMATIC LP + +Please note this excludes voting power from: +- Staked wapGHST and unstaked wapGHST held in a wallet (see aavegotchi-agip-37-wap-ghst) +- amGHST (see erc20-balance-of) +- Unstaked GHST-FUD, GHST-FOMO, GHST-ALPHA, GHST-KEK, GHST-GLTR LP tokens (see erc20-tokens-per-uni) + +## References + +Aavegotchi AGIP 37: https://snapshot.org/#/aavegotchi.eth/proposal/0x9923aab6825158ec2503d88e3ee2f9c5fbb12000581d06343ac9829aa59b66a6 \ No newline at end of file diff --git a/src/strategies/aavegotchi-agip-37-gltr-staked-lp/examples.json b/src/strategies/aavegotchi-agip-37-gltr-staked-lp/examples.json new file mode 100644 index 000000000..1839c52fd --- /dev/null +++ b/src/strategies/aavegotchi-agip-37-gltr-staked-lp/examples.json @@ -0,0 +1,34 @@ +[ + { + "name": "AGIP 37: Voting Power for GHST-FUD, GHST-FOMO, GHST-ALPHA, GHST-KEK, GHST-GLTR, GHST-USDC, and GHST-WMATIC staked in the GLTR farming contract. Note: Excludes wapGHST.", + "strategy": { + "name": "aavegotchi-agip-37-gltr-staked-lp", + "params": { + "ghstAddress": "0x385Eeac5cB85A38A9a07A70c73e0a3271CfB54A7", + "gltrStakingAddress": "0x1fE64677Ab1397e20A1211AFae2758570fEa1B8c", + "amGhstAddress": "0x080b5BF8f360F624628E0fb961F4e67c9e3c7CF1", + "wapGhstAddress": "0x73958d46B7aA2bc94926d8a215Fa560A5CdCA3eA", + "wapGhstPoolId": 0, + "ghstFudAddress": "0xfec232cc6f0f3aeb2f81b2787a9bc9f6fc72ea5c", + "ghstFudPoolId": 1, + "ghstFomoAddress": "0x641ca8d96b01db1e14a5fba16bc1e5e508a45f2b", + "ghstFomoPoolId": 2, + "ghstAlphaAddress": "0xc765eca0ad3fd27779d36d18e32552bd7e26fd7b", + "ghstAlphaPoolId": 3, + "ghstKekAddress": "0xbfad162775ebfb9988db3f24ef28ca6bc2fb92f0", + "ghstKekPoolId": 4, + "ghstUsdcAddress": "0x096c5ccb33cfc5732bcd1f3195c13dbefc4c82f4", + "ghstUsdcPoolId": 5, + "ghstWmaticAddress": "0xf69e93771F11AECd8E554aA165C3Fe7fd811530c", + "ghstWmaticPoolId": 6, + "ghstGltrAddress": "0xb0E35478a389dD20050D66a67FB761678af99678", + "ghstGltrPoolId": 7, + "symbol": "GHST", + "decimals": 18 + } + }, + "network": "137", + "addresses": ["0x26cf02F892B04aF4Cf350539CE2C77FCF79Ec172", "0x027Ffd3c119567e85998f4E6B9c3d83D5702660c", "0xc4cb6cb969e8b4e309ab98e4da51b77887afad96"], + "snapshot": 33423178 + } +] diff --git a/src/strategies/aavegotchi-agip-37-gltr-staked-lp/index.ts b/src/strategies/aavegotchi-agip-37-gltr-staked-lp/index.ts new file mode 100644 index 000000000..4aa4955a8 --- /dev/null +++ b/src/strategies/aavegotchi-agip-37-gltr-staked-lp/index.ts @@ -0,0 +1,166 @@ +import { multicall } from '../../utils'; + +export const author = 'programmablewealth'; +export const version = '0.0.1'; + +const tokenAbi = [ + 'function balanceOf(address account) view returns (uint256)', + 'function totalSupply() view returns (uint256)', + 'function allUserInfo(address _user) view returns (tuple(address lpToken, uint256 allocPoint, uint256 pending, uint256 userBalance, uint256 poolBalance)[] _info)', + 'function convertToAssets(uint256 shares) view returns (uint)', +]; + +export async function strategy( + _space, + network, + provider, + addresses, + options, + snapshot +) { + options.ghstAddress = options.ghstAddress || '0x385Eeac5cB85A38A9a07A70c73e0a3271CfB54A7'; + + options.gltrStakingAddress = options.gltrStakingAddress || '0x1fE64677Ab1397e20A1211AFae2758570fEa1B8c'; + + options.amGhstAddress = options.amGhstAddress || '0x080b5BF8f360F624628E0fb961F4e67c9e3c7CF1'; + + options.wapGhstAddress = options.wapGhstAddress || '0x73958d46B7aA2bc94926d8a215Fa560A5CdCA3eA'; + options.wapGhstPoolId = options.wapGhstPoolId || 0; + + options.ghstFudAddress = options.ghstFudAddress || '0xfec232cc6f0f3aeb2f81b2787a9bc9f6fc72ea5c'; + options.ghstFudPoolId = options.ghstFudPoolId || 1; + + options.ghstFomoAddress = options.ghstFomoAddress || '0x641ca8d96b01db1e14a5fba16bc1e5e508a45f2b'; + options.ghstFomoPoolId = options.ghstFomoPoolId || 2; + + options.ghstAlphaAddress = options.ghstAlphaAddress || '0xc765eca0ad3fd27779d36d18e32552bd7e26fd7b'; + options.ghstAlphaPoolId = options.ghstAlphaPoolId || 3; + + options.ghstKekAddress = options.ghstKekAddress || '0xbfad162775ebfb9988db3f24ef28ca6bc2fb92f0'; + options.ghstKekPoolId = options.ghstKekPoolId || 4; + + options.ghstUsdcAddress = options.ghstUsdcAddress || '0x096c5ccb33cfc5732bcd1f3195c13dbefc4c82f4'; + options.ghstUsdcPoolId = options.ghstUsdcPoolId || 5; + + options.ghstWmaticAddress = options.ghstWmaticAddress || '0xf69e93771F11AECd8E554aA165C3Fe7fd811530c'; + options.ghstWmaticPoolId = options.ghstWmaticPoolId || 6; + + options.ghstGltrAddress = options.ghstGltrAddress || '0xb0E35478a389dD20050D66a67FB761678af99678'; + options.ghstGltrPoolId = options.ghstGltrPoolId || 7; + + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const stakeQuery = addresses.map((address: string) => [ + options.gltrStakingAddress, + 'allUserInfo', + [address] + ]); + + let slicedStakedQueries:any = [stakeQuery]; + if (stakeQuery.length > 1) { + let middle = stakeQuery.length/2; + slicedStakedQueries = [ + stakeQuery.slice(0, middle), + stakeQuery.slice(middle, stakeQuery.length) + ]; + } + + let res = await multicall( + network, + provider, + tokenAbi, + [ + [options.ghstFudAddress, 'totalSupply', []], + [options.ghstAddress, 'balanceOf', [options.ghstFudAddress]], + [options.ghstFomoAddress, 'totalSupply', []], + [options.ghstAddress, 'balanceOf', [options.ghstFomoAddress]], + [options.ghstAlphaAddress, 'totalSupply', []], + [options.ghstAddress, 'balanceOf', [options.ghstAlphaAddress]], + [options.ghstKekAddress, 'totalSupply', []], + [options.ghstAddress, 'balanceOf', [options.ghstKekAddress]], + [options.ghstGltrAddress, 'totalSupply', []], + [options.ghstAddress, 'balanceOf', [options.ghstGltrAddress]], + [options.ghstUsdcAddress, 'totalSupply', []], + [options.ghstAddress, 'balanceOf', [options.ghstUsdcAddress]], + [options.ghstWmaticAddress, 'totalSupply', []], + [options.ghstAddress, 'balanceOf', [options.ghstWmaticAddress]], + ...slicedStakedQueries[0], + ], + { blockTag } + ); + + if (slicedStakedQueries.length > 1) { + const res2 = await multicall( + network, + provider, + tokenAbi, + [ + ...slicedStakedQueries[1] + ], + { blockTag } + ); + + res = [...res, ...res2]; + } + + const tokensPerUni = (balanceInUni: number, totalSupply: number) => { + return balanceInUni / 1e18 / (totalSupply / 1e18); + }; + + let lpTokensStartIndex = 0; + let lpTokensPerUni = { + ghstFudLp: tokensPerUni(res[lpTokensStartIndex+1], res[lpTokensStartIndex]), + ghstFomoLp: tokensPerUni(res[lpTokensStartIndex+3], res[lpTokensStartIndex+2]), + ghstAlphaLp: tokensPerUni(res[lpTokensStartIndex+5], res[lpTokensStartIndex+4]), + ghstKekLp: tokensPerUni(res[lpTokensStartIndex+7], res[lpTokensStartIndex+6]), + ghstGltrLp: tokensPerUni(res[lpTokensStartIndex+9], res[lpTokensStartIndex+8]), + ghstUsdcLp: tokensPerUni(res[lpTokensStartIndex+11], res[lpTokensStartIndex+10]), + ghstWmaticLp: tokensPerUni(res[lpTokensStartIndex+13], res[lpTokensStartIndex+12]), + }; + + let entries = {}; + for (let addressIndex = 0; addressIndex < addresses.length; addressIndex++) { + let i = addressIndex + 14; + let tokens = { + staked: { + ghstFudLp: Number(res[i]._info[options.ghstFudPoolId].userBalance.toString()) / 1e18, + ghstFomoLp: Number(res[i]._info[options.ghstFomoPoolId].userBalance.toString()) / 1e18, + ghstAlphaLp: Number(res[i]._info[options.ghstAlphaPoolId].userBalance.toString()) / 1e18, + ghstKekLp: Number(res[i]._info[options.ghstKekPoolId].userBalance.toString()) / 1e18, + ghstGltrLp: Number(res[i]._info[options.ghstGltrPoolId].userBalance.toString()) / 1e18, + ghstUsdcLp: Number(res[i]._info[options.ghstUsdcPoolId].userBalance.toString()) / 1e18, + ghstWmaticLp: Number(res[i]._info[options.ghstWmaticPoolId].userBalance.toString()) / 1e18 + }, + }; + + let votingPower = { + staked: { + ghstFudLp: tokens.staked.ghstFudLp * lpTokensPerUni.ghstFudLp, + ghstFomoLp: tokens.staked.ghstFomoLp * lpTokensPerUni.ghstFomoLp, + ghstAlphaLp: tokens.staked.ghstAlphaLp * lpTokensPerUni.ghstAlphaLp, + ghstKekLp: tokens.staked.ghstKekLp * lpTokensPerUni.ghstKekLp, + ghstGltrLp: tokens.staked.ghstGltrLp * lpTokensPerUni.ghstGltrLp, + ghstUsdcLp: tokens.staked.ghstUsdcLp * lpTokensPerUni.ghstUsdcLp, + ghstWmaticLp: tokens.staked.ghstWmaticLp * lpTokensPerUni.ghstWmaticLp + } + }; + + let totalVotingPower = 0; + for (let k = 0; k < Object.keys(votingPower.staked).length; k++) { + let key = Object.keys(votingPower.staked)[k]; + totalVotingPower += votingPower.staked[key]; + } + + let address = addresses[addressIndex]; + + // let loggedString = "TOKENS SUMMARY FOR " + address; + // loggedString += "\nSTAKED TOKENS\n" + JSON.stringify(tokens.staked); + // loggedString += "\nSTAKED VOTING POWER\n" + JSON.stringify(votingPower.staked); + // loggedString += "\nTOTAL VOTING POWER\n" + totalVotingPower; + // console.log(loggedString); + + entries[address] = totalVotingPower; + } + + return entries; +} \ No newline at end of file diff --git a/src/strategies/index.ts b/src/strategies/index.ts index e6d6d1f30..f39ea6806 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -371,6 +371,7 @@ import * as syntheticNounsClaimerOwner from './synthetic-nouns-with-claimer'; import * as depositInSablierStream from './deposit-in-sablier-stream'; import * as echelonWalletPrimeAndCachedKey from './echelon-wallet-prime-and-cached-key'; import * as nation3VotesWIthDelegations from './nation3-votes-with-delegations'; +import * as aavegotchiAgip37GltrStakedLp from './aavegotchi-agip-37-gltr-staked-lp'; import * as erc20TokensPerUni from './erc20-tokens-per-uni'; const strategies = { @@ -747,6 +748,7 @@ const strategies = { 'deposit-in-sablier-stream': depositInSablierStream, 'echelon-wallet-prime-and-cached-key': echelonWalletPrimeAndCachedKey, 'nation3-votes-with-delegations': nation3VotesWIthDelegations, + 'aavegotchi-agip-37-gltr-staked-lp': aavegotchiAgip37GltrStakedLp, 'erc20-tokens-per-uni': erc20TokensPerUni }; From 55583bf555ba8e8a9f26b1c597b2aee5d664136b Mon Sep 17 00:00:00 2001 From: programmablewealth <68889286+programmablewealth@users.noreply.github.com> Date: Wed, 28 Sep 2022 21:52:45 +1000 Subject: [PATCH 136/815] wap-ghst strat (#849) Co-authored-by: Chaitanya --- .../aavegotchi-agip-37-wap-ghst/README.md | 9 + .../aavegotchi-agip-37-wap-ghst/examples.json | 34 ++++ .../aavegotchi-agip-37-wap-ghst/index.ts | 166 ++++++++++++++++++ src/strategies/index.ts | 2 + 4 files changed, 211 insertions(+) create mode 100644 src/strategies/aavegotchi-agip-37-wap-ghst/README.md create mode 100644 src/strategies/aavegotchi-agip-37-wap-ghst/examples.json create mode 100644 src/strategies/aavegotchi-agip-37-wap-ghst/index.ts diff --git a/src/strategies/aavegotchi-agip-37-wap-ghst/README.md b/src/strategies/aavegotchi-agip-37-wap-ghst/README.md new file mode 100644 index 000000000..45c8a29a7 --- /dev/null +++ b/src/strategies/aavegotchi-agip-37-wap-ghst/README.md @@ -0,0 +1,9 @@ +# Aavegotchi AGIP 37 Strategy WAP GHST + +## Description + +This snapshot strategy enables voting power for staked and unstaked wapGHST. + +## References + +Aavegotchi AGIP 37: https://snapshot.org/#/aavegotchi.eth/proposal/0x9923aab6825158ec2503d88e3ee2f9c5fbb12000581d06343ac9829aa59b66a6 \ No newline at end of file diff --git a/src/strategies/aavegotchi-agip-37-wap-ghst/examples.json b/src/strategies/aavegotchi-agip-37-wap-ghst/examples.json new file mode 100644 index 000000000..227096e42 --- /dev/null +++ b/src/strategies/aavegotchi-agip-37-wap-ghst/examples.json @@ -0,0 +1,34 @@ +[ + { + "name": "AGIP-37: This snapshot strategy enables voting power for staked and unstaked wapGHST", + "strategy": { + "name": "aavegotchi-agip-37-wap-ghst", + "params": { + "ghstAddress": "0x385Eeac5cB85A38A9a07A70c73e0a3271CfB54A7", + "gltrStakingAddress": "0x1fE64677Ab1397e20A1211AFae2758570fEa1B8c", + "amGhstAddress": "0x080b5BF8f360F624628E0fb961F4e67c9e3c7CF1", + "wapGhstAddress": "0x73958d46B7aA2bc94926d8a215Fa560A5CdCA3eA", + "wapGhstPoolId": 0, + "ghstFudAddress": "0xfec232cc6f0f3aeb2f81b2787a9bc9f6fc72ea5c", + "ghstFudPoolId": 1, + "ghstFomoAddress": "0x641ca8d96b01db1e14a5fba16bc1e5e508a45f2b", + "ghstFomoPoolId": 2, + "ghstAlphaAddress": "0xc765eca0ad3fd27779d36d18e32552bd7e26fd7b", + "ghstAlphaPoolId": 3, + "ghstKekAddress": "0xbfad162775ebfb9988db3f24ef28ca6bc2fb92f0", + "ghstKekPoolId": 4, + "ghstUsdcAddress": "0x096c5ccb33cfc5732bcd1f3195c13dbefc4c82f4", + "ghstUsdcPoolId": 5, + "ghstWmaticAddress": "0xf69e93771F11AECd8E554aA165C3Fe7fd811530c", + "ghstWmaticPoolId": 6, + "ghstGltrAddress": "0xb0E35478a389dD20050D66a67FB761678af99678", + "ghstGltrPoolId": 7, + "symbol": "GHST", + "decimals": 18 + } + }, + "network": "137", + "addresses": ["0x26cf02F892B04aF4Cf350539CE2C77FCF79Ec172", "0x027Ffd3c119567e85998f4E6B9c3d83D5702660c", "0xDEA88c9FE09106b58cA7c026c82383c56eE1E041", "0x3a564B24EffA1Cb7Dc836AD094BaD28e69FCa371"], + "snapshot": 33423178 + } +] diff --git a/src/strategies/aavegotchi-agip-37-wap-ghst/index.ts b/src/strategies/aavegotchi-agip-37-wap-ghst/index.ts new file mode 100644 index 000000000..e8f7ea665 --- /dev/null +++ b/src/strategies/aavegotchi-agip-37-wap-ghst/index.ts @@ -0,0 +1,166 @@ +import { multicall } from '../../utils'; + +export const author = 'programmablewealth'; +export const version = '0.0.1'; + +const tokenAbi = [ + 'function balanceOf(address account) view returns (uint256)', + 'function totalSupply() view returns (uint256)', + 'function allUserInfo(address _user) view returns (tuple(address lpToken, uint256 allocPoint, uint256 pending, uint256 userBalance, uint256 poolBalance)[] _info)', + 'function convertToAssets(uint256 shares) view returns (uint)', +]; + +export async function strategy( + _space, + network, + provider, + addresses, + options, + snapshot +) { + options.ghstAddress = options.ghstAddress || '0x385Eeac5cB85A38A9a07A70c73e0a3271CfB54A7'; + + options.gltrStakingAddress = options.gltrStakingAddress || '0x1fE64677Ab1397e20A1211AFae2758570fEa1B8c'; + + options.amGhstAddress = options.amGhstAddress || '0x080b5BF8f360F624628E0fb961F4e67c9e3c7CF1'; + + options.wapGhstAddress = options.wapGhstAddress || '0x73958d46B7aA2bc94926d8a215Fa560A5CdCA3eA'; + options.wapGhstPoolId = options.wapGhstPoolId || 0; + + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const walletQuery = addresses.map((address: string) => [ + options.wapGhstAddress, + 'balanceOf', + [address] + ]); + + const stakeQuery = addresses.map((address: string) => [ + options.gltrStakingAddress, + 'allUserInfo', + [address] + ]); + + let slicedWalletQueries:any = [walletQuery]; + if (walletQuery.length > 1) { + let middle = walletQuery.length/2; + slicedWalletQueries = [ + walletQuery.slice(0, middle), + walletQuery.slice(middle, walletQuery.length) + ]; + } + + let res = await multicall( + network, + provider, + tokenAbi, + [ + ...slicedWalletQueries[0], + ], + { blockTag } + ); + + if (slicedWalletQueries.length > 1) { + let res2 = await multicall( + network, + provider, + tokenAbi, + [ + ...slicedWalletQueries[1], + ], + { blockTag } + ); + + res = [...res, ...res2]; + } + + let slicedStakeQueries:any = [walletQuery]; + if (stakeQuery.length > 1) { + let middle = stakeQuery.length/2; + slicedStakeQueries = [ + stakeQuery.slice(0, middle), + stakeQuery.slice(middle, stakeQuery.length) + ]; + } + + const res3 = await multicall( + network, + provider, + tokenAbi, + [ + ...slicedStakeQueries[0], + ], + { blockTag } + ); + res = [...res, ...res3]; + + if (slicedStakeQueries.length > 1) { + let res4 = await multicall( + network, + provider, + tokenAbi, + [ + ...slicedStakeQueries[1], + ], + { blockTag } + ); + + res = [...res, ...res4]; + } + + let unitWapGHST_res = await multicall( + network, + provider, + tokenAbi, + [ + [options.wapGhstAddress, 'convertToAssets', ["1000000000000000000"]] + ], + { blockTag } + ); + let wapGHST_ghstMulitiplier = Number(unitWapGHST_res[0].toString()) / 1e18; + + let entries = {}; + for (let addressIndex = 0; addressIndex < addresses.length; addressIndex++) { + let tokens = { + staked: { + wapGhst: Number(res[addressIndex + addresses.length]._info[options.wapGhstPoolId].userBalance.toString()) / 1e18, + }, + unstaked: { + wapGhst: Number(res[addressIndex].toString()) / 1e18, + } + }; + + let votingPower = { + staked: { + wapGhst: tokens.staked.wapGhst * wapGHST_ghstMulitiplier, + }, + unstaked: { + wapGhst: tokens.unstaked.wapGhst * wapGHST_ghstMulitiplier, + }, + }; + + let totalVotingPower = 0; + for (let k = 0; k < Object.keys(votingPower.unstaked).length; k++) { + let key = Object.keys(votingPower.unstaked)[k]; + totalVotingPower += votingPower.unstaked[key]; + } + for (let k = 0; k < Object.keys(votingPower.staked).length; k++) { + let key = Object.keys(votingPower.staked)[k]; + totalVotingPower += votingPower.staked[key]; + } + + let address = addresses[addressIndex]; + + // let loggedString = "TOKENS SUMMARY FOR " + address; + // loggedString += "\nSTAKED TOKENS\n" + JSON.stringify(tokens.staked); + // loggedString += "\nUNSTAKED TOKENS\n" + JSON.stringify(tokens.unstaked); + // loggedString += "\nSTAKED VOTING POWER\n" + JSON.stringify(votingPower.staked); + // loggedString += "\nUNSTAKED VOTING POWER\n" + JSON.stringify(votingPower.unstaked); + // loggedString += "\nTOTAL VOTING POWER\n" + totalVotingPower; + // console.log(loggedString); + + entries[address] = totalVotingPower; + } + + return entries; +} \ No newline at end of file diff --git a/src/strategies/index.ts b/src/strategies/index.ts index f39ea6806..37fc4d016 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -371,6 +371,7 @@ import * as syntheticNounsClaimerOwner from './synthetic-nouns-with-claimer'; import * as depositInSablierStream from './deposit-in-sablier-stream'; import * as echelonWalletPrimeAndCachedKey from './echelon-wallet-prime-and-cached-key'; import * as nation3VotesWIthDelegations from './nation3-votes-with-delegations'; +import * as aavegotchiAgip37WapGhst from './aavegotchi-agip-37-wap-ghst'; import * as aavegotchiAgip37GltrStakedLp from './aavegotchi-agip-37-gltr-staked-lp'; import * as erc20TokensPerUni from './erc20-tokens-per-uni'; @@ -748,6 +749,7 @@ const strategies = { 'deposit-in-sablier-stream': depositInSablierStream, 'echelon-wallet-prime-and-cached-key': echelonWalletPrimeAndCachedKey, 'nation3-votes-with-delegations': nation3VotesWIthDelegations, + 'aavegotchi-agip-37-wap-ghst': aavegotchiAgip37WapGhst, 'aavegotchi-agip-37-gltr-staked-lp': aavegotchiAgip37GltrStakedLp, 'erc20-tokens-per-uni': erc20TokensPerUni }; From 7777ab6eb9e45e2cf0967ce8f853fbb6f2584433 Mon Sep 17 00:00:00 2001 From: Mark Howard Date: Wed, 28 Sep 2022 13:13:12 +0100 Subject: [PATCH 137/815] Add hedgey-multi strategy [hedgey-multi] (#837) * feature: Adds hedgey strategy for multiple contracts with a multiplier function * fix: sets author and max number of contracts * fix: removed eval and added lockedTokenMonthlyMultiplier * fix: updating readme Co-authored-by: Chaitanya --- src/strategies/hedgey-multi/README.md | 16 ++ src/strategies/hedgey-multi/examples.json | 25 +++ src/strategies/hedgey-multi/index.ts | 217 ++++++++++++++++++++++ src/strategies/index.ts | 2 + 4 files changed, 260 insertions(+) create mode 100644 src/strategies/hedgey-multi/README.md create mode 100644 src/strategies/hedgey-multi/examples.json create mode 100644 src/strategies/hedgey-multi/index.ts diff --git a/src/strategies/hedgey-multi/README.md b/src/strategies/hedgey-multi/README.md new file mode 100644 index 000000000..42f2440e4 --- /dev/null +++ b/src/strategies/hedgey-multi/README.md @@ -0,0 +1,16 @@ +# Hedgey strategy + +Calculates voting rights based on the underlying tokens locked in the Hedgey protocol from multiple contracts with a multiplyer + +## Examples + +### Input parameters + +An array of ContractDetails + + - address: The address of the contract + - token: The address of the token that is taken into account for the score + - decimal: The decimal value the token uses + - contractType: Can be NFT for the standard NFT contract or TokenInfusedNFT for the token infused NFT contract + - lockedTokenMultiplier: a simple multiplyer for locked tokens + - lockedTokenMonthlyMultiplier: a multiplier based on the amount of time the tokens will be unlocked for diff --git a/src/strategies/hedgey-multi/examples.json b/src/strategies/hedgey-multi/examples.json new file mode 100644 index 000000000..3ae14084c --- /dev/null +++ b/src/strategies/hedgey-multi/examples.json @@ -0,0 +1,25 @@ +[ + { + "name": "Example voting based on hedgey token underlying balance from multiple contracts with a multiplyer", + "strategy": { + "name": "hedgey-multi", + "params": { + "contracts": [{ + "address": "0x4bc8ea84bdc3ebb01d495e5d1605d4f082aeb5d7", + "token": "0xccDE1F2B71573a865d3896eb019C41Bf4BF92e65", + "decimal": 18, + "contractType": "NFT", + "lockedTokenMultiplier": 2, + "lockedTokenMonthlyMultiplier": { + "default": 1, + "1": 1.5, + "2": 2 + } + }] + } + }, + "network": "4", + "snapshot": 11452455, + "addresses": ["0x92d9802eFcD0485876DDC13c16cEA67e6aD5EB35"] + } +] diff --git a/src/strategies/hedgey-multi/index.ts b/src/strategies/hedgey-multi/index.ts new file mode 100644 index 000000000..5e6867ba4 --- /dev/null +++ b/src/strategies/hedgey-multi/index.ts @@ -0,0 +1,217 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import { Multicaller } from '../../utils'; + +export const author = 'bark4mark'; +export const version = '0.1.0'; + +const MAX_CONTRACTS = 8; + +enum ContractType { + NFT = 'NFT', + TokenInfusedNFT = 'TokenInfusedNFT' +} + +type ContractDetails = { + address: string; + token: string; + decimal: number; + contractType: ContractType; + lockedTokenMultiplier: number; + lockedTokenMonthlyMultiplier: any; +}; + +const abis = { + NFT: [ + 'function balanceOf(address owner) external view returns (uint256 balance)', + 'function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId)', + 'function futures(uint256 index) external view returns (uint256 amount, address token, uint256 unlockDate)', + 'function token() external view returns (address token)' + ], + TokenInfusedNFT: [ + 'function futures(uint256 index) external view returns (uint256 amount, uint256 unlockDate)' + ] +}; + +const compareAddresses = (address1: string, address2: string): boolean => { + if (!address1 || !address2) return false; + return address1.toLowerCase() === address2.toLowerCase(); +}; + +const getMonthDifference = (start: Date, end: Date): number => { + return ( + end.getMonth() - + start.getMonth() + + 12 * (end.getFullYear() - start.getFullYear()) + ); +}; + +export async function strategy( + _space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const contractDetails: ContractDetails[] = options.contracts; + if (contractDetails.length > MAX_CONTRACTS) { + throw new Error(`Max number (${MAX_CONTRACTS}) of contracts exceeded`); + } + const balanceOfMulti = new Multicaller(network, provider, abis.NFT, { + blockTag + }); + + contractDetails.forEach((contractDetail) => { + addresses.forEach((address: string) => { + balanceOfMulti.call( + `${contractDetail.address}/${address}`, + contractDetail.address, + 'balanceOf', + [address] + ); + }); + if (contractDetail.contractType === ContractType.TokenInfusedNFT) { + balanceOfMulti.call( + `${contractDetail.address}/token`, + contractDetail.address, + 'token' + ); + } + }); + + const balanceOfResult = await balanceOfMulti.execute(); + const nftHolderMulti = new Multicaller(network, provider, abis.NFT, { + blockTag + }); + + contractDetails.forEach((contractDetail) => { + addresses.forEach((address: string) => { + const balance = balanceOfResult[`${contractDetail.address}/${address}`]; + for (let index = 0; index < balance; index++) { + nftHolderMulti.call( + `${contractDetail.contractType}/${contractDetail.address}/${address}/${index}`, + contractDetail.address, + 'tokenOfOwnerByIndex', + [address, index] + ); + } + }); + }); + + const nftHolders = await nftHolderMulti.execute(); + + const nftDealsMulti = new Multicaller(network, provider, abis.NFT, { + blockTag + }); + + const tiNFTDealsMulti = new Multicaller( + network, + provider, + abis.TokenInfusedNFT, + { blockTag } + ); + + for (const [path, nftId] of Object.entries(nftHolders)) { + const [contractType, contractAddress, address] = path.split('/'); + switch (contractType) { + case ContractType.NFT: + nftDealsMulti.call( + `${contractAddress}/${address}`, + contractAddress, + 'futures', + [nftId] + ); + break; + case ContractType.TokenInfusedNFT: + tiNFTDealsMulti.call( + `${contractAddress}/${address}`, + contractAddress, + 'futures', + [nftId] + ); + break; + } + } + + const nftDeals = await nftDealsMulti.execute(); + const tiNFTDeals = await tiNFTDealsMulti.execute(); + + const votes = {}; + + for (const [path, deal] of Object.entries(nftDeals)) { + const [contractAddress, address] = path.split('/'); + const contractDetail = contractDetails.find( + (element) => element.address === contractAddress + ); + + if (!contractDetail) continue; + if (!compareAddresses(deal.token, contractDetail.token)) continue; + + const amount = BigNumber.from(deal.amount).div( + BigNumber.from(10).pow(contractDetail.decimal) + ); + + let score = amount.toNumber(); + score = score * contractDetail.lockedTokenMultiplier; + const durationStart = new Date(); + const unlockDate = new Date(deal.unlockDate * 1000); + + const months = getMonthDifference(durationStart, unlockDate); + let monthlyMultiplier = contractDetail.lockedTokenMonthlyMultiplier[months]; + + if (!monthlyMultiplier) + monthlyMultiplier = + contractDetail.lockedTokenMonthlyMultiplier['default']; + + score = score * monthlyMultiplier; + + let existingAmount = votes[address]; + if (existingAmount) { + existingAmount = existingAmount + score; + } else { + votes[address] = score; + } + } + + for (const [path, deal] of Object.entries(tiNFTDeals)) { + const [contractAddress, address] = path.split('/'); + const contractDetail = contractDetails.find( + (element) => element.address === contractAddress + ); + + if (!contractDetail) continue; + + const contractToken = balanceOfResult[`${contractDetail.address}/token`]; + if (!compareAddresses(contractToken, contractDetail.token)) continue; + + const amount = BigNumber.from(deal.amount).div( + BigNumber.from(10).pow(contractDetail.decimal) + ); + + let score = amount.toNumber(); + score = score * contractDetail.lockedTokenMultiplier; + const durationStart = new Date(); + const unlockDate = new Date(deal.unlockDate * 1000); + + const months = getMonthDifference(durationStart, unlockDate); + if (months > 1) { + let monthlyMultiplier = + contractDetail.lockedTokenMonthlyMultiplier[months]; + + if (!monthlyMultiplier) + monthlyMultiplier = + contractDetail.lockedTokenMonthlyMultiplier['default']; + + score = score * monthlyMultiplier; + } + let existingAmount = votes[address]; + if (existingAmount) { + existingAmount = existingAmount + score; + } else { + votes[address] = score; + } + } + + return votes; +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 37fc4d016..453174d9f 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -322,6 +322,7 @@ import * as recusalList from './recusal-list'; import * as rowdyRoos from './rowdy-roos'; import * as ethermon721 from './ethermon-erc721'; import * as hedgey from './hedgey'; +import * as hedgeyMulti from './hedgey-multi'; import * as sybilProtection from './sybil-protection'; import * as veBalanceOfAtNFT from './ve-balance-of-at-nft'; import * as genzeesFromSubgraph from './genzees-from-subgraph'; @@ -701,6 +702,7 @@ const strategies = { 'citydao-square-root': citydaoSquareRoot, 'rowdy-roos': rowdyRoos, hedgey, + 'hedgey-multi': hedgeyMulti, 've-balance-of-at-nft': veBalanceOfAtNFT, 'genzees-from-subgraph': genzeesFromSubgraph, 'gin-finance': ginFinance, From 63e7f58ff55363108bb58768ce97aee8190d7a9c Mon Sep 17 00:00:00 2001 From: Sagar Upadhyay <4917613+usagar80@users.noreply.github.com> Date: Fri, 30 Sep 2022 10:21:40 +0530 Subject: [PATCH 138/815] Staking token calculation bug fixing [gatenet-total-staked] (#854) * New Strategy - Gatenet-Total-Staked * GraphQL Sungraph Interactions * Update strategy code * Update strategy logic and examples * Update readme.MD for GATENet strategy * Update README.md * Convert JSON ABI to String ABI and remove unwanted files. * Set subgraph URL into parameters * Temp: Subgraph timestamp condition. * Update GQL code to limit result to block number & timespamp only * Remove unwanted code line * Remove unwanted code line * Implementing Minimum stake policy into strategy. * Update Typos * Update README.md Text * Fixing condition level bug to calculate Voting Power * Fixing condition level bug to calculate Voting Power * Fixing condition level bug to calculate Voting Power Co-authored-by: Daz-Mac <78415757+Daz-Mac@users.noreply.github.com> --- .../gatenet-total-staked/examples.json | 24 +++++++++++------- src/strategies/gatenet-total-staked/index.ts | 25 +++++++++++++------ 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/strategies/gatenet-total-staked/examples.json b/src/strategies/gatenet-total-staked/examples.json index 629aa3671..661603890 100644 --- a/src/strategies/gatenet-total-staked/examples.json +++ b/src/strategies/gatenet-total-staked/examples.json @@ -13,15 +13,21 @@ }, "network": "4", "addresses": [ - "0x8900cCBdC60fD97E3B7c8529A9987F8c0f8A1125", - "0xB868F9378ddbf023938C00A344e6430eeB3a6042", - "0x970DAECA395D1324C674bFFD35cA7e363153Ed1e", - "0x4946D49A2464263deF3cfa194572600343548c4c", - "0xb7cc944b93eA5FD6bBa02810c855B64a1c29eDf5", - "0xF2c6B24058779f740A84aC4a84FAC827b4affC6A", - "0xC48c8F74B4aeC9cC7669700CBfAF83fa7c2469e3", - "0xf61FD1558A7F540A11B8Da876Fce795dE983B8E1" + "0xDC70958F76A639922823A8990Cb115B1816E5Ca0", + "0x6646e8428B5029369392B15a6c2e4743bfBdb03a", + "0xCF4a5c2aA6d35F8B1A52E4b336D192b3dEaae416", + "0x3a61B9a71F9dc0182B1910EbB8315a12157Ff293", + "0xa7a7aCC9b9f3eB7136b3F4e33E95fD68bf28c134", + "0xE97D8f38746c2b6114e7AC7ae185750bDE2FF211", + "0x8b273e4042387789bcAeC10dD33D91E7fe9F4179", + "0xc100ADEC02c12fd0A205d589769851213dCc27dE", + "0x96A1003B7FF56a2Df974B6A7e9ddC586f4761f77", + "0x9BA85d16db13D25de2426d5eb42b55794B1efF22", + "0xb60A6e063C15D79afBE1E389e52b3b2f2796aF8B", + "0xbF33c13F3eBC9175ADcC1c4614c84f73288E9101", + "0x66F06B8C449CF2c8ef2D3274738d2185491C6e35", + "0xC48c8F74B4aeC9cC7669700CBfAF83fa7c2469e3" ], - "snapshot": 10537384 + "snapshot": 11464656 } ] diff --git a/src/strategies/gatenet-total-staked/index.ts b/src/strategies/gatenet-total-staked/index.ts index 09c89ce8e..6b2ceeda6 100644 --- a/src/strategies/gatenet-total-staked/index.ts +++ b/src/strategies/gatenet-total-staked/index.ts @@ -105,13 +105,24 @@ export async function strategy( (s) => s.sender.toLowerCase() === address.toLowerCase() ); - if (compoundWithdraws.length > 0 && compoundDeposits.length > 0) { - const rawTransactions = compoundDeposits - .concat(compoundWithdraws) - .concat(transactionsList.stakings) - .sort(function (a, b) { - return a.time - b.time; - }); + if (compoundDeposits.length > 0) { + let rawTransactions; + // Keeping split condition for the case of Only deposite transaction. + if (compoundWithdraws.length > 0) { + rawTransactions = compoundDeposits + .concat(compoundWithdraws) + .concat(transactionsList.stakings) + .sort(function (a, b) { + return a.time - b.time; + }); + } else { + rawTransactions = compoundDeposits + .concat(transactionsList.stakings) + .sort(function (a, b) { + return a.time - b.time; + }); + } + const transactions = rawTransactions .map((transaction) => { const type = getTransactionType(transaction); From b0673ade69c02a3ab1799264685d9c24cfc22772 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 1 Oct 2022 00:03:04 +0530 Subject: [PATCH 139/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.36 (#855) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index c4ee683dc..47a63d82a 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.35", + "@snapshot-labs/snapshot.js": "^0.4.36", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", "copyfiles": "^2.4.1", diff --git a/yarn.lock b/yarn.lock index e6c86bd04..2b877df5c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.35": - version "0.4.35" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.35.tgz#9137f40916f6c4054dee1bd18586dc2a0e9a1eb2" - integrity sha512-3AIw536Z7HgeM/7PIwqNKGPffiEL/c0VsYPT+18Z7wEHFgI/UMilhCYcHpZxbnE6AYhlPLowRSFtNwHjwvwRww== +"@snapshot-labs/snapshot.js@^0.4.36": + version "0.4.36" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.36.tgz#ffa8d4d9de2dc6d2f3cbdaf0096f8a7eea232a37" + integrity sha512-PzjFirSj8/3AoZmA+NUxozKFSP1h89R94RIX2ty+cLpY9fSR+bKL/iyvp4lHmvFVApBLxTq6XW8zE5tdSkyLLg== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From ca0defadefb3b1db43dd906da8f7ab5344e9835d Mon Sep 17 00:00:00 2001 From: Caranell Date: Sat, 1 Oct 2022 08:44:08 +0400 Subject: [PATCH 140/815] [nation3-votes-with-delegations] Fix minor errors (#856) * Fix strategy errors * Add handling for different-cased addresses * Use `getAddress` instead of `toLowerCase` Co-authored-by: Chaitanya --- .../examples.json | 11 +++++------ .../nation3-votes-with-delegations/index.ts | 18 +++++++++++------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/strategies/nation3-votes-with-delegations/examples.json b/src/strategies/nation3-votes-with-delegations/examples.json index 507976620..b90731a69 100644 --- a/src/strategies/nation3-votes-with-delegations/examples.json +++ b/src/strategies/nation3-votes-with-delegations/examples.json @@ -10,12 +10,11 @@ }, "network": "1", "addresses": [ - "0xE4BE9b821f84Ec062865372914c8392CA8F31464", - "0x05a4448597935c508e4ad0D2CF56d56beDb246Ce", - "0x69A5c0Db191697D11b0Ac5637c3445D38AF4b15b", - "0x443d40B2AA10cb01884A97281Dc8ac3cCb0eef2a", - "0x6412517845128C289e111Ad9dA26100f78e529d8" + "0x47d80912400ef8f8224531EBEB1ce8f2ACf4b75a", + "0x636d65212C815b93B8E5b069f7082169cec851b7", + "0x327b0c1Ecd110651dC9994b6764b695c9cdC29bA", + "0x460AF11e497dc273fC163414943C6fd95d17B1fd" ], - "snapshot": 15491432 + "snapshot": 15638762 } ] diff --git a/src/strategies/nation3-votes-with-delegations/index.ts b/src/strategies/nation3-votes-with-delegations/index.ts index 02653c59d..3412614df 100644 --- a/src/strategies/nation3-votes-with-delegations/index.ts +++ b/src/strategies/nation3-votes-with-delegations/index.ts @@ -1,6 +1,7 @@ import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; import { formatUnits } from '@ethersproject/units'; import { Multicaller } from '../../utils'; +import { getAddress } from '@ethersproject/address'; export const author = 'caranell'; export const version = '0.1.0'; @@ -22,12 +23,14 @@ export async function strategy( space, network, provider, - addresses, + addresses: string[], options, snapshot ): Promise> { const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const formattedAddresses = addresses.map((addr) => getAddress(addr)); + const erc721OwnerCaller = new Multicaller(network, provider, ownerAbi, { blockTag }); @@ -47,7 +50,7 @@ export async function strategy( erc721LastTokenIdCaller.call('lastTokenId', options.erc721, 'getNextId'); - addresses.forEach((address) => { + formattedAddresses.forEach((address) => { erc20BalanceCaller.call(address, options.erc20, 'balanceOf', [address]); }); @@ -76,17 +79,17 @@ export async function strategy( const erc721OwnersArr = Object.entries(erc721Owners); const delegatedTokens = erc721OwnersArr.filter( - ([id, address]) => address != erc721Signers[id] + ([id, address]) => address !== erc721Signers[id] ); const result = Object.fromEntries( - addresses.map((address) => { + formattedAddresses.map((address) => { const tokenDelegations = delegatedTokens.find( ([, addr]) => addr === address ); if (tokenDelegations?.length) { - const realOwners = erc721OwnersArr.find(([id]) => + const realOwners = erc721OwnersArr.filter(([id]) => tokenDelegations.includes(id) ); @@ -95,9 +98,10 @@ export async function strategy( } const ownerAddresses = realOwners.map(([, addr]) => addr); + const erc20Balance = ownerAddresses.reduce((sum, addr) => { - return sum + parseFloat(formatUnits(erc20Balances[addr], DECIMALS)); - }, 0); + return sum.add(erc20Balances[addr] || 0); + }, BigNumber.from(0)); return [address, parseFloat(formatUnits(erc20Balance, DECIMALS))]; } else { From 213c3badcea24a021430c43922e66400c066b9a3 Mon Sep 17 00:00:00 2001 From: Maxbrand99 Date: Sat, 1 Oct 2022 01:26:08 -0400 Subject: [PATCH 141/815] Cross Chain cyberkongz [cyberkongz-v3] (#852) * Cross Chain cyberkongz * Update index.ts * Update examples.json * Update index.ts * Update index.ts Co-authored-by: Chaitanya --- src/strategies/cyberkongz-v3/examples.json | 58 +++++++++++++++++ src/strategies/cyberkongz-v3/index.ts | 74 ++++++++++++++++++++++ src/strategies/index.ts | 2 + 3 files changed, 134 insertions(+) create mode 100644 src/strategies/cyberkongz-v3/examples.json create mode 100644 src/strategies/cyberkongz-v3/index.ts diff --git a/src/strategies/cyberkongz-v3/examples.json b/src/strategies/cyberkongz-v3/examples.json new file mode 100644 index 000000000..69b8ccac7 --- /dev/null +++ b/src/strategies/cyberkongz-v3/examples.json @@ -0,0 +1,58 @@ +[ + { + "name": "Multichain CyberKongz, CyberKongz VX and Banana holdings", + "strategy": { + "name": "cyberkongz-v3", + "params": { + "symbol": "KONGZ", + "chains": [ + { + "network": "1", + "registries": { + "0x57a204aa1042f6e66dd7730813f4024114d74f37": "OG", + "0x7ea3cca10668b8346aec0bf1844a49e995527c8b": "VX", + "0xe2311ae37502105b442bbef831e9b53c5d2e9b3b": "BANANA" + } + }, + { + "network": "137", + "registries": { + "0xbc91347e80886453f3f8bbd6d7ac07c122d87735": "BANANA", + "0x05df72d911e52ab122f7d9955728bc96a718782c": "VX" + } + } + ], + "skipList": [ + "0xb14b87790643d2dab44b06692d37dd95b4b30e56", + "0x9d59eba4deaee09466ba9d4073bf912bc72982b0", + "0x0f4676178b5c53ae0a655f1b19a96387e4b8b5f2", + "0xcfa9a297a406a48d1137172c18de04c944b47ba9", + "0x820f92c1b3ad8e962e6c6d9d7caf2a550aec46fb", + "0x9ffad2ff3a59d8579e3b0edc6c8f2f591c94dfab", + "0xe058d87fc1185e38ab68893136834715b30961e1", + "0xe2311ae37502105b442bbef831e9b53c5d2e9b3b", + "0x7a08865A3E7c291f3b794210Bc51D559B49DFd15", + "0xe6f45376f64e1f568bd1404c155e5ffd2f80f7ad", + "0x40ec5b33f54e0e8a33a975908c5ba1c14e5bbbdf", + "0x0000000000000000000000000000000000000000", + "0xD6a92755Ac5384867083Abd79aD007DE389b955e", + "0x000000000000000000000000000000000000dead", + "0x70C575588B98C1F46B1382c706AdAf398A874e3E", + "0xab8eee3493a55a7bd8126865fd662b7097928088" + ] + } + }, + "network": "1", + "addresses": [ + "0xf521Bb7437bEc77b0B15286dC3f49A87b9946773", + "0x721931508df2764fd4f70c53da646cb8aed16ace", + "0xa63571f2ce7cf4e9a566a1f248f5d0ad3ba78726", + "0x9279c4cfb0e85e2dff8825ce141f9794c7c7170a", + "0x6f35b0cfc58eb1e21eef8a439bbb0ce4c929d32a", + "0xe34bded2b256430a9be53cbf5cba3b6d866d55f3", + "0xb14b87790643d2dab44b06692d37dd95b4b30e56", + "0xd32f25Dfa932b8064A81B8254E7997CAeBc85F97" + ], + "snapshot": 15021651 + } +] diff --git a/src/strategies/cyberkongz-v3/index.ts b/src/strategies/cyberkongz-v3/index.ts new file mode 100644 index 000000000..1c39a28e2 --- /dev/null +++ b/src/strategies/cyberkongz-v3/index.ts @@ -0,0 +1,74 @@ +import { formatUnits } from '@ethersproject/units'; +import {getProvider, getSnapshots, multicall} from '../../utils'; + +export const author = 'maxbrand99'; +export const version = '1.0.0'; + +const bananaContract = '0xe2311ae37502105b442bbef831e9b53c5d2e9b3b'; + +const abi = [ + 'function balanceOf(address account) external view returns (uint256)', + 'function totalSupply() external view returns (uint256)' +]; + +export async function strategy(space, network, provider, addresses, options, snapshot) { + const allAddresses = {}; + const promises: any = []; + const blocks = await getSnapshots(network, snapshot, provider, options.chains.map((s) => s.network || network)); + const allCalls: any[] = []; + const chainCalls = {1: [], 137: []} + options.chains.forEach((chain) => { + if (chain.network == 1 || chain.network == 137) { + Object.keys(chain.registries).forEach((registry) => { + allAddresses[registry] = chain.registries[registry] + addresses.forEach((address: any) => { + chainCalls[chain.network].push([registry, 'balanceOf', [address]]); + allCalls.push([registry, 'balanceOf', [address]]); + }); + }); + } + }) + + Object.keys(chainCalls).forEach((chainID) => { + const blockTag = typeof blocks[chainID] === 'number' ? blocks[chainID] : 'latest'; + promises.push(multicall(chainID, getProvider(chainID), abi, chainCalls[chainID], {blockTag})); + }) + + const results = await Promise.all(promises); + + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const nanaCall = [[bananaContract, 'totalSupply', []]]; + let nanaSupply = await multicall(network, provider, abi, nanaCall, {blockTag}); + + + const response: any[] = [] + results.forEach((result) => { + result.forEach((value) => { + response.push(value) + }) + }) + + response.forEach((value: any, i: number) => { + const address = allCalls[i][2][0]; + if (allAddresses[allCalls[i][0]] == "BANANA" && options.skipList.find((add) => add === address)) { + nanaSupply -= value; + } + }); + + const merged = {}; + response.forEach((value: any, i: number) => { + const address = allCalls[i][2][0]; + if (options.skipList.find((add) => add === address)) { + return; + } + merged[address] = (merged[address] || 0) as number; + if (allAddresses[allCalls[i][0]] == "OG") + merged[address] += parseFloat(formatUnits((3 * value).toString(), 0)); + else if (allAddresses[allCalls[i][0]] == "VX") + merged[address] += parseFloat(formatUnits(value.toString(), 0)); + else if (allAddresses[allCalls[i][0]] == "BANANA") + merged[address] += parseFloat(formatUnits(Math.floor((15000 * value) / nanaSupply).toString(), 0)); + }); + + return merged; +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 453174d9f..258c68427 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -213,6 +213,7 @@ import * as lootCharacterGuilds from './loot-character-guilds'; import * as swapr from './swapr'; import * as cyberkongz from './cyberkongz'; import * as cyberkongzV2 from './cyberkongz-v2'; +import * as cyberkongzV3 from './cyberkongz-v3'; import * as compLikeVotesInclusive from './comp-like-votes-inclusive'; import * as mstable from './mstable'; import * as hashesVoting from './hashes-voting'; @@ -594,6 +595,7 @@ const strategies = { 'loot-character-guilds': lootCharacterGuilds, cyberkongz: cyberkongz, 'cyberkongz-v2': cyberkongzV2, + 'cyberkongz-v3': cyberkongzV3, 'comp-like-votes-inclusive': compLikeVotesInclusive, mstable, 'hashes-voting': hashesVoting, From 65bf02f243747c625bd219b73a9cf2f25db4f70f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 2 Oct 2022 22:35:14 +0530 Subject: [PATCH 142/815] Automated lint (#858) Co-authored-by: ChaituVR --- .../examples.json | 6 +- .../index.ts | 141 ++++++++++++------ .../aavegotchi-agip-37-wap-ghst/examples.json | 7 +- .../aavegotchi-agip-37-wap-ghst/index.ts | 81 +++++----- src/strategies/cyberkongz-v3/examples.json | 112 +++++++------- src/strategies/cyberkongz-v3/index.ts | 63 +++++--- .../erc20-tokens-per-uni/examples.json | 5 +- src/strategies/erc20-tokens-per-uni/index.ts | 17 ++- src/strategies/hedgey-multi/examples.json | 24 +-- 9 files changed, 271 insertions(+), 185 deletions(-) diff --git a/src/strategies/aavegotchi-agip-37-gltr-staked-lp/examples.json b/src/strategies/aavegotchi-agip-37-gltr-staked-lp/examples.json index 1839c52fd..8b8669b68 100644 --- a/src/strategies/aavegotchi-agip-37-gltr-staked-lp/examples.json +++ b/src/strategies/aavegotchi-agip-37-gltr-staked-lp/examples.json @@ -28,7 +28,11 @@ } }, "network": "137", - "addresses": ["0x26cf02F892B04aF4Cf350539CE2C77FCF79Ec172", "0x027Ffd3c119567e85998f4E6B9c3d83D5702660c", "0xc4cb6cb969e8b4e309ab98e4da51b77887afad96"], + "addresses": [ + "0x26cf02F892B04aF4Cf350539CE2C77FCF79Ec172", + "0x027Ffd3c119567e85998f4E6B9c3d83D5702660c", + "0xc4cb6cb969e8b4e309ab98e4da51b77887afad96" + ], "snapshot": 33423178 } ] diff --git a/src/strategies/aavegotchi-agip-37-gltr-staked-lp/index.ts b/src/strategies/aavegotchi-agip-37-gltr-staked-lp/index.ts index 4aa4955a8..24d60c732 100644 --- a/src/strategies/aavegotchi-agip-37-gltr-staked-lp/index.ts +++ b/src/strategies/aavegotchi-agip-37-gltr-staked-lp/index.ts @@ -7,7 +7,7 @@ const tokenAbi = [ 'function balanceOf(address account) view returns (uint256)', 'function totalSupply() view returns (uint256)', 'function allUserInfo(address _user) view returns (tuple(address lpToken, uint256 allocPoint, uint256 pending, uint256 userBalance, uint256 poolBalance)[] _info)', - 'function convertToAssets(uint256 shares) view returns (uint)', + 'function convertToAssets(uint256 shares) view returns (uint)' ]; export async function strategy( @@ -18,34 +18,45 @@ export async function strategy( options, snapshot ) { - options.ghstAddress = options.ghstAddress || '0x385Eeac5cB85A38A9a07A70c73e0a3271CfB54A7'; + options.ghstAddress = + options.ghstAddress || '0x385Eeac5cB85A38A9a07A70c73e0a3271CfB54A7'; - options.gltrStakingAddress = options.gltrStakingAddress || '0x1fE64677Ab1397e20A1211AFae2758570fEa1B8c'; - - options.amGhstAddress = options.amGhstAddress || '0x080b5BF8f360F624628E0fb961F4e67c9e3c7CF1'; + options.gltrStakingAddress = + options.gltrStakingAddress || '0x1fE64677Ab1397e20A1211AFae2758570fEa1B8c'; - options.wapGhstAddress = options.wapGhstAddress || '0x73958d46B7aA2bc94926d8a215Fa560A5CdCA3eA'; + options.amGhstAddress = + options.amGhstAddress || '0x080b5BF8f360F624628E0fb961F4e67c9e3c7CF1'; + + options.wapGhstAddress = + options.wapGhstAddress || '0x73958d46B7aA2bc94926d8a215Fa560A5CdCA3eA'; options.wapGhstPoolId = options.wapGhstPoolId || 0; - - options.ghstFudAddress = options.ghstFudAddress || '0xfec232cc6f0f3aeb2f81b2787a9bc9f6fc72ea5c'; + + options.ghstFudAddress = + options.ghstFudAddress || '0xfec232cc6f0f3aeb2f81b2787a9bc9f6fc72ea5c'; options.ghstFudPoolId = options.ghstFudPoolId || 1; - - options.ghstFomoAddress = options.ghstFomoAddress || '0x641ca8d96b01db1e14a5fba16bc1e5e508a45f2b'; + + options.ghstFomoAddress = + options.ghstFomoAddress || '0x641ca8d96b01db1e14a5fba16bc1e5e508a45f2b'; options.ghstFomoPoolId = options.ghstFomoPoolId || 2; - - options.ghstAlphaAddress = options.ghstAlphaAddress || '0xc765eca0ad3fd27779d36d18e32552bd7e26fd7b'; + + options.ghstAlphaAddress = + options.ghstAlphaAddress || '0xc765eca0ad3fd27779d36d18e32552bd7e26fd7b'; options.ghstAlphaPoolId = options.ghstAlphaPoolId || 3; - - options.ghstKekAddress = options.ghstKekAddress || '0xbfad162775ebfb9988db3f24ef28ca6bc2fb92f0'; + + options.ghstKekAddress = + options.ghstKekAddress || '0xbfad162775ebfb9988db3f24ef28ca6bc2fb92f0'; options.ghstKekPoolId = options.ghstKekPoolId || 4; - - options.ghstUsdcAddress = options.ghstUsdcAddress || '0x096c5ccb33cfc5732bcd1f3195c13dbefc4c82f4'; + + options.ghstUsdcAddress = + options.ghstUsdcAddress || '0x096c5ccb33cfc5732bcd1f3195c13dbefc4c82f4'; options.ghstUsdcPoolId = options.ghstUsdcPoolId || 5; - options.ghstWmaticAddress = options.ghstWmaticAddress || '0xf69e93771F11AECd8E554aA165C3Fe7fd811530c'; + options.ghstWmaticAddress = + options.ghstWmaticAddress || '0xf69e93771F11AECd8E554aA165C3Fe7fd811530c'; options.ghstWmaticPoolId = options.ghstWmaticPoolId || 6; - options.ghstGltrAddress = options.ghstGltrAddress || '0xb0E35478a389dD20050D66a67FB761678af99678'; + options.ghstGltrAddress = + options.ghstGltrAddress || '0xb0E35478a389dD20050D66a67FB761678af99678'; options.ghstGltrPoolId = options.ghstGltrPoolId || 7; const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; @@ -56,9 +67,9 @@ export async function strategy( [address] ]); - let slicedStakedQueries:any = [stakeQuery]; + let slicedStakedQueries: any = [stakeQuery]; if (stakeQuery.length > 1) { - let middle = stakeQuery.length/2; + const middle = stakeQuery.length / 2; slicedStakedQueries = [ stakeQuery.slice(0, middle), stakeQuery.slice(middle, stakeQuery.length) @@ -84,7 +95,7 @@ export async function strategy( [options.ghstAddress, 'balanceOf', [options.ghstUsdcAddress]], [options.ghstWmaticAddress, 'totalSupply', []], [options.ghstAddress, 'balanceOf', [options.ghstWmaticAddress]], - ...slicedStakedQueries[0], + ...slicedStakedQueries[0] ], { blockTag } ); @@ -94,9 +105,7 @@ export async function strategy( network, provider, tokenAbi, - [ - ...slicedStakedQueries[1] - ], + [...slicedStakedQueries[1]], { blockTag } ); @@ -107,33 +116,69 @@ export async function strategy( return balanceInUni / 1e18 / (totalSupply / 1e18); }; - let lpTokensStartIndex = 0; - let lpTokensPerUni = { - ghstFudLp: tokensPerUni(res[lpTokensStartIndex+1], res[lpTokensStartIndex]), - ghstFomoLp: tokensPerUni(res[lpTokensStartIndex+3], res[lpTokensStartIndex+2]), - ghstAlphaLp: tokensPerUni(res[lpTokensStartIndex+5], res[lpTokensStartIndex+4]), - ghstKekLp: tokensPerUni(res[lpTokensStartIndex+7], res[lpTokensStartIndex+6]), - ghstGltrLp: tokensPerUni(res[lpTokensStartIndex+9], res[lpTokensStartIndex+8]), - ghstUsdcLp: tokensPerUni(res[lpTokensStartIndex+11], res[lpTokensStartIndex+10]), - ghstWmaticLp: tokensPerUni(res[lpTokensStartIndex+13], res[lpTokensStartIndex+12]), + const lpTokensStartIndex = 0; + const lpTokensPerUni = { + ghstFudLp: tokensPerUni( + res[lpTokensStartIndex + 1], + res[lpTokensStartIndex] + ), + ghstFomoLp: tokensPerUni( + res[lpTokensStartIndex + 3], + res[lpTokensStartIndex + 2] + ), + ghstAlphaLp: tokensPerUni( + res[lpTokensStartIndex + 5], + res[lpTokensStartIndex + 4] + ), + ghstKekLp: tokensPerUni( + res[lpTokensStartIndex + 7], + res[lpTokensStartIndex + 6] + ), + ghstGltrLp: tokensPerUni( + res[lpTokensStartIndex + 9], + res[lpTokensStartIndex + 8] + ), + ghstUsdcLp: tokensPerUni( + res[lpTokensStartIndex + 11], + res[lpTokensStartIndex + 10] + ), + ghstWmaticLp: tokensPerUni( + res[lpTokensStartIndex + 13], + res[lpTokensStartIndex + 12] + ) }; - let entries = {}; + const entries = {}; for (let addressIndex = 0; addressIndex < addresses.length; addressIndex++) { - let i = addressIndex + 14; - let tokens = { + const i = addressIndex + 14; + const tokens = { staked: { - ghstFudLp: Number(res[i]._info[options.ghstFudPoolId].userBalance.toString()) / 1e18, - ghstFomoLp: Number(res[i]._info[options.ghstFomoPoolId].userBalance.toString()) / 1e18, - ghstAlphaLp: Number(res[i]._info[options.ghstAlphaPoolId].userBalance.toString()) / 1e18, - ghstKekLp: Number(res[i]._info[options.ghstKekPoolId].userBalance.toString()) / 1e18, - ghstGltrLp: Number(res[i]._info[options.ghstGltrPoolId].userBalance.toString()) / 1e18, - ghstUsdcLp: Number(res[i]._info[options.ghstUsdcPoolId].userBalance.toString()) / 1e18, - ghstWmaticLp: Number(res[i]._info[options.ghstWmaticPoolId].userBalance.toString()) / 1e18 - }, + ghstFudLp: + Number(res[i]._info[options.ghstFudPoolId].userBalance.toString()) / + 1e18, + ghstFomoLp: + Number(res[i]._info[options.ghstFomoPoolId].userBalance.toString()) / + 1e18, + ghstAlphaLp: + Number(res[i]._info[options.ghstAlphaPoolId].userBalance.toString()) / + 1e18, + ghstKekLp: + Number(res[i]._info[options.ghstKekPoolId].userBalance.toString()) / + 1e18, + ghstGltrLp: + Number(res[i]._info[options.ghstGltrPoolId].userBalance.toString()) / + 1e18, + ghstUsdcLp: + Number(res[i]._info[options.ghstUsdcPoolId].userBalance.toString()) / + 1e18, + ghstWmaticLp: + Number( + res[i]._info[options.ghstWmaticPoolId].userBalance.toString() + ) / 1e18 + } }; - let votingPower = { + const votingPower = { staked: { ghstFudLp: tokens.staked.ghstFudLp * lpTokensPerUni.ghstFudLp, ghstFomoLp: tokens.staked.ghstFomoLp * lpTokensPerUni.ghstFomoLp, @@ -147,11 +192,11 @@ export async function strategy( let totalVotingPower = 0; for (let k = 0; k < Object.keys(votingPower.staked).length; k++) { - let key = Object.keys(votingPower.staked)[k]; + const key = Object.keys(votingPower.staked)[k]; totalVotingPower += votingPower.staked[key]; } - let address = addresses[addressIndex]; + const address = addresses[addressIndex]; // let loggedString = "TOKENS SUMMARY FOR " + address; // loggedString += "\nSTAKED TOKENS\n" + JSON.stringify(tokens.staked); @@ -163,4 +208,4 @@ export async function strategy( } return entries; -} \ No newline at end of file +} diff --git a/src/strategies/aavegotchi-agip-37-wap-ghst/examples.json b/src/strategies/aavegotchi-agip-37-wap-ghst/examples.json index 227096e42..370c41a79 100644 --- a/src/strategies/aavegotchi-agip-37-wap-ghst/examples.json +++ b/src/strategies/aavegotchi-agip-37-wap-ghst/examples.json @@ -28,7 +28,12 @@ } }, "network": "137", - "addresses": ["0x26cf02F892B04aF4Cf350539CE2C77FCF79Ec172", "0x027Ffd3c119567e85998f4E6B9c3d83D5702660c", "0xDEA88c9FE09106b58cA7c026c82383c56eE1E041", "0x3a564B24EffA1Cb7Dc836AD094BaD28e69FCa371"], + "addresses": [ + "0x26cf02F892B04aF4Cf350539CE2C77FCF79Ec172", + "0x027Ffd3c119567e85998f4E6B9c3d83D5702660c", + "0xDEA88c9FE09106b58cA7c026c82383c56eE1E041", + "0x3a564B24EffA1Cb7Dc836AD094BaD28e69FCa371" + ], "snapshot": 33423178 } ] diff --git a/src/strategies/aavegotchi-agip-37-wap-ghst/index.ts b/src/strategies/aavegotchi-agip-37-wap-ghst/index.ts index e8f7ea665..0a60b1179 100644 --- a/src/strategies/aavegotchi-agip-37-wap-ghst/index.ts +++ b/src/strategies/aavegotchi-agip-37-wap-ghst/index.ts @@ -7,7 +7,7 @@ const tokenAbi = [ 'function balanceOf(address account) view returns (uint256)', 'function totalSupply() view returns (uint256)', 'function allUserInfo(address _user) view returns (tuple(address lpToken, uint256 allocPoint, uint256 pending, uint256 userBalance, uint256 poolBalance)[] _info)', - 'function convertToAssets(uint256 shares) view returns (uint)', + 'function convertToAssets(uint256 shares) view returns (uint)' ]; export async function strategy( @@ -18,13 +18,17 @@ export async function strategy( options, snapshot ) { - options.ghstAddress = options.ghstAddress || '0x385Eeac5cB85A38A9a07A70c73e0a3271CfB54A7'; + options.ghstAddress = + options.ghstAddress || '0x385Eeac5cB85A38A9a07A70c73e0a3271CfB54A7'; - options.gltrStakingAddress = options.gltrStakingAddress || '0x1fE64677Ab1397e20A1211AFae2758570fEa1B8c'; - - options.amGhstAddress = options.amGhstAddress || '0x080b5BF8f360F624628E0fb961F4e67c9e3c7CF1'; + options.gltrStakingAddress = + options.gltrStakingAddress || '0x1fE64677Ab1397e20A1211AFae2758570fEa1B8c'; - options.wapGhstAddress = options.wapGhstAddress || '0x73958d46B7aA2bc94926d8a215Fa560A5CdCA3eA'; + options.amGhstAddress = + options.amGhstAddress || '0x080b5BF8f360F624628E0fb961F4e67c9e3c7CF1'; + + options.wapGhstAddress = + options.wapGhstAddress || '0x73958d46B7aA2bc94926d8a215Fa560A5CdCA3eA'; options.wapGhstPoolId = options.wapGhstPoolId || 0; const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; @@ -41,9 +45,9 @@ export async function strategy( [address] ]); - let slicedWalletQueries:any = [walletQuery]; + let slicedWalletQueries: any = [walletQuery]; if (walletQuery.length > 1) { - let middle = walletQuery.length/2; + const middle = walletQuery.length / 2; slicedWalletQueries = [ walletQuery.slice(0, middle), walletQuery.slice(middle, walletQuery.length) @@ -54,29 +58,25 @@ export async function strategy( network, provider, tokenAbi, - [ - ...slicedWalletQueries[0], - ], + [...slicedWalletQueries[0]], { blockTag } ); if (slicedWalletQueries.length > 1) { - let res2 = await multicall( + const res2 = await multicall( network, provider, tokenAbi, - [ - ...slicedWalletQueries[1], - ], + [...slicedWalletQueries[1]], { blockTag } ); res = [...res, ...res2]; } - let slicedStakeQueries:any = [walletQuery]; + let slicedStakeQueries: any = [walletQuery]; if (stakeQuery.length > 1) { - let middle = stakeQuery.length/2; + const middle = stakeQuery.length / 2; slicedStakeQueries = [ stakeQuery.slice(0, middle), stakeQuery.slice(middle, stakeQuery.length) @@ -87,69 +87,68 @@ export async function strategy( network, provider, tokenAbi, - [ - ...slicedStakeQueries[0], - ], + [...slicedStakeQueries[0]], { blockTag } ); res = [...res, ...res3]; if (slicedStakeQueries.length > 1) { - let res4 = await multicall( + const res4 = await multicall( network, provider, tokenAbi, - [ - ...slicedStakeQueries[1], - ], + [...slicedStakeQueries[1]], { blockTag } ); res = [...res, ...res4]; } - let unitWapGHST_res = await multicall( + const unitWapGHST_res = await multicall( network, provider, tokenAbi, - [ - [options.wapGhstAddress, 'convertToAssets', ["1000000000000000000"]] - ], + [[options.wapGhstAddress, 'convertToAssets', ['1000000000000000000']]], { blockTag } ); - let wapGHST_ghstMulitiplier = Number(unitWapGHST_res[0].toString()) / 1e18; + const wapGHST_ghstMulitiplier = Number(unitWapGHST_res[0].toString()) / 1e18; - let entries = {}; + const entries = {}; for (let addressIndex = 0; addressIndex < addresses.length; addressIndex++) { - let tokens = { + const tokens = { staked: { - wapGhst: Number(res[addressIndex + addresses.length]._info[options.wapGhstPoolId].userBalance.toString()) / 1e18, + wapGhst: + Number( + res[addressIndex + addresses.length]._info[ + options.wapGhstPoolId + ].userBalance.toString() + ) / 1e18 }, unstaked: { - wapGhst: Number(res[addressIndex].toString()) / 1e18, + wapGhst: Number(res[addressIndex].toString()) / 1e18 } }; - let votingPower = { + const votingPower = { staked: { - wapGhst: tokens.staked.wapGhst * wapGHST_ghstMulitiplier, + wapGhst: tokens.staked.wapGhst * wapGHST_ghstMulitiplier }, unstaked: { - wapGhst: tokens.unstaked.wapGhst * wapGHST_ghstMulitiplier, - }, + wapGhst: tokens.unstaked.wapGhst * wapGHST_ghstMulitiplier + } }; let totalVotingPower = 0; for (let k = 0; k < Object.keys(votingPower.unstaked).length; k++) { - let key = Object.keys(votingPower.unstaked)[k]; + const key = Object.keys(votingPower.unstaked)[k]; totalVotingPower += votingPower.unstaked[key]; } for (let k = 0; k < Object.keys(votingPower.staked).length; k++) { - let key = Object.keys(votingPower.staked)[k]; + const key = Object.keys(votingPower.staked)[k]; totalVotingPower += votingPower.staked[key]; } - let address = addresses[addressIndex]; + const address = addresses[addressIndex]; // let loggedString = "TOKENS SUMMARY FOR " + address; // loggedString += "\nSTAKED TOKENS\n" + JSON.stringify(tokens.staked); @@ -163,4 +162,4 @@ export async function strategy( } return entries; -} \ No newline at end of file +} diff --git a/src/strategies/cyberkongz-v3/examples.json b/src/strategies/cyberkongz-v3/examples.json index 69b8ccac7..608d40280 100644 --- a/src/strategies/cyberkongz-v3/examples.json +++ b/src/strategies/cyberkongz-v3/examples.json @@ -1,58 +1,58 @@ [ - { - "name": "Multichain CyberKongz, CyberKongz VX and Banana holdings", - "strategy": { - "name": "cyberkongz-v3", - "params": { - "symbol": "KONGZ", - "chains": [ - { - "network": "1", - "registries": { - "0x57a204aa1042f6e66dd7730813f4024114d74f37": "OG", - "0x7ea3cca10668b8346aec0bf1844a49e995527c8b": "VX", - "0xe2311ae37502105b442bbef831e9b53c5d2e9b3b": "BANANA" - } - }, - { - "network": "137", - "registries": { - "0xbc91347e80886453f3f8bbd6d7ac07c122d87735": "BANANA", - "0x05df72d911e52ab122f7d9955728bc96a718782c": "VX" - } - } - ], - "skipList": [ - "0xb14b87790643d2dab44b06692d37dd95b4b30e56", - "0x9d59eba4deaee09466ba9d4073bf912bc72982b0", - "0x0f4676178b5c53ae0a655f1b19a96387e4b8b5f2", - "0xcfa9a297a406a48d1137172c18de04c944b47ba9", - "0x820f92c1b3ad8e962e6c6d9d7caf2a550aec46fb", - "0x9ffad2ff3a59d8579e3b0edc6c8f2f591c94dfab", - "0xe058d87fc1185e38ab68893136834715b30961e1", - "0xe2311ae37502105b442bbef831e9b53c5d2e9b3b", - "0x7a08865A3E7c291f3b794210Bc51D559B49DFd15", - "0xe6f45376f64e1f568bd1404c155e5ffd2f80f7ad", - "0x40ec5b33f54e0e8a33a975908c5ba1c14e5bbbdf", - "0x0000000000000000000000000000000000000000", - "0xD6a92755Ac5384867083Abd79aD007DE389b955e", - "0x000000000000000000000000000000000000dead", - "0x70C575588B98C1F46B1382c706AdAf398A874e3E", - "0xab8eee3493a55a7bd8126865fd662b7097928088" - ] - } - }, - "network": "1", - "addresses": [ - "0xf521Bb7437bEc77b0B15286dC3f49A87b9946773", - "0x721931508df2764fd4f70c53da646cb8aed16ace", - "0xa63571f2ce7cf4e9a566a1f248f5d0ad3ba78726", - "0x9279c4cfb0e85e2dff8825ce141f9794c7c7170a", - "0x6f35b0cfc58eb1e21eef8a439bbb0ce4c929d32a", - "0xe34bded2b256430a9be53cbf5cba3b6d866d55f3", - "0xb14b87790643d2dab44b06692d37dd95b4b30e56", - "0xd32f25Dfa932b8064A81B8254E7997CAeBc85F97" - ], - "snapshot": 15021651 - } + { + "name": "Multichain CyberKongz, CyberKongz VX and Banana holdings", + "strategy": { + "name": "cyberkongz-v3", + "params": { + "symbol": "KONGZ", + "chains": [ + { + "network": "1", + "registries": { + "0x57a204aa1042f6e66dd7730813f4024114d74f37": "OG", + "0x7ea3cca10668b8346aec0bf1844a49e995527c8b": "VX", + "0xe2311ae37502105b442bbef831e9b53c5d2e9b3b": "BANANA" + } + }, + { + "network": "137", + "registries": { + "0xbc91347e80886453f3f8bbd6d7ac07c122d87735": "BANANA", + "0x05df72d911e52ab122f7d9955728bc96a718782c": "VX" + } + } + ], + "skipList": [ + "0xb14b87790643d2dab44b06692d37dd95b4b30e56", + "0x9d59eba4deaee09466ba9d4073bf912bc72982b0", + "0x0f4676178b5c53ae0a655f1b19a96387e4b8b5f2", + "0xcfa9a297a406a48d1137172c18de04c944b47ba9", + "0x820f92c1b3ad8e962e6c6d9d7caf2a550aec46fb", + "0x9ffad2ff3a59d8579e3b0edc6c8f2f591c94dfab", + "0xe058d87fc1185e38ab68893136834715b30961e1", + "0xe2311ae37502105b442bbef831e9b53c5d2e9b3b", + "0x7a08865A3E7c291f3b794210Bc51D559B49DFd15", + "0xe6f45376f64e1f568bd1404c155e5ffd2f80f7ad", + "0x40ec5b33f54e0e8a33a975908c5ba1c14e5bbbdf", + "0x0000000000000000000000000000000000000000", + "0xD6a92755Ac5384867083Abd79aD007DE389b955e", + "0x000000000000000000000000000000000000dead", + "0x70C575588B98C1F46B1382c706AdAf398A874e3E", + "0xab8eee3493a55a7bd8126865fd662b7097928088" + ] + } + }, + "network": "1", + "addresses": [ + "0xf521Bb7437bEc77b0B15286dC3f49A87b9946773", + "0x721931508df2764fd4f70c53da646cb8aed16ace", + "0xa63571f2ce7cf4e9a566a1f248f5d0ad3ba78726", + "0x9279c4cfb0e85e2dff8825ce141f9794c7c7170a", + "0x6f35b0cfc58eb1e21eef8a439bbb0ce4c929d32a", + "0xe34bded2b256430a9be53cbf5cba3b6d866d55f3", + "0xb14b87790643d2dab44b06692d37dd95b4b30e56", + "0xd32f25Dfa932b8064A81B8254E7997CAeBc85F97" + ], + "snapshot": 15021651 + } ] diff --git a/src/strategies/cyberkongz-v3/index.ts b/src/strategies/cyberkongz-v3/index.ts index 1c39a28e2..5788b4381 100644 --- a/src/strategies/cyberkongz-v3/index.ts +++ b/src/strategies/cyberkongz-v3/index.ts @@ -1,5 +1,5 @@ import { formatUnits } from '@ethersproject/units'; -import {getProvider, getSnapshots, multicall} from '../../utils'; +import { getProvider, getSnapshots, multicall } from '../../utils'; export const author = 'maxbrand99'; export const version = '1.0.0'; @@ -11,46 +11,67 @@ const abi = [ 'function totalSupply() external view returns (uint256)' ]; -export async function strategy(space, network, provider, addresses, options, snapshot) { +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { const allAddresses = {}; const promises: any = []; - const blocks = await getSnapshots(network, snapshot, provider, options.chains.map((s) => s.network || network)); + const blocks = await getSnapshots( + network, + snapshot, + provider, + options.chains.map((s) => s.network || network) + ); const allCalls: any[] = []; - const chainCalls = {1: [], 137: []} + const chainCalls = { 1: [], 137: [] }; options.chains.forEach((chain) => { if (chain.network == 1 || chain.network == 137) { Object.keys(chain.registries).forEach((registry) => { - allAddresses[registry] = chain.registries[registry] + allAddresses[registry] = chain.registries[registry]; addresses.forEach((address: any) => { chainCalls[chain.network].push([registry, 'balanceOf', [address]]); allCalls.push([registry, 'balanceOf', [address]]); }); }); } - }) + }); Object.keys(chainCalls).forEach((chainID) => { - const blockTag = typeof blocks[chainID] === 'number' ? blocks[chainID] : 'latest'; - promises.push(multicall(chainID, getProvider(chainID), abi, chainCalls[chainID], {blockTag})); - }) + const blockTag = + typeof blocks[chainID] === 'number' ? blocks[chainID] : 'latest'; + promises.push( + multicall(chainID, getProvider(chainID), abi, chainCalls[chainID], { + blockTag + }) + ); + }); const results = await Promise.all(promises); const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; const nanaCall = [[bananaContract, 'totalSupply', []]]; - let nanaSupply = await multicall(network, provider, abi, nanaCall, {blockTag}); - + let nanaSupply = await multicall(network, provider, abi, nanaCall, { + blockTag + }); - const response: any[] = [] + const response: any[] = []; results.forEach((result) => { result.forEach((value) => { - response.push(value) - }) - }) + response.push(value); + }); + }); response.forEach((value: any, i: number) => { const address = allCalls[i][2][0]; - if (allAddresses[allCalls[i][0]] == "BANANA" && options.skipList.find((add) => add === address)) { + if ( + allAddresses[allCalls[i][0]] == 'BANANA' && + options.skipList.find((add) => add === address) + ) { nanaSupply -= value; } }); @@ -62,12 +83,14 @@ export async function strategy(space, network, provider, addresses, options, sna return; } merged[address] = (merged[address] || 0) as number; - if (allAddresses[allCalls[i][0]] == "OG") + if (allAddresses[allCalls[i][0]] == 'OG') merged[address] += parseFloat(formatUnits((3 * value).toString(), 0)); - else if (allAddresses[allCalls[i][0]] == "VX") + else if (allAddresses[allCalls[i][0]] == 'VX') merged[address] += parseFloat(formatUnits(value.toString(), 0)); - else if (allAddresses[allCalls[i][0]] == "BANANA") - merged[address] += parseFloat(formatUnits(Math.floor((15000 * value) / nanaSupply).toString(), 0)); + else if (allAddresses[allCalls[i][0]] == 'BANANA') + merged[address] += parseFloat( + formatUnits(Math.floor((15000 * value) / nanaSupply).toString(), 0) + ); }); return merged; diff --git a/src/strategies/erc20-tokens-per-uni/examples.json b/src/strategies/erc20-tokens-per-uni/examples.json index eb95a76eb..a2e8c6a3a 100644 --- a/src/strategies/erc20-tokens-per-uni/examples.json +++ b/src/strategies/erc20-tokens-per-uni/examples.json @@ -9,7 +9,10 @@ } }, "network": "137", - "addresses": ["0x26cf02F892B04aF4Cf350539CE2C77FCF79Ec172", "0x027Ffd3c119567e85998f4E6B9c3d83D5702660c"], + "addresses": [ + "0x26cf02F892B04aF4Cf350539CE2C77FCF79Ec172", + "0x027Ffd3c119567e85998f4E6B9c3d83D5702660c" + ], "snapshot": 33423178 } ] diff --git a/src/strategies/erc20-tokens-per-uni/index.ts b/src/strategies/erc20-tokens-per-uni/index.ts index 8de513b0b..4ed233988 100644 --- a/src/strategies/erc20-tokens-per-uni/index.ts +++ b/src/strategies/erc20-tokens-per-uni/index.ts @@ -5,7 +5,7 @@ export const version = '0.0.1'; const tokenAbi = [ 'function balanceOf(address account) view returns (uint256)', - 'function totalSupply() view returns (uint256)', + 'function totalSupply() view returns (uint256)' ]; export async function strategy( @@ -31,7 +31,7 @@ export async function strategy( [ ...poolTokensBalanceQueries, [options.poolTokenAddress, 'totalSupply', []], - [options.erc20TokenAddress, 'balanceOf', [options.poolTokenAddress]], + [options.erc20TokenAddress, 'balanceOf', [options.poolTokenAddress]] ], { blockTag } ); @@ -40,12 +40,17 @@ export async function strategy( return balanceInUni / 1e18 / (totalSupply / 1e18); }; - let entries = {}; + const entries = {}; for (let addressIndex = 0; addressIndex < addresses.length; addressIndex++) { - let address = addresses[addressIndex]; - let result = res[addressIndex] * tokensPerUni(res[poolTokensBalanceQueries.length + 1], res[poolTokensBalanceQueries.length]); + const address = addresses[addressIndex]; + const result = + res[addressIndex] * + tokensPerUni( + res[poolTokensBalanceQueries.length + 1], + res[poolTokensBalanceQueries.length] + ); entries[address] = Number(result.toString()) / 1e18; } return entries; -} \ No newline at end of file +} diff --git a/src/strategies/hedgey-multi/examples.json b/src/strategies/hedgey-multi/examples.json index 3ae14084c..fca088df0 100644 --- a/src/strategies/hedgey-multi/examples.json +++ b/src/strategies/hedgey-multi/examples.json @@ -4,18 +4,20 @@ "strategy": { "name": "hedgey-multi", "params": { - "contracts": [{ - "address": "0x4bc8ea84bdc3ebb01d495e5d1605d4f082aeb5d7", - "token": "0xccDE1F2B71573a865d3896eb019C41Bf4BF92e65", - "decimal": 18, - "contractType": "NFT", - "lockedTokenMultiplier": 2, - "lockedTokenMonthlyMultiplier": { - "default": 1, - "1": 1.5, - "2": 2 + "contracts": [ + { + "address": "0x4bc8ea84bdc3ebb01d495e5d1605d4f082aeb5d7", + "token": "0xccDE1F2B71573a865d3896eb019C41Bf4BF92e65", + "decimal": 18, + "contractType": "NFT", + "lockedTokenMultiplier": 2, + "lockedTokenMonthlyMultiplier": { + "default": 1, + "1": 1.5, + "2": 2 + } } - }] + ] } }, "network": "4", From 47c59b9466fdc6eb1fae57ee02046b2d047acbf1 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Tue, 4 Oct 2022 23:57:12 +0530 Subject: [PATCH 143/815] Update strategy checklist (#862) --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5b83fe856..fba3c21b0 100755 --- a/README.md +++ b/README.md @@ -50,7 +50,8 @@ Here is a simple checklist to look when reviewing a PR for a new strategy: - There should be a maximum of 5 requests, a request can use "fetch" a "subgraphRequest" or "multicall". - The strategy should not send a request for each voters, this doesn't scale. - The strategy PR should not add any dependency in Snapshot.js. -- The score returned by the strategy should use the same casing for address than on the input, or should return checksummed addresses. +- The score returned by the strategy should use the same casing for address than on the input, or should return checksum addresses. +- Make sure voting power of one address does not depend on other addresses. #### Example From 2ebf880c69a629677a19252fa03363945eb3a34b Mon Sep 17 00:00:00 2001 From: system32 <23362597+Raecaug@users.noreply.github.com> Date: Wed, 5 Oct 2022 04:24:38 -0400 Subject: [PATCH 144/815] Adding new strategy lrc-nft-dao-search [lrc-nft-dao-search] (#863) * Delete index.ts * Updated index.ts Added 'lrc-nft-dao-search' strategy to index * Adding new strategy 'lrc-nft-dao-search' Adds new strategy, which is an extended functionality version of karamorf's. --- src/strategies/index.ts | 2 + src/strategies/lrc-nft-dao-search/README.md | 28 +++++ .../lrc-nft-dao-search/examples.json | 21 ++++ src/strategies/lrc-nft-dao-search/index.ts | 117 ++++++++++++++++++ 4 files changed, 168 insertions(+) create mode 100644 src/strategies/lrc-nft-dao-search/README.md create mode 100644 src/strategies/lrc-nft-dao-search/examples.json create mode 100644 src/strategies/lrc-nft-dao-search/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 258c68427..861ea0255 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -347,6 +347,7 @@ import * as dopamine from './dopamine'; import * as lrcL2SubgraphBalanceOf from './lrc-l2-subgraph-balance-of'; import * as lrcL2NftBalanceOf from './lrc-l2-nft-balance-of'; import * as lrcLPSubgraphBalanceOf from './lrc-lp-subgraph-balance-of'; +import * as lrcNFTDAOSearch from './lrc-nft-dao-search'; import * as erc3525VestingVoucher from './erc3525-vesting-voucher'; import * as rariFuse from './rari-fuse'; import * as selfswap from './selfswap'; @@ -727,6 +728,7 @@ const strategies = { 'lrc-l2-subgraph-balance-of': lrcL2SubgraphBalanceOf, 'lrc-l2-nft-balance-of': lrcL2NftBalanceOf, 'lrc-lp-subgraph-balance-of': lrcLPSubgraphBalanceOf, + 'lrc-nft-dao-search': lrcNFTDAOSearch, 'rari-fuse': rariFuse, 'bancor-pool-token-underlying-balance': bancorPoolTokenUnderlyingBalance, selfswap, diff --git a/src/strategies/lrc-nft-dao-search/README.md b/src/strategies/lrc-nft-dao-search/README.md new file mode 100644 index 000000000..f7112f189 --- /dev/null +++ b/src/strategies/lrc-nft-dao-search/README.md @@ -0,0 +1,28 @@ +# lrc-nft-dao-search + +This is an improvement of karamorf's lrc-l2-nft-balance of Snapshot voting strategy by raecaug(system32). +The extended functionality allows space owners to(alongside all of lrc-l2-nft-balance-of's functionality) specify individual nft ids within a token contract with the nft_ids option. +This option is not needed, and if excluded the query will search for all nfts minted under that token contract address. +No other behavior has been changed. + + +Strategy to read account balances for NFTs (72 or 1155) from LoopringV2 subgraph. Assumes we only want tokens minted by a specific account id. + +Here is an example of parameters: + +```json +{ + "graph": "https://api.thegraph.com/subgraphs/name/juanmardefago/loopring36", + "minter_account_id": "74447", + "tokens": ["token (Collection contract address) to include"], + "nft_ids": ["nftIDs, unique to every nft, even those under the same token contract"], + "blacklisted_account_ids": ["38482"], + "blacklisted_nft_ids": ["... nft id's to exclude ..."] +} +``` + +Use explorer.loopring.io to look up addresses and find account id's. + +Account id `38482` maps to `0x000000000000000000000000000000000000dead` and is used for burning tokens. + +to note: either the `minter_account_id` or the `tokens` parameter must be provided for this query to work. You do not need to specify both, just one of them. diff --git a/src/strategies/lrc-nft-dao-search/examples.json b/src/strategies/lrc-nft-dao-search/examples.json new file mode 100644 index 000000000..f885ecdb8 --- /dev/null +++ b/src/strategies/lrc-nft-dao-search/examples.json @@ -0,0 +1,21 @@ +[ + { + "name": "LoopringDAOSearch", + "strategy": { + "name": "lrc-nft-dao-search", + "params": { + "graph": "https://api.thegraph.com/subgraphs/name/juanmardefago/loopring36", + "minter_account_id": "157510", + "tokens": ["0xb6d91e38e4ac53c9f8952c6c6b1c7aee66c8b6f0"], + "nft_ids": ["0x1e31297dd163ca44a5fad74de4ffbebf1ba11d46e1b448b0e105449d827fb264"], + "blacklisted_account_ids": [""], + "blacklisted_nft_ids": [""] + } + }, + "network": "1", + "addresses": [ + "0xeE253D3fCC30787a1E58570E355010d0b9C33B60" + ], + "snapshot": 15677787 + } +] diff --git a/src/strategies/lrc-nft-dao-search/index.ts b/src/strategies/lrc-nft-dao-search/index.ts new file mode 100644 index 000000000..56f99d865 --- /dev/null +++ b/src/strategies/lrc-nft-dao-search/index.ts @@ -0,0 +1,117 @@ +// Original code by Karamorf, upgraded by Raecaug(system32) +// Allows querys of Loopring L2 accounts & balances by specifying a nft minter, token contract address(and optionally specifying individual ids to white/blacklist) + +import { subgraphRequest } from '../../utils'; +export const author = 'raecaug'; +export const version = '0.1.2'; + +const LIMIT = 1000; + +function makeQuery( + snapshot, // This is an Ethereum block # or defaults to 'latest' + minter, // This is referred to as account # or account id on the Loopring L2 block explorer + tokens, // NFT collection contract addresses, also referred to as 'token address' + skip, // Used to skip response lines in requests + blacklisted_account_ids, // Ditto properties of 'minter' + blacklisted_nft_ids, // This is the nft id, which is unique for every nft ever minted, allows distinction between nfts in a collection at the chain level + nft_ids // Ditto properties of blacklisted version +) { + const query: any = { // Query constructor, builds request with params from snapshot space settings + accountNFTSlots: { + __args: { + where: { + nft_: { + id_not_in: blacklisted_nft_ids, // Excluding blacklisted nft ids + nftID_in: nft_ids // Including uniquely specified nft ids + }, + account_not_in: blacklisted_account_ids // Excluding blacklisted account ids + }, + first: LIMIT, + skip: skip + }, + account: { address: true }, + balance: true + } + }; + + if (minter && minter !== '') { //Check to ensure minter id is specified and not blank + query.accountNFTSlots.__args.where.nft_.minter = minter; + } + + if (tokens && tokens.length > 0) { //Check to ensure at least 1 token to search for is specified + query.accountNFTSlots.__args.where.nft_.token_in = tokens; + } + + if (snapshot !== 'latest') { // If the snapshot date is manually specified, overwrite the 'latest' block, strict inequality check operand used + query.accountNFTSlots.__args = { + ...query.accountNFTSlots.__args, + block: { + number: snapshot + } + }; + } + + return query; +} + +export async function strategy( // *****Logical execution begins here; args passed in by Snapshot settings***** + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + let blacklisted_account_ids = options.blacklisted_account_ids; + let blacklisted_nft_ids = options.blacklisted_nft_ids; + + let nft_ids = options.nft_ids; // Unique NFT ids, distinguishable from 1155 token contracts + + const balances = {}; // Initialization + let skip = 0; + let response_size = 0; + + if (!blacklisted_account_ids || blacklisted_account_ids.length === 0) { // If no blacklisted accts specified, set to empty + blacklisted_account_ids = ['']; + } + + if (!blacklisted_nft_ids || blacklisted_nft_ids.length === 0) { // If no unique nft_ids specified, set to empty + blacklisted_nft_ids = ['']; + } + + if (!nft_ids || nft_ids.length === 0) { // If no unique nft_ids specified, set to empty + nft_ids = ['']; + } + + + + do { // Transmit query and await results + const response = await subgraphRequest( // Constructs response variable from subgraph query function + options.graph, // Parameter 1, options specified + makeQuery( // Query constructor(defined above) called, results are the second parameter + snapshot, + options.minter_account_id, + options.tokens, + skip, + blacklisted_account_ids, + blacklisted_nft_ids, + nft_ids + ) + ); + + response.accountNFTSlots.forEach((slot) => { // Checking against each accountNFTSlot element + if (!balances.hasOwnProperty(slot.account.address)) { + balances[slot.account.address] = 0; // If nothing returned, set this accounts balance to 0 + } + balances[slot.account.address] += parseInt(slot.balance); // Otherwise, a bigint is returned, parse it and store in balances array + }); + response_size = response.accountNFTSlots.length; // Value is set to 0 on loop entry, updated here, will break loop for anything other than 1000 + skip += response_size; + } while (response_size == LIMIT); + + const scores = Object.fromEntries( + addresses.map((address) => [address, balances[address.toLowerCase()]]) // Map returned addresses and balances as scores array + ); + + return scores; // Returns addresses and balances to Snapshot +} From 1eaccff6a99481de70a855ae9a67c108251be850 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 5 Oct 2022 15:41:16 +0530 Subject: [PATCH 145/815] Automated lint (#865) Co-authored-by: ChaituVR --- .../lrc-nft-dao-search/examples.json | 8 +-- src/strategies/lrc-nft-dao-search/index.ts | 51 +++++++++++-------- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/src/strategies/lrc-nft-dao-search/examples.json b/src/strategies/lrc-nft-dao-search/examples.json index f885ecdb8..a944db039 100644 --- a/src/strategies/lrc-nft-dao-search/examples.json +++ b/src/strategies/lrc-nft-dao-search/examples.json @@ -7,15 +7,15 @@ "graph": "https://api.thegraph.com/subgraphs/name/juanmardefago/loopring36", "minter_account_id": "157510", "tokens": ["0xb6d91e38e4ac53c9f8952c6c6b1c7aee66c8b6f0"], - "nft_ids": ["0x1e31297dd163ca44a5fad74de4ffbebf1ba11d46e1b448b0e105449d827fb264"], + "nft_ids": [ + "0x1e31297dd163ca44a5fad74de4ffbebf1ba11d46e1b448b0e105449d827fb264" + ], "blacklisted_account_ids": [""], "blacklisted_nft_ids": [""] } }, "network": "1", - "addresses": [ - "0xeE253D3fCC30787a1E58570E355010d0b9C33B60" - ], + "addresses": ["0xeE253D3fCC30787a1E58570E355010d0b9C33B60"], "snapshot": 15677787 } ] diff --git a/src/strategies/lrc-nft-dao-search/index.ts b/src/strategies/lrc-nft-dao-search/index.ts index 56f99d865..a18cba427 100644 --- a/src/strategies/lrc-nft-dao-search/index.ts +++ b/src/strategies/lrc-nft-dao-search/index.ts @@ -9,20 +9,21 @@ const LIMIT = 1000; function makeQuery( snapshot, // This is an Ethereum block # or defaults to 'latest' - minter, // This is referred to as account # or account id on the Loopring L2 block explorer - tokens, // NFT collection contract addresses, also referred to as 'token address' - skip, // Used to skip response lines in requests + minter, // This is referred to as account # or account id on the Loopring L2 block explorer + tokens, // NFT collection contract addresses, also referred to as 'token address' + skip, // Used to skip response lines in requests blacklisted_account_ids, // Ditto properties of 'minter' - blacklisted_nft_ids, // This is the nft id, which is unique for every nft ever minted, allows distinction between nfts in a collection at the chain level - nft_ids // Ditto properties of blacklisted version + blacklisted_nft_ids, // This is the nft id, which is unique for every nft ever minted, allows distinction between nfts in a collection at the chain level + nft_ids // Ditto properties of blacklisted version ) { - const query: any = { // Query constructor, builds request with params from snapshot space settings + const query: any = { + // Query constructor, builds request with params from snapshot space settings accountNFTSlots: { __args: { where: { nft_: { id_not_in: blacklisted_nft_ids, // Excluding blacklisted nft ids - nftID_in: nft_ids // Including uniquely specified nft ids + nftID_in: nft_ids // Including uniquely specified nft ids }, account_not_in: blacklisted_account_ids // Excluding blacklisted account ids }, @@ -34,15 +35,18 @@ function makeQuery( } }; - if (minter && minter !== '') { //Check to ensure minter id is specified and not blank + if (minter && minter !== '') { + //Check to ensure minter id is specified and not blank query.accountNFTSlots.__args.where.nft_.minter = minter; } - if (tokens && tokens.length > 0) { //Check to ensure at least 1 token to search for is specified + if (tokens && tokens.length > 0) { + //Check to ensure at least 1 token to search for is specified query.accountNFTSlots.__args.where.nft_.token_in = tokens; } - if (snapshot !== 'latest') { // If the snapshot date is manually specified, overwrite the 'latest' block, strict inequality check operand used + if (snapshot !== 'latest') { + // If the snapshot date is manually specified, overwrite the 'latest' block, strict inequality check operand used query.accountNFTSlots.__args = { ...query.accountNFTSlots.__args, block: { @@ -67,28 +71,32 @@ export async function strategy( // *****Logical execution begins here; args pass let nft_ids = options.nft_ids; // Unique NFT ids, distinguishable from 1155 token contracts - const balances = {}; // Initialization + const balances = {}; // Initialization let skip = 0; let response_size = 0; - if (!blacklisted_account_ids || blacklisted_account_ids.length === 0) { // If no blacklisted accts specified, set to empty + if (!blacklisted_account_ids || blacklisted_account_ids.length === 0) { + // If no blacklisted accts specified, set to empty blacklisted_account_ids = ['']; } - if (!blacklisted_nft_ids || blacklisted_nft_ids.length === 0) { // If no unique nft_ids specified, set to empty + if (!blacklisted_nft_ids || blacklisted_nft_ids.length === 0) { + // If no unique nft_ids specified, set to empty blacklisted_nft_ids = ['']; } - if (!nft_ids || nft_ids.length === 0) { // If no unique nft_ids specified, set to empty + if (!nft_ids || nft_ids.length === 0) { + // If no unique nft_ids specified, set to empty nft_ids = ['']; } - - - do { // Transmit query and await results - const response = await subgraphRequest( // Constructs response variable from subgraph query function + do { + // Transmit query and await results + const response = await subgraphRequest( + // Constructs response variable from subgraph query function options.graph, // Parameter 1, options specified - makeQuery( // Query constructor(defined above) called, results are the second parameter + makeQuery( + // Query constructor(defined above) called, results are the second parameter snapshot, options.minter_account_id, options.tokens, @@ -99,14 +107,15 @@ export async function strategy( // *****Logical execution begins here; args pass ) ); - response.accountNFTSlots.forEach((slot) => { // Checking against each accountNFTSlot element + response.accountNFTSlots.forEach((slot) => { + // Checking against each accountNFTSlot element if (!balances.hasOwnProperty(slot.account.address)) { balances[slot.account.address] = 0; // If nothing returned, set this accounts balance to 0 } balances[slot.account.address] += parseInt(slot.balance); // Otherwise, a bigint is returned, parse it and store in balances array }); response_size = response.accountNFTSlots.length; // Value is set to 0 on loop entry, updated here, will break loop for anything other than 1000 - skip += response_size; + skip += response_size; } while (response_size == LIMIT); const scores = Object.fromEntries( From 9cbb02710eb49d991e759887ba05b4b2c9e0e49a Mon Sep 17 00:00:00 2001 From: Caranell Date: Wed, 5 Oct 2022 20:17:44 +0400 Subject: [PATCH 146/815] [nation3-votes-with-delegations] Rework delegated votes calculation (#868) * Fix strategy errors * Add handling for different-cased addresses * Use `getAddress` instead of `toLowerCase` * Fix incorrect delegatedTokens counting Co-authored-by: Chaitanya --- .../nation3-votes-with-delegations/index.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/strategies/nation3-votes-with-delegations/index.ts b/src/strategies/nation3-votes-with-delegations/index.ts index 3412614df..05de39e7e 100644 --- a/src/strategies/nation3-votes-with-delegations/index.ts +++ b/src/strategies/nation3-votes-with-delegations/index.ts @@ -78,15 +78,18 @@ export async function strategy( ]); const erc721OwnersArr = Object.entries(erc721Owners); - const delegatedTokens = erc721OwnersArr.filter( - ([id, address]) => address !== erc721Signers[id] + const erc721SignersArr = Object.entries(erc721Signers); + + const delegatedTokens = erc721SignersArr.filter( + ([id, address]) => address !== erc721Owners[id] ); const result = Object.fromEntries( formattedAddresses.map((address) => { - const tokenDelegations = delegatedTokens.find( - ([, addr]) => addr === address - ); + // Getting ids of all tokens delegated to this address + const tokenDelegations = delegatedTokens + .filter(([, addr]) => addr === address) + .map(([id]) => id); if (tokenDelegations?.length) { const realOwners = erc721OwnersArr.filter(([id]) => From 41ad1cc450ebc33aba21a26d143125c65632eaf0 Mon Sep 17 00:00:00 2001 From: Icculus Her Emissary <108549099+IcculusHerEmissary@users.noreply.github.com> Date: Wed, 5 Oct 2022 14:06:19 -0400 Subject: [PATCH 147/815] Add new strategy wagdie-subgraph [wagdie-subgraph] (#864) * add wagdie snapshot * update author --- src/strategies/index.ts | 2 + src/strategies/wagdie-subgraph/README.md | 25 +++++++++ src/strategies/wagdie-subgraph/examples.json | 18 +++++++ src/strategies/wagdie-subgraph/index.ts | 53 ++++++++++++++++++++ 4 files changed, 98 insertions(+) create mode 100644 src/strategies/wagdie-subgraph/README.md create mode 100644 src/strategies/wagdie-subgraph/examples.json create mode 100644 src/strategies/wagdie-subgraph/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 861ea0255..de83f06ba 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -355,6 +355,7 @@ import * as xrookBalanceOfUnderlyingWeighted from './xrook-balance-of-underlying import * as bancorPoolTokenUnderlyingBalance from './bancor-pool-token-underlying-balance'; import * as orbsNetworkDelegation from './orbs-network-delegation'; import * as balanceOfSubgraph from './balance-of-subgraph'; +import * as wagdieSubgraph from './wagdie-subgraph'; import * as erc3525FlexibleVoucher from './erc3525-flexible-voucher'; import * as erc721PairWeights from './erc721-pair-weights'; import * as harmonyStaking from './harmony-staking'; @@ -736,6 +737,7 @@ const strategies = { 'xrook-balance-of-underlying-weighted': xrookBalanceOfUnderlyingWeighted, 'orbs-network-delegation': orbsNetworkDelegation, 'balance-of-subgraph': balanceOfSubgraph, + 'wagdie-subgraph': wagdieSubgraph, 'erc721-pair-weights': erc721PairWeights, 'harmony-staking': harmonyStaking, 'echelon-cached-erc1155-decay': echelonCachedErc1155Decay, diff --git a/src/strategies/wagdie-subgraph/README.md b/src/strategies/wagdie-subgraph/README.md new file mode 100644 index 000000000..cd7f69eec --- /dev/null +++ b/src/strategies/wagdie-subgraph/README.md @@ -0,0 +1,25 @@ +# WAGDIE Balance from Subgraph +### Modified from balance-of-subgraph + +Calculates users balance of users WAGDIE in wallet and staked in the Forsaken Lands. + +``` +accounts{ + id + ownedWAGDIE +} +``` + + +## Example + +The space config will look like this: + +```JSON +{ + // subgraphURL for the request + "subGraphURL": "https://api.thegraph.com/subgraphs/name/wagdie/wagdieworld-mainnet", + // scoreMultiplier can be used to increase users' scores by a certain magnitude + "scoreMultiplier": 1, +} +``` diff --git a/src/strategies/wagdie-subgraph/examples.json b/src/strategies/wagdie-subgraph/examples.json new file mode 100644 index 000000000..46816cf84 --- /dev/null +++ b/src/strategies/wagdie-subgraph/examples.json @@ -0,0 +1,18 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "wagdie-subgraph", + "params": { + "subGraphURL": "https://api.thegraph.com/subgraphs/name/wagdie/wagdieworld-mainnet" + } + }, + "network": "1", + "addresses": [ + "0x004689958ae25378331aeff1793145b3f38d6ad0", + "0x0165726095c46a107ad1d81059800aacec861391", + "0x0000000000a880cdfda22a458f37694e899ed0aa" + ], + "snapshot": 15678972 + } +] diff --git a/src/strategies/wagdie-subgraph/index.ts b/src/strategies/wagdie-subgraph/index.ts new file mode 100644 index 000000000..e6ff9858f --- /dev/null +++ b/src/strategies/wagdie-subgraph/index.ts @@ -0,0 +1,53 @@ +import { getAddress } from '@ethersproject/address'; +import { subgraphRequest } from '../../utils'; + +const SUBGRAPH_URL = { + '1': 'https://api.thegraph.com/subgraphs/name/wagdie/wagdieworld-mainnet' +}; + +export const author = 'IcculusHerEmissary'; +export const version = '0.1.0'; + +export async function strategy( + _space, + network, + _provider, + addresses, + options, + snapshot +) { + const params = { + accounts: { + __args: { + where: { + id_in: addresses.map((address) => address.toLowerCase()), + ownedWAGDIE_gt: 0 + } + }, + id: true, + ownedWAGDIE: true + } + }; + if (snapshot !== 'latest') { + // @ts-ignore + params.accounts.__args.block = { number: snapshot }; + } + const result = await subgraphRequest( + options.subGraphURL ? options.subGraphURL : SUBGRAPH_URL[network], + params + ); + const score = {}; + if (result && result.accounts) { + result.accounts.forEach((account) => { + const accountAddress = getAddress(account.id); + let accountscore = Number(account.ownedWAGDIE); + + if (options.scoreMultiplier) { + accountscore = accountscore * options.scoreMultiplier; + } + if (!score[accountAddress]) score[accountAddress] = 0; + score[accountAddress] = score[accountAddress] + accountscore; + }); + } + return score || {}; +} From 6c7b43fcba88a7c578f85be383d67f203ce50a5a Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Thu, 6 Oct 2022 17:20:33 +0530 Subject: [PATCH 148/815] [validation] validation strategy (#866) * [ticket-mulitple-validity] ticket strategy with mulitple validity * [validation] validation strategy * update * Update src/strategies/validation/index.ts * Update src/strategies/validation/examples.json * Update src/strategies/validation/README.md * Rename to validationThreshold --- src/strategies/index.ts | 2 + src/strategies/ticket-validity/README.md | 15 ++++- src/strategies/validation/README.md | 32 ++++++++++ src/strategies/validation/examples.json | 45 ++++++++++++++ src/strategies/validation/index.ts | 79 ++++++++++++++++++++++++ 5 files changed, 170 insertions(+), 3 deletions(-) create mode 100644 src/strategies/validation/README.md create mode 100644 src/strategies/validation/examples.json create mode 100644 src/strategies/validation/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index de83f06ba..c31194f0d 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -90,6 +90,7 @@ import * as delegation from './delegation'; import * as ticket from './ticket'; import * as work from './work'; import * as ticketValidity from './ticket-validity'; +import * as validation from './validation'; import * as opium from './opium'; import * as ocean from './ocean-marketplace'; import * as ocean_v4 from './ocean-marketplace-v4'; @@ -490,6 +491,7 @@ const strategies = { ticket, work, 'ticket-validity': ticketValidity, + validation, opium, 'ocean-marketplace': ocean, 'ocean-marketplace-v4': ocean_v4, diff --git a/src/strategies/ticket-validity/README.md b/src/strategies/ticket-validity/README.md index 94510acaf..85bfa94a3 100644 --- a/src/strategies/ticket-validity/README.md +++ b/src/strategies/ticket-validity/README.md @@ -2,12 +2,21 @@ Weight 1 score for any address that holds greater than 0 tokens. +Parameters: + +| Parameter | Description | Default value | +| :--- | :--- | :--- | +| `min` | Minimum voting power | 0 | +| `address` | Token address to check | | +| `symbol` | Token symbol | optional | + ## Examples ```JSON { - "strategies": [ - ["ticket-validity"] - ] + { + "address": "0x6b175474e89094c44da98b954eedeac495271d0f", + "symbol": "DAI" + } } ``` diff --git a/src/strategies/validation/README.md b/src/strategies/validation/README.md new file mode 100644 index 000000000..6408779ff --- /dev/null +++ b/src/strategies/validation/README.md @@ -0,0 +1,32 @@ +# validation strategy + +Checks validity of users to vote with validationStrategies passed and if user is not valid it will return 0 as score. If user is valid it will return the voting power of the strategies passed into votingStrategies. + +Parameters: + +| Parameter | Description | Default value | +| ------------- | ------------------------------------------ | ------------- | +| `symbol` | Token symbol | optional | +| `validationStrategies` | List of strategies to check validation (Max 3) | | +| `votingStrategies` | List of strategies to return voting power (Max 3)| | +| `validationThreshold` | Minimum voting power in a strategy | 1 | + +Example to return 1 voting power if user hold any USDC: + +```json +{ + "symbol": "UNI", + "validationStrategies": [{ + "name": "erc20-balance-of", + "params": { + "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "decimals": 6 + } + }], + "validationThreshold": 1, + "votingStrategies": [{ + "name": "ticket", + "params": {} + }] +} +``` diff --git a/src/strategies/validation/examples.json b/src/strategies/validation/examples.json new file mode 100644 index 000000000..3c6e34b91 --- /dev/null +++ b/src/strategies/validation/examples.json @@ -0,0 +1,45 @@ +[ + { + "name": "Validation strategy", + "strategy": { + "name": "validation", + "params": { + "symbol": "UNI", + "validationStrategies": [ + { + "name": "erc20-balance-of", + "params": { + "address": "0x6b175474e89094c44da98b954eedeac495271d0f", + "decimals": 18 + } + }, + { + "name": "erc20-balance-of", + "params": { + "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "decimals": 6 + } + } + ], + "validationThreshold": 1, + "votingStrategies": [ + { + "name": "ticket", + "params": {} + } + ] + } + }, + "network": "1", + "addresses": [ + "0xa478c2975ab1ea89e8196811f51a7b7ade33eb11", + "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", + "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", + "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", + "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e", + "0x1d5E65a087eBc3d03a294412E46CE5D6882969f4", + "0xbcca60bb61934080951369a648fb03df4f96263c" + ], + "snapshot": 11437846 + } +] diff --git a/src/strategies/validation/index.ts b/src/strategies/validation/index.ts new file mode 100644 index 000000000..2cce2323a --- /dev/null +++ b/src/strategies/validation/index.ts @@ -0,0 +1,79 @@ +import { getAddress } from '@ethersproject/address'; +import strategies from '..'; + +export const author = 'snapshot-labs'; +export const version = '0.1.0'; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const { + validationStrategies = [], + votingStrategies = [], + validationThreshold = 1 + } = options; + // Limit validationStrategies to 3 strategies + if (validationStrategies.length === 0 || votingStrategies.length === 0) { + throw new Error('No validation strategies provided.'); + } + if (validationStrategies.length > 3 || votingStrategies.length > 3) { + throw new Error('Too many strategies provided.'); + } + + const promises: any = []; + for (const strategy of validationStrategies) { + promises.push( + strategies[strategy.name].strategy( + space, + network, + provider, + addresses, + strategy.params, + snapshot + ) + ); + } + + const results = await Promise.all(promises); + let validatedAddresses: string[] = []; + results.forEach((result) => { + for (const address in result) { + if (result[address] >= validationThreshold) { + validatedAddresses.push(getAddress(address)); + } + } + }); + validatedAddresses = [...new Set(validatedAddresses)]; + + const scores = {}; + if (validatedAddresses.length > 0) { + const promises: any = []; + for (const strategy of votingStrategies) { + promises.push( + strategies[strategy.name].strategy( + space, + network, + provider, + validatedAddresses, + strategy.params, + snapshot + ) + ); + } + + const results = await Promise.all(promises); + results.forEach((result) => { + for (const address in result) { + if (!scores[address]) scores[address] = 0; + scores[address] += result[address]; + } + }); + } + + return scores; +} From cbce8e5690948258495bb60063b7f338f0cdb64f Mon Sep 17 00:00:00 2001 From: Icculus Her Emissary <108549099+IcculusHerEmissary@users.noreply.github.com> Date: Thu, 6 Oct 2022 13:46:03 -0400 Subject: [PATCH 149/815] Updated wagdie-subgraph strategy [wagdie-subgraph] (#870) * add wagdie snapshot * update author * allow location location based votes * update readme * switch to character query, add location filter * cleanup --- src/strategies/wagdie-subgraph/README.md | 7 +- src/strategies/wagdie-subgraph/examples.json | 15 ++-- src/strategies/wagdie-subgraph/index.ts | 73 ++++++++++++++------ 3 files changed, 66 insertions(+), 29 deletions(-) diff --git a/src/strategies/wagdie-subgraph/README.md b/src/strategies/wagdie-subgraph/README.md index cd7f69eec..b8552f6f4 100644 --- a/src/strategies/wagdie-subgraph/README.md +++ b/src/strategies/wagdie-subgraph/README.md @@ -4,9 +4,10 @@ Calculates users balance of users WAGDIE in wallet and staked in the Forsaken Lands. ``` -accounts{ +characters{ id - ownedWAGDIE + owner {id} + location {id} } ``` @@ -21,5 +22,7 @@ The space config will look like this: "subGraphURL": "https://api.thegraph.com/subgraphs/name/wagdie/wagdieworld-mainnet", // scoreMultiplier can be used to increase users' scores by a certain magnitude "scoreMultiplier": 1, + // Array of location IDs to limit votes to specific locations. Can be set to ["all"] to include all locations. + "location": ["1", "2"] } ``` diff --git a/src/strategies/wagdie-subgraph/examples.json b/src/strategies/wagdie-subgraph/examples.json index 46816cf84..3459d9c68 100644 --- a/src/strategies/wagdie-subgraph/examples.json +++ b/src/strategies/wagdie-subgraph/examples.json @@ -4,15 +4,20 @@ "strategy": { "name": "wagdie-subgraph", "params": { - "subGraphURL": "https://api.thegraph.com/subgraphs/name/wagdie/wagdieworld-mainnet" + "subGraphURL": "https://api.thegraph.com/subgraphs/name/wagdie/wagdieworld-mainnet", + "scoreMultiplier": 1, + "location": [ + "all" + ] } }, "network": "1", "addresses": [ - "0x004689958ae25378331aeff1793145b3f38d6ad0", - "0x0165726095c46a107ad1d81059800aacec861391", - "0x0000000000a880cdfda22a458f37694e899ed0aa" + "0xca8307d015aa664a186ad67da19ac6fc4b6c0198", + "0x326937d5f4ad932db9d814ee7d852bc77b9d2e0d", + "0x4F0EceDCd73dA0315134741d9D3830B08fE32e95", + "0xf36fc687c16f3021635b848a7d7450f5217240da" ], - "snapshot": 15678972 + "snapshot": 15690081 } ] diff --git a/src/strategies/wagdie-subgraph/index.ts b/src/strategies/wagdie-subgraph/index.ts index e6ff9858f..a07a4d989 100644 --- a/src/strategies/wagdie-subgraph/index.ts +++ b/src/strategies/wagdie-subgraph/index.ts @@ -16,38 +16,67 @@ export async function strategy( options, snapshot ) { + // initialize scores + const scores = {}; + for (const address of addresses) { + scores[getAddress(address)] = 0; + } + + // If graph doesn't exist return + if (!SUBGRAPH_URL[network]) { + return scores; + } + const params = { - accounts: { + characters: { __args: { where: { - id_in: addresses.map((address) => address.toLowerCase()), - ownedWAGDIE_gt: 0 - } + owner_in: addresses.map((address) => address.toLowerCase()), + id_gt: '', + burned: false + }, + orderBy: 'id', + orderDirection: 'asc', + first: 1000 }, id: true, - ownedWAGDIE: true + owner: { + id: true + }, + location: { + id: true + }, } }; + if (snapshot !== 'latest') { // @ts-ignore - params.accounts.__args.block = { number: snapshot }; + params.characters.__args.block = { number: snapshot }; } - const result = await subgraphRequest( - options.subGraphURL ? options.subGraphURL : SUBGRAPH_URL[network], - params - ); - const score = {}; - if (result && result.accounts) { - result.accounts.forEach((account) => { - const accountAddress = getAddress(account.id); - let accountscore = Number(account.ownedWAGDIE); - - if (options.scoreMultiplier) { - accountscore = accountscore * options.scoreMultiplier; + + let hasNext = true; + while (hasNext) { + const result = await subgraphRequest( + SUBGRAPH_URL[network], + params + ); + + const characters = result && result.characters ? result.characters : []; + const latest = characters[characters.length - 1]; + console.log(options.location) + + for (const character of characters) { + const userAddress = getAddress(character.owner.id); + const charId = character?.location?.id + if (options.location.includes("all") || options.location.includes(charId)) { + scores[userAddress] = (scores[userAddress] ?? 0) + + options.scoreMultiplier; } - if (!score[accountAddress]) score[accountAddress] = 0; - score[accountAddress] = score[accountAddress] + accountscore; - }); + } + + hasNext = characters.length === params.characters.__args.first; + params.characters.__args.where.id_gt = latest ? latest.id : ''; } - return score || {}; + + return scores || {}; } From ffa5162e8d2746ab879e9e9648aab5649576adb6 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Fri, 7 Oct 2022 11:13:27 +0530 Subject: [PATCH 150/815] Addresses in example should be minimum 5 and maximum 20 --- test/strategy.test.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/strategy.test.ts b/test/strategy.test.ts index f950ecee7..7ec841eea 100644 --- a/test/strategy.test.ts +++ b/test/strategy.test.ts @@ -54,6 +54,11 @@ describe.each(examples)( expect(example.strategy.name).toBe(strategy); }); + it('Addresses in example should be minimum 5 and maximum 20', () => { + expect(example.addresses.length).toBeGreaterThanOrEqual(5); + expect(example.addresses.length).toBeLessThanOrEqual(20); + }); + it('Strategy should run without any errors', async () => { const getScoresStart = performance.now(); scores = await callGetScores(example); From 42ec0660bcf5a41480e6283b0587367a34280eae Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 9 Oct 2022 17:06:44 +0530 Subject: [PATCH 151/815] Automated lint (#872) Co-authored-by: ChaituVR --- src/strategies/wagdie-subgraph/examples.json | 4 +--- src/strategies/wagdie-subgraph/index.ts | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/strategies/wagdie-subgraph/examples.json b/src/strategies/wagdie-subgraph/examples.json index 3459d9c68..a25028987 100644 --- a/src/strategies/wagdie-subgraph/examples.json +++ b/src/strategies/wagdie-subgraph/examples.json @@ -6,9 +6,7 @@ "params": { "subGraphURL": "https://api.thegraph.com/subgraphs/name/wagdie/wagdieworld-mainnet", "scoreMultiplier": 1, - "location": [ - "all" - ] + "location": ["all"] } }, "network": "1", diff --git a/src/strategies/wagdie-subgraph/index.ts b/src/strategies/wagdie-subgraph/index.ts index a07a4d989..250c1bbe3 100644 --- a/src/strategies/wagdie-subgraph/index.ts +++ b/src/strategies/wagdie-subgraph/index.ts @@ -45,7 +45,7 @@ export async function strategy( }, location: { id: true - }, + } } }; @@ -56,21 +56,21 @@ export async function strategy( let hasNext = true; while (hasNext) { - const result = await subgraphRequest( - SUBGRAPH_URL[network], - params - ); + const result = await subgraphRequest(SUBGRAPH_URL[network], params); const characters = result && result.characters ? result.characters : []; const latest = characters[characters.length - 1]; - console.log(options.location) + console.log(options.location); for (const character of characters) { const userAddress = getAddress(character.owner.id); - const charId = character?.location?.id - if (options.location.includes("all") || options.location.includes(charId)) { - scores[userAddress] = (scores[userAddress] ?? 0) + - options.scoreMultiplier; + const charId = character?.location?.id; + if ( + options.location.includes('all') || + options.location.includes(charId) + ) { + scores[userAddress] = + (scores[userAddress] ?? 0) + options.scoreMultiplier; } } From ac9bfe4f3e622cc10d346f7dc93576230a6ec825 Mon Sep 17 00:00:00 2001 From: Fabien Date: Mon, 10 Oct 2022 16:46:03 +0700 Subject: [PATCH 152/815] Update examples.json --- src/strategies/balancer/examples.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategies/balancer/examples.json b/src/strategies/balancer/examples.json index 875146ddb..6d7c78f02 100644 --- a/src/strategies/balancer/examples.json +++ b/src/strategies/balancer/examples.json @@ -5,7 +5,7 @@ "name": "balancer", "params": { "address": "0xba100000625a3754423978a60c9317c58a424e3D", - "symbol": "BAL BPT V1+V2", + "symbol": "BAL (in Balancer)", "decimals": 18 } }, From a69319fa5e2d8b9011bd2c09d8f9303cbd9b7200 Mon Sep 17 00:00:00 2001 From: Tiago Silva <66181828+tiagofilipenunes@users.noreply.github.com> Date: Mon, 10 Oct 2022 19:25:42 +0100 Subject: [PATCH 153/815] Adding Bancor 3 Standard Rewards Strategy (#874) This strategy 1. Gets the latest Standard Rewards program for a token by getting latestProgramId for the underlyingToken. 2. Calculates the underlying value of the LP tokens in that Standard Rewards Program for each provider. --- .../examples.json | 26 +++++++ .../index.ts | 70 +++++++++++++++++++ src/strategies/index.ts | 4 +- 3 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 src/strategies/bancor-standard-rewards-underlying-balance/examples.json create mode 100644 src/strategies/bancor-standard-rewards-underlying-balance/index.ts diff --git a/src/strategies/bancor-standard-rewards-underlying-balance/examples.json b/src/strategies/bancor-standard-rewards-underlying-balance/examples.json new file mode 100644 index 000000000..14e07792e --- /dev/null +++ b/src/strategies/bancor-standard-rewards-underlying-balance/examples.json @@ -0,0 +1,26 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "bancor-standard-rewards-underlying-balance", + "params": { + "symbol": "bnCROWN", + "decimals": 18, + "underlyingTokenAddress": "0x444d6088B0F625f8C20192623B3C43001135E0fa", + "bancorNetworkInfoAddress": "0x8E303D296851B320e6a697bAcB979d13c9D6E760", + "bancorStandardRewardsAddress": "0xb0B958398ABB0b5DB4ce4d7598Fb868f5A00f372" + } + }, + "network": "1", + "addresses": [ + "0x671e4d58F407BE00fCC383732C020A7Ac1AFde73", + "0xA2C12dBe82f19eF06850d4693F2b2D5724b8eA3E", + "0x57577a7981c74f01cd919776228DBC416A683999", + "0xc19417805208ff8cf0293a5795f3c3d8bd68d9d4", + "0xe67da97f7a14a38ad6d3e7e5784fecbf7160b643", + "0x307b361717d720834d27002e4b08d3a4307877ee", + "0xeb54669ac46b44d6a29eedda0daf7d9a8c4f7386" + ], + "snapshot": 15718324 + } +] diff --git a/src/strategies/bancor-standard-rewards-underlying-balance/index.ts b/src/strategies/bancor-standard-rewards-underlying-balance/index.ts new file mode 100644 index 000000000..75db1873e --- /dev/null +++ b/src/strategies/bancor-standard-rewards-underlying-balance/index.ts @@ -0,0 +1,70 @@ +import { formatUnits } from '@ethersproject/units'; +import { BigNumberish } from '@ethersproject/bignumber'; +import { call } from '../../utils'; +import { Multicaller } from '../../utils'; + +export const author = 'tiagofilipenunes'; +export const version = '0.1.0'; + +const bancorNetworkInfoABI = [ + 'function poolTokenToUnderlying(address pool, uint256 poolTokenAmount) external view returns (uint256)' +]; + +const standardRewardsABI = [ + 'function providerStake(address provider, uint256 id) external view returns (uint256)', + 'function latestProgramId(address pool) external view returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + + // Get last provider Program ID + const latestProgramId = await call( + provider, + standardRewardsABI, + [ + options.bancorStandardRewardsAddress, + 'latestProgramId', + [options.underlyingTokenAddress] + ], + { blockTag } + ); + + // Get each provider's stake in the standard rewards contract + const multi = new Multicaller(network, provider, standardRewardsABI, { blockTag }); + addresses.forEach((address) => + multi.call(address, options.bancorStandardRewardsAddress, 'providerStake', [address, latestProgramId.toString()]) + ); + const scores: Record = await multi.execute(); + + + // Get the Underlying Value of the Pool Token * 10**(decimals) to convert from wei + const poolTokenDecimalScaling = (10 ** options.decimals).toString(); + const underlyingValue = await call( + provider, + bancorNetworkInfoABI, + [ + options.bancorNetworkInfoAddress, + 'poolTokenToUnderlying', + [options.underlyingTokenAddress, poolTokenDecimalScaling] + ], + { blockTag } + ).then((res) => parseFloat(formatUnits(res, 2*options.decimals))); + + // Update the providers' stakes in the standard rewards contract to their converted underlying value + return Object.fromEntries( + Object.entries(scores).map((res: any) => [ + res[0], + res[1] * underlyingValue + ]) + ); + +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index c31194f0d..71f5a3568 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -379,6 +379,7 @@ import * as nation3VotesWIthDelegations from './nation3-votes-with-delegations'; import * as aavegotchiAgip37WapGhst from './aavegotchi-agip-37-wap-ghst'; import * as aavegotchiAgip37GltrStakedLp from './aavegotchi-agip-37-gltr-staked-lp'; import * as erc20TokensPerUni from './erc20-tokens-per-uni'; +import * as bancorStandardRewardsUnderlyingBalance from './bancor-standard-rewards-underlying-balance'; const strategies = { 'forta-shares': fortaShares, @@ -761,7 +762,8 @@ const strategies = { 'nation3-votes-with-delegations': nation3VotesWIthDelegations, 'aavegotchi-agip-37-wap-ghst': aavegotchiAgip37WapGhst, 'aavegotchi-agip-37-gltr-staked-lp': aavegotchiAgip37GltrStakedLp, - 'erc20-tokens-per-uni': erc20TokensPerUni + 'erc20-tokens-per-uni': erc20TokensPerUni, + 'bancor-standard-rewards-underlying-balance': bancorStandardRewardsUnderlyingBalance }; Object.keys(strategies).forEach(function (strategyName) { From 699ab6eb8af6b64eb9877347395afc7b6bdceccb Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Tue, 11 Oct 2022 11:54:06 +0530 Subject: [PATCH 154/815] Strategies depend on other addresses (#875) * Strategies depend on other addresses * Update strategy.test.ts --- src/strategies/delegation/examples.json | 26 ++++------ src/strategies/delegation/index.ts | 1 + .../erc20-balance-of-delegation/examples.json | 19 ++++---- .../erc20-balance-of-delegation/index.ts | 1 + test/strategy.test.ts | 48 +++++++++++++++---- 5 files changed, 59 insertions(+), 36 deletions(-) diff --git a/src/strategies/delegation/examples.json b/src/strategies/delegation/examples.json index d28135545..54cfe9e9b 100644 --- a/src/strategies/delegation/examples.json +++ b/src/strategies/delegation/examples.json @@ -4,23 +4,15 @@ "strategy": { "name": "delegation", "params": { - "symbol": "YFI (delegated)", - "delegationSpace": "yam.eth", + "symbol": "POH (delegated)", + "delegationSpace": "poh.eth", "strategies": [ { "name": "erc20-balance-of", "params": { - "address": "0xBa37B002AbaFDd8E89a1995dA52740bbC013D992", - "symbol": "YFI", - "decimals": 18 - } - }, - { - "name": "yearn-vault", - "params": { - "address": "0xBA2E7Fed597fd0E3e70f5130BcDbbFE06bB94fe1", - "symbol": "YFI (yYFI)", - "decimals": 18 + "address": "0x1dAD862095d40d43c2109370121cf087632874dB", + "symbol": "POH", + "decimals": 0 } } ] @@ -28,10 +20,10 @@ }, "network": "1", "addresses": [ - "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", - "0x4C7909d6F029b3a5798143C843F4f8e5341a3473", - "0x7A1057E6e9093DA9C1D4C1D049609B6889fC4c67" + "0x3c13f2B56AF614aC6381265EcB3B619bA26CC641", + "0x048fee7c3279a24af0790b6b002ded42be021d2b", + "0x139a9032a46c3afe3456eb5f0a35183b5f189cae" ], - "snapshot": 11739710 + "snapshot": 15705816 } ] diff --git a/src/strategies/delegation/index.ts b/src/strategies/delegation/index.ts index 8ed219e16..7ea2d7ff5 100644 --- a/src/strategies/delegation/index.ts +++ b/src/strategies/delegation/index.ts @@ -3,6 +3,7 @@ import { getScoresDirect } from '../../utils'; export const author = 'bonustrack'; export const version = '0.1.0'; +export const dependOnOtherAddress = true; export async function strategy( space, diff --git a/src/strategies/erc20-balance-of-delegation/examples.json b/src/strategies/erc20-balance-of-delegation/examples.json index e7207c12b..df88e9b93 100644 --- a/src/strategies/erc20-balance-of-delegation/examples.json +++ b/src/strategies/erc20-balance-of-delegation/examples.json @@ -4,19 +4,18 @@ "strategy": { "name": "erc20-balance-of-delegation", "params": { - "address": "0x4f96fe3b7a6cf9725f59d353f723c1bdb64ca6aa", - "symbol": "DAI", - "decimals": 18, - "delegationSpace": "gearbox.eth" + "symbol": "POHD", + "address": "0x1dAD862095d40d43c2109370121cf087632874dB", + "decimals": 0, + "delegationSpace": "poh.eth" } }, - "network": "42", + "network": "1", "addresses": [ - "0xeeec0e4927704ab3bbe5df7f4effa818b43665a3", - "0xe7Bf80807514d91B8B6321044CA2785d59541d5c", - "0xe105766f0156DAec8a46E407E35634542fA012E6", - "0xeEFA7451c03d52ce909A93654664c46cf81DdD21" + "0x3c13f2B56AF614aC6381265EcB3B619bA26CC641", + "0x048fee7c3279a24af0790b6b002ded42be021d2b", + "0x139a9032a46c3afe3456eb5f0a35183b5f189cae" ], - "snapshot": 29610886 + "snapshot": 15705816 } ] diff --git a/src/strategies/erc20-balance-of-delegation/index.ts b/src/strategies/erc20-balance-of-delegation/index.ts index ea05124a0..a7efca433 100644 --- a/src/strategies/erc20-balance-of-delegation/index.ts +++ b/src/strategies/erc20-balance-of-delegation/index.ts @@ -3,6 +3,7 @@ import { getDelegations } from '../../utils/delegation'; export const author = 'bonustrack'; export const version = '0.1.0'; +export const dependOnOtherAddress = true; export async function strategy( space, diff --git a/test/strategy.test.ts b/test/strategy.test.ts index 7ec841eea..b532c23e2 100644 --- a/test/strategy.test.ts +++ b/test/strategy.test.ts @@ -54,11 +54,18 @@ describe.each(examples)( expect(example.strategy.name).toBe(strategy); }); - it('Addresses in example should be minimum 5 and maximum 20', () => { - expect(example.addresses.length).toBeGreaterThanOrEqual(5); + it('Addresses in example should be minimum 3 and maximum 20', () => { + expect(example.addresses.length).toBeGreaterThanOrEqual(3); expect(example.addresses.length).toBeLessThanOrEqual(20); }); + it('Must use a snapshot block number in the past', async () => { + expect(typeof example.snapshot).toBe('number'); + const provider = snapshot.utils.getProvider(example.network); + const blockNumber = await snapshot.utils.getBlockNumber(provider); + expect(example.snapshot).toBeLessThanOrEqual(blockNumber); + }); + it('Strategy should run without any errors', async () => { const getScoresStart = performance.now(); scores = await callGetScores(example); @@ -99,13 +106,6 @@ describe.each(examples)( ); }); - it('File examples.json must use a snapshot block number in the past', async () => { - expect(typeof example.snapshot).toBe('number'); - const provider = snapshot.utils.getProvider(example.network); - const blockNumber = await snapshot.utils.getBlockNumber(provider); - expect(example.snapshot).toBeLessThanOrEqual(blockNumber); - }); - it('Returned addresses should be either same case as input addresses or checksum addresses', () => { expect( Object.keys(scores[0]).every( @@ -115,6 +115,36 @@ describe.each(examples)( ) ).toBe(true); }); + + (snapshot.strategies[strategy].dependOnOtherAddress ? it.skip : it)( + 'Voting power should not depend on other addresses', + async () => { + // limit addresses to have only 10 addresses + const testAddresses = example.addresses.slice(0, 10); + const scoresOneByOne = await Promise.all( + testAddresses.map((address) => + callGetScores({ + ...example, + addresses: [address] + }) + ) + ); + + const oldScores = {}; + const newScores = {}; + + scoresOneByOne.forEach((score) => { + const address = Object.keys(score[0])[0]; + const value = Object.values(score[0])[0]; + if (value) newScores[address] = value; + const oldScore = scores[0][address]; + if (oldScore) oldScores[address] = oldScore; + }); + + expect(newScores).not.toEqual({}); + expect(newScores).toEqual(oldScores); + } + ); } ); From f2669b6abb5025f7a29e7fbf6d0c138f3f43b92e Mon Sep 17 00:00:00 2001 From: programmablewealth <68889286+programmablewealth@users.noreply.github.com> Date: Tue, 11 Oct 2022 17:26:16 +1100 Subject: [PATCH 155/815] Bug fix for when there is only one address. (#876) Co-authored-by: Chaitanya --- .../aavegotchi-agip-37-wap-ghst/examples.json | 10 +++------- src/strategies/aavegotchi-agip-37-wap-ghst/index.ts | 2 +- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/strategies/aavegotchi-agip-37-wap-ghst/examples.json b/src/strategies/aavegotchi-agip-37-wap-ghst/examples.json index 370c41a79..45142d94d 100644 --- a/src/strategies/aavegotchi-agip-37-wap-ghst/examples.json +++ b/src/strategies/aavegotchi-agip-37-wap-ghst/examples.json @@ -28,12 +28,8 @@ } }, "network": "137", - "addresses": [ - "0x26cf02F892B04aF4Cf350539CE2C77FCF79Ec172", - "0x027Ffd3c119567e85998f4E6B9c3d83D5702660c", - "0xDEA88c9FE09106b58cA7c026c82383c56eE1E041", - "0x3a564B24EffA1Cb7Dc836AD094BaD28e69FCa371" - ], - "snapshot": 33423178 + "addresses": ["0x26cf02F892B04aF4Cf350539CE2C77FCF79Ec172", "0x027Ffd3c119567e85998f4E6B9c3d83D5702660c", "0xDEA88c9FE09106b58cA7c026c82383c56eE1E041", + "0x3a564B24EffA1Cb7Dc836AD094BaD28e69FCa371"], + "snapshot": 34185374 } ] diff --git a/src/strategies/aavegotchi-agip-37-wap-ghst/index.ts b/src/strategies/aavegotchi-agip-37-wap-ghst/index.ts index 0a60b1179..d89bcec04 100644 --- a/src/strategies/aavegotchi-agip-37-wap-ghst/index.ts +++ b/src/strategies/aavegotchi-agip-37-wap-ghst/index.ts @@ -74,7 +74,7 @@ export async function strategy( res = [...res, ...res2]; } - let slicedStakeQueries: any = [walletQuery]; + let slicedStakeQueries:any = [stakeQuery]; if (stakeQuery.length > 1) { const middle = stakeQuery.length / 2; slicedStakeQueries = [ From 1a8232139067a4a072b8046e22024ba4d5e08ec4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 11 Oct 2022 19:56:07 +0530 Subject: [PATCH 156/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.37 (#877) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 47a63d82a..6b722bd45 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.36", + "@snapshot-labs/snapshot.js": "^0.4.37", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", "copyfiles": "^2.4.1", diff --git a/yarn.lock b/yarn.lock index 2b877df5c..beb1c5dda 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.36": - version "0.4.36" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.36.tgz#ffa8d4d9de2dc6d2f3cbdaf0096f8a7eea232a37" - integrity sha512-PzjFirSj8/3AoZmA+NUxozKFSP1h89R94RIX2ty+cLpY9fSR+bKL/iyvp4lHmvFVApBLxTq6XW8zE5tdSkyLLg== +"@snapshot-labs/snapshot.js@^0.4.37": + version "0.4.37" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.37.tgz#3a20b15f059cee0b7e7b3c7660c9d1646f903a44" + integrity sha512-lSnSYJn4xe9zm52YrnO2Ku7JnZjuTG9mPgcm+fRSiBY0OmaLGKMRcvKBFxgA6gEUyqRgb/6ov8WB6e4yzyDFyA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 8a32ecfedb6910750d190eec209c2e8c6ae0aac2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment?= <55331875+clement-ux@users.noreply.github.com> Date: Wed, 12 Oct 2022 07:23:58 +0200 Subject: [PATCH 157/815] Add strategy [sd-boost-delegation] (#879) * sd-boost-delegation * Update src/strategies/sd-boost-delegation/index.ts Co-authored-by: Chaitanya --- src/strategies/index.ts | 4 +- src/strategies/sd-boost-delegation/README.md | 18 ++++++ .../sd-boost-delegation/examples.json | 27 +++++++++ src/strategies/sd-boost-delegation/index.ts | 60 +++++++++++++++++++ 4 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 src/strategies/sd-boost-delegation/README.md create mode 100644 src/strategies/sd-boost-delegation/examples.json create mode 100644 src/strategies/sd-boost-delegation/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 71f5a3568..217fcc890 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -380,6 +380,7 @@ import * as aavegotchiAgip37WapGhst from './aavegotchi-agip-37-wap-ghst'; import * as aavegotchiAgip37GltrStakedLp from './aavegotchi-agip-37-gltr-staked-lp'; import * as erc20TokensPerUni from './erc20-tokens-per-uni'; import * as bancorStandardRewardsUnderlyingBalance from './bancor-standard-rewards-underlying-balance'; +import * as sdBoostDelegation from './sd-boost-delegation'; const strategies = { 'forta-shares': fortaShares, @@ -763,7 +764,8 @@ const strategies = { 'aavegotchi-agip-37-wap-ghst': aavegotchiAgip37WapGhst, 'aavegotchi-agip-37-gltr-staked-lp': aavegotchiAgip37GltrStakedLp, 'erc20-tokens-per-uni': erc20TokensPerUni, - 'bancor-standard-rewards-underlying-balance': bancorStandardRewardsUnderlyingBalance + 'bancor-standard-rewards-underlying-balance': bancorStandardRewardsUnderlyingBalance, + 'sd-boost-delegation': sdBoostDelegation }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/sd-boost-delegation/README.md b/src/strategies/sd-boost-delegation/README.md new file mode 100644 index 000000000..7941799b9 --- /dev/null +++ b/src/strategies/sd-boost-delegation/README.md @@ -0,0 +1,18 @@ +# sd-boost-delegation + +This strategy is used by StakeDAO to vote with sdToken adapted for veSDT boost delegation (without TWAVP). +``` +VotingPower(user) = veToken.balanceOf(liquidLocker) * (sdTokenGauge.working_balances(user) / sdTokenGauge.working_supply) +``` + +Here is an example of parameters: + +```json +{ + "veToken": "0x5f3b5DfEb7B28CDbD7FAba78963EE202a494e2A2", + "liquidLocker": "0x52f541764E6e90eeBc5c21Ff570De0e2D63766B6", + "sdTokenGauge": "0x7f50786A0b15723D741727882ee99a0BF34e3466", + "symbol": "sdToken", + "decimals": 18 +} +``` diff --git a/src/strategies/sd-boost-delegation/examples.json b/src/strategies/sd-boost-delegation/examples.json new file mode 100644 index 000000000..33b4582ff --- /dev/null +++ b/src/strategies/sd-boost-delegation/examples.json @@ -0,0 +1,27 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "sd-boost-delegation", + "params": { + "veToken": "0x5f3b5DfEb7B28CDbD7FAba78963EE202a494e2A2", + "liquidLocker": "0x52f541764E6e90eeBc5c21Ff570De0e2D63766B6", + "sdTokenGauge": "0x7f50786A0b15723D741727882ee99a0BF34e3466", + "symbol": "sdToken", + "decimals": 18, + "sampleSize": 30, + "sampleStep": 5, + "avgBlockTime": 12.0 + } + }, + "network": "1", + "addresses": [ + "0xa7888f85bd76deef3bd03d4dbcf57765a49883b3", + "0x8d9f950c23b73edf79ce52f74c6fb589cd2cbd90", + "0x4af79ffcabb09083af6ccc3b2c20fe989519f6d7", + "0xa429ac8bd9382e7f69645cc30bd718b5d33d674b", + "0x7c9f43215D3B3D5055433a9d7B12bCBf9F4be442" + ], + "snapshot": 15725810 + } +] \ No newline at end of file diff --git a/src/strategies/sd-boost-delegation/index.ts b/src/strategies/sd-boost-delegation/index.ts new file mode 100644 index 000000000..39a53cc50 --- /dev/null +++ b/src/strategies/sd-boost-delegation/index.ts @@ -0,0 +1,60 @@ +import { multicall } from '../../utils'; + +export const author = 'clement-ux'; +export const version = '0.0.1'; +export const dependOnOtherAddress = false; +const abi = [ + 'function balanceOf(address account) external view returns (uint256)', + 'function working_supply() external view returns (uint256)', + 'function working_balances(address account) external view returns (uint256)' +]; + + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + // BlockTag + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + // Query + const workingBalanceQuery = addresses.map((address: any) => [ + options.sdTokenGauge, 'working_balances', [address] + ]) + + // Multicall + const response = await multicall( + network, + provider, + abi, + [ + [options.sdTokenGauge, 'working_supply'], + [options.veToken, 'balanceOf', [options.liquidLocker]], + ...workingBalanceQuery + ], + { + blockTag + } + ); + + // Constant + const workingSupply = response[0]; // working supply on gauge + const votingPowerLiquidLocker = response[1]; // balanceOf veCRV LiquidLocker + + // Return + return Object.fromEntries( + Array(addresses.length) + .fill('x') + .map((_, i) => { + const votingPower = + workingSupply > 0 + ? (response[i+2] * votingPowerLiquidLocker) / (workingSupply*10**options.decimals) + : 0; + return [addresses[i], votingPower]; + }) + ); +} From df989038189a62d06551b78474715d161e2c07a4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 12 Oct 2022 10:58:03 +0530 Subject: [PATCH 158/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.38 (#880) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 6b722bd45..883fb7f7b 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.37", + "@snapshot-labs/snapshot.js": "^0.4.38", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", "copyfiles": "^2.4.1", diff --git a/yarn.lock b/yarn.lock index beb1c5dda..4081febfb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.37": - version "0.4.37" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.37.tgz#3a20b15f059cee0b7e7b3c7660c9d1646f903a44" - integrity sha512-lSnSYJn4xe9zm52YrnO2Ku7JnZjuTG9mPgcm+fRSiBY0OmaLGKMRcvKBFxgA6gEUyqRgb/6ov8WB6e4yzyDFyA== +"@snapshot-labs/snapshot.js@^0.4.38": + version "0.4.38" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.38.tgz#0ed42d1759b36838e2836c7586fd7c578348c414" + integrity sha512-WT6rUI6sQMWxqDspWdeaTeyAxZ2EE/9enVfzS+pAFyCuB/4VIZrbBY+d8Ho4nGeNu2Tn+YqT7cRdW406d8c6zA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From fffae58b67415fb77071ba45d0cd0540867eb5e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment?= <55331875+clement-ux@users.noreply.github.com> Date: Wed, 12 Oct 2022 09:56:19 +0200 Subject: [PATCH 159/815] Add strategy [sd-boost-delegation-twavp] (#881) * sd-boost-delegation-twavp * Update src/strategies/sd-boost-delegation-twavp/index.ts Co-authored-by: Chaitanya --- src/strategies/index.ts | 4 +- .../sd-boost-delegation-twavp/README.md | 26 +++++ .../sd-boost-delegation-twavp/examples.json | 27 +++++ .../sd-boost-delegation-twavp/index.ts | 103 ++++++++++++++++++ 4 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 src/strategies/sd-boost-delegation-twavp/README.md create mode 100644 src/strategies/sd-boost-delegation-twavp/examples.json create mode 100644 src/strategies/sd-boost-delegation-twavp/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 217fcc890..20e3b863f 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -381,6 +381,7 @@ import * as aavegotchiAgip37GltrStakedLp from './aavegotchi-agip-37-gltr-staked- import * as erc20TokensPerUni from './erc20-tokens-per-uni'; import * as bancorStandardRewardsUnderlyingBalance from './bancor-standard-rewards-underlying-balance'; import * as sdBoostDelegation from './sd-boost-delegation'; +import * as sdBoostDelegationTWAVP from './sd-boost-delegation-twavp'; const strategies = { 'forta-shares': fortaShares, @@ -765,7 +766,8 @@ const strategies = { 'aavegotchi-agip-37-gltr-staked-lp': aavegotchiAgip37GltrStakedLp, 'erc20-tokens-per-uni': erc20TokensPerUni, 'bancor-standard-rewards-underlying-balance': bancorStandardRewardsUnderlyingBalance, - 'sd-boost-delegation': sdBoostDelegation + 'sd-boost-delegation': sdBoostDelegation, + 'sd-boost-delegation-twavp': sdBoostDelegationTWAVP }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/sd-boost-delegation-twavp/README.md b/src/strategies/sd-boost-delegation-twavp/README.md new file mode 100644 index 000000000..c786c2a00 --- /dev/null +++ b/src/strategies/sd-boost-delegation-twavp/README.md @@ -0,0 +1,26 @@ +# sd-boost-delegation-twavp + +This strategy is used by Stake DAO to vote with sdToken using Time Weigthed Averaged Voting Power (TWAVP) system and adapted for veSDT boost delegation. + +``` +VotingPower(user) = veToken.balanceOf(liquidLocker) * (average.sdTokenGauge.working_balances(user) / sdTokenGauge.working_supply) +``` + +>_sampleSize: in days_ +>_sampleStep: the number of block for `average` calculation (max 5)_ +>_avgBlockTime: in seconds_ + +Here is an example of parameters: + +```json +{ + "veToken": "0x5f3b5DfEb7B28CDbD7FAba78963EE202a494e2A2", + "liquidLocker": "0x52f541764E6e90eeBc5c21Ff570De0e2D63766B6", + "sdTokenGauge": "0x7f50786A0b15723D741727882ee99a0BF34e3466", + "symbol": "sdToken", + "decimals": 18, + "sampleSize": 30, + "sampleStep": 5, + "avgBlockTime": 12.0 +} +``` \ No newline at end of file diff --git a/src/strategies/sd-boost-delegation-twavp/examples.json b/src/strategies/sd-boost-delegation-twavp/examples.json new file mode 100644 index 000000000..1323e2b95 --- /dev/null +++ b/src/strategies/sd-boost-delegation-twavp/examples.json @@ -0,0 +1,27 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "sd-boost-delegation-twavp", + "params": { + "veToken": "0x5f3b5DfEb7B28CDbD7FAba78963EE202a494e2A2", + "liquidLocker": "0x52f541764E6e90eeBc5c21Ff570De0e2D63766B6", + "sdTokenGauge": "0x7f50786A0b15723D741727882ee99a0BF34e3466", + "symbol": "sdToken", + "decimals": 18, + "sampleSize": 30, + "sampleStep": 5, + "avgBlockTime": 12.0 + } + }, + "network": "1", + "addresses": [ + "0xa7888f85bd76deef3bd03d4dbcf57765a49883b3", + "0x8d9f950c23b73edf79ce52f74c6fb589cd2cbd90", + "0x4af79ffcabb09083af6ccc3b2c20fe989519f6d7", + "0xa429ac8bd9382e7f69645cc30bd718b5d33d674b", + "0x7c9f43215D3B3D5055433a9d7B12bCBf9F4be442" + ], + "snapshot": 15725810 + } +] \ No newline at end of file diff --git a/src/strategies/sd-boost-delegation-twavp/index.ts b/src/strategies/sd-boost-delegation-twavp/index.ts new file mode 100644 index 000000000..545243ca1 --- /dev/null +++ b/src/strategies/sd-boost-delegation-twavp/index.ts @@ -0,0 +1,103 @@ +import { multicall } from '../../utils'; + +export const author = 'clement-ux'; +export const version = '0.0.1'; +export const dependOnOtherAddress = false; + +const abi = [ + 'function balanceOf(address account) external view returns (uint256)', + 'function working_supply() external view returns (uint256)', + 'function working_balances(address account) external view returns (uint256)' +]; + + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + // Maximum of 5 multicall + if (options.sampleStep > 5) { + throw new Error('maximum of 5 call'); + } + + // About the blockList + const av_blockEmission = options.avgBlockTime; + const lastBlock = await provider.getBlockNumber(); + let blockTag = typeof snapshot === 'number' ? snapshot : lastBlock; + const nbrsEmittedBlock = Math.floor( + (options.sampleSize * 60 * 60 * 24) / av_blockEmission + ); + const blockTagList: number[] = []; + for (let i = 1; i < options.sampleStep + 1; i++) { + blockTagList.push( + blockTag - + Math.floor( + (nbrsEmittedBlock * (options.sampleStep - i)) / options.sampleStep + ) + ); + } + //console.log('Used block List: ', blockTagList); + + // Query + const workingBalanceQuery = addresses.map((address: any) => [ + options.sdTokenGauge, 'working_balances', [address] + ]) + + const response: number[] = []; + + for (let i = 0; i < options.sampleStep; i++) { + blockTag = blockTagList[i]; + response.push( + await multicall( + network, + provider, + abi, + [ + [options.sdTokenGauge, 'working_supply'], + [options.veToken, 'balanceOf', [options.liquidLocker]], + ...workingBalanceQuery + ], + { + blockTag + } + ) + ); + } + + // Constant + // Get Working supply on the gauge + const workingSupply = response[response.length-1][0]; + const votingPowerLiquidLocker = response[response.length-1][1]; + + const averageWorkingBalance = Object.fromEntries( + Array(addresses.length) + .fill('x') + .map((_, i) => { + let sum = Number(0); + //console.log(`==================${addresses[i]}==================`); + for(let j = 0; j < response.length; j++) { + sum += Number(response[j][i+2]); + //console.log(Number(response[j][i+2])) + } + //console.log("Adjusted Balance : ", sum/(response.length*10**options.decimals)) + return[addresses[i], sum/(response.length)] + }) + ); + + return Object.fromEntries( + Array(addresses.length) + .fill('x') + .map((_, i) => { + // Get votingPower : user voting power + const votingPower = + workingSupply > 0 + ? (averageWorkingBalance[addresses[i]] * votingPowerLiquidLocker) / (workingSupply*10**options.decimals) + : 0; + return [addresses[i], votingPower]; + }) + ); +} From e079a2ed75715a6a9c638c0bddf068d562958881 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 12 Oct 2022 13:59:32 +0530 Subject: [PATCH 160/815] Automated lint (#882) Co-authored-by: ChaituVR --- .../aavegotchi-agip-37-wap-ghst/examples.json | 8 +++- .../aavegotchi-agip-37-wap-ghst/index.ts | 2 +- .../index.ts | 19 ++++---- src/strategies/index.ts | 3 +- .../sd-boost-delegation-twavp/examples.json | 2 +- .../sd-boost-delegation-twavp/index.ts | 46 ++++++++++--------- .../sd-boost-delegation/examples.json | 2 +- src/strategies/sd-boost-delegation/index.ts | 20 ++++---- 8 files changed, 55 insertions(+), 47 deletions(-) diff --git a/src/strategies/aavegotchi-agip-37-wap-ghst/examples.json b/src/strategies/aavegotchi-agip-37-wap-ghst/examples.json index 45142d94d..b26817fde 100644 --- a/src/strategies/aavegotchi-agip-37-wap-ghst/examples.json +++ b/src/strategies/aavegotchi-agip-37-wap-ghst/examples.json @@ -28,8 +28,12 @@ } }, "network": "137", - "addresses": ["0x26cf02F892B04aF4Cf350539CE2C77FCF79Ec172", "0x027Ffd3c119567e85998f4E6B9c3d83D5702660c", "0xDEA88c9FE09106b58cA7c026c82383c56eE1E041", - "0x3a564B24EffA1Cb7Dc836AD094BaD28e69FCa371"], + "addresses": [ + "0x26cf02F892B04aF4Cf350539CE2C77FCF79Ec172", + "0x027Ffd3c119567e85998f4E6B9c3d83D5702660c", + "0xDEA88c9FE09106b58cA7c026c82383c56eE1E041", + "0x3a564B24EffA1Cb7Dc836AD094BaD28e69FCa371" + ], "snapshot": 34185374 } ] diff --git a/src/strategies/aavegotchi-agip-37-wap-ghst/index.ts b/src/strategies/aavegotchi-agip-37-wap-ghst/index.ts index d89bcec04..accd33216 100644 --- a/src/strategies/aavegotchi-agip-37-wap-ghst/index.ts +++ b/src/strategies/aavegotchi-agip-37-wap-ghst/index.ts @@ -74,7 +74,7 @@ export async function strategy( res = [...res, ...res2]; } - let slicedStakeQueries:any = [stakeQuery]; + let slicedStakeQueries: any = [stakeQuery]; if (stakeQuery.length > 1) { const middle = stakeQuery.length / 2; slicedStakeQueries = [ diff --git a/src/strategies/bancor-standard-rewards-underlying-balance/index.ts b/src/strategies/bancor-standard-rewards-underlying-balance/index.ts index 75db1873e..8af1793ad 100644 --- a/src/strategies/bancor-standard-rewards-underlying-balance/index.ts +++ b/src/strategies/bancor-standard-rewards-underlying-balance/index.ts @@ -25,7 +25,6 @@ export async function strategy( ) { const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - // Get last provider Program ID const latestProgramId = await call( provider, @@ -39,13 +38,17 @@ export async function strategy( ); // Get each provider's stake in the standard rewards contract - const multi = new Multicaller(network, provider, standardRewardsABI, { blockTag }); + const multi = new Multicaller(network, provider, standardRewardsABI, { + blockTag + }); addresses.forEach((address) => - multi.call(address, options.bancorStandardRewardsAddress, 'providerStake', [address, latestProgramId.toString()]) + multi.call(address, options.bancorStandardRewardsAddress, 'providerStake', [ + address, + latestProgramId.toString() + ]) ); const scores: Record = await multi.execute(); - // Get the Underlying Value of the Pool Token * 10**(decimals) to convert from wei const poolTokenDecimalScaling = (10 ** options.decimals).toString(); const underlyingValue = await call( @@ -57,14 +60,10 @@ export async function strategy( [options.underlyingTokenAddress, poolTokenDecimalScaling] ], { blockTag } - ).then((res) => parseFloat(formatUnits(res, 2*options.decimals))); + ).then((res) => parseFloat(formatUnits(res, 2 * options.decimals))); // Update the providers' stakes in the standard rewards contract to their converted underlying value return Object.fromEntries( - Object.entries(scores).map((res: any) => [ - res[0], - res[1] * underlyingValue - ]) + Object.entries(scores).map((res: any) => [res[0], res[1] * underlyingValue]) ); - } diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 20e3b863f..7ca8ea473 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -765,7 +765,8 @@ const strategies = { 'aavegotchi-agip-37-wap-ghst': aavegotchiAgip37WapGhst, 'aavegotchi-agip-37-gltr-staked-lp': aavegotchiAgip37GltrStakedLp, 'erc20-tokens-per-uni': erc20TokensPerUni, - 'bancor-standard-rewards-underlying-balance': bancorStandardRewardsUnderlyingBalance, + 'bancor-standard-rewards-underlying-balance': + bancorStandardRewardsUnderlyingBalance, 'sd-boost-delegation': sdBoostDelegation, 'sd-boost-delegation-twavp': sdBoostDelegationTWAVP }; diff --git a/src/strategies/sd-boost-delegation-twavp/examples.json b/src/strategies/sd-boost-delegation-twavp/examples.json index 1323e2b95..251076728 100644 --- a/src/strategies/sd-boost-delegation-twavp/examples.json +++ b/src/strategies/sd-boost-delegation-twavp/examples.json @@ -24,4 +24,4 @@ ], "snapshot": 15725810 } -] \ No newline at end of file +] diff --git a/src/strategies/sd-boost-delegation-twavp/index.ts b/src/strategies/sd-boost-delegation-twavp/index.ts index 545243ca1..e9ab6810b 100644 --- a/src/strategies/sd-boost-delegation-twavp/index.ts +++ b/src/strategies/sd-boost-delegation-twavp/index.ts @@ -10,7 +10,6 @@ const abi = [ 'function working_balances(address account) external view returns (uint256)' ]; - export async function strategy( space, network, @@ -44,8 +43,10 @@ export async function strategy( // Query const workingBalanceQuery = addresses.map((address: any) => [ - options.sdTokenGauge, 'working_balances', [address] - ]) + options.sdTokenGauge, + 'working_balances', + [address] + ]); const response: number[] = []; @@ -53,16 +54,16 @@ export async function strategy( blockTag = blockTagList[i]; response.push( await multicall( - network, - provider, - abi, + network, + provider, + abi, [ [options.sdTokenGauge, 'working_supply'], [options.veToken, 'balanceOf', [options.liquidLocker]], ...workingBalanceQuery - ], + ], { - blockTag + blockTag } ) ); @@ -70,22 +71,22 @@ export async function strategy( // Constant // Get Working supply on the gauge - const workingSupply = response[response.length-1][0]; - const votingPowerLiquidLocker = response[response.length-1][1]; + const workingSupply = response[response.length - 1][0]; + const votingPowerLiquidLocker = response[response.length - 1][1]; const averageWorkingBalance = Object.fromEntries( Array(addresses.length) - .fill('x') - .map((_, i) => { - let sum = Number(0); - //console.log(`==================${addresses[i]}==================`); - for(let j = 0; j < response.length; j++) { - sum += Number(response[j][i+2]); - //console.log(Number(response[j][i+2])) - } - //console.log("Adjusted Balance : ", sum/(response.length*10**options.decimals)) - return[addresses[i], sum/(response.length)] - }) + .fill('x') + .map((_, i) => { + let sum = Number(0); + //console.log(`==================${addresses[i]}==================`); + for (let j = 0; j < response.length; j++) { + sum += Number(response[j][i + 2]); + //console.log(Number(response[j][i+2])) + } + //console.log("Adjusted Balance : ", sum/(response.length*10**options.decimals)) + return [addresses[i], sum / response.length]; + }) ); return Object.fromEntries( @@ -95,7 +96,8 @@ export async function strategy( // Get votingPower : user voting power const votingPower = workingSupply > 0 - ? (averageWorkingBalance[addresses[i]] * votingPowerLiquidLocker) / (workingSupply*10**options.decimals) + ? (averageWorkingBalance[addresses[i]] * votingPowerLiquidLocker) / + (workingSupply * 10 ** options.decimals) : 0; return [addresses[i], votingPower]; }) diff --git a/src/strategies/sd-boost-delegation/examples.json b/src/strategies/sd-boost-delegation/examples.json index 33b4582ff..e9238976d 100644 --- a/src/strategies/sd-boost-delegation/examples.json +++ b/src/strategies/sd-boost-delegation/examples.json @@ -24,4 +24,4 @@ ], "snapshot": 15725810 } -] \ No newline at end of file +] diff --git a/src/strategies/sd-boost-delegation/index.ts b/src/strategies/sd-boost-delegation/index.ts index 39a53cc50..70b5dffe7 100644 --- a/src/strategies/sd-boost-delegation/index.ts +++ b/src/strategies/sd-boost-delegation/index.ts @@ -9,7 +9,6 @@ const abi = [ 'function working_balances(address account) external view returns (uint256)' ]; - export async function strategy( space, network, @@ -23,21 +22,23 @@ export async function strategy( // Query const workingBalanceQuery = addresses.map((address: any) => [ - options.sdTokenGauge, 'working_balances', [address] - ]) + options.sdTokenGauge, + 'working_balances', + [address] + ]); // Multicall const response = await multicall( - network, - provider, - abi, + network, + provider, + abi, [ [options.sdTokenGauge, 'working_supply'], [options.veToken, 'balanceOf', [options.liquidLocker]], ...workingBalanceQuery - ], + ], { - blockTag + blockTag } ); @@ -52,7 +53,8 @@ export async function strategy( .map((_, i) => { const votingPower = workingSupply > 0 - ? (response[i+2] * votingPowerLiquidLocker) / (workingSupply*10**options.decimals) + ? (response[i + 2] * votingPowerLiquidLocker) / + (workingSupply * 10 ** options.decimals) : 0; return [addresses[i], votingPower]; }) From bba3b8a3ab721928364198a82012a28d5c851852 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 12 Oct 2022 21:56:22 +0530 Subject: [PATCH 161/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.39 (#883) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 883fb7f7b..a11c38a21 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.38", + "@snapshot-labs/snapshot.js": "^0.4.39", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", "copyfiles": "^2.4.1", diff --git a/yarn.lock b/yarn.lock index 4081febfb..3cfdd4cd6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.38": - version "0.4.38" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.38.tgz#0ed42d1759b36838e2836c7586fd7c578348c414" - integrity sha512-WT6rUI6sQMWxqDspWdeaTeyAxZ2EE/9enVfzS+pAFyCuB/4VIZrbBY+d8Ho4nGeNu2Tn+YqT7cRdW406d8c6zA== +"@snapshot-labs/snapshot.js@^0.4.39": + version "0.4.39" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.39.tgz#4c31d609e76949dac1021f88e2165ba21f37cbe4" + integrity sha512-XGIC1rJ5y161hmsaDuZtQw/lOWR0yabQzzJ74s09kDDYgaGlx8VEDreS5ciYXp3vKkNTK2bG7coh7PiiZw4nDw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From be9f4e67aa4aec72bd582c885a307bcfc8a06563 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Oct 2022 10:32:27 +0530 Subject: [PATCH 162/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.40 (#886) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index a11c38a21..8cf3848eb 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.39", + "@snapshot-labs/snapshot.js": "^0.4.40", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", "copyfiles": "^2.4.1", diff --git a/yarn.lock b/yarn.lock index 3cfdd4cd6..31807d753 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.39": - version "0.4.39" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.39.tgz#4c31d609e76949dac1021f88e2165ba21f37cbe4" - integrity sha512-XGIC1rJ5y161hmsaDuZtQw/lOWR0yabQzzJ74s09kDDYgaGlx8VEDreS5ciYXp3vKkNTK2bG7coh7PiiZw4nDw== +"@snapshot-labs/snapshot.js@^0.4.40": + version "0.4.40" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.40.tgz#64dcea55c3f349470c2470d9fd520deeef7d1973" + integrity sha512-/6VHbDZANx36c4nMCiPrg3LR52jjysow+F/79lp7h8B3sNHMqHCTDmheBM6pTguQ3+cCgfKLOrZn62C9laQW2A== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 2fbfa291f51109b272d25a99339bfd73ec434225 Mon Sep 17 00:00:00 2001 From: BrassLion Date: Thu, 13 Oct 2022 08:26:28 +0100 Subject: [PATCH 163/815] Change Arrow vesting to return voting power based on potential vested tokens (#884) --- src/strategies/arrow-vesting/index.ts | 77 ++++++++++----------------- 1 file changed, 29 insertions(+), 48 deletions(-) diff --git a/src/strategies/arrow-vesting/index.ts b/src/strategies/arrow-vesting/index.ts index b1085b66e..76309c0fb 100644 --- a/src/strategies/arrow-vesting/index.ts +++ b/src/strategies/arrow-vesting/index.ts @@ -1,22 +1,20 @@ -import { BigNumberish, BigNumber } from '@ethersproject/bignumber'; import { Contract } from '@ethersproject/contracts'; import { formatUnits } from '@ethersproject/units'; import { Multicaller } from '../../utils'; export const author = 'BrassLion'; -export const version = '0.1.0'; +export const version = '0.1.1'; const vestingFactoryAbi = [ 'function escrows_length() public view returns (uint256)', - 'function escrows(uint256 index) public view returns (address)' + 'function escrows(uint256 index) public view returns (address)', ]; const vestingContractAbi = [ - 'function recipient() public view returns (address)' -]; - -const tokenAbi = [ - 'function balanceOf(address account) external view returns (uint256)' + 'function recipient() public view returns (address)', + 'function total_locked() public view returns (uint256)', + 'function start_time() public view returns (uint256)', + 'function end_time() public view returns (uint256)', ]; export async function strategy( @@ -33,10 +31,10 @@ export async function strategy( const vestingFactory = new Contract( options.vestingFactory, vestingFactoryAbi, - provider + provider, ); - const vestingContractCount = await vestingFactory.escrows_length(); + const vestingContractCount = await vestingFactory.escrows_length({blockTag: blockTag}); const vestingFactoryMulti = new Multicaller( network, @@ -46,15 +44,13 @@ export async function strategy( ); [...Array(vestingContractCount.toNumber()).keys()].forEach((contractIdx) => { - vestingFactoryMulti.call(contractIdx, options.vestingFactory, 'escrows', [ - contractIdx - ]); + vestingFactoryMulti.call(contractIdx, options.vestingFactory, 'escrows', [contractIdx]); }); const vestingContracts: Record = await vestingFactoryMulti.execute(); - // Get all beneficiaries of vesting contracts. + // Get all vesting contract parameters. const vestingContractMulti = new Multicaller( network, provider, @@ -63,50 +59,35 @@ export async function strategy( ); Object.values(vestingContracts).forEach((vestingContractAddress) => { - vestingContractMulti.call( - vestingContractAddress, - vestingContractAddress, - 'recipient', - [] - ); - }); - - const vestingContractRecipients: Record = - await vestingContractMulti.execute(); - - // Get all balances of vesting contracts. - const tokenMulti = new Multicaller(network, provider, tokenAbi, { blockTag }); - - Object.values(vestingContracts).forEach((vestingContractAddress) => { - tokenMulti.call(vestingContractAddress, options.address, 'balanceOf', [ - vestingContractAddress - ]); + vestingContractMulti.call(`${vestingContractAddress}.recipient`, vestingContractAddress, 'recipient', []); + vestingContractMulti.call(`${vestingContractAddress}.total_locked`, vestingContractAddress, 'total_locked', []); + vestingContractMulti.call(`${vestingContractAddress}.start_time`, vestingContractAddress, 'start_time', []); + vestingContractMulti.call(`${vestingContractAddress}.end_time`, vestingContractAddress, 'end_time', []); }); - const vestingContractBalances: Record = - await tokenMulti.execute(); + const vestingContractParameters: Record = await vestingContractMulti.execute(); // Sum all vesting contract balances by recipient over requested addresses. - const addressBalances: Record = {}; + const block = await provider.getBlock(blockTag) + const time = block.timestamp + const addressBalances: Record = {}; addresses.forEach((address) => { - addressBalances[address] = BigNumber.from(0); + addressBalances[address] = 0; }); - Object.values(vestingContracts).forEach((vestingContractAddress) => { - const recipient = vestingContractRecipients[vestingContractAddress]; + Object.entries(vestingContractParameters).forEach(([contractAddress, params]) => { + const recipient = params["recipient"]; + const start = params["start_time"] - if (recipient in addressBalances) { - addressBalances[recipient] = addressBalances[recipient].add( - vestingContractBalances[vestingContractAddress] - ); + if (recipient in addressBalances && time > start) { + + const locked = parseFloat(formatUnits(params["total_locked"], options.decimals)) + const end = params["end_time"] + + addressBalances[recipient] += Math.min(locked * (time - start) / (end - start), locked); } }); - return Object.fromEntries( - Object.entries(addressBalances).map(([address, balance]) => [ - address, - parseFloat(formatUnits(balance, options.decimals)) - ]) - ); + return addressBalances } From 9624a332890872cd23608b268f186eef3f53f75a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment?= <55331875+clement-ux@users.noreply.github.com> Date: Fri, 14 Oct 2022 21:02:59 +0200 Subject: [PATCH 164/815] change sd-boost-delegation(-twavp) names (#887) --- src/strategies/index.ts | 8 ++++---- .../README.md | 2 +- .../examples.json | 2 +- .../index.ts | 0 .../{sd-boost-delegation => sd-vote-boost}/README.md | 2 +- .../examples.json | 7 ++----- .../{sd-boost-delegation => sd-vote-boost}/index.ts | 0 7 files changed, 9 insertions(+), 12 deletions(-) rename src/strategies/{sd-boost-delegation-twavp => sd-vote-boost-twavp}/README.md (96%) rename src/strategies/{sd-boost-delegation => sd-vote-boost-twavp}/examples.json (95%) rename src/strategies/{sd-boost-delegation-twavp => sd-vote-boost-twavp}/index.ts (100%) rename src/strategies/{sd-boost-delegation => sd-vote-boost}/README.md (95%) rename src/strategies/{sd-boost-delegation-twavp => sd-vote-boost}/examples.json (81%) rename src/strategies/{sd-boost-delegation => sd-vote-boost}/index.ts (100%) diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 7ca8ea473..cf66a052a 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -380,8 +380,8 @@ import * as aavegotchiAgip37WapGhst from './aavegotchi-agip-37-wap-ghst'; import * as aavegotchiAgip37GltrStakedLp from './aavegotchi-agip-37-gltr-staked-lp'; import * as erc20TokensPerUni from './erc20-tokens-per-uni'; import * as bancorStandardRewardsUnderlyingBalance from './bancor-standard-rewards-underlying-balance'; -import * as sdBoostDelegation from './sd-boost-delegation'; -import * as sdBoostDelegationTWAVP from './sd-boost-delegation-twavp'; +import * as sdVoteBoost from './sd-vote-boost'; +import * as sdVoteBoostTWAVP from './sd-vote-boost-twavp'; const strategies = { 'forta-shares': fortaShares, @@ -767,8 +767,8 @@ const strategies = { 'erc20-tokens-per-uni': erc20TokensPerUni, 'bancor-standard-rewards-underlying-balance': bancorStandardRewardsUnderlyingBalance, - 'sd-boost-delegation': sdBoostDelegation, - 'sd-boost-delegation-twavp': sdBoostDelegationTWAVP + 'sd-vote-boost': sdVoteBoost, + 'sd-vote-boost-twavp': sdVoteBoostTWAVP }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/sd-boost-delegation-twavp/README.md b/src/strategies/sd-vote-boost-twavp/README.md similarity index 96% rename from src/strategies/sd-boost-delegation-twavp/README.md rename to src/strategies/sd-vote-boost-twavp/README.md index c786c2a00..8b15abd26 100644 --- a/src/strategies/sd-boost-delegation-twavp/README.md +++ b/src/strategies/sd-vote-boost-twavp/README.md @@ -1,4 +1,4 @@ -# sd-boost-delegation-twavp +# sd-vote-boost-twavp This strategy is used by Stake DAO to vote with sdToken using Time Weigthed Averaged Voting Power (TWAVP) system and adapted for veSDT boost delegation. diff --git a/src/strategies/sd-boost-delegation/examples.json b/src/strategies/sd-vote-boost-twavp/examples.json similarity index 95% rename from src/strategies/sd-boost-delegation/examples.json rename to src/strategies/sd-vote-boost-twavp/examples.json index e9238976d..9be59268e 100644 --- a/src/strategies/sd-boost-delegation/examples.json +++ b/src/strategies/sd-vote-boost-twavp/examples.json @@ -2,7 +2,7 @@ { "name": "Example query", "strategy": { - "name": "sd-boost-delegation", + "name": "sd-vote-boost-twavp", "params": { "veToken": "0x5f3b5DfEb7B28CDbD7FAba78963EE202a494e2A2", "liquidLocker": "0x52f541764E6e90eeBc5c21Ff570De0e2D63766B6", diff --git a/src/strategies/sd-boost-delegation-twavp/index.ts b/src/strategies/sd-vote-boost-twavp/index.ts similarity index 100% rename from src/strategies/sd-boost-delegation-twavp/index.ts rename to src/strategies/sd-vote-boost-twavp/index.ts diff --git a/src/strategies/sd-boost-delegation/README.md b/src/strategies/sd-vote-boost/README.md similarity index 95% rename from src/strategies/sd-boost-delegation/README.md rename to src/strategies/sd-vote-boost/README.md index 7941799b9..769e99324 100644 --- a/src/strategies/sd-boost-delegation/README.md +++ b/src/strategies/sd-vote-boost/README.md @@ -1,4 +1,4 @@ -# sd-boost-delegation +# sd-vote-boost This strategy is used by StakeDAO to vote with sdToken adapted for veSDT boost delegation (without TWAVP). ``` diff --git a/src/strategies/sd-boost-delegation-twavp/examples.json b/src/strategies/sd-vote-boost/examples.json similarity index 81% rename from src/strategies/sd-boost-delegation-twavp/examples.json rename to src/strategies/sd-vote-boost/examples.json index 251076728..9e471543c 100644 --- a/src/strategies/sd-boost-delegation-twavp/examples.json +++ b/src/strategies/sd-vote-boost/examples.json @@ -2,16 +2,13 @@ { "name": "Example query", "strategy": { - "name": "sd-boost-delegation-twavp", + "name": "sd-vote-boost", "params": { "veToken": "0x5f3b5DfEb7B28CDbD7FAba78963EE202a494e2A2", "liquidLocker": "0x52f541764E6e90eeBc5c21Ff570De0e2D63766B6", "sdTokenGauge": "0x7f50786A0b15723D741727882ee99a0BF34e3466", "symbol": "sdToken", - "decimals": 18, - "sampleSize": 30, - "sampleStep": 5, - "avgBlockTime": 12.0 + "decimals": 18 } }, "network": "1", diff --git a/src/strategies/sd-boost-delegation/index.ts b/src/strategies/sd-vote-boost/index.ts similarity index 100% rename from src/strategies/sd-boost-delegation/index.ts rename to src/strategies/sd-vote-boost/index.ts From 8d0de06c0547d947b17ef88c9a5e358427d472f6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 17 Oct 2022 11:48:48 +0530 Subject: [PATCH 165/815] Automated lint (#888) Co-authored-by: ChaituVR --- src/strategies/arrow-vesting/index.ts | 79 +++++++++++++++++++-------- 1 file changed, 55 insertions(+), 24 deletions(-) diff --git a/src/strategies/arrow-vesting/index.ts b/src/strategies/arrow-vesting/index.ts index 76309c0fb..000e80e87 100644 --- a/src/strategies/arrow-vesting/index.ts +++ b/src/strategies/arrow-vesting/index.ts @@ -7,14 +7,14 @@ export const version = '0.1.1'; const vestingFactoryAbi = [ 'function escrows_length() public view returns (uint256)', - 'function escrows(uint256 index) public view returns (address)', + 'function escrows(uint256 index) public view returns (address)' ]; const vestingContractAbi = [ 'function recipient() public view returns (address)', 'function total_locked() public view returns (uint256)', 'function start_time() public view returns (uint256)', - 'function end_time() public view returns (uint256)', + 'function end_time() public view returns (uint256)' ]; export async function strategy( @@ -31,10 +31,12 @@ export async function strategy( const vestingFactory = new Contract( options.vestingFactory, vestingFactoryAbi, - provider, + provider ); - const vestingContractCount = await vestingFactory.escrows_length({blockTag: blockTag}); + const vestingContractCount = await vestingFactory.escrows_length({ + blockTag: blockTag + }); const vestingFactoryMulti = new Multicaller( network, @@ -44,7 +46,9 @@ export async function strategy( ); [...Array(vestingContractCount.toNumber()).keys()].forEach((contractIdx) => { - vestingFactoryMulti.call(contractIdx, options.vestingFactory, 'escrows', [contractIdx]); + vestingFactoryMulti.call(contractIdx, options.vestingFactory, 'escrows', [ + contractIdx + ]); }); const vestingContracts: Record = @@ -59,35 +63,62 @@ export async function strategy( ); Object.values(vestingContracts).forEach((vestingContractAddress) => { - vestingContractMulti.call(`${vestingContractAddress}.recipient`, vestingContractAddress, 'recipient', []); - vestingContractMulti.call(`${vestingContractAddress}.total_locked`, vestingContractAddress, 'total_locked', []); - vestingContractMulti.call(`${vestingContractAddress}.start_time`, vestingContractAddress, 'start_time', []); - vestingContractMulti.call(`${vestingContractAddress}.end_time`, vestingContractAddress, 'end_time', []); + vestingContractMulti.call( + `${vestingContractAddress}.recipient`, + vestingContractAddress, + 'recipient', + [] + ); + vestingContractMulti.call( + `${vestingContractAddress}.total_locked`, + vestingContractAddress, + 'total_locked', + [] + ); + vestingContractMulti.call( + `${vestingContractAddress}.start_time`, + vestingContractAddress, + 'start_time', + [] + ); + vestingContractMulti.call( + `${vestingContractAddress}.end_time`, + vestingContractAddress, + 'end_time', + [] + ); }); - const vestingContractParameters: Record = await vestingContractMulti.execute(); + const vestingContractParameters: Record = + await vestingContractMulti.execute(); // Sum all vesting contract balances by recipient over requested addresses. - const block = await provider.getBlock(blockTag) - const time = block.timestamp + const block = await provider.getBlock(blockTag); + const time = block.timestamp; const addressBalances: Record = {}; addresses.forEach((address) => { addressBalances[address] = 0; }); - Object.entries(vestingContractParameters).forEach(([contractAddress, params]) => { - const recipient = params["recipient"]; - const start = params["start_time"] - - if (recipient in addressBalances && time > start) { - - const locked = parseFloat(formatUnits(params["total_locked"], options.decimals)) - const end = params["end_time"] - - addressBalances[recipient] += Math.min(locked * (time - start) / (end - start), locked); + Object.entries(vestingContractParameters).forEach( + ([contractAddress, params]) => { + const recipient = params['recipient']; + const start = params['start_time']; + + if (recipient in addressBalances && time > start) { + const locked = parseFloat( + formatUnits(params['total_locked'], options.decimals) + ); + const end = params['end_time']; + + addressBalances[recipient] += Math.min( + (locked * (time - start)) / (end - start), + locked + ); + } } - }); + ); - return addressBalances + return addressBalances; } From 06c360e41d4637de71299c9a6c315da155fccb04 Mon Sep 17 00:00:00 2001 From: Fabien Date: Tue, 18 Oct 2022 21:56:22 +0700 Subject: [PATCH 166/815] Simplify example for delegation --- src/strategies/delegation/examples.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/strategies/delegation/examples.json b/src/strategies/delegation/examples.json index 54cfe9e9b..e2f824d51 100644 --- a/src/strategies/delegation/examples.json +++ b/src/strategies/delegation/examples.json @@ -5,13 +5,11 @@ "name": "delegation", "params": { "symbol": "POH (delegated)", - "delegationSpace": "poh.eth", "strategies": [ { "name": "erc20-balance-of", "params": { "address": "0x1dAD862095d40d43c2109370121cf087632874dB", - "symbol": "POH", "decimals": 0 } } From 8c6f09772eb4968fbb41ecec7c2db2e5ac07d87a Mon Sep 17 00:00:00 2001 From: dappguru <66567435+dappguru@users.noreply.github.com> Date: Wed, 19 Oct 2022 14:34:11 +0200 Subject: [PATCH 167/815] add clqdr-balance-with-lp [clqdr-balance-with-lp] (#890) * add clqdr-balance-with-lp * update clqdr voting power Co-authored-by: thenaursa --- .../clqdr-balance-with-lp/examples.json | 35 +++++ src/strategies/clqdr-balance-with-lp/index.ts | 138 ++++++++++++++++++ src/strategies/index.ts | 5 +- 3 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 src/strategies/clqdr-balance-with-lp/examples.json create mode 100644 src/strategies/clqdr-balance-with-lp/index.ts diff --git a/src/strategies/clqdr-balance-with-lp/examples.json b/src/strategies/clqdr-balance-with-lp/examples.json new file mode 100644 index 000000000..e497c6675 --- /dev/null +++ b/src/strategies/clqdr-balance-with-lp/examples.json @@ -0,0 +1,35 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "clqdr-balance-with-lp", + "params": { + "address": "0x814c66594a22404e101FEcfECac1012D8d75C156", + "symbol": "cLQDR", + "decimals": 18 + } + }, + "network": "250", + "addresses": [ + "0xf4c5b06ff9cd8f685ddcc58202597e56f1c0faee", + "0x70ECC7FecAea8D67e820035ED48c53706E7F2079", + "0xb5ae3c648709913ef9739e9f6edb5a821c6ab160", + "0x9675fe51fcfa05dbff4d027706f0a97b74fe5dc7", + "0x85644679fd440cd55c7046f2748ec5479cb3c3ab", + "0x1d5E65a087eBc3d03a294412E46CE5D6882969f4", + "0x1f254336E5c46639A851b9CfC165697150a6c327", + "0x2ec3F80BeDA63Ede96BA20375032CDD3aAfb3030", + "0x4AcBcA6BE2f8D2540bBF4CA77E45dA0A4a095Fa2", + "0x4F3D348a6D09837Ae7961B1E0cEe2cc118cec777", + "0x6D7f23A509E212Ba7773EC1b2505d1A134f54fbe", + "0x07a1f6fc89223c5ebD4e4ddaE89Ac97629856A0f", + "0x8d5F05270da470e015b67Ab5042BDbE2D2FEFB48", + "0x8d07D225a769b7Af3A923481E1FdF49180e6A265", + "0x8f60501dE5b9b01F9EAf1214dbE1924aA97F7fd0", + "0x9B8e8dD9151260c21CB6D7cc59067cd8DF306D58", + "0x17ea92D6FfbAA1c7F6B117c1E9D0c88ABdc8b84C", + "0x38C0039247A31F3939baE65e953612125cB88268" + ], + "snapshot": 49467339 + } +] diff --git a/src/strategies/clqdr-balance-with-lp/index.ts b/src/strategies/clqdr-balance-with-lp/index.ts new file mode 100644 index 000000000..16c7d5290 --- /dev/null +++ b/src/strategies/clqdr-balance-with-lp/index.ts @@ -0,0 +1,138 @@ +import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller, multicall } from '../../utils'; + +export const author = 'LiquidDriver-finance'; +export const version = '0.0.1'; + +const liquidMasterAddress = '0x6e2ad6527901c9664f016466b8DA1357a004db0f' +const beetsMasterAddress = '0x8166994d9ebBe5829EC86Bd81258149B87faCfd3' +const lpAddress = '0xEAdCFa1F34308b144E96FcD7A07145E027A8467d' +const beetsVaultAddress = '0x20dd72Ed959b6147912C2e529F0a0C651c33c9ce' +const clqdrPoolId = '0xeadcfa1f34308b144e96fcd7a07145e027a8467d000000000000000000000331' + +const contractAbi = [ + 'function userInfo(uint256, address) view returns (uint256 amount, int256 rewardDebt)', + 'function totalSupply() view returns (uint256)', + 'function balanceOf(address _owner) view returns (uint256 balance)', + 'function getPoolTokens(bytes32 poolId) view returns (uint256[], uint256[], uint256)', + 'function getVirtualSupply() external view returns (uint256)', +] + +const bn = (num: any): BigNumber => { + return BigNumber.from(num.toString()); +}; + +const addUserBalance = (userBalances, user: string, balance) => { + if (userBalances[user]) { + return (userBalances[user] = userBalances[user].add(balance)); + } else { + return (userBalances[user] = balance); + } +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const res = await multicall( + network, + provider, + contractAbi, + [ + [beetsVaultAddress, 'getPoolTokens', [clqdrPoolId]], + [lpAddress, 'getVirtualSupply', []], + ], + { blockTag } + ); + + const totalClqdrInBeets = bn(res[0][1][1]); + + const virtualSupply = bn(res[1]); + + const userCLqdrBalances: any = []; + for (let i = 0; i < addresses.length - 1; i++) { + userCLqdrBalances[addresses[i]] = bn(0); + } + + const clqdrMulti = new Multicaller(network, provider, contractAbi, { blockTag }); + addresses.forEach((address) => + clqdrMulti.call(address, options.address, 'balanceOf', [address]) + ); + const clqdrToken: Record = await clqdrMulti.execute(); + + Object.fromEntries( + Object.entries(clqdrToken).map(([address, balance]) => { + return addUserBalance(userCLqdrBalances, address, balance); + }) + ); + + const userLpBalances: any = []; + for (let i = 0; i < addresses.length - 1; i++) { + userLpBalances[addresses[i]] = bn(0); + } + + const multi = new Multicaller(network, provider, contractAbi, { blockTag }); + addresses.forEach((address) => + multi.call(address, lpAddress, 'balanceOf', [address]) + ); + const resultToken: Record = await multi.execute(); + + Object.fromEntries( + Object.entries(resultToken).map(([address, balance]) => { + return addUserBalance(userLpBalances, address, balance); + }) + ); + + const multiLiquidMaster = new Multicaller(network, provider, contractAbi, { + blockTag + }); + + addresses.forEach((address) => + multiLiquidMaster.call(address, liquidMasterAddress, 'userInfo', ['43', address]) + ); + const resultLiquidMaster: Record = + await multiLiquidMaster.execute(); + + Object.fromEntries( + Object.entries(resultLiquidMaster).map(([address, balance]) => { + return addUserBalance(userLpBalances, address, balance[0]); + }) + ); + + const multiBeetsMaster = new Multicaller(network, provider, contractAbi, { + blockTag + }); + + addresses.forEach((address) => + multiBeetsMaster.call(address, beetsMasterAddress, 'userInfo', ['69', address]) + ); + const resultBeetsMaster: Record = + await multiBeetsMaster.execute(); + + Object.fromEntries( + Object.entries(resultBeetsMaster).map(([address, balance]) => { + return addUserBalance(userLpBalances, address, balance[0]); + }) + ); + + return Object.fromEntries( + Object.entries(userLpBalances).map(([address, balance]) => { + // @ts-ignore + const clqdrBalanceInLp = totalClqdrInBeets.mul(balance).div(virtualSupply); + const totalBalance = userCLqdrBalances[address].add(clqdrBalanceInLp); + return [ + address, + // @ts-ignore + parseFloat(formatUnits(totalBalance, options.decimals)) + ] + }) + ); +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index cf66a052a..a1cbbf305 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -382,6 +382,8 @@ import * as erc20TokensPerUni from './erc20-tokens-per-uni'; import * as bancorStandardRewardsUnderlyingBalance from './bancor-standard-rewards-underlying-balance'; import * as sdVoteBoost from './sd-vote-boost'; import * as sdVoteBoostTWAVP from './sd-vote-boost-twavp'; +import * as clqdrBalanceWithLp from './clqdr-balance-with-lp'; + const strategies = { 'forta-shares': fortaShares, @@ -768,7 +770,8 @@ const strategies = { 'bancor-standard-rewards-underlying-balance': bancorStandardRewardsUnderlyingBalance, 'sd-vote-boost': sdVoteBoost, - 'sd-vote-boost-twavp': sdVoteBoostTWAVP + 'sd-vote-boost-twavp': sdVoteBoostTWAVP, + 'clqdr-balance-with-lp': clqdrBalanceWithLp }; Object.keys(strategies).forEach(function (strategyName) { From df8c8dcf1ca60b0da14976ba0f2360b2ac405aeb Mon Sep 17 00:00:00 2001 From: vpoklopic <78506565+vpoklopic@users.noreply.github.com> Date: Thu, 20 Oct 2022 09:44:16 +0200 Subject: [PATCH 168/815] [thales] Update subgraph link for Thales strategy (#892) * Thales strategy * Change Thales strategy to pull data from OP mainnet * Update src/strategies/thales/index.ts Co-authored-by: Chaitanya * Update subgraph link for Thales strategy * Update src/strategies/thales/index.ts Co-authored-by: Chaitanya Co-authored-by: Chaitanya --- src/strategies/thales/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/strategies/thales/index.ts b/src/strategies/thales/index.ts index 8da37635b..9c6846e1e 100644 --- a/src/strategies/thales/index.ts +++ b/src/strategies/thales/index.ts @@ -3,10 +3,10 @@ import { formatUnits } from '@ethersproject/units'; import { subgraphRequest } from '../../utils'; export const author = 'vpoklopic'; -export const version = '1.0.1'; +export const version = '1.0.2'; const THALES_SUBGRAPH_URL = - 'https://api.thegraph.com/subgraphs/name/thales-markets/thales-optimism'; + 'https://api.thegraph.com/subgraphs/name/thales-markets/thales-token'; export async function strategy( _space, From 755abc1e0b818ee3eed9130b6b1ccf999da02cc6 Mon Sep 17 00:00:00 2001 From: Fabien Date: Thu, 20 Oct 2022 17:48:57 +0700 Subject: [PATCH 169/815] Refactor validations to class and change params (#891) * Add getVp and getDelegations functions * Update dependencies * Export functions getVp and getDelegations * Remove unused file * Add validations strategies * Add test for validation * Add pkg script for validation test * Refactor validation to class and change params * Add 'latest' in snapshot type Co-authored-by: Chaitanya --- src/utils/vp.ts | 4 +- src/validations/aave/examples.json | 29 ++------ src/validations/aave/index.ts | 95 +++++++++++------------- src/validations/basic/examples.json | 17 +++-- src/validations/basic/index.ts | 50 ++++++------- src/validations/nouns/examples.json | 29 ++------ src/validations/nouns/index.ts | 89 +++++++++++----------- src/validations/timeperiod/examples.json | 15 ++-- src/validations/timeperiod/index.ts | 35 ++++----- src/validations/validation.ts | 29 ++++++++ test/validation.test.ts | 28 ++++--- 11 files changed, 199 insertions(+), 221 deletions(-) create mode 100644 src/validations/validation.ts diff --git a/src/utils/vp.ts b/src/utils/vp.ts index ad61e31da..3eff86e14 100644 --- a/src/utils/vp.ts +++ b/src/utils/vp.ts @@ -1,5 +1,6 @@ import { formatBytes32String } from '@ethersproject/strings'; import { getAddress } from '@ethersproject/address'; +import subgraphs from '@snapshot-labs/snapshot.js/src/delegationSubgraphs.json'; import { getProvider, getSnapshots, @@ -7,7 +8,6 @@ import { subgraphRequest } from '../utils'; import _strategies from '../strategies'; -import subgraphs from '@snapshot-labs/snapshot.js/src/delegationSubgraphs.json'; const DELEGATION_CONTRACT = '0x469788fE6E9E9681C6ebF3bF78e7Fd26Fc015446'; const EMPTY_ADDRESS = '0x0000000000000000000000000000000000000000'; @@ -25,7 +25,7 @@ export async function getVp( strategies: any[], snapshot: number | 'latest', space: string, - delegation: boolean + delegation?: boolean ) { const networks = [...new Set(strategies.map((s) => s.network || network))]; const snapshots = await getSnapshots( diff --git a/src/validations/aave/examples.json b/src/validations/aave/examples.json index 4a1322ec2..03c17b080 100644 --- a/src/validations/aave/examples.json +++ b/src/validations/aave/examples.json @@ -1,31 +1,12 @@ [ { "name": "Example of Aave Proposition Power proposal validation", - "validation": { - "name": "aave", - "params": {} - }, + "author": "0x5BC928BF0DAb1e4A2ddd9e347b0F22e88026D76c", + "space": "aave.eth", "network": "1", - "userAddress": "0x5BC928BF0DAb1e4A2ddd9e347b0F22e88026D76c", - "space": { - "name": "Aave", - "skin": "aave", - "admins": [ - "0x8d07D225a769b7Af3A923481E1FdF49180e6A265", - "0xc8E0345596D7196941E61D3aB607E57Fe61F85E7" - ], - "avatar": "ipfs://QmRKgfxSiCU3EmkN52ZaxgKvDyPFUR5DdPvnKxwyLRncKS", - "domain": "signal.aave.com", - "github": "aave", - "symbol": "AAVE", - "filters": { - "minScore": 1, - "onlyMembers": false - }, - "members": [], - "network": "1", - "plugins": {}, - "twitter": "AaveAave", + "snapshot": "latest", + "params": { + "minScore": 1, "strategies": [ { "name": "erc20-balance-of", diff --git a/src/validations/aave/index.ts b/src/validations/aave/index.ts index 8408a2bdf..4344d7147 100644 --- a/src/validations/aave/index.ts +++ b/src/validations/aave/index.ts @@ -1,55 +1,50 @@ +import Validation from '../validation'; import { getProvider, getScoresDirect } from '../../utils'; -export const author = 'kartojal'; -export const version = '0.1.0'; - -/** - * Aave Space Validation proposal validation uses: - * - Proposition power of GovernanceStrategy contract - * - Other active Aave Snapshot voting strategies - * - * The current validation implementation mutates the "strategies" field of the space - * to be able to use proposition power instead of voting power for "aave-governance-power". - * - */ - -export default async function validate( - author: string, - space, - proposal, - options -): Promise { - const onlyMembers = options.onlyMembers || space.filters?.onlyMembers; - const minScore = options.minScore || space.filters?.minScore; - const members = (space.members || []).map((address) => address.toLowerCase()); - const strategies = [...space.strategies]; - - const aaveGovernanceStrategyIndex = strategies.findIndex( - ({ name }) => name === 'aave-governance-power' - ); - - // Use the proposition power instead of voting power - if (aaveGovernanceStrategyIndex >= 0) { - strategies[aaveGovernanceStrategyIndex].params.powerType = 'proposition'; - } - - if (members.includes(author.toLowerCase())) return true; - - if (onlyMembers) return false; - - if (minScore) { - const scores = await getScoresDirect( - space.id || space.key, - strategies, - space.network, - getProvider(space.network), - [author] +export default class extends Validation { + public id = 'aave'; + public github = 'kartojal'; + public version = '0.2.0'; + + /** + * Aave Space Validation proposal validation uses: + * - Proposition power of GovernanceStrategy contract + * - Other active Aave Snapshot voting strategies + * + * The current validation implementation mutates the "strategies" field of the space + * to be able to use proposition power instead of voting power for "aave-governance-power". + * + */ + async validate(): Promise { + const minScore = this.params.minScore; + const strategies = this.params.strategies; + + const aaveGovernanceStrategyIndex = strategies.findIndex( + ({ name }) => name === 'aave-governance-power' ); - const totalScore: any = scores - .map((score: any) => Object.values(score).reduce((a, b: any) => a + b, 0)) - .reduce((a, b: any) => a + b, 0); - if (totalScore < minScore) return false; - } - return true; + // Use the proposition power instead of voting power + if (aaveGovernanceStrategyIndex >= 0) { + strategies[aaveGovernanceStrategyIndex].params.powerType = 'proposition'; + } + + if (minScore) { + const scores = await getScoresDirect( + this.space, + strategies, + this.network, + getProvider(this.network), + [this.author], + this.snapshot || 'latest' + ); + const totalScore: any = scores + .map((score: any) => + Object.values(score).reduce((a, b: any) => a + b, 0) + ) + .reduce((a, b: any) => a + b, 0); + if (totalScore < minScore) return false; + } + + return true; + } } diff --git a/src/validations/basic/examples.json b/src/validations/basic/examples.json index 0dcf2b063..1dd454cc2 100644 --- a/src/validations/basic/examples.json +++ b/src/validations/basic/examples.json @@ -1,11 +1,18 @@ [ { "name": "Example of a basic proposal validation", - "validation": { - "name": "basic", - "params": {} - }, + "author": "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", + "space": "fabien.eth", "network": "1", - "userAddress": "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7" + "snapshot": "latest", + "params": { + "minScore": 1, + "strategies": [ + { + "name": "ticket", + "params": {} + } + ] + } } ] diff --git a/src/validations/basic/index.ts b/src/validations/basic/index.ts index 92104f866..2e0886217 100644 --- a/src/validations/basic/index.ts +++ b/src/validations/basic/index.ts @@ -1,33 +1,31 @@ +import Validation from '../validation'; import { getProvider, getScoresDirect } from '../../utils'; -export default async function validate( - author: string, - space, - proposal, - options -): Promise { - const strategies = options.strategies || space.strategies; - const onlyMembers = options.onlyMembers || space.filters?.onlyMembers; - const minScore = options.minScore || space.filters?.minScore; - const members = (space.members || []).map((address) => address.toLowerCase()); +export default class extends Validation { + public id = 'basic'; + public github = 'bonustrack'; + public version = '0.2.0'; - if (members.includes(author.toLowerCase())) return true; + async validate(): Promise { + const minScore = this.params.minScore; - if (onlyMembers) return false; + if (minScore) { + const scores = await getScoresDirect( + this.space, + this.params.strategies, + this.network, + getProvider(this.network), + [this.author], + this.snapshot || 'latest' + ); + const totalScore: any = scores + .map((score: any) => + Object.values(score).reduce((a, b: any) => a + b, 0) + ) + .reduce((a, b: any) => a + b, 0); + if (totalScore < minScore) return false; + } - if (minScore) { - const scores = await getScoresDirect( - space.id || space.key, - strategies, - space.network, - getProvider(space.network), - [author] - ); - const totalScore: any = scores - .map((score: any) => Object.values(score).reduce((a, b: any) => a + b, 0)) - .reduce((a, b: any) => a + b, 0); - if (totalScore < minScore) return false; + return true; } - - return true; } diff --git a/src/validations/nouns/examples.json b/src/validations/nouns/examples.json index 0e9a3c96d..75c558f21 100644 --- a/src/validations/nouns/examples.json +++ b/src/validations/nouns/examples.json @@ -1,31 +1,12 @@ [ { "name": "Example of Nouns Proposition Power proposal validation", - "validation": { - "name": "nouns", - "params": {} - }, + "author": "0x03CD30Ab7b6eFaDfdc5D49Ec2B83DDD6a898e054", + "space": "nouns.eth", "network": "4", - "userAddress": "0x03CD30Ab7b6eFaDfdc5D49Ec2B83DDD6a898e054", - "space": { - "name": "Nouns", - "skin": "nouns", - "admins": [ - "0xe6bcaacdca149114446612255cc4721bf7261b5b", - "0xC4D2f3231879A26A2cAB5F1783D8a65f6B7191bE" - ], - "avatar": "ipfs://QmRKdsssCU3EmkN52ZaxgKvDyPFUR5DdPvnKxwyLRncKS", - "domain": "signal.nouns.com", - "github": "nouns", - "symbol": "NOUNS", - "filters": { - "minScore": 1, - "onlyMembers": false - }, - "members": [], - "network": "4", - "plugins": {}, - "twitter": "NounishNounlet", + "snapshot": "latest", + "params": { + "minScore": 1, "strategies": [ { "name": "erc20-balance-of", diff --git a/src/validations/nouns/index.ts b/src/validations/nouns/index.ts index df395cf23..3630c7ff7 100644 --- a/src/validations/nouns/index.ts +++ b/src/validations/nouns/index.ts @@ -1,52 +1,47 @@ +import Validation from '../validation'; import { getProvider, getScoresDirect } from '../../utils'; -export const author = 'waterdrops'; -export const version = '0.1.0'; - -/** - * Nouns Space Validation proposal validation uses: - * - * The current validation implementation mutates the "strategies" field of the space - * to be able to use proposition power instead of voting power for "nouns-rfp-power". - * - */ - -export default async function validate( - author: string, - space, - proposal, - options -): Promise { - const onlyMembers = options.onlyMembers || space.filters?.onlyMembers; - const minScore = options.minScore || space.filters?.minScore; - const members = (space.members || []).map((address) => address.toLowerCase()); - const strategies = [...space.strategies]; - - const nounsRFPStrategyIndex = strategies.findIndex( - ({ name }) => name === 'nouns-rfp-power' - ); - - // Use the proposition power instead of the voting power - if (nounsRFPStrategyIndex >= 0) - strategies[nounsRFPStrategyIndex].params.powerType = 'proposition'; - - if (members.includes(author.toLowerCase())) return true; - - if (onlyMembers) return false; - - if (minScore) { - const scores = await getScoresDirect( - space.id || space.key, - strategies, - space.network, - getProvider(space.network), - [author] +export default class extends Validation { + public id = 'nouns'; + public github = 'waterdrops'; + public version = '0.2.0'; + + /** + * Nouns Space Validation proposal validation uses: + * + * The current validation implementation mutates the "strategies" field of the space + * to be able to use proposition power instead of voting power for "nouns-rfp-power". + * + */ + async validate(): Promise { + const minScore = this.params.minScore; + const strategies = this.params.strategies; + + const nounsRFPStrategyIndex = strategies.findIndex( + ({ name }) => name === 'nouns-rfp-power' ); - const totalScore: any = scores - .map((score: any) => Object.values(score).reduce((a, b: any) => a + b, 0)) - .reduce((a, b: any) => a + b, 0); - if (totalScore < minScore) return false; - } - return true; + // Use the proposition power instead of the voting power + if (nounsRFPStrategyIndex >= 0) + strategies[nounsRFPStrategyIndex].params.powerType = 'proposition'; + + if (minScore) { + const scores = await getScoresDirect( + this.space, + strategies, + this.network, + getProvider(this.network), + [this.author], + this.snapshot || 'latest' + ); + const totalScore: any = scores + .map((score: any) => + Object.values(score).reduce((a, b: any) => a + b, 0) + ) + .reduce((a, b: any) => a + b, 0); + if (totalScore < minScore) return false; + } + + return true; + } } diff --git a/src/validations/timeperiod/examples.json b/src/validations/timeperiod/examples.json index 02381e38e..92e7d8c56 100644 --- a/src/validations/timeperiod/examples.json +++ b/src/validations/timeperiod/examples.json @@ -1,14 +1,13 @@ [ { "name": "Example of a prop entry time constrained validation", - "validation": { - "name": "timeperiod", - "params": { - "propEntryStart": 1659108444521, - "propEntryEnd": 1659194844521 - } - }, + "author": "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", + "space": "fabien.eth", "network": "1", - "userAddress": "" + "snapshot": "latest", + "params": { + "propEntryStart": 1659108444521, + "propEntryEnd": 1659194844521 + } } ] diff --git a/src/validations/timeperiod/index.ts b/src/validations/timeperiod/index.ts index 91f69e86d..c31a95b4b 100644 --- a/src/validations/timeperiod/index.ts +++ b/src/validations/timeperiod/index.ts @@ -1,26 +1,21 @@ -export default async function validate( - author: string, - space, - proposal, - options -): Promise { - const onlyMembers = options.onlyMembers || space.filters?.onlyMembers; - const members = (space.members || []).map((address) => address.toLowerCase()); - const { propEntryStart = 0, propEntryEnd = 0 } = options; +import Validation from '../validation'; - if (!propEntryStart || !propEntryEnd || propEntryStart >= propEntryEnd) - return false; +export default class extends Validation { + public id = 'timeperiod'; + public github = 'stevef'; + public version = '0.2.0'; - if (members.includes(author.toLowerCase())) return true; + async validate(): Promise { + const { propEntryStart = 0, propEntryEnd = 0 } = this.params; - if (onlyMembers) return false; + if (!propEntryStart || !propEntryEnd || propEntryStart >= propEntryEnd) + return false; - const now = new Date().getTime(); - const startTime = new Date(propEntryStart).getTime(); - const endTime = new Date(propEntryEnd).getTime(); + const now = new Date().getTime(); + const startTime = new Date(propEntryStart).getTime(); + const endTime = new Date(propEntryEnd).getTime(); - // Only allow proposals being submitted in this time window. - if (now >= startTime && now <= endTime) return true; - - return false; + // Only allow proposals being submitted in this time window. + return now >= startTime && now <= endTime; + } } diff --git a/src/validations/validation.ts b/src/validations/validation.ts new file mode 100644 index 000000000..34c28bcc3 --- /dev/null +++ b/src/validations/validation.ts @@ -0,0 +1,29 @@ +export default class Validation { + public id = ''; + public github = ''; + public version = ''; + + public author: string; + public space: string; + public network: string; + public snapshot: number | 'latest'; + public params: any; + + constructor( + author: string, + space: string, + network: string, + snapshot: number | 'latest', + params: any + ) { + this.author = author; + this.space = space; + this.network = network; + this.snapshot = snapshot; + this.params = params; + } + + async validate(): Promise { + return true; + } +} diff --git a/test/validation.test.ts b/test/validation.test.ts index 1a5729717..54f7f7533 100644 --- a/test/validation.test.ts +++ b/test/validation.test.ts @@ -1,20 +1,18 @@ import snapshot from '../src'; -import examples from '../src/validations/aave/examples.json'; +import examples from '../src/validations/basic/examples.json'; -const name = examples[0].validation.name; -const params = examples[0].validation.params || {}; -const author = examples[0].userAddress; -const space = examples[0].space; -const proposal = {}; +const [example] = examples; +const id = 'basic'; -describe('', () => { - it('validation', async () => { - const validation = await snapshot.validations[name]( - author, - space, - proposal, - params +describe('validation', () => { + it(`validate: ${id} "${example.name}"`, async () => { + const validation = new snapshot.validations[id]( + example.author, + example.space, + example.network, + 'latest', + example.params ); - expect(validation).toMatchSnapshot(); - }, 20e3); + expect(await validation.validate()).toBe(true); + }, 10e3); }); From 4fc26f41cbd93e7c9f5e11ef33ff17d57145e070 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Fri, 21 Oct 2022 04:10:21 +0530 Subject: [PATCH 170/815] Passport validation (#895) * Passport validation * Fix build issues * Clean Co-authored-by: bonustrack --- package.json | 4 +- src/validations/index.ts | 4 +- src/validations/passport/examples.json | 19 ++++++ src/validations/passport/helper.ts | 81 ++++++++++++++++++++++++++ src/validations/passport/index.ts | 29 +++++++++ test/validation.test.ts | 4 +- yarn.lock | 63 ++++++++++++++++++++ 7 files changed, 200 insertions(+), 4 deletions(-) create mode 100644 src/validations/passport/examples.json create mode 100644 src/validations/passport/helper.ts create mode 100644 src/validations/passport/index.ts diff --git a/package.json b/package.json index 8cf3848eb..aaf4d887a 100755 --- a/package.json +++ b/package.json @@ -35,12 +35,14 @@ "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", "@snapshot-labs/snapshot.js": "^0.4.40", + "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", "copyfiles": "^2.4.1", "cross-fetch": "^3.1.5", "eth-ens-namehash": "^2.0.8", - "json-to-graphql-query": "^2.2.4" + "json-to-graphql-query": "^2.2.4", + "tulons": "^0.0.7" }, "devDependencies": { "@types/jest": "^28.1.4", diff --git a/src/validations/index.ts b/src/validations/index.ts index 419465fb8..6fbd4764b 100644 --- a/src/validations/index.ts +++ b/src/validations/index.ts @@ -2,10 +2,12 @@ import basic from './basic'; import aave from './aave'; import nouns from './nouns'; import timeperiod from './timeperiod'; +import passport from './passport'; export default { basic, aave, nouns, - timeperiod + timeperiod, + passport }; diff --git a/src/validations/passport/examples.json b/src/validations/passport/examples.json new file mode 100644 index 000000000..23548fe9b --- /dev/null +++ b/src/validations/passport/examples.json @@ -0,0 +1,19 @@ +[ + { + "name": "Example of a passport proposal validation", + "author": "0x24F15402C6Bb870554489b2fd2049A85d75B982f", + "space": "fabien.eth", + "network": "1", + "snapshot": "latest", + "params": { + "stamps": [ + { "id": "Ens", "weight": 2 }, + { "id": "Twitter", "weight": 0.5 }, + { "id": "GitHub", "weight": 0.5 }, + { "id": "POAP", "weight": 2 }, + { "id": "SnapshotVotesProvider", "weight": 2 } + ], + "min_weight": 1 + } + } +] diff --git a/src/validations/passport/helper.ts b/src/validations/passport/helper.ts new file mode 100644 index 000000000..c4ca2cba7 --- /dev/null +++ b/src/validations/passport/helper.ts @@ -0,0 +1,81 @@ +import DIDKit from '@spruceid/didkit-wasm-node/didkit_wasm'; +import { Tulons } from 'tulons'; + +const CERAMIC_URL = 'https://ceramic.passport-iam.gitcoin.co'; +const CERAMIC_NETWORK_ID = 1; + +export const getPassport = async (address) => { + // Ceramic connection details + + // Ceramic definition ids on the Ceramic account model + const CERAMIC_GITCOIN_PASSPORT_STREAM_ID = + 'kjzl6cwe1jw148h1e14jb5fkf55xmqhmyorp29r9cq356c7ou74ulowf8czjlzs'; + const tulons = new Tulons(CERAMIC_URL, CERAMIC_NETWORK_ID); + + // Ceramic data is stored as address -> DID -> Genesis/IDX Stream -> Data Stream + const { streams } = await tulons.getGenesis(address); + if (streams[CERAMIC_GITCOIN_PASSPORT_STREAM_ID]) { + return await tulons.getHydrated( + await tulons.getStream(streams[CERAMIC_GITCOIN_PASSPORT_STREAM_ID]) + ); + } + return false; +}; + +export const getVerifiedStamps = async (passport, address, stampsRequired) => { + if (!passport) return false; + + const stamps = passport.stamps || []; + + // filter out stamps with stampsRequired + const stampsFiltered = stamps.filter((stamp) => + stampsRequired.map((a) => a.id).includes(stamp.provider) + ); + + // verify stamps + let stampsVerified = await Promise.all( + stampsFiltered.map(async (stamp) => verifyStamp(stamp, address)) + ); + stampsVerified = stampsVerified.filter((s) => s.verified); + return stampsVerified; +}; + +const verifyStamp = async (stamp, address) => { + // given the stamp exists... + if (stamp) { + stamp.verified = true; + const stampAddress = stamp.credential.credentialSubject.id + .replace(`did:pkh:eip155:${CERAMIC_NETWORK_ID}:`, '') + .toLowerCase(); + + stamp.verified = + stampAddress !== address.toLowerCase() ? false : stamp.verified; + + // finally verify that the credential verifies with DIDKit + if (stamp.verified) { + stamp.verified = await verifyCredential(stamp.credential); + } + } + + return stamp; +}; + +const verifyCredential = async (credential) => { + const { expirationDate, proof } = credential; + + // check that the credential is still valid (not expired) + if (new Date(expirationDate) > new Date()) { + try { + const verify = JSON.parse( + await DIDKit.verifyCredential( + JSON.stringify(credential), + `{"proofPurpose":"${proof.proofPurpose}"}` + ) + ) as { checks: string[]; warnings: string[]; errors: string[] }; + return verify.errors.length === 0; + } catch (e) { + return false; + } + } + return false; +}; diff --git a/src/validations/passport/index.ts b/src/validations/passport/index.ts new file mode 100644 index 000000000..91331009f --- /dev/null +++ b/src/validations/passport/index.ts @@ -0,0 +1,29 @@ +import Validation from '../validation'; +import { getPassport, getVerifiedStamps } from './helper'; + +export default class extends Validation { + public id = 'passport'; + public github = 'snapshot-labs'; + public version = '0.1.0'; + + async validate(): Promise { + const passport: any = await getPassport(this.author); + if (!passport) return false; + if (!passport.stamps || !this.params.stamps) return false; + + const verifiedStamps: false | any[] = await getVerifiedStamps( + passport, + this.author, + this.params.stamps + ); + if (!verifiedStamps) return false; + + let weight = 0; + this.params.stamps.forEach((stamp: any) => { + const found = verifiedStamps.find((s: any) => s.provider === stamp.id); + if (found?.verified) weight += stamp.weight; + }); + + return weight >= this.params.min_weight; + } +} diff --git a/test/validation.test.ts b/test/validation.test.ts index 54f7f7533..c970880a7 100644 --- a/test/validation.test.ts +++ b/test/validation.test.ts @@ -1,8 +1,8 @@ import snapshot from '../src'; -import examples from '../src/validations/basic/examples.json'; +import examples from '../src/validations/passport/examples.json'; const [example] = examples; -const id = 'basic'; +const id = 'passport'; describe('validation', () => { it(`validate: ${id} "${example.name}"`, async () => { diff --git a/yarn.lock b/yarn.lock index 31807d753..e285c565b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1181,6 +1181,11 @@ json-to-graphql-query "^2.2.4" lodash.set "^4.3.2" +"@spruceid/didkit-wasm-node@^0.2.1": + version "0.2.1" + resolved "https://registry.yarnpkg.com/@spruceid/didkit-wasm-node/-/didkit-wasm-node-0.2.1.tgz#85f7023979b4ef84bd6de16c79c67b6e9a08e1db" + integrity sha512-c8e3u5FIRS/2Gf6UHnRPnfRozgKgby4avZzlvIiaJRDVLl1LaX1SE13vEvKV2rAq6NMfZrV4YG908M4uVlT90Q== + "@types/babel__core@^7.1.14": version "7.1.19" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.19.tgz#7b497495b7d1b4812bdb9d02804d0576f43ee460" @@ -1572,6 +1577,19 @@ array.prototype.flat@^1.2.5: define-properties "^1.1.3" es-abstract "^1.19.0" +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +axios@^0.27.2: + version "0.27.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972" + integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ== + dependencies: + follow-redirects "^1.14.9" + form-data "^4.0.0" + babel-jest@^28.1.2: version "28.1.2" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-28.1.2.tgz#2b37fb81439f14d34d8b2cc4a4bd7efabf9acbfe" @@ -1835,6 +1853,13 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -1934,6 +1959,11 @@ define-properties@^1.1.3: dependencies: object-keys "^1.0.12" +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + detect-newline@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" @@ -2355,6 +2385,20 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.6.tgz#022e9218c637f9f3fc9c35ab9c9193f05add60b2" integrity sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ== +follow-redirects@^1.14.9: + version "1.15.2" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" + integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== + +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -3315,6 +3359,18 @@ micromatch@^4.0.4: braces "^3.0.1" picomatch "^2.2.3" +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" @@ -4050,6 +4106,13 @@ tsutils@^3.21.0: dependencies: tslib "^1.8.1" +tulons@^0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/tulons/-/tulons-0.0.7.tgz#31677402ab51dc51478d375f90df76ea2ca8cbb9" + integrity sha512-JyL9Vn4PPG2TTEJS35yqQgAMLd3IX9pFIlbiLmv47HuHTo2F3ihYg2yfMqde4hqGY1nGk77iJ/lvsTbAURJ8rg== + dependencies: + axios "^0.27.2" + type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" From 48bf90d0419e7c76b8c340cfae6beebec5259b0f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 21 Oct 2022 15:08:06 +0530 Subject: [PATCH 171/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.41 (#893) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index aaf4d887a..6767a02a1 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.40", + "@snapshot-labs/snapshot.js": "^0.4.41", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index e285c565b..341585c6e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.40": - version "0.4.40" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.40.tgz#64dcea55c3f349470c2470d9fd520deeef7d1973" - integrity sha512-/6VHbDZANx36c4nMCiPrg3LR52jjysow+F/79lp7h8B3sNHMqHCTDmheBM6pTguQ3+cCgfKLOrZn62C9laQW2A== +"@snapshot-labs/snapshot.js@^0.4.41": + version "0.4.41" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.41.tgz#7bdcaacdabf39cdb8e985affdbd4ad0b0c254084" + integrity sha512-xH4HUW1PRtnjo6BUsCHb0ZtXPYgPnzi1xZPRRq2VVWixQpgRWs3VVBXjmV6LfhlGDkjmoBX2mIh9M+kgdDsQsw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From b79197727cfba0f7bd7807dfd24077e687382b31 Mon Sep 17 00:00:00 2001 From: Michael Otis <34221002+michaelotis@users.noreply.github.com> Date: Sat, 22 Oct 2022 13:12:25 -0500 Subject: [PATCH 172/815] Add strategy [single-staking-autocompound-balanceof] (#894) * Create new strategy for autocompounding vault * Apply suggestions from code review Co-authored-by: Chaitanya Co-authored-by: Chaitanya --- src/strategies/index.ts | 2 + .../README.md | 12 +++++ .../examples.json | 19 ++++++++ .../index.ts | 48 +++++++++++++++++++ 4 files changed, 81 insertions(+) create mode 100644 src/strategies/single-staking-autocompound-balanceof/README.md create mode 100644 src/strategies/single-staking-autocompound-balanceof/examples.json create mode 100644 src/strategies/single-staking-autocompound-balanceof/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index a1cbbf305..385bab68a 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -204,6 +204,7 @@ import * as flexaCapacityStaking from './flexa-capacity-staking'; import * as sunriseGamingUniv2Lp from './sunrisegaming-univ2-lp'; import * as sunriseGamingStaking from './sunrisegaming-staking'; import * as sUmamiHolders from './sumami-holders'; +import * as singleStakingAutoCompoundBalanceOf from './single-staking-autocompound-balanceof'; import * as singleStakingPoolsBalanceOf from './single-staking-pools-balanceof'; import * as occStakeOf from './occ-stake-of'; import * as hoprStaking from './hopr-staking'; @@ -593,6 +594,7 @@ const strategies = { 'flexa-capacity-staking': flexaCapacityStaking, 'sunrisegaming-univ2-lp': sunriseGamingUniv2Lp, 'sunrisegaming-staking': sunriseGamingStaking, + 'single-staking-autocompound-balanceof': singleStakingAutoCompoundBalanceOf, 'single-staking-pools-balanceof': singleStakingPoolsBalanceOf, 'hopr-staking': hoprStaking, 'hopr-staking-s2': hoprStakingS2, diff --git a/src/strategies/single-staking-autocompound-balanceof/README.md b/src/strategies/single-staking-autocompound-balanceof/README.md new file mode 100644 index 000000000..b64b32d14 --- /dev/null +++ b/src/strategies/single-staking-autocompound-balanceof/README.md @@ -0,0 +1,12 @@ +# single-staking-autocompound-balanceof + +Used for fetching the staked token balance in an autocompounding single staking pool + +Here is an example of parameters: + +```json +{ + "stakingPoolAddress": "0xC122d1F67bbC3e40aec198C54B9eC13E1b0990eC", + "decimals": 18 +} +``` diff --git a/src/strategies/single-staking-autocompound-balanceof/examples.json b/src/strategies/single-staking-autocompound-balanceof/examples.json new file mode 100644 index 000000000..2e9f77227 --- /dev/null +++ b/src/strategies/single-staking-autocompound-balanceof/examples.json @@ -0,0 +1,19 @@ +[ + { + "name": "Single Staking Amount from Autocompounding Vault", + "strategy": { + "name": "single-staking-autocompound-balanceof", + "params": { + "stakingPoolAddress": "0xC122d1F67bbC3e40aec198C54B9eC13E1b0990eC", + "symbol": "FUZZ", + "decimals": 18 + } + }, + "network": "1666600000", + "addresses": [ + "0x12e49d93588e0056bd25530C3B1E8AAc68F4B70a", + "0x8C612B03b3358C1E535706695c635C360034B968", + "0x24d19f100ba142543a863fc2294b188e35ab55b9"], + "snapshot": 32877171 + } +] diff --git a/src/strategies/single-staking-autocompound-balanceof/index.ts b/src/strategies/single-staking-autocompound-balanceof/index.ts new file mode 100644 index 000000000..b1c445e38 --- /dev/null +++ b/src/strategies/single-staking-autocompound-balanceof/index.ts @@ -0,0 +1,48 @@ +/* eslint-disable prettier/prettier */ +import { formatUnits } from '@ethersproject/units'; +import { multicall, Multicaller } from '../../utils'; + +export const author = 'michaelotis'; +export const version = '0.1.0'; +export const dependOnOtherAddress = false; + +const abi = [ + 'function userInfo(address) view returns (uint256 shares, uint256 lastDepositedTime, uint256 fuzzAtLastUserAction, uint256 lastUserActionTime)', + 'function getPricePerFullShare() view returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multi = new Multicaller(network, provider, abi, { blockTag }); + + addresses.forEach((address) => + multi.call(address, options.stakingPoolAddress, 'userInfo', [address]) + ); + + const [[[getPricePerFullShare]]] = await Promise.all([ + multicall( + network, + provider, + abi, + [[options.stakingPoolAddress, 'getPricePerFullShare', []]], + { blockTag } + ) + ]); + + const result: Record = await multi.execute(); + + return Object.fromEntries( + Object.entries(result).map(([address, userInfo]) => [ + address, + parseFloat(formatUnits(userInfo.shares, options.decimals)) * parseFloat(formatUnits(getPricePerFullShare, options.decimals)) + ]) + ); +} From 8515bf8e9a77d53594635ce5ba7402dee4cfa550 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 23 Oct 2022 23:16:30 +0530 Subject: [PATCH 173/815] Automated lint (#897) Co-authored-by: ChaituVR --- src/strategies/clqdr-balance-with-lp/index.ts | 40 ++++++++++++------- src/strategies/index.ts | 1 - .../examples.json | 7 ++-- 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/src/strategies/clqdr-balance-with-lp/index.ts b/src/strategies/clqdr-balance-with-lp/index.ts index 16c7d5290..66d2a26aa 100644 --- a/src/strategies/clqdr-balance-with-lp/index.ts +++ b/src/strategies/clqdr-balance-with-lp/index.ts @@ -5,19 +5,20 @@ import { Multicaller, multicall } from '../../utils'; export const author = 'LiquidDriver-finance'; export const version = '0.0.1'; -const liquidMasterAddress = '0x6e2ad6527901c9664f016466b8DA1357a004db0f' -const beetsMasterAddress = '0x8166994d9ebBe5829EC86Bd81258149B87faCfd3' -const lpAddress = '0xEAdCFa1F34308b144E96FcD7A07145E027A8467d' -const beetsVaultAddress = '0x20dd72Ed959b6147912C2e529F0a0C651c33c9ce' -const clqdrPoolId = '0xeadcfa1f34308b144e96fcd7a07145e027a8467d000000000000000000000331' +const liquidMasterAddress = '0x6e2ad6527901c9664f016466b8DA1357a004db0f'; +const beetsMasterAddress = '0x8166994d9ebBe5829EC86Bd81258149B87faCfd3'; +const lpAddress = '0xEAdCFa1F34308b144E96FcD7A07145E027A8467d'; +const beetsVaultAddress = '0x20dd72Ed959b6147912C2e529F0a0C651c33c9ce'; +const clqdrPoolId = + '0xeadcfa1f34308b144e96fcd7a07145e027a8467d000000000000000000000331'; const contractAbi = [ 'function userInfo(uint256, address) view returns (uint256 amount, int256 rewardDebt)', 'function totalSupply() view returns (uint256)', 'function balanceOf(address _owner) view returns (uint256 balance)', 'function getPoolTokens(bytes32 poolId) view returns (uint256[], uint256[], uint256)', - 'function getVirtualSupply() external view returns (uint256)', -] + 'function getVirtualSupply() external view returns (uint256)' +]; const bn = (num: any): BigNumber => { return BigNumber.from(num.toString()); @@ -29,7 +30,7 @@ const addUserBalance = (userBalances, user: string, balance) => { } else { return (userBalances[user] = balance); } -} +}; export async function strategy( space, @@ -39,7 +40,6 @@ export async function strategy( options, snapshot ): Promise> { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; const res = await multicall( @@ -48,7 +48,7 @@ export async function strategy( contractAbi, [ [beetsVaultAddress, 'getPoolTokens', [clqdrPoolId]], - [lpAddress, 'getVirtualSupply', []], + [lpAddress, 'getVirtualSupply', []] ], { blockTag } ); @@ -62,7 +62,9 @@ export async function strategy( userCLqdrBalances[addresses[i]] = bn(0); } - const clqdrMulti = new Multicaller(network, provider, contractAbi, { blockTag }); + const clqdrMulti = new Multicaller(network, provider, contractAbi, { + blockTag + }); addresses.forEach((address) => clqdrMulti.call(address, options.address, 'balanceOf', [address]) ); @@ -96,7 +98,10 @@ export async function strategy( }); addresses.forEach((address) => - multiLiquidMaster.call(address, liquidMasterAddress, 'userInfo', ['43', address]) + multiLiquidMaster.call(address, liquidMasterAddress, 'userInfo', [ + '43', + address + ]) ); const resultLiquidMaster: Record = await multiLiquidMaster.execute(); @@ -112,7 +117,10 @@ export async function strategy( }); addresses.forEach((address) => - multiBeetsMaster.call(address, beetsMasterAddress, 'userInfo', ['69', address]) + multiBeetsMaster.call(address, beetsMasterAddress, 'userInfo', [ + '69', + address + ]) ); const resultBeetsMaster: Record = await multiBeetsMaster.execute(); @@ -126,13 +134,15 @@ export async function strategy( return Object.fromEntries( Object.entries(userLpBalances).map(([address, balance]) => { // @ts-ignore - const clqdrBalanceInLp = totalClqdrInBeets.mul(balance).div(virtualSupply); + const clqdrBalanceInLp = totalClqdrInBeets + .mul(balance) + .div(virtualSupply); const totalBalance = userCLqdrBalances[address].add(clqdrBalanceInLp); return [ address, // @ts-ignore parseFloat(formatUnits(totalBalance, options.decimals)) - ] + ]; }) ); } diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 385bab68a..139fd9be2 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -385,7 +385,6 @@ import * as sdVoteBoost from './sd-vote-boost'; import * as sdVoteBoostTWAVP from './sd-vote-boost-twavp'; import * as clqdrBalanceWithLp from './clqdr-balance-with-lp'; - const strategies = { 'forta-shares': fortaShares, 'ethermon-erc721': ethermon721, diff --git a/src/strategies/single-staking-autocompound-balanceof/examples.json b/src/strategies/single-staking-autocompound-balanceof/examples.json index 2e9f77227..996fdfcc5 100644 --- a/src/strategies/single-staking-autocompound-balanceof/examples.json +++ b/src/strategies/single-staking-autocompound-balanceof/examples.json @@ -11,9 +11,10 @@ }, "network": "1666600000", "addresses": [ - "0x12e49d93588e0056bd25530C3B1E8AAc68F4B70a", - "0x8C612B03b3358C1E535706695c635C360034B968", - "0x24d19f100ba142543a863fc2294b188e35ab55b9"], + "0x12e49d93588e0056bd25530C3B1E8AAc68F4B70a", + "0x8C612B03b3358C1E535706695c635C360034B968", + "0x24d19f100ba142543a863fc2294b188e35ab55b9" + ], "snapshot": 32877171 } ] From ea4d2c65e79822093e23c796be1b26c09e7a744a Mon Sep 17 00:00:00 2001 From: Fabien Date: Tue, 25 Oct 2022 01:12:32 +0700 Subject: [PATCH 174/815] [spreadsheet] Add strategy spreadsheet (#898) * Add getVp and getDelegations functions * Update dependencies * Export functions getVp and getDelegations * Remove unused file * Add validations strategies * Add test for validation * Add pkg script for validation test * Refactor validation to class and change params * Add 'latest' in snapshot type * Add strategy Spreadsheet * Fix lint * Update src/strategies/spreadsheet/index.ts Co-authored-by: Chaitanya --- src/strategies/arrow-vesting/index.ts | 32 ++++++------ src/strategies/clqdr-balance-with-lp/index.ts | 2 +- src/strategies/index.ts | 4 +- src/strategies/spreadsheet/README.md | 20 +++++++ src/strategies/spreadsheet/examples.json | 19 +++++++ src/strategies/spreadsheet/index.ts | 52 +++++++++++++++++++ src/strategies/spreadsheet/schema.json | 25 +++++++++ 7 files changed, 135 insertions(+), 19 deletions(-) create mode 100644 src/strategies/spreadsheet/README.md create mode 100644 src/strategies/spreadsheet/examples.json create mode 100644 src/strategies/spreadsheet/index.ts create mode 100644 src/strategies/spreadsheet/schema.json diff --git a/src/strategies/arrow-vesting/index.ts b/src/strategies/arrow-vesting/index.ts index 000e80e87..a8569d213 100644 --- a/src/strategies/arrow-vesting/index.ts +++ b/src/strategies/arrow-vesting/index.ts @@ -101,24 +101,22 @@ export async function strategy( addressBalances[address] = 0; }); - Object.entries(vestingContractParameters).forEach( - ([contractAddress, params]) => { - const recipient = params['recipient']; - const start = params['start_time']; - - if (recipient in addressBalances && time > start) { - const locked = parseFloat( - formatUnits(params['total_locked'], options.decimals) - ); - const end = params['end_time']; - - addressBalances[recipient] += Math.min( - (locked * (time - start)) / (end - start), - locked - ); - } + Object.entries(vestingContractParameters).forEach(([, params]) => { + const recipient = params['recipient']; + const start = params['start_time']; + + if (recipient in addressBalances && time > start) { + const locked = parseFloat( + formatUnits(params['total_locked'], options.decimals) + ); + const end = params['end_time']; + + addressBalances[recipient] += Math.min( + (locked * (time - start)) / (end - start), + locked + ); } - ); + }); return addressBalances; } diff --git a/src/strategies/clqdr-balance-with-lp/index.ts b/src/strategies/clqdr-balance-with-lp/index.ts index 66d2a26aa..6dcd9d743 100644 --- a/src/strategies/clqdr-balance-with-lp/index.ts +++ b/src/strategies/clqdr-balance-with-lp/index.ts @@ -133,8 +133,8 @@ export async function strategy( return Object.fromEntries( Object.entries(userLpBalances).map(([address, balance]) => { - // @ts-ignore const clqdrBalanceInLp = totalClqdrInBeets + // @ts-ignore .mul(balance) .div(virtualSupply); const totalBalance = userCLqdrBalances[address].add(clqdrBalanceInLp); diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 139fd9be2..e75c1b747 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -384,6 +384,7 @@ import * as bancorStandardRewardsUnderlyingBalance from './bancor-standard-rewar import * as sdVoteBoost from './sd-vote-boost'; import * as sdVoteBoostTWAVP from './sd-vote-boost-twavp'; import * as clqdrBalanceWithLp from './clqdr-balance-with-lp'; +import * as spreadsheet from './spreadsheet'; const strategies = { 'forta-shares': fortaShares, @@ -772,7 +773,8 @@ const strategies = { bancorStandardRewardsUnderlyingBalance, 'sd-vote-boost': sdVoteBoost, 'sd-vote-boost-twavp': sdVoteBoostTWAVP, - 'clqdr-balance-with-lp': clqdrBalanceWithLp + 'clqdr-balance-with-lp': clqdrBalanceWithLp, + spreadsheet }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/spreadsheet/README.md b/src/strategies/spreadsheet/README.md new file mode 100644 index 000000000..f737d34b6 --- /dev/null +++ b/src/strategies/spreadsheet/README.md @@ -0,0 +1,20 @@ +# Spreadsheet + +Define voting power in Google Sheets. + +### Getting started + +- Check the template here: https://docs.google.com/spreadsheets/d/13aJrpOUtajyMLvmjvEqutnEP0FkuH3Z-LPH9m9Mbhis/edit?usp=sharing +- Select: File > Make a copy +- On the newly created file select: File > Share > Publish to web +- On the modal "Publish to web" click "Publish" button +- Copy the id within the URL and use it as "id" parameter for the strategy +- You are ready! + +Here is an example of the strategy parameters + +```json +{ + "id": "2PACX-1vTmam7vShzrscNDQ0zy0IC11jJztebhWrK5_5kFT6N_WsEJXDXStmxrOlNmHt9IRf9g7VenegU8vGzh" +} +``` diff --git a/src/strategies/spreadsheet/examples.json b/src/strategies/spreadsheet/examples.json new file mode 100644 index 000000000..47fa1fd47 --- /dev/null +++ b/src/strategies/spreadsheet/examples.json @@ -0,0 +1,19 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "spreadsheet", + "params": { + "id": "2PACX-1vTmam7vShzrscNDQ0zy0IC11jJztebhWrK5_5kFT6N_WsEJXDXStmxrOlNmHt9IRf9g7VenegU8vGzh" + } + }, + "network": "1", + "addresses": [ + "0x5BC928BF0DAb1e4A2ddd9e347b0F22e88026D76c", + "0x4C7909d6F029b3a5798143C843F4f8e5341a3473", + "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", + "0xdD36Aa96D9BD4b49DA6E6734fF18Cc69F90F9435" + ], + "snapshot": 12857715 + } +] diff --git a/src/strategies/spreadsheet/index.ts b/src/strategies/spreadsheet/index.ts new file mode 100644 index 000000000..38be16229 --- /dev/null +++ b/src/strategies/spreadsheet/index.ts @@ -0,0 +1,52 @@ +import fetch from 'cross-fetch'; + +export const author = 'bonustrack'; +export const version = '0.1.0'; +export const dependOnOtherAddress = false; +function csvToJson(csv) { + const lines = csv.split('\n'); + const keys = lines[0].split(',').map((key) => key.trim()); + return lines.slice(1).map((line) => + line.split(',').reduce((acc, cur, i) => { + const toAdd = {}; + toAdd[keys[i]] = cur.trim(); + return { ...acc, ...toAdd }; + }, {}) + ); +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const block = await provider.getBlock(snapshot); + const ts = block.timestamp; + + const res = await fetch( + `https://docs.google.com/spreadsheets/d/e/${options.id}/pub?gid=0&single=true&output=csv` + ); + const text = await res.text(); + const csv = (csvToJson(text) || []).map((item) => ({ + address: item.address, + vp: parseFloat(item['voting power'] || '0'), + ts: parseInt(item.timestamp || '0') + })); + + return Object.fromEntries( + addresses.map((address) => { + const items = csv + .filter( + (item) => + item.address.toLowerCase() === address.toLowerCase() && + item.ts <= ts + ) + .sort((a, b) => a.ts - b.ts); + const vp = (items.pop() || {}).vp || 0; + return [address, vp]; + }) + ); +} diff --git a/src/strategies/spreadsheet/schema.json b/src/strategies/spreadsheet/schema.json new file mode 100644 index 000000000..661725000 --- /dev/null +++ b/src/strategies/spreadsheet/schema.json @@ -0,0 +1,25 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. UNI"], + "maxLength": 16 + }, + "id": { + "type": "string", + "title": "Spreadsheet id", + "examples": ["e.g. 2PACX-1vTmam7vShzrscND..."] + } + }, + "required": ["id"], + "additionalProperties": false + } + } +} From 95cdcf93667ca30cb6d9d5f1bc73d6eed8729c12 Mon Sep 17 00:00:00 2001 From: omahs <73983677+omahs@users.noreply.github.com> Date: Mon, 24 Oct 2022 20:32:30 +0200 Subject: [PATCH 175/815] Fix: typos (#899) * Fix: typos Fix: typos * Fix: typos Fix: typos Co-authored-by: Chaitanya --- README.md | 4 ++-- src/strategies/anti-whale/README.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index fba3c21b0..4f688f905 100755 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ ts-node test/scores.ts ### Checklist for adding a new strategy -Here is a simple checklist to look when reviewing a PR for a new strategy: +Here is a simple checklist to look at when reviewing a PR for a new strategy: #### Overview @@ -65,7 +65,7 @@ Here is a simple checklist to look when reviewing a PR for a new strategy: #### Recommended -- Add a README.md file that describe the strategy and provide an example of parameters. +- Add a README.md file that describes the strategy and provides an example of parameters. - Use string ABI instead of object. ### License diff --git a/src/strategies/anti-whale/README.md b/src/strategies/anti-whale/README.md index 5d6d96d68..28e1a77cd 100644 --- a/src/strategies/anti-whale/README.md +++ b/src/strategies/anti-whale/README.md @@ -2,9 +2,9 @@ ## Description -This strategy executes a configured strategy and applies an anti-whale measure to its results to reduce the impact of big wallets in the the resulting value, reducing the effect on the voting power as the token amount increases. +This strategy executes a configured strategy and applies an anti-whale measure to its results to reduce the impact of big wallets in the resulting value, reducing the effect on the voting power as the token amount increases. -It will apply the the following to the result: +It will apply the following to the result: ```none If result > antiWhale.threshold From 033d66fb9d7162d68dcb959929b41aa26a973ebf Mon Sep 17 00:00:00 2001 From: bonustrack Date: Tue, 25 Oct 2022 04:51:40 +0700 Subject: [PATCH 176/815] Add anchorage strategy --- src/strategies/anchorage/README.md | 3 + src/strategies/anchorage/examples.json | 26 ++++++++ src/strategies/anchorage/index.ts | 79 ++++++++++++++++++++++++ src/strategies/index.ts | 4 +- src/strategies/spreadsheet/README.md | 8 ++- src/strategies/spreadsheet/examples.json | 3 +- src/strategies/spreadsheet/index.ts | 3 +- 7 files changed, 120 insertions(+), 6 deletions(-) create mode 100644 src/strategies/anchorage/README.md create mode 100644 src/strategies/anchorage/examples.json create mode 100644 src/strategies/anchorage/index.ts diff --git a/src/strategies/anchorage/README.md b/src/strategies/anchorage/README.md new file mode 100644 index 000000000..c33a04bf3 --- /dev/null +++ b/src/strategies/anchorage/README.md @@ -0,0 +1,3 @@ +# Anchorage delegation + +This strategy is managed by Anchorage team to handle delegations. diff --git a/src/strategies/anchorage/examples.json b/src/strategies/anchorage/examples.json new file mode 100644 index 000000000..9cfdf6210 --- /dev/null +++ b/src/strategies/anchorage/examples.json @@ -0,0 +1,26 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "anchorage", + "params": { + "symbol": "DAI (anchorage)", + "strategies": [ + { + "name": "erc20-balance-of", + "params": { + "address": "0x6B175474E89094C44Da98b954EedeAC495271d0F", + "decimals": 18 + } + } + ] + } + }, + "network": "1", + "addresses": [ + "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", + "0x4C7909d6F029b3a5798143C843F4f8e5341a3473" + ], + "snapshot": 15820600 + } +] diff --git a/src/strategies/anchorage/index.ts b/src/strategies/anchorage/index.ts new file mode 100644 index 000000000..fff4bcd22 --- /dev/null +++ b/src/strategies/anchorage/index.ts @@ -0,0 +1,79 @@ +import fetch from 'cross-fetch'; +import { getAddress } from '@ethersproject/address'; +import { getScoresDirect } from '../../utils'; + +export const author = 'bonustrack'; +export const version = '0.1.0'; +export const dependOnOtherAddress = true; + +const SPREADSHEET_ID = + '2PACX-1vQsn8e6KQOwqfHoA4rWDke63jTwfcshHxcZwOzVharOoAARWy6aX0TvN-uzzgtmAn3F5vDbuDKnk5Jw'; +const GID = '506976679'; + +function csvToJson(csv) { + const lines = csv.split('\n'); + const keys = lines[0].split(',').map((key) => key.trim()); + return lines.slice(1).map((line) => + line.split(',').reduce((acc, cur, i) => { + const toAdd = {}; + toAdd[keys[i]] = cur.trim(); + return { ...acc, ...toAdd }; + }, {}) + ); +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const block = await provider.getBlock(snapshot); + const ts = block.timestamp; + + const url = `https://docs.google.com/spreadsheets/d/e/${SPREADSHEET_ID}/pub?gid=${GID}&single=true&output=csv`; + const res = await fetch(url); + const text = await res.text(); + const csv = csvToJson(text) || []; + + const delegations = Object.fromEntries( + csv + .map((item) => ({ + ...item, + delegator: getAddress(item.delegator), + delegate: getAddress(item.delegate), + ts: parseInt(item.timestamp || '0') + })) + .filter( + (item) => + item.ts <= ts && + item.space === space && + !addresses.includes(item.delegator) + ) + .sort((a, b) => a.ts - b.ts) + .map((item) => [item.delegator, item.delegate]) + ); + + const delegatorScores = await getScoresDirect( + space, + options.strategies, + network, + provider, + Object.keys(delegations), + snapshot + ); + + const scores = {}; + delegatorScores.forEach((score) => { + Object.entries(score).forEach(([address, vp]) => { + if (delegations[address] && addresses.includes(delegations[address])) { + if (!scores[delegations[address]]) scores[delegations[address]] = 0; + scores[delegations[address]] += vp; + } + }); + }); + + return scores; +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index e75c1b747..ad2fe3b9b 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -385,6 +385,7 @@ import * as sdVoteBoost from './sd-vote-boost'; import * as sdVoteBoostTWAVP from './sd-vote-boost-twavp'; import * as clqdrBalanceWithLp from './clqdr-balance-with-lp'; import * as spreadsheet from './spreadsheet'; +import * as anchorage from './anchorage'; const strategies = { 'forta-shares': fortaShares, @@ -774,7 +775,8 @@ const strategies = { 'sd-vote-boost': sdVoteBoost, 'sd-vote-boost-twavp': sdVoteBoostTWAVP, 'clqdr-balance-with-lp': clqdrBalanceWithLp, - spreadsheet + spreadsheet, + anchorage }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/spreadsheet/README.md b/src/strategies/spreadsheet/README.md index f737d34b6..6ab92fc47 100644 --- a/src/strategies/spreadsheet/README.md +++ b/src/strategies/spreadsheet/README.md @@ -8,13 +8,15 @@ Define voting power in Google Sheets. - Select: File > Make a copy - On the newly created file select: File > Share > Publish to web - On the modal "Publish to web" click "Publish" button -- Copy the id within the URL and use it as "id" parameter for the strategy +- Copy the long id within the URL and use it as "sheetId" parameter for the strategy +- And use the id after "pub?gid=" as "gid" parameter - You are ready! -Here is an example of the strategy parameters +Here is an example of the strategy parameters: ```json { - "id": "2PACX-1vTmam7vShzrscNDQ0zy0IC11jJztebhWrK5_5kFT6N_WsEJXDXStmxrOlNmHt9IRf9g7VenegU8vGzh" + "sheetId": "2PACX-1vTmam7vShzrscNDQ0zy0IC11jJztebhWrK5_5kFT6N_WsEJXDXStmxrOlNmHt9IRf9g7VenegU8vGzh", + "gid": "0" } ``` diff --git a/src/strategies/spreadsheet/examples.json b/src/strategies/spreadsheet/examples.json index 47fa1fd47..b60fdb334 100644 --- a/src/strategies/spreadsheet/examples.json +++ b/src/strategies/spreadsheet/examples.json @@ -4,7 +4,8 @@ "strategy": { "name": "spreadsheet", "params": { - "id": "2PACX-1vTmam7vShzrscNDQ0zy0IC11jJztebhWrK5_5kFT6N_WsEJXDXStmxrOlNmHt9IRf9g7VenegU8vGzh" + "sheetId": "2PACX-1vTmam7vShzrscNDQ0zy0IC11jJztebhWrK5_5kFT6N_WsEJXDXStmxrOlNmHt9IRf9g7VenegU8vGzh", + "gid": "0" } }, "network": "1", diff --git a/src/strategies/spreadsheet/index.ts b/src/strategies/spreadsheet/index.ts index 38be16229..3c0e375c9 100644 --- a/src/strategies/spreadsheet/index.ts +++ b/src/strategies/spreadsheet/index.ts @@ -3,6 +3,7 @@ import fetch from 'cross-fetch'; export const author = 'bonustrack'; export const version = '0.1.0'; export const dependOnOtherAddress = false; + function csvToJson(csv) { const lines = csv.split('\n'); const keys = lines[0].split(',').map((key) => key.trim()); @@ -27,7 +28,7 @@ export async function strategy( const ts = block.timestamp; const res = await fetch( - `https://docs.google.com/spreadsheets/d/e/${options.id}/pub?gid=0&single=true&output=csv` + `https://docs.google.com/spreadsheets/d/e/${options.sheetId}/pub?gid=${options.gid}&single=true&output=csv` ); const text = await res.text(); const csv = (csvToJson(text) || []).map((item) => ({ From e1c9972d9108ffe9bd7be4d8c618b51351c2bbd7 Mon Sep 17 00:00:00 2001 From: Swen Mun Date: Tue, 25 Oct 2022 17:27:12 +0900 Subject: [PATCH 177/815] Introduce ninechronicles-staked-and-dcc [ninechronicles-staked-and-dcc] (#901) * Introduce ninechronicles-staked-and-dcc * Update src/strategies/ninechronicles-staked-and-dcc/index.ts * Update src/strategies/ninechronicles-staked-and-dcc/index.ts Co-authored-by: Chaitanya --- src/strategies/index.ts | 5 +- .../ninechronicles-staked-and-dcc/README.md | 52 ++++++++ .../examples.json | 33 +++++ .../ninechronicles-staked-and-dcc/index.ts | 119 ++++++++++++++++++ 4 files changed, 208 insertions(+), 1 deletion(-) create mode 100644 src/strategies/ninechronicles-staked-and-dcc/README.md create mode 100644 src/strategies/ninechronicles-staked-and-dcc/examples.json create mode 100644 src/strategies/ninechronicles-staked-and-dcc/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index ad2fe3b9b..d8719ad8c 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -384,9 +384,11 @@ import * as bancorStandardRewardsUnderlyingBalance from './bancor-standard-rewar import * as sdVoteBoost from './sd-vote-boost'; import * as sdVoteBoostTWAVP from './sd-vote-boost-twavp'; import * as clqdrBalanceWithLp from './clqdr-balance-with-lp'; +import * as ninechroniclesStakedAndDcc from './ninechronicles-staked-and-dcc'; import * as spreadsheet from './spreadsheet'; import * as anchorage from './anchorage'; + const strategies = { 'forta-shares': fortaShares, 'ethermon-erc721': ethermon721, @@ -776,7 +778,8 @@ const strategies = { 'sd-vote-boost-twavp': sdVoteBoostTWAVP, 'clqdr-balance-with-lp': clqdrBalanceWithLp, spreadsheet, - anchorage + anchorage, + 'ninechronicles-staked-and-dcc': ninechroniclesStakedAndDcc, }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/ninechronicles-staked-and-dcc/README.md b/src/strategies/ninechronicles-staked-and-dcc/README.md new file mode 100644 index 000000000..9e4003923 --- /dev/null +++ b/src/strategies/ninechronicles-staked-and-dcc/README.md @@ -0,0 +1,52 @@ +# Nine Chronicles DAO voting strategy (by staked assets and D:CC) + +This strategy returns calculated score based on staked assets ([Nine Chronicles Gold (NCG)][NCG], [LP Token for [wNCG](20WETH-80WNCG)][20WETH-80WNCG] and [D:CC]) of given accounts. + +[NCG]: https://docs.nine-chronicles.com/introduction/intro/nine-chronicles-gold-ncg +[20WETH-80WNCG]: https://etherscan.io/token/0xe8cc7E765647625B95F59C15848379D10B9AB4af +[wNCG]: https://etherscan.io/token/0xf203ca1769ca8e9e8fe1da9d147db68b6c919817 +[D:CC]: https://dcc.nine-chronicles.com/ + + +## Calculation + +``` +score = (w1 * staked_ncg) + (w2 * staked_lp_tokens) + (w3 * dcc_balance) +``` + +- `staked_ncg`: The staked NCG amounts of given account. (on Nine Chronicles mainnet) +- `staked_lp_tokens`: The staked LP token amounts in the staking contract of given account. (on Ethereum mainnet) + - This value only refer staking contract from [Planetarium] and staked value on its backeed pool will be ignored. +- `w1`, `w2`, `w3`: Weights for each amounts. it can be configured by parameters. + + +## Parameters + +- `symbol` - (**Optional**, `string`): The symbol of voting score. +- `ethLPTokenStakingAddress` - (**Required**, `string`): The address of staking contract on Ethereum. +- `ethDccAddress` - (**Required**, `string`): The address of D:CC token contract on Ethereum. +- `ncGraphQLEndpoint` - (**Required**, `string`): The GraphQL endpoint of Nine Chronicles to query. +- `ncBlockHash` - (**Required**, `string`): The target Block Hash of Nine Chronicles. +- `lpTokenDecimal` - (**Optional**, `number`): The decimal precision for staked token. default is 18. +- `weights` - (**Optional**, `number`): Weight values for the fomular . these values must be integers without decimal parts. + - `stakedNCG`: Weight for staked NCG. (`w1`) + - `stakedLPToken`: Weight for staked LP token. (`w2`) + - `dcc`: Weight for D:CC. (`w3`) + + +## Examples + +```json +{ + "symbol": "Staked 9c assets + DCC", + "ethLPTokenStakingAddress": "0xcc2db561d149a6d2f071a2809492d72e07838f69", + "ethDccAddress": "0xcea65a86195c911912ce48b6636ddd365c208130", + "ncGraphQLEndpoint": "http://9c-main-rpc-31.nine-chronicles.com/graphql", + "ncBlockHash": "711ce4bcdc0fb5264577876f217a794b2448ccce24e3c7ea0fb9794e420863e4", + "lpTokenDecimal": 18, + "weights": { + "stakedToken": 1, + "stakedNCG": 1, + "dcc": 999 +} +``` diff --git a/src/strategies/ninechronicles-staked-and-dcc/examples.json b/src/strategies/ninechronicles-staked-and-dcc/examples.json new file mode 100644 index 000000000..e689a732e --- /dev/null +++ b/src/strategies/ninechronicles-staked-and-dcc/examples.json @@ -0,0 +1,33 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "ninechronicles-staked-and-dcc", + "params": { + "symbol": "Staked 9c assets + DCC", + "ethLPTokenStakingAddress": "0xc53b567A70dB04E928FB96D6A417971aa88fdA38", + "ethDccAddress": "0xcea65a86195c911912ce48b6636ddd365c208130", + "ncGraphQLEndpoint": "http://9c-main-rpc-31.nine-chronicles.com/graphql", + "ncBlockHash": "711ce4bcdc0fb5264577876f217a794b2448ccce24e3c7ea0fb9794e420863e4", + "lpTokenDecimal": 18, + "weights": { + "stakedLPToken": 1, + "stakedNCG": 1, + "dcc": 999 + } + } + }, + "network": "1", + "addresses": [ + "0x10e19ba32927b28eb5424f7b6a3e2eaa5a607f47", + "0x97aa9e72FAf4B83A719D31B840Bd4F60282E9833", + "0x7916d7c934a7a5ba67f4c88ddb0c9fec76ebd8b5", + "0x93b220bc7c36ea8e4c64192301b680273a184ec3", + "0x30f1d1ffad34b24bb8310ad9dd237b854b4daea7", + "0x961c18a23306fe44c4323adcb3bc343b0d193670", + "0x03eA88F51D9D290e5E72e6F7C70abD2bB9CE9b78", + "0x8D45A60b37D09bEEdA9c1C86b7e4d714Ae625254" + ], + "snapshot": 15797760 + } +] diff --git a/src/strategies/ninechronicles-staked-and-dcc/index.ts b/src/strategies/ninechronicles-staked-and-dcc/index.ts new file mode 100644 index 000000000..a7b8bf0b0 --- /dev/null +++ b/src/strategies/ninechronicles-staked-and-dcc/index.ts @@ -0,0 +1,119 @@ +import { getAddress as formatEthAddress } from '@ethersproject/address'; +import { BigNumber } from '@ethersproject/bignumber'; +import { formatUnits, parseUnits } from '@ethersproject/units'; +import { strategy as erc721BalanceOfStrategy } from '../erc721'; +import { Multicaller, subgraphRequest } from '../../utils'; + +export const author = 'longfin'; +export const version = '1.0.0'; +export const dependOnOtherAddress = false; + +const lpStakingABI = [ + 'function stakedTokenBalance(address account) view returns (uint256)', +] + +interface Options { + ethLPTokenStakingAddress: string, + ethDccAddress: string, + ncBlockHash: string, + ncGraphQLEndpoint: string, + lpTokenDecimal: number, + weights: { + stakedLPToken: number, + dcc: number, + stakedNCG: number + } +} + +export async function strategy( + space, + network, + provider, + addresses: string[], + options, + snapshot +): Promise> { + const { + ethLPTokenStakingAddress, + ethDccAddress, + ncBlockHash, + ncGraphQLEndpoint, + lpTokenDecimal = 18, + weights: { + stakedLPToken: stakedLpTokenWeight = 1, + dcc: dccWeight = 999, + stakedNCG: stakedNCGWeight = 1, + }, + } : Options = options; + + addresses = addresses.map(formatEthAddress); + + const dccScores = erc721BalanceOfStrategy( + space, + network, + provider, + addresses, + { address: ethDccAddress }, + snapshot + ).then(scores => { + Object.keys(scores).forEach(addr => { + scores[addr] *= dccWeight; + }); + return scores + }); + + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const multiCaller = new Multicaller(network, provider, lpStakingABI, { blockTag }); + addresses.forEach((address) => + multiCaller.call(address, ethLPTokenStakingAddress, 'stakedTokenBalance', [address]) + ); + const stakedTokenScores = multiCaller.execute().then((rawScores: Record) => { + const scores = {}; + Object.keys(rawScores).forEach(addr => { + scores[addr] = parseFloat(formatUnits(rawScores[addr].mul(stakedLpTokenWeight), lpTokenDecimal)); + }); + + return scores; + }); + const stakedNCGQuery = { + stateQuery: { + __args: { + hash: ncBlockHash, + }, + + stakeStates: { + __args: { + addresses: addresses, + }, + + deposit: true, + } + } + }; + + const stakedNCGScores = subgraphRequest(ncGraphQLEndpoint, stakedNCGQuery).then(resp => { + const scores: Record = {}; + addresses.forEach((addr, i) => { + const stakeState = resp.stateQuery.stakeStates[i]; + scores[addr] = parseFloat(formatUnits(parseUnits(stakeState?.deposit ?? "0.00", 2).mul(stakedNCGWeight), 2)); + }); + + return scores; + }); + + const allScores = await Promise.all([ + dccScores, + stakedTokenScores, + stakedNCGScores, + ]); + + return allScores.reduce((total, scores) => { + for (const [address, value] of Object.entries(scores)) { + if (!total[address]) { + total[address] = 0; + } + total[address] += value; + } + return total; + }, {}); +} From ffb381e4234a5df77831a1dd45d8ba883ac93f6c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 25 Oct 2022 15:49:52 +0530 Subject: [PATCH 178/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.42 (#902) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 6767a02a1..2440de90c 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.41", + "@snapshot-labs/snapshot.js": "^0.4.42", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 341585c6e..cb1022c7b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.41": - version "0.4.41" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.41.tgz#7bdcaacdabf39cdb8e985affdbd4ad0b0c254084" - integrity sha512-xH4HUW1PRtnjo6BUsCHb0ZtXPYgPnzi1xZPRRq2VVWixQpgRWs3VVBXjmV6LfhlGDkjmoBX2mIh9M+kgdDsQsw== +"@snapshot-labs/snapshot.js@^0.4.42": + version "0.4.42" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.42.tgz#2439708bd97c2eb2fc3fa1f747f5644c19d15a00" + integrity sha512-2LA4tFpd5EWRgltM0b8VLW+ii14s7BoRjj96FJQQAMreViK3Wl9Y/lu8T+A1Mm3lYnaInoQ3Xb4q/AqFYq10DA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From c4159c13a3d529d1fe796ae9d5da6ce6c4d8401c Mon Sep 17 00:00:00 2001 From: Andy Espagnolo Date: Tue, 25 Oct 2022 15:36:36 -0300 Subject: [PATCH 179/815] [decentraland-wearable-rarity] fix: decentraland-wearable-rarity undefined id value (#905) * fix: decentraland-wearable-rarity undefined id value * fix: add missing id field in query * Update examples.json Co-authored-by: Chaitanya --- src/strategies/decentraland-wearable-rarity/examples.json | 3 ++- src/strategies/decentraland-wearable-rarity/index.ts | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/strategies/decentraland-wearable-rarity/examples.json b/src/strategies/decentraland-wearable-rarity/examples.json index 04c4c192f..2104c70cb 100644 --- a/src/strategies/decentraland-wearable-rarity/examples.json +++ b/src/strategies/decentraland-wearable-rarity/examples.json @@ -27,7 +27,8 @@ "network": "1", "addresses": [ "0xd210dc1dd26751503cbf1b8c9154224707820da8", - "0x8cff6832174091dae86f0244e3fd92d4ced2fe07" + "0x8cff6832174091dae86f0244e3fd92d4ced2fe07", + "0xFC9C4C0e17c3A3139a77d86282eCf18687C14780" ], "snapshot": 12453375 } diff --git a/src/strategies/decentraland-wearable-rarity/index.ts b/src/strategies/decentraland-wearable-rarity/index.ts index 85257adb6..9ef09182a 100644 --- a/src/strategies/decentraland-wearable-rarity/index.ts +++ b/src/strategies/decentraland-wearable-rarity/index.ts @@ -51,6 +51,7 @@ export async function strategy( orderDirection: 'asc', first: 1000 }, + id: true, owner: { id: true }, @@ -86,7 +87,9 @@ export async function strategy( } hasNext = nfts.length === params.nfts.__args.first; - params.nfts.__args.where.id_gt = latest ? latest.id : ''; + if (hasNext) { + params.nfts.__args.where.id_gt = latest?.id || ''; + } } // return result From 6e099e68627856f44992f504b1acb48756be16e0 Mon Sep 17 00:00:00 2001 From: lukaszh2o <111342592+lukaszh2o@users.noreply.github.com> Date: Wed, 26 Oct 2022 14:30:39 +0200 Subject: [PATCH 180/815] Staked-Balancer: remove unused variable in subgraph call [staked-balancer] (#904) * Staked-Balancer: remove unused variable in subgraph call * Staked-Balancer: remove unnecessary accumulation of score --- src/strategies/staked-balancer/index.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/strategies/staked-balancer/index.ts b/src/strategies/staked-balancer/index.ts index 3613f4301..9818bde21 100644 --- a/src/strategies/staked-balancer/index.ts +++ b/src/strategies/staked-balancer/index.ts @@ -30,7 +30,6 @@ const params = { pool: { __args: { id: '' }, totalShares: true, - address: true, tokens: { __args: { where: { address: '' } @@ -108,9 +107,7 @@ export async function strategy( response.forEach((value, i) => { const userAddress = getAddress(addresses[i]); - if (!score[userAddress]) score[userAddress] = 0; - score[userAddress] = - score[userAddress] + (value / stkTotalSupply) * tokensPerStkLP; + score[userAddress] = (value / stkTotalSupply) * tokensPerStkLP; }); } } From 145e3b44c230dce433d2edeb50c251c7423d1c60 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Wed, 26 Oct 2022 19:32:16 +0530 Subject: [PATCH 181/815] Test strategy with score API body (#908) * Test strategy with score API body * Test strategy with score API body --- test/strategy-with-params.test.ts | 1352 +++++++++++++++++++++++++++++ 1 file changed, 1352 insertions(+) create mode 100644 test/strategy-with-params.test.ts diff --git a/test/strategy-with-params.test.ts b/test/strategy-with-params.test.ts new file mode 100644 index 000000000..2b01b6227 --- /dev/null +++ b/test/strategy-with-params.test.ts @@ -0,0 +1,1352 @@ +// To test strategies by copy pasting score API body here +import snapshot from '../src'; + +const scoreAPIObj = { + params: { + space: 'snapshot.dcl.eth', + network: '1', + snapshot: 'latest', + strategies: [ + { + name: 'delegation', + network: '1', + params: { + symbol: 'VP (delegated)', + strategies: [ + { + 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 + } + } + } + ] + } + } + ], + addresses: [ + '0x2011c83e8f75c0ceb90ec140d8e8adfc836e3685', + '0x59ee84e74662e824e44835322bf6078f4f93dd37', + '0x86c62a0dd8690fa2ba6e3e3d9a18d021dbd2565a', + '0x34807e0c31596a5bb70752827a4b37ab442e4d51', + '0x676eb0dc5644dbcb2c37849ad76432a73af0b582', + '0x84da37133a088fbf4e21d80aec2cc260b52ea116', + '0x329c54289ff5d6b7b7dae13592c6b1eda1543ed4', + '0x6666b6665edafcfda38644c16e7c1b5e61c9fccc', + '0x8572f4abdf27d7857e541908322e8acf51bfd098', + '0xa72ef9bb82d59464eaa63f461c273f8028b20f5c', + '0x038db6c62d0f072616e2b8db7d3d7cfc829f7f65', + '0xd5e9ef1cedad0d135d543d286a2c190b16cbb89e', + '0xe448eb808799d553f47d5a1d306f32d65e54ab37', + '0xfd1af514b8b2bf00d1999497668bff26ccdf4c8a', + '0x019700312686b2ee895679a841ab0d6423d9b990', + '0xcefecc5239f5378714cc959f2033e1406f22590c', + '0x177b5f17061067dbbdca7fab17b1deb9ef35d34a', + '0x49b93f2de2428f66e43686bb4db0f96a9e35b61c', + '0xd6eff8f07caf3443a1178407d3de4129149d6ef6', + '0x019accbe7f0823598ea968b7271f39735016da9b', + '0x56254877ee2ec3163e265d9d4ac464467f85dc36', + '0xa7ca47e39484611fa1d53ce8c29a645de646c989', + '0x95d8ea71b9c03ced1f3847a035c4376f8d2623b9', + '0x772782c79d3cb9d86080a18dcbd59f6eb2094285', + '0x4f20cb7a1d567a54350a18dacb0cc803aebb4483', + '0x48aceaf27c7ac4f0d83a536cbc4333a8cb621bca', + '0xa9a80bd6ab5b4cff9b988f92c6e96bdb8c6e82f6', + '0x58805f572924b83b8c224184d2cf60ad3302dbdf', + '0x6986e8c8da33753443959690c240b03931bd1edc', + '0x1298324e97f39ee5cd34fad6c6bd93eb7527b443', + '0x7378f2fc0e601757150b03a0ec46c67878cf5b89', + '0xd8da6bf26964af9d7eed9e03e53415d37aa96045', + '0x8d26dfce440ac64dcc2a5c12d17c981e73c284e9', + '0xc1b8662a68f3eb66bc5e5c4de7c1ef04dc344d53', + '0x13d0a01820336b22a6f7c64a72c64fe7b7a12858', + '0xeafec5f10a77e70c50dde83932ef7714f76a39d1', + '0x3b048c30cbdc8350bd36f813d4ba587c348251dc', + '0x15a6779b27e8bf8dc6fb3b7d30adaf286eb5f620', + '0x9506e7bafa7267c7c488f73782181438a16a023d', + '0x0d779d67a428457cabec145a0f94703d14cd496b', + '0xdc1f98682f4f8a5c6d54f345f448437b83f5e432', + '0xac0367375ec176d30f38dbc50904209f4dc67cf4', + '0x5b9a65eabc2cbfc5eceec377afa4399f702eb3d4', + '0x380336041fed6d3de0c0a1f5079668760cd64779', + '0x80f74e931bc14079b3491661225366b785155c00', + '0xc8381ca290c198f5ab739a1841ce8aedb0b330d5', + '0xff65f352156d2c69f9abbf1aef18e6d85314ecce', + '0x9b6568d72a6f6269049fac3998d1fadf1e6263cc', + '0xdb339999c2d1c17f57990741e4df9d897210041d', + '0x3c13f2b56af614ac6381265ecb3b619ba26cc641', + '0x070341aa5ed571f0fb2c4a5641409b1a46b4961b', + '0xf1e7aaf22d00dabc416eb1e0ace91e927ec995bc', + '0x247e0896706bb09245549e476257a0a1129db418', + '0x6cc50580d43da2435b15379885e9f991f3f0d53e', + '0x6d5e5ba88861df8dba0eb53ebad1ba89eb4b238b', + '0x2a52309edf998799c4a8b89324ccad91848c8676', + '0x06d2c0c85e4c0208520217229ae30a8a5027a25f', + '0x99afec42330b25b833fd5175e468560be45fe1a6', + '0x1a4bac477d0b1ab39b08a5feeb182575fa3acfb6', + '0x69b5c281d94fd48766156d4a570da013415dd9b9', + '0x863f632312e5231780d0df269e03fb2a8de95234', + '0x18cd6c94e3ea483b8250f9ce4a941134d04da577', + '0x9dab43bc15bd29cfe3030ca1b7edb3eeb9f3b6c1', + '0x408505ec4bb812b9b649a653390a7b683cea3d54', + '0xbba0a9f8b72f1ad3b0772d276d21f5c9a07e0154', + '0x342d694377f431da175bc1317046ab424a612cd8', + '0x278b24ea2dfed88f2e61d3053bf9ca736b566666', + '0x259fefa88044a97f9426c519f9ef7de8079017a8', + '0x52a56ea0224109b0ca7e81b540a891994e36d398', + '0x7e6d4810ea233d7588e3675d704571e29c4bcbba', + '0x3274f7f013b09fc4831b479e9bb2a8a0de65f9f1', + '0xf49a19f72d0e106df462cfd6b5bebe42b6001616', + '0x7b7254d6be53c1ae75e3f816e3c159be7fadaf7c', + '0x54448fd12feb61007a551f19634d42763eb87b63', + '0xfc17747c89e93e2deeada88419e857a907a20313', + '0xb5f4ebcc5a90e58d953ee9e64e365c2468f31f51', + '0xea1d10d8737989337326c48930f46cb75ef6d889', + '0x52d3d3d9f78c3bb37e21d0ff79235bff038bd794', + '0x9ccb0759a404d96d48cc14876c7c24ca3fcb8c63', + '0x37ed74a0da66c0392c4c5901c3b3b97675871fe1', + '0xfd92f2a69853741b4ce65497a70f09e608568fa6', + '0xe66b278fa9fbb181522f6916ec2f6d66ab846e04', + '0xe1eedbd1e08478707c794e7e8b1ee623f5fa6d64', + '0xd09065b41d01a55b820cdb7c2d9a22b3bf4a3ce7', + '0xbf66bcbaf57fbb359f7e244f49eb7c4ff6f9a3c1', + '0x1262374b3b66680b43b17458470d5d2a096fdaf9', + '0x3764c0fff07cadab943141bf0f20d47051d3e08d', + '0xfc9cb04a120ff2392641577f5ee5454bd8013045', + '0x55b16934c3661e1990939bc57322554d9b09f262', + '0x7a482ba0a8a00884c5ef0cd867cdec22e9cf1f9c', + '0xb09234b8a25c19b37ad0f5306a66860b80d6a695', + '0xea172676e4105e92cc52dbf45fd93b274ec96676', + '0xb0f7806249bc44cd0fd6a62cb8e5448463caaca5', + '0x420f8e67196e20695b98a9728cb2a29416e9c687', + '0xe4e21b2e465d942ce32c9e1be1ab909685ed6c80', + '0x54acf9e0702f8ab74a366636704bd66f79283078', + '0xf1c748fec2e524b61b904688b5f6aa9c583f0a27', + '0xaf8fbf59e221d27b55dc3adc2366f9230bcf5096', + '0x6280aeb92c12ef44e04a053d3d23e563b4217382', + '0x9381caa558f19a821a2360c59fdf3db60c09ff52', + '0x89a1d730aa1e78a0ede8dea988acecff0a6e99a9', + '0x6194a166ba7560fa0bde0a07c93e714574a1df3f', + '0x36de990133d36d7e3df9a820aa3ede5a2320de71', + '0x065c6eb1376397d11e0746c5efdb30520c49c799', + '0x809fa673fe2ab515faa168259cb14e2bedebf68e', + '0xa0766028f1712c641a9a7d34535b9caa10f5b496', + '0xe0b2add5c2d094008d014369ab6bc5c42cf3acad', + '0xe7710d16410ec069f66d5ba3e5e700278e18b22a', + '0xbb323cd5544dfc50764625000e2a5f43e2f44250', + '0x82e8e9e21275861fb0733d654dba0f1680da99ec', + '0xf5819cc26f0481c9b86294b4c24027518a04bd5b', + '0xe63ddc147253f8d004b14224df49b529de47a665', + '0xe7f13052fe2ba7d038dac18de5e730542e3979bc', + '0xd85e5de67026eca9e691e97512b32d680104ba40', + '0xa66eab67e44b41aeaeef7ebc5ae3afb5050e8ad2', + '0xfcf770e9b83a2841ca6d724993b52199092ee31f', + '0x3cf368faecdb4a4e542c0efd17850ae133688c2a', + '0xf6e63fa58b2ed3bbc22362fdb6cc8cd23d40f2b2', + '0x075e83d9d1a35e07964d1cc8b99b5c46a6064ad4', + '0xeba5a44937596429d8a8fc117fb6e514783bd7e9', + '0x664eabe08871a7b7f13ade88bc34605ed5eaeae6', + '0x00cf83784120829dc797d5a9258430abaee0dcaf', + '0xb8e22d8d5c6e59b61796c278e71502afc021bce8', + '0x510ff10effd8b645d177b04541544dd54067c839', + '0x1b97dc8a97757429a231fbf0ba65e1102b8f51f3', + '0x597d94248c5181232e83ee054b74f01548090f33', + '0x7bafc0d5c5892f2041fd9f2415a7611042218e22', + '0x752515a3a1091b9f1c04416cf79d1f14d2340085', + '0x2684a202a374d87bb321a744482b89bf6deaf8bd', + '0xa07411eeb941a656168073046e66ce3c89eb7bb7', + '0xdac652ed4b450f4677bb0807dcfe767143f55555', + '0x511a22cdd2c4ee8357bb02df2578037ffe8a4d8d', + '0xeb4db23c27253077fb3080adda6c5c127b0dacae', + '0xcddccc9976f7fd5658ac82aa8b12baaf334d27f6', + '0x34bf0d00c38d714e7ffd96cc4e8c796f43832624', + '0xe1522b4b27d6a117202a1171085662e3a7a00176', + '0x623fb5ff84192947e8908ff6b3624c89216eb7a0', + '0xf863045ffcddbba9970d65096119195aaa493d9d', + '0xfdbc7dd315d0d23262a7d25ed2ad94d029262e11', + '0x5886f65425cad457776d7a89a399907c97e608e5', + '0x598f8af1565003ae7456dac280a18ee826df7a2c', + '0xeb1c22baacafac7836f20f684c946228401ff01c', + '0x6bb1edc0ba3bcf9de061e338e38606c6ea6ed3bf', + '0xb861fdaa17e31e2ec381e2de76df01ace3db6e79', + '0xaa3e5ee4fdc831e5274fe7836c95d670dc2502e6', + '0x59d2c715ab5beeca6649b8d4b5f45072edc37073', + '0xe47e75857c1fc64c222e7566e3ea5909c7ed96f3', + '0x2aca081a6ce45f1554a3889c138cf1cc7d486ef8', + '0xe5b2c5eb872a6fa9fc32ad1db8effdf8d50bd16c', + '0xb520f068a908a1782a543aacc3847adb77a04778', + '0xf0d14e6f8a5d6b48f431aa9b412b76432c8d1ce6', + '0xb7642f2f8651b738e68b7dedd0d42d99b55c0bc6', + '0x46d2f3dbe93156ed2fbfcbea4f470d032ba5637c', + '0x97ee11a38024fd2c71a0cf8443c6e029a40555dc', + '0x1085b070d20a1470a10f17bff6451abd46ff1e65', + '0x6687c671980e65ebd722b9146fc61e2471558dd6', + '0xe7a9725f7c6127a637125239ae547c444ea618d6', + '0x76f700d4a111cbb59a8718aaf4335ca23016dc56', + '0x247ea2a6d8e302ca31e8b28758014b468755bde2', + '0x28235de0121700a462b5098cff7d3615b050551f', + '0xb09df9094ecbef033d2684ef71bc85cfbb881861', + '0x521b0fef9cdcf250abaf8e7bc798cbe13fa98692', + '0xa14e1651ff7039b8de7ac3bfd064de6c5ec71d0f', + '0xff88bd69dc4d42b292b4acade8e24a20979c0098', + '0x8c3fab73727e370c1f319bc7fe5e25fd9bea991e', + '0x0c3699715de1739ef5a8a0f3a667a7092ee7e0b4', + '0x0ecddcf41754360ab129d7ca4c8abf220f9c32bd', + '0xbce0b2edca1fbe32891ac6096b8ea7408dd099c2', + '0x78afce8414fb4dfcb01c35db53547e71283779e7', + '0xaa214a094d44b5c94121e215bd1b5496a11fd56e', + '0x121111a0b0c09ceca66c7a8bb5b4b3098572a0ea', + '0xfb8ff1e56f2cf118d75c2a65275988dcfc327a33', + '0x6fde637aa768a8e5abddc6b5d03f1310cf5de8c0', + '0x9da423a15a87e145d9daef73f30a710cb4106bd2', + '0x7ee358178c3b1f2049813cbf4fc1249a378b4c2b', + '0xaeeb3b86314009f5ee315c49414646a1f5709d1c', + '0x245bd6b5d8f494df8256ae44737a1e5d59769ab4', + '0x5415e37ade67d741f2ada552d22eef7ad3b8ee12', + '0x6a0a93cd6d6fb7a36bf6234ef4650bf9474e7682', + '0xa4244f6711052752e6bb0271bf17c756e6598406', + '0xbb14766b9455c10b2d583427d586954bce20e703', + '0x6d68de1b67f28c7a49d467b5256e700d27843474', + '0xd99f0782fe35d9fcc87a8ea8b6fb8cf2a1c335b7', + '0xf4b0556b9b6f53e00a1fdd2b0478ce841991d8fa', + '0xafedea4d17a86a3825b3a0d9e0f209747acd9ce0', + '0x3a7489ecdc5d2f5a44b6b36107ddd69851999a32', + '0x299eff44279648f21ebb1bdabd7e4167b5149c20', + '0x701902858a6a9b6f36603244622732d9ec57a82a', + '0x8746952f0953f3865774ff730905087d05d4136b', + '0x90857dd31aef29d288c1f8c14222f5cbd1bbb19a', + '0xf15c8706bcb25ad2df408bbd17c0937f622b1218', + '0x913085b2c999ff9c48c0f279fdc7e2e4f2027065', + '0x26416423d530b1931a2a7a6b7d435fac65eed27d', + '0xff1c9c9c1dbfce00a9815a9c3748473199999999', + '0x58b7aa5bed029a5d149e108ad4bdf836d10f70ea', + '0xb9cae3a1b5b204a83f34efdee17d0354d11d0d9c', + '0xdabf789d130ec34fcc4e8d07e60335d002b3eebb', + '0x245f4a734c7cbd1a22be7c630d0e0d71e5f0d1bc', + '0x8f2d55e5a07a684c6bbc76f3dfc45c9e31d250ac', + '0xd09b3507232f8927b91c045fb1166941f3a223af', + '0x6e0b95f6db35a06650c898dfebe867bb7b120c95', + '0xdddd696973fd58db7aec22f96fbdcf40371e9fb1', + '0xb3253287141a9f2c922e2de141a72f24a79d9d25', + '0xc2c321575392e05ca99191c261d8b52ff4b715e6', + '0xc43f948bba82a80b90fce97b20bb414d50402c99', + '0xddf4da877d64c694ac69175feedb19a2591f7d7f', + '0xa4d7b8fe519f2995bf536005e588458254ea1983', + '0xad43b94803912c3b8bca9280a611f656c6fe1727', + '0x882e1b0973e6d1888802926523d055136ab7a8f3', + '0x96612d11511d57dba6705d43381dbbf6662783eb', + '0x295ff892a2b5941ed26ff8a10fecf90554092719', + '0xfc947bfa5540a7f63d3df050e47ab5cc7fb4ebd7', + '0x267569102682e2ea8b3005ef08907002788d98e8', + '0x99e060e20eca95fed24ecfb291161cb8069bfe85', + '0x4959211f78f82b83491f81d3daac4cc6cfb11d49', + '0x799e2eb280b7bb066c2b9c18237e60df88888888', + '0x0f725bb2d8161638eb89d6b6a7e9e80204a2f58f', + '0x2ad91063e489cc4009df7fee45c25c8be684cf6a', + '0x96e8b56bf062d3e2b019f2cdda69b8c7709f2759', + '0xcdef06d81219c87bcfd41e1d78e4defdab381eff', + '0xc3202329e49681e5efa7f0c6a96941515cd8fb20', + '0x021edd67d43b365a6401a5ee704aa6f264f3f4e4', + '0xf077464d85c3dcb99ac0dfba704aabf0678fdd50', + '0xe90cb10506d9cf4da667152013ced583ee085e15', + '0x001fa6f74c8eeaa372c8437a3bdd22b630d9a7b6', + '0xdb24eff70fb73bcb2b9eacbf3adceb7717813fff', + '0xe209cea72adf17f325550b6185786c2a6fffd995', + '0xc26c20fc4efe179e3f91127c540a339d2abaad67', + '0x0b1b848dd5436412ecc8c0cf1e1d7dffe92f2c25', + '0x5700f03f87db485fdb90e18b3100f00b235886f1', + '0x3fb38cee8d0ba7dcf59403a8c397626dc9c7a13b', + '0x80b3a71723fd38cd9589ca32fa40edc781f1a9c2', + '0x29b751d45a171eead92779e41f74d94a17de3b84', + '0x6d9aba400a2a487a5fb76c6d56518835553cd284', + '0x5d95baebb8412ad827287240a5c281e3bb30d27e', + '0x91e2e2d26076c8a1eadb69273605c16ef01928ce', + '0xd97c0fab0d7554f019bd6a8f6ab26bb4c66d34af', + '0xfb4604f1bf9e1f9a1a9a83537fd8f7efd55868d7', + '0x34c65d21dc2ded4afae9a1f86b9536485b3daa82', + '0x8733f2635daff538b452390940152202cdf1addc', + '0xd28a1ba7734bfac7bca65fa3551f5bf80be616ee', + '0xe017a4e967c9939d01628e805dc0cc3370184e63', + '0x17a91203a9e9c3519c2f76210497ef7f4be2352f', + '0x5b60117255df27fdd885629c0210d9dd975ff975', + '0x2418c48f9a08efe64fe7a0c312f2e5212701dd2a', + '0x46e86697535a2473d88fc92e056c3f70381ffa06', + '0x66f6950719d99f4366665b6d5e1d4d4c8ecf7cdd', + '0x14d0f956e40a96bdf89c27b8c6df0130003cb7de', + '0xb789e62b3b86909e7814475c21c2a55862a2df8b', + '0xa6a6aa6c41085d080eff519c43f9d1daf4a75ca6', + '0x0cfdfb55841bf953097d8f41b9bfd985a6bfadd9', + '0x434a1803a63ef1b9235d713b9ab1092f7fb8b4f4', + '0x8f577da95028582a80b0f026cc4ce2d579d880a3', + '0x53161705022ec05e52bd1b255d86251d2b920ce3', + '0x8d5237037a590a2db531f3cfb8f42605cf306f34', + '0x2e88de004cd9c510290b0471ce1405c1d589adcc', + '0xe73a198e7c07c418d7dcfd42f5e953074abbd125', + '0x2c5abc767ab347a852112b80bf62b221f15a6fe7', + '0x34a0e8081340d93aae4af9703742f358c43ec3a0', + '0x404e22482fd5f7f83197a825de3a1a2880ebd746', + '0x5d076c3c4f7bf2db6831c90fc8f1539e07ff71d1', + '0xcbf89166c719bd564753566d6062fd7b0ed9fc35', + '0x173831e62264568d735884835d7b1c234a5333a3', + '0x0143bd0cc24d0e1ea46353be5a7972f42abcb175', + '0x0e45cc7886c754bd56dfd3e91e4285a0ad6da5dc', + '0x66c25a700f9c762891b4d6fbf5af9dc2eb04266a', + '0x69af7c632b913a504b757eac63804edc35c67d15', + '0xf3f9aacba109d92ea971db08870302642da3c9e4', + '0x9b7ac890054204814caa67323d960dfc96a77dfd', + '0x1649228697139b0c67bd7785e366455e4b0331a2', + '0x816384b4e6644f3a1cb683e1cb83409a464532ea', + '0xee620a0991d57f464aad452789a4564ba51245e8', + '0x7db3ca5ad4c8f648d21fa7d682d3c6ca9d4f5dd7', + '0x7e8ba3fa5f0102004e734437f18eb2de612c3187', + '0xd87fa9fed90948cd7dea9f77c06b9168ac07f407', + '0xf7ac4a05a64a3c2b1414914f4a84afb0c6d6eaf5', + '0xbd03add5da0e173c67c9c1073ffba017147c42d4', + '0x49ea4121ba8e5dda4d16372431f63744327d7e0e', + '0x9eec7679dbb2b11e82a737388f74f3ab5fcd723c', + '0x68d36dcbdd7bbf206e27134f28103abe7cf972df', + '0x86edb92e217605dbecf606548e48daaf1b817da1', + '0x69c488bcda156379b6661f08a35db627e5d467dd', + '0x7287148e527b71453960d98feb7f587d51a33eae', + '0x5f87fcd19388834d3c54c38216e0e8facbc73985', + '0x73e8de3f2f913ecbdec97524430746acf65578a2', + '0x4a7abb0532b3f6eeead7ab0adf3498798ec989b7', + '0x6d5861c59386136d982dedab62bb7396e16c3f04', + '0x4a0de283b1d52acb5822ebc1f4370781175cea20', + '0xb3230632867040fb46199e30b45d6ee9a17c28a6', + '0xc6c68296f0d9694c45977f5842303568d0f8b90c', + '0x25b10099286b986a7f70b5976ce670054b8dffa8', + '0x128bc803a104748db0259c90867fcebfb4877a1d', + '0x50f385a1f8a16d94f3722e8c27d32ed935f76099', + '0x0636211443e91468ee3657e1d7faede7059c4843', + '0x6e09aad52a2613a5f93bf34f35b72e54c54c3a71', + '0xdfdc274d86351ecae8964a66625e7d930fb80a98', + '0x54ec859108495f86d438fe46d1492fdc246d77ad', + '0x447c9058be5c164e0c4aae380381e7a5215052d4', + '0xbc32f39ac1318cf75f7cdce4d730216239f10ce8', + '0x7ed9f10b5299b44d28f2aebf8d057919698cb94a', + '0xcc93ba13a7d488d2514e0012bb82cb9f05938295', + '0x16731946f50416acc945559a2cad0f7f070e8dfa', + '0xaf5c595eaa0ed462a75157513d99e1e3b0d1a570', + '0xf337a885a7543cab542b2d3f5a8c1945036e0c42', + '0xc3c169221e5497f4b3cd9a934170bc04e16f5df3', + '0xb00d51d3992bc412f783d0e21edcf952ce651d91', + '0x6a77883ed4e65a1df591fda2f5252fd7c548f198', + '0x1d95efd2321919e8c531de44e0763570a8c0eaef', + '0x21b09851315e0d46ebe383ea17ed1dcab9453975', + '0x73c8c76d074d007af0bb6fc5b5895c9b9c79fb1d', + '0x9c0c308d2ee659524dcf1d17be48deb651870d36', + '0x2956337f7db1382e7d0911aadb86aff3a44a33cf', + '0x030a52068049dc7b25f5bee4680a124b88a4b918', + '0x8d30fb6e0de03a4e73f6edc5fad309a8762e07a9', + '0xe003e26af7d15b9b9d9884aa9a5ca9c22c8d7d67', + '0xa3c0a5e0465e65e56d36d1a7f4684c317d9ce875', + '0x8b1b2582db809ee1ca51f0688f53f38cfd48f84e', + '0xb33ec1252e0e6d5fa87827cc74e8d7e2845d19d6', + '0x9e2b38c9ef8ff91f2c73ab0475bce66b14a4b31f', + '0x30303b5e2beb969b05c7d09b9c2a05104defc1d5', + '0xb1bda708e5e0d965959f802cb3353c3e535c70ee', + '0x8bd8d92dd614782f1d09db91bc517677f656692b', + '0x05a1ff0a32bc24265bcb39499d0c5d9a6cb2011c', + '0xd015853ec31b0918e321dca0247f4bd4cb47aaf4', + '0xfeb1509893be3963f295036c94bb74bf9c50ad36', + '0x0f051a642a1c4b2c268c7d6a83186159b149021b', + '0x4acedc1cc0faa5df2c4fedf4038869237f9609a2', + '0x60a0f99757c3f6060d1ce71f8d35bcc910d06458', + '0x7374eb44d1395d92e2d97d1d9c81ee764c69ef2c', + '0xa30a390e9c076cadaa0dc04e0ee941fd71600bc8', + '0xf872703f1c8f93fa186869bac83bac5a0c87c3c8', + '0x2ed8f7feb231c5cc7faa0075911c8d0cceeb353b', + '0x55bc991b2edf3ddb4c520b222be4f378418ff0fa', + '0xde1e6a7ed0ad3f61d531a8a78e83ccddbd6e0c49', + '0xfcacace2713d41c02666e2643e5583793196c935', + '0xa663422598271f49118f836691329112d1a9e2b9', + '0x95a9159bc960ec2d2d4b7120e48e7a0c83b325ee', + '0x0e1f93fca07f26527c406b9c604be4c54ee6610e', + '0xcc606c6dd687ea98df53dc4937a20a14cb470f83', + '0x6cf807bb1dee8e2d4c55e8cf6c875544edb2fcfe', + '0xba20104d5284d7fb855e48f6919b6e5166fab2fb', + '0xbd19a3f0a9cace18513a1e2863d648d13975cb30', + '0x84ae710058c1239420fc924621c8dca6733d1306', + '0x88a26a07ac1d80bb6544d85da1c1d6089bc7d39f', + '0x63fb86f437aee0dad657040563dbb6ba7ca23d70', + '0x93f735233c496e2728c25f8d6b14d9b3c32f0123', + '0x083fc10ce7e97cafbae0fe332a9c4384c5f54e45', + '0x2d419804d07ef4d20ec827f58ce535089c62cb47', + '0x0dee0846d49401a7d593dec46334ffb3aa777777', + '0x58469bd6bae417b4f07543b3cb6bfeb2ba9aea51', + '0xe6bc40a1b7751722089bdd7c8b5bd544d6f43fe1', + '0x8691fdd1923e99ec8e43df85c4b969205a96338a', + '0x0a28f530202fb53baa84c1e6c5109098ec59617e', + '0x63d00e168cf0fa157f69a856833a1c0236410aeb', + '0x234d953a9404bf9dbc3b526271d440cd2870bcd2', + '0x705eb6591bcc428431b6b37182fe385acf0e0523', + '0x469788fe6e9e9681c6ebf3bf78e7fd26fc015446', + '0xa7abf764980827e6b7549cdf601f29f08d16d68e', + '0x70d95a4e6f514149af97de9a107d12bf1cf57169', + '0x9dbc779af862272b8e537392b74105da8b21c199', + '0x76fb13f00cdbdd5eac8e2664cf14be791af87cb0', + '0x561ada4b0243f1d83df80d1653e9f76e84128b0b', + '0xee2db4c44ee6b94be3e4cc0e0a09759b04505db9', + '0x796ef6cf62749d1fed7647a8488cee4cbd7037ca', + '0xdb4f3a2def81c523a76856d145fa05f330057e3b', + '0xdb721052993b705dfd0ab11340eee70ac9a15431', + '0x442dccee68425828c106a3662014b4f131e3bd9b', + '0x7b0cb81744376d3bd5e5488af035ac9aaacc333e', + '0xbf4221ff6744754d95eba4e9c219be987d9edad0', + '0x7461d0e562e54c591d5cc56c32ef280a3130ced6', + '0x4733984976c73c8184d0768cde7bf27e3a404932', + '0xe6ae9beb6a234a3658168cc853989921a6cfed8a', + '0x8721e85957691438a5d154ee498d9224a2b35e89', + '0x1db69adbd1c9eea371b63098b6efbf5f8b17ff06', + '0x6d7f519a18e903b1642fdeb6419907b2b912cfbc', + '0x9d9e26932d012b2ab21b974fe1552f4025b1e1cc', + '0x8e3a9e64889df8a20ca8c519b415674d0a8ea099', + '0xb3ede99d77a8e7ee37026293fd6c740c1b4ec0f1', + '0x6e5e81125a0ba80f659b33b84c0c470b5d9f0187', + '0x00e7332f9cd4c05a0645ac959fb1be60ec24f94f', + '0x981cac16246d9641be07bba6e19e304b74b173bc', + '0xf79aa684927b27175477b2d9439a9e4f819e4877', + '0x04e8b7915440d50b9d0ac7adaa59b5ae9f1a622a', + '0x89c4acb8b5b5b8e5b2121934b9e143569a914c80', + '0x8d278ad2e9f114b359c23d9b1a86e015a87b228f', + '0x53f5dfc33e7cc4b66f5d5086038dfe338e60dd59', + '0x3650e0c30427e6223728927c2e773ed9babe7d77', + '0xbf71dbb7179087a76a22cb9b30ca41ea635de41f', + '0x2b1123c561e54d7906e46aded6871dbc00998410', + '0x9e6e344f94305d36ea59912b0911fe2c9149ed3e', + '0x060ceb6e7039f71e2b5e87762662d77250c80fcd', + '0xac96570cf5bb71e557f117651ce4b100b6d06af8', + '0xbeccce91213583d2462d268a2ffe397accd0f509', + '0x492328fc6c13aac8445fcf3ea717eb315b9d20e3', + '0xac136edaa6e5280e344dd3a2d463d7c5ed93cdc5', + '0x95d47a23f342a3acf442683b31d69daf3b1b31d0', + '0xa520dcdc9d94f2d1cb9087984d74b38e9aa5739a', + '0x1fe5844315ba92e86eb64c8317cdb2f11c8fe544', + '0x6cf385da1f795cb26811867438e5f215e9b9bdf4', + '0xdc0b3127a71367227311f02fe4dda2a6ccdbae78', + '0xd31433d53be2c070c8a9d4f6d2420c07926ba392', + '0xf46c246c69f547bc3b864648bf13324c355e519b', + '0x1f4fe5985143b971fc8d5917a65f83d4e49bd334', + '0x0e93982dc0e777261f9a4d7430f7c4f9032c498b', + '0x716f6481c7d18d89173fe537105bee2b9ee9b88c', + '0x594b596cc36802eb5f64c89c9eab8f53c9d1be2a', + '0xb431481b23aff6efa40fe19094845a293ce09f0c', + '0xa5996fd3b10dd9ca6813eb9dae04ec8fc97eb41d', + '0xe8c4b9799bbe954fe4ca819eb6501a00ad8ddab1', + '0x2b0bcc79e812e46a73849c0911fa3e4e391ecdc5', + '0x70308ee8f336ae621c823d8c57c0d661cdc5b6bd', + '0x85277bd3d3273994ce65fa1bb9d0bf7da0b1980b', + '0xaa7a9d80971e58641442774c373c94aafee87d66', + '0x2292d4416a8ff57619cfa32be4aa5a392496b260', + '0x996d5d0739853292bf8eae5ddca7be1523a80dad', + '0xd7e7bca98ab9fb25e17ad73429e89a40b55708be', + '0xa66d38d132461f69b5aa1958233ee120f513d451', + '0x415f8151801e5291fdfa45d1743df32d8db420b8', + '0x21827e17cc3d119ff39bc2c4ddaf31ec83f6a3c1', + '0xcdc571c6749e5d2229e9f69ec6d45d653ff297c1', + '0x13d89b34bd57f483f4023ca147d1f093436cf4f4', + '0x103e6196d1b1634fd71512674f29002dedd6cd92', + '0x0db3af39d0ce8c9cfbd0a82b391aceb79edf17b8', + '0x4100dfac5f44b72419638d0fb2eec4abbd299ebb', + '0xb0d9afc919cfffac3be922aa3baf2df55e588813', + '0xc3d2bc827b2ddddee0ec1917a898024e66d4eb83', + '0x78d29f8f33af8a1f4ad1eb33f5c46c953cb0ceef', + '0x9eef87f4c08d8934cb2a3309df4dec5635338115', + '0xc9a25adcf11fc7e6fc8d419f4d4c861b8d57ef37', + '0x28bcdcb0db88e457294545330e81915b8d0e7775', + '0x0e490b76e06975158b065c17a1124f2144ecfa39', + '0x454a31b41113c675548b86aad9037e4288b709c8', + '0xac0a1fc7a7bda7338e67902e3db84a70db30be3d', + '0x4a14aac44555d43963c0b6d6fa311610137dbb17', + '0x98ab20307fdaba1ce8b16d69d22461c6dbe85459', + '0x410812f2f67370b1f8628759fec499f41643973f', + '0xef4fd55584434903aa6fc9baa61eacdde5355da0', + '0x33a26ebd7c2dbbac379fc130b2c37339cf19148b', + '0x0d7ed52754cf759ca4da2f163a61be89d3e00399', + '0x0827ed3a46c9793005e4d68e838de577cd8dd752', + '0xc8b5c265f485f70e15d1b593115e7700cf5c8ebe', + '0xe2d48f03082deef8eb557b00a54ac9fc38aa4709', + '0x10f5d45854e038071485ac9e402308cf80d2d2fe', + '0x427c1dfc5bcb038f4d64847485e5cc44dac49eea', + '0x265b1827f8b33b1ff1abadaaf6bf15e7f6967204', + '0x36b0f5c5780ec9c31c1d04aef76a07a35d564c2b', + '0x873f2ccfeb3c10154067df4f3adf67242c62b71e', + '0xbce35d5a3e89995730b3c979a01319d06e41776f', + '0xed7461fd98758a84b76d6e941cbb92891443c36f', + '0xad72c67ca8279a4f4f3b7494c21d4ebfc80f3085', + '0x6321036d639b8acde7ed249ad49f9c09458cf7f4', + '0x15a9df4fb3fc90452234f97c4a0921eb52b85c70', + '0xe400a85a6169bd8be439bb0dc9eac81f19f26843', + '0x2bc2390c826ae5a86fb0e2cb88eb15344a6f3183', + '0x963d71304d39d57b7686b904e78cde90622bf1a1', + '0x3adc0dcdf2fbf3ff563fd16b16d5a67f0c141706', + '0x6fe74660d9ccad62f5ce15657e95453f1c54b6fb', + '0x358608e463a58fd4394679210f4df4b8281fb4ea', + '0x5501e91ece6370be413d677cdb18de7fceae3bf9', + '0xac0b95836400d1705fa5f73b6ca7472bb82fef5b', + '0x0e24f8be98b14a20cd122a999c7340601f5535d3', + '0x6af855deb29e3bddfd8434369a78521102c1c998', + '0x4050da825d515d1993ede7847cb95d0f1ef9b293', + '0x59282cd1dbbf3698f23c436d509cc9c359696c3d', + '0x983110309620d911731ac0932219af06091b6744', + '0x4c7946a6dcc6933b61ea6ef8292b3de7c165a6e7', + '0xf91d4103198959eab7a43507cf4c4982332adc14', + '0x84ecf15af6fec307afeab934b46947967bc02d5f', + '0xbf344337111369a2784a61316003d4f5fc3b62b8', + '0x897c7b62ddefaf1ef0259f5e32c131fac577ec96', + '0x77234d179222a005778d53e9dcf4990dbd1377d9', + '0x7d7dcef3bb919347f5031127799ee2679a9111a0', + '0x58b8411cbd5e5a08a6165c7e5656e0d429591910', + '0x504e7620069a0a8354434ded3150ed7e2ecf5153', + '0x482c96b007ea453cb55a3dc11ceb8830e18f0639', + '0x3fbf9d32904faf5288d964da683b7ad7bfabc56a', + '0xd2f1e21b558728c03ff3e7b9180614c9ed16a2af', + '0xbeee816c3ab89976b22faba9a17e12488e30bcaa', + '0x153b2252eddcb3690ae6f5e9f38be13779e1364d', + '0x21639a426a07498c4e7157ba909f92da2d57ce87', + '0xb933aee47c438f22de0747d57fc239fe37878dd1', + '0x8a8feacc614fa4b59cc2501f680c28e98e57bd14', + '0x1ebb6d5c69072f11136c0c8e3a5821c0b788a533', + '0xc9e7d61bbdef3f821da08bfdb19a2bf7e0ec60b7', + '0xa77610fcb5288bc95849c64136df159dd3efe6ac', + '0x3146b08a028f6f1aaf00702706cdc3007e3be3da', + '0xce6bbca1aba0a0c4b93855f9ff5cf81bc856e280', + '0x0b8d3abb07291a74845a75aca47eb9d6a3ef19cf', + '0xd1b642f26ec49b7f02a755247033c37fe6555555', + '0xc3c89976280fd96bc73aa64d15bf665252aac0a6', + '0x768c26e52234a0efdf77a033549fc074a6ff1663', + '0x8218a2445679e38f358e42f88fe2125c98440d59', + '0x84310a21dd8622778f80f0923d16a2e460d94ced', + '0x2048a301ee41de509d4e4d83f2bca8035558731a', + '0xcb83e217b89f600abcc70aea8f1022c9683265e4', + '0x25ea5369f36599ebca65f3552831484cc0d8b92b', + '0x6649e95a9070f2e2e5cd9efeb885eb7a24768ebc', + '0x717263c9d33812b94f0c8315bb042d39b7638928', + '0xbef99f5f55cf7cdb3a70998c57061b7e1386a9b0', + '0xbd4f277fc9166d18c202aff35913a8f7e53b39df', + '0x19e40001703481b3b7c03b4285479d0912968b6d', + '0x2a5b95c0770bd74b66d7214e60ea6619fd233687', + '0x1833d2a04271974e7504fb0cf681c54333904d7e', + '0xb0145ae156d201d6e371d07265fe3c045071c967', + '0xb00cd8e790ec45971a04695849a17a647eb74463', + '0x309934b6b1ef896d04f3536d50db456cd22d3b58', + '0x763b1638b5a54fc0fd269b286263dc9227ae8428', + '0xe81f882f114255c04044c6a2534d7887f981b14b', + '0xc670d73b27537f2aa8ad823d413a7ba7e8015c38', + '0x67e3ea119e141406c37e2ca783b749fe1437673f', + '0xfcd8a64e02e633c8a8c4ee77f79887bf9e7e2d62', + '0x2bcd3566124a613033a5c9467aec84c5949ecda8', + '0xd7169d72187c58461085883727dbb2bdcea71295', + '0x1538cdf5f3b345be5cf7d236467bfa5f6c35953b', + '0x0291634a27fa16daaed450310f3d7820debecdc3', + '0x19c94f2f663d91ef475efb8906f08e5d04a68573', + '0x8d5469c906dc6f2185ac0ac523ec8313456e65c7', + '0xc129b60376046f9132cdb90c7398209eb2db0c4e', + '0xce8c14435fe642f2af259a768e060c4e845606c3', + '0xcf7cc36ccc46a15126ed3c1fa796db718f330730', + '0xe2d9942b99db16f3bcac5787babdf5ef1c415fff', + '0x5e349eca2dc61abcd9dd99ce94d04136151a09ee', + '0x8c26b5d5cf28073de8ebac0bae2ec0e03deda176', + '0x14e9e9f0a8d9bac4cad8c1ce339826f42924e542', + '0x1f5638b94302b8ffc6a92d68472594ed8f9d9fbb', + '0x29519122d08771ca4c83c8e3fa981df18721f76d', + '0x1b89d5617f698942a2fd894d00e5104aa10eaded', + '0x9419ebc42ef5be9add0f6036eba6238db936a03e', + '0x369e32aed1dc5c33c85ab20977fb645a803e4a70', + '0x50e149530fc34dac0d2b6eaec4906624a82a3b42', + '0xdd5aa88ad0b7e1fb429ce7419c37ca178c6d77ac', + '0x60025d943eff43bc92db19cc9bfe8c8d94b658ee', + '0xabf107de3e01c7c257e64e0a18d60a733aad395d', + '0x01c7b3b2be439441e3cc8644b64b664d5e4e997f', + '0xa98be6f81336a23812bc672e6a936b1b4f3fac64', + '0x0ee54951f58819092730decfb3f8b0be1f909759', + '0xaf25f79ffd2fc428c80392f0796ec9c3b2e37fac', + '0x8f1076ad980585af2b207bf4f81eb2334f025f9b', + '0x557156b8fe6a203dc1a60869bff5555a0ade30dc', + '0xf5fdaa91b9bcbbde2e3626e4c4c817b34bd796f9', + '0xb222525a29c7f35d826b3832501d5e980498ae63', + '0x60f095317a3be2a75fc34feb424e32ac223b6242', + '0xe485895fe0f7427830786dba7effd8efb0541d36', + '0xc35f3f92a9f27a157b309a9656cfea30e5c9cce3', + '0x965a8e0dcdeed52d6c3aaa593c77ab4434f0a47e', + '0x74b367e3c04544c0f6c4af3838ce040ab1296619', + '0x496a42e6f7d6775290a702610e56a2ef6c33c996', + '0xc2e7f4247ffc0601a491c36517258a79c5da8594', + '0x3db5f5be025ba8bc01cf9cf308e006d8a74b7019', + '0x20b38b1d24732c9bddb55ca86844df0ed8c53f00', + '0x1d31f0c8c4cc4301d8cfa4ea9a5f86eaeba2f868', + '0xa0c6134f9e9a35753fa1de0344ba44cb85f7bfb5', + '0x382146445d8de18529376bca66dca0d4959e416f', + '0x2951b1f7058bd2c05f01954002c450bac0873847', + '0x5426001dbabf1aa6de300b290175e021ab80be99', + '0x3c47f81b6b02a10d5c0c51557647c55dd7f5c71f', + '0xb58ab14a6cd1252c0dba3bc3c97829b2be110e97', + '0xf29158bf9b5da0d885b3cf0a29b1eacacf751497', + '0xa97547e522f722cfc6b1cae486683af4fb51a4ac', + '0xc416a1ca1356d7c81d60050a9d998f29ef831a7b', + '0xae06ac0d353329cccadc2fd978042591447c3de2', + '0xf8873db67345f0a9cbe38443319f75d548a42ef8', + '0x08990008277cdc0e9fd7fd47ba578d38a33cae38', + '0x435bc8377ba7e2765742bb60366310b8f6accf33', + '0x182325ee5bb901b19e88f06cbc38e53d851e1efe', + '0x609f524e0886d6e2000a61a9e48295ed48be7a6e', + '0xc8bca21b2ccb400586622c3f1c1e7bd653aba5f5', + '0x3f478216041713a4b1ecb672515cc1b039bbe790', + '0x3bdd24e2c257cab717beb1ad377d48e7268d0b9b', + '0xb66eebab55ed82a46b43cf0cef16948ad1ae6634', + '0x099686478448ce02f8e61c6b01904d0548daeae5', + '0x8d0efe7db232fe95f9073d3a0abdb4b6bb7cc68e', + '0xf12c67e80e309eac0c4dc18fb26e68f9672297e9', + '0xc97c5931c53223b434b64b44d03f4d5b404126b1', + '0x5cee16d12dbd293ba4b593e6bb0ea4b645fd8ff3', + '0xd4fa2130949a51e5d77a5d43d1911fd0786d9624', + '0x017c88a88b5af20123147967ca4ea01a6b834671', + '0x572c08a1e5b05bd5944322369aa143d23a2fe498', + '0x9b328488a8f0fa20628bb959769f0ba78de06466', + '0xb133a238da0cbf19ab5d22fcff5f2cf1e27a0f78', + '0x4145d3e2f3cd0bacec559d27eb51768ddede67a2', + '0xd31a84c20bc430ad75e6a1903e7ddbee52211072', + '0x20c9990414fe9f7ecfa574b81ee18de7296d05ed', + '0x6711614aa7f61ee0fd79757ce4d8ab706d962c1e', + '0xf94bfbd175219331f9ff323ea703ebd2a05fd33a', + '0xab48b6648dcc56b89bb2eea7ff7b767ceb117614', + '0xa0a5992a12b01b019e2edfb04fccdae28bf198c3', + '0x5e382071464a6f9ea29708a045983dc265b0d86d', + '0xc659fd78a395d70ec69ff034b4378a712e7edb64', + '0xcfa73faeb0aa5521a88665550933dcc76dff353a', + '0x16c5efd522b2fdba7342f13e4dc65681ff674f0d', + '0x285b7eea81a5b66b62e7276a24c1e0f83f7409c1', + '0xd4ff70980ed9f4a3ea6ecc17743f27733aeec7cf', + '0x31ab1aae341b34c005a800a30d6337c5f9495547', + '0x69b5f5e85ce1b82b383034a1c2629c143b8e29a9', + '0x5eb27c71969c678d21585c8a2f37d4df1ad9b6e7', + '0xd517535e148cf3848ddf1611aaf1750e788c6a0a', + '0x22aabd935aee16c653f9af38c470384e15e91d69', + '0x4fb230987d40e3faab29cfb810e583b72cfdbb52', + '0xb1ea5a3e5ea7fa1834d48058ecda26d8c59e8251', + '0xf396126d4ce9e8b8f8c70b5173b46834aeef66a2', + '0xcfbf921ab668f216f9d5b547cfc22aae6b48e612', + '0x646bfdd1316372bc684305c6b9591e669f86b11c', + '0xfdffca1246924de90f54f867db89476d011e5ce5', + '0x365047213abe97401e8bfa2c48d12d2731601f98', + '0xa30e41acb4bd7cf8f2ac1f3b90e815953548315f', + '0xb2a33ae0e07fd2ca8dbde9545f6ce0b3234dc4e8', + '0x5a95ca824c297081339bc941cd8c42fceef5d1b6', + '0x7e014e5efc01a79d1a7bd3171ad513134508556d', + '0xedf458ce355c755e1973778b51b917066d4c0bad', + '0xc0fdf7c2899bb2d0bba9f5e6542eb9ba8fcf6c61', + '0x8575e9f5250bf3d11a87a01ff4c859851bd595ad', + '0xdf12ed87641f32699b05c836f68ff2f00dfd74a9', + '0xad2c0039c24ef650c49d52d76ddd105673b91f21', + '0x8933e3d147488503398e041a01395494a05ce107', + '0xd41d8eb7b366ac4f931c9697d02b5a4d26190ee5', + '0x1590e7f4c3e1b4493abb462e34593aef3a9397dd', + '0xd6e62a97a55537cd04847bb73e22208bd20106aa', + '0x092e7acb2c8f13546ccff96bc6a6005ae9fe5162', + '0x29c66f54fe449041555d510afd0c1657fb3624e4', + '0x36b624180e8b8b10a120d9f543b134d7b312e371', + '0xf7775879a3fce35d2a99154392ffa6db22cde2ea', + '0xd9df7441f87c197887cf438eebe3368637e76a78', + '0x55e6d267222337e072ffb2291d440056fb32fe05', + '0xeae56c66d764767523d553b2a3d1936567af0cb8', + '0x6caa802c6895ecd31601518c7f6b9ef6f9349238', + '0x8fff28d297ee222eacc1077e7b4aa9d96afd2d3b', + '0xf1258d74c5188cbb1e5fe3d8508223525a4fcb23', + '0x5f1b771406e26fc4408f7a3ea78ffb58e1302505', + '0x069da1bad547d67abf26c42358d3a6a8a78deca0', + '0x1ee993a70bf0bd859ca5ab7a078a8ef31aa1242b', + '0x549a9021661a85b6bc51c07b3a451135848d0048', + '0xd67515557f107847869d652d35050c345ce7fa77', + '0x1f7fe11e6cc07a184072d726a20beeaa13273874', + '0x76404919d5d21eb48f9017f8159628bece538093', + '0xdac976629020966a03ed95f19d0db8f3a8a7215a', + '0x6e5ba5499bd4bba442dc88242f9c7929ad3151ee', + '0xa830e164e20d077c29d7c3bf781a14fdbc4ed217', + '0x109d0d2aee08485e786d5150951c5ee99e7ffc2e', + '0x3e7c4e57a1dc4dd4bbe81befbe3e437f69619dab', + '0x1c040e6442cae9a13b40127a055ff101be436c97', + '0xaf8738a35eb57a2c69eefd4ed48947ab45fcf765', + '0xbee57ac12a72b9900e0d909acbe2e19afcec6af2', + '0xfe97b38192cb30add0bbe5e01e6a617562cc8318', + '0xbe387571ad2305b3a8452b038483d29344daa8c5', + '0x63cc3233583d4f6baa198c330cee239c615a7719', + '0x04c2e657cb2b0d86d7129819808430d889ed2660', + '0xfd2c8f9a963837fc9a6ee153cbe4200a60962ec6', + '0x2d4911172c21d05344f0beb9e2b20395f6bb95cd', + '0xde6ea9a2992df0dfa3ca5cf09f9f7c2592930342', + '0x52fa613b2097808e275356c6a174d0b767f8e0c4', + '0x2ce5f9f52c1eec9a1183f91139c59b485ff39dad', + '0xa4bce756033c95042c5778c565d322d55c3165ee', + '0xfcfc1ffea98ec60b5f411528ca28f37a5d0fb40c', + '0x4594e5b20f06d674257973b353ea287a591ee31d', + '0x9e50e97e8f3c689f0d3806ff7760ea077f284b91', + '0x392027fdc620d397ca27f0c1c3dcb592f27a4dc3', + '0xf1f5bad5bc2dec3f19fe757336c55716f7af013d', + '0x18ae0fe9a45e4f7dedbeb5ce2ff33062ea4c616d', + '0xeb7ff5536e8c699545e960f6867dcbdb6d6fa243', + '0xf3bfa97c8f0a981bd7f54fffae3e751ab7d7fe8b', + '0x127831833355ba81d81105dcf824c3e2b7654c55', + '0x613e052555ac74ff6af0fc64e40e8035c1e9dcf8', + '0x163d8d30efcc8c2f6b1f0b6d575f87db186cf2dc', + '0x4ca2a670bd5505b870b21331a53d9bb4ae6e2084', + '0x0ef55b04385a86a0bb658b3a66253870d97ff3fa', + '0x30154562b81788b2a4fd126682795a49a02ccae1', + '0xbab545da9730607f78310c9336dd44677b2d4ac7', + '0x8115afd8dffce5579381ad27524b6feeae917bef', + '0xd894de705b1fa1548c8c7ad1b827b32f6ca36475', + '0xcab28be5f5315407d9fac010f8435628f0124017', + '0x196fea559e8fd846160a6c39d581653b281aa70d', + '0x84a38630b242b1eecaf6d4c351109945604bc4fb', + '0xabf484da77edcee1f355ec2d5a56892433098c63', + '0xe092c2b293523b386c6bf336c9c22fcc82aa1995', + '0x8a830f105a42e705cfe3a0295dfcfd7259ed4570', + '0xb6418ba9662e39d4acf4483a4877ccd4cd0b7aea', + '0xe3b9878690b92166cf4ab71e6935bb4ecb1ee83a', + '0x6fbc9e9e489dd1e511c91f43a34be0df2145d9bf', + '0xe088888a95e1edd741c6208b3ffc76f3df6f699e', + '0x4fe5f268e5053a05108ebaf13ebd9a825e6fb6f2', + '0xe4c88a29683cc71a02234c622140756d2b89c027', + '0x4e216c511db4f48ba59bf05b59d5da93a9b9460a', + '0x2be830c9c4a3eb3f9ebf736eed948e9ec1f1f33b', + '0x75ba5ee883c2ede43282bde16e38d6ca8edccdf3', + '0xce95728d52ba3d54ad62959240c5eeccc2975b57', + '0x600c832400ca1d88104a21bbedd4258327e1bdb2', + '0x0d6a42558f44279dcfa8f81d22f28794ee423244', + '0xc7a424bda8be9e9053b257f0143c1ee624f9223d', + '0xfa22719c1970c7a6c5ee8b7eb4886f6df515b994', + '0x1e09a216b70d46229f3fe86d3ad2e47ae01f7989', + '0x2404d6857d7e90c3ed9e74e0d372a4d6d7399504', + '0xa291017d892e62b5ed74cea8d38d9cb00a583343', + '0x56e9cbe44e612aad90737fcd911c4756423c533a', + '0x57c2570f1a4228a3aeff4fe533826c2a04a2d52f', + '0x53f9a8d4b527e219988deaf5d8246a4427eb2e31', + '0xaa96a50a2f67111262fe24576bd85bb56ec65016', + '0x697f21718a14a93bd76b1b97b32dc02f1f3ff382', + '0x6637b1df3a1143b8c5b1c564f45e4e73789e4f12', + '0x93617280d57564241b4ad4f4e09e02968f3f2d76', + '0x0ddc4e320965e37a061f8209e45cb990b05024a4', + '0xcebcf99dd171427316d5d5c65bc8e5dc107cfc34', + '0x48095f2f07d169297b6239f93e748f6f8b8ab002', + '0xd324ef9fd4415aee2046090c3c16641ce7b1256f', + '0xd16cd424ea8c4ffe338d568d6b3173c69e1b079d', + '0xcb11f95159731c169b0e52e266bbb644afedbcbc', + '0xfd1978685d39e1d27aacf2ccdd8c5a1c93afbd39', + '0x60af6197d08dea71a22581f13b72018b8c2671a7', + '0x84b9893b23ba436173d947cbbcd3a4a260678484', + '0x7b13c2f7aaa8c772bd0a13a86b0cf633faf790b0', + '0xe2c48e3b683299b914f9616a89e38d9f40ad29a8', + '0x0936e1c4fb71b3af9a5537bc7462e6887dbf70c1', + '0xa1d2c091ffd5b2f5c432d16d375494e3d6b377d1', + '0x9f24b31a187e0edbee71c498681ce2eaa9849903', + '0xace97931a8b720ad5712b3bcdd36978888252a11', + '0xfa6f8535d062c275ca222404cee408fcdd582c9b', + '0x9f87c1acaf3afc6a5557c58284d9f8609470b571', + '0xb70b037b9fa364eeb041d960fb9171e1a48121e6', + '0x15fee449bd712b7b4a751af84840a678d2e2a1fe', + '0xab8327ea7e696a51a50f2598c3886bc0da097583', + '0x0237f177a6240c30ab6226fe8e0024dcdd0dd3c2', + '0xb3bdff7d489d625e1ea5c2ea989a11a6a1761c3c', + '0xcc9fc76031067dd735fcd39389b216e6410f79e6', + '0x5ef3f2c03b78bb006f56abc431f5da2534c2870d', + '0x98f1845354c5b3a8d9525bccd23b49ee7465385d', + '0xc8a69971daa3c3add85ab0d0af297515769ddffc', + '0xbf17ca43d17faba14a9592b1a5599a3b8c91926c', + '0x02de4774a7f12cf868392778295ac38adeabd2da', + '0x3026e5dca7a3f50a482d5f06fb18ce607386531b', + '0x6439abb662e3e5f0eb95dcd25a576a722383d8d2', + '0xdc38c6fa12cf847dc11eb5e067e24f2183497469', + '0x01e198818a895f01562e0a087595e5b1c7bb8d5c', + '0x213361feacf78d85f682c9028e985e747e3955ac', + '0xeb83f345df0ccb0d00f521a21bf398f860067467', + '0x5da915b1dc5ead330980c8d28e2a1e01d3c1d7bd', + '0xa550215d922af5af685461887190cbe1cb7c8071', + '0x14e15663428672cda90b88dc68f4102443202d83', + '0x193991827e291599a262e7fa7d212ff1ae31d110', + '0xf738700b8f25cb8ffcb6c523439d9bc236d8d14a', + '0xac151dfbec956d60b0e15338e736e24b110e2f3d', + '0x76ea7a29d0ead7cac2627866b814382e362bee7e', + '0xafe4043c9ffd31753c5be2b76dfc45aaa70ebd6f', + '0x445856b60b3a1417d5ce90a62a5cd30bbba40138', + '0x4be97ec3f1c6a386d5ddf2c0a72e98463bb107ad', + '0x95318e316f3e02fe0dd9d01d3f3e094d0a16b738', + '0xcf10cd8b5dc2323b1eb6de6164647756bad4de4d', + '0xc1f8ef5171660f529a3991828926b16999b74a03', + '0x7ae0fa5d8f8ff14f86d9db10d63dc3dfb614af23', + '0x5b0fde1af68f166d37189638b35573a57faba6a5', + '0x2036cafe136f1ba6201ca6da6fcf461bd4c5e635', + '0x4f392ff97549f8b70c8acf44438de66f311200ab', + '0x7bc4d94c7bf180800b90af45d6b00aeb2cb687b5', + '0x801abde79477c69720008e273fe267806c28c7c1', + '0x8cdcfffb937f73089b5147a38ac40d8cdd738da6', + '0xaf0e126d11161fd002200e980103b78470e660e4', + '0x7bcffb4597b358058b0f259ab29081a246ed53d0', + '0x8becd7ebf3f910090f9264dfd0bb221ea04af8c3', + '0x5b976b898902c76ffd1fad01c17e16913effe5ad', + '0xd3de0160a8eebc98b65a0d22563633b41733e983', + '0x08f8c46f9f71e301ba41f59c253c412f1a129dad', + '0x86d480c513265b5f9cf29e0faebbde8d3859bab3', + '0x9a739c2e212754c3d8432cb717dc9437e5b3dfae', + '0xe1b6f760118bedd623013fecda7a32fc8b511629', + '0x2b42af260ba1e0449ffe40fbd62978295bb7e904', + '0x8d303a8453f2b7178253ff35037f6ddbc5ba2e4d', + '0x9937e3e274be96a624d7cd00f384eb71c741dd1b', + '0xd95476c57b41cbdf1b19a49d4520c19ab3fab707', + '0x320d136b22b641e2467eaea653f6545e1f2c0071', + '0xa1aa8362b18272cae23b57691a0339c948e119d9', + '0x947b7742c403f20e5faccdac5e092c943e7d0277', + '0x968a0e5603c5d4dbf24cbd7df562921d158ad19c', + '0x2bc319ca1f0cb08b410be7eb94bf7c123375cd54', + '0x4a9a2f31e2009045950df5aab36950609de93c78', + '0x3b60e31cfc48a9074cd5bebb26c9eaa77650a43f', + '0xbdb41bff7e828e2dc2d15eb67257455db818f1dc', + '0x4f2b94a19fde65fb5c405265d47c7b1df1df4821', + '0x2662576b9e16b1882c88f820220ca6946702dcc0', + '0xe68b3e1160eacab13c408f1cedb15b486da73b99', + '0xd1932cb72828e6b5d9996ca2d2fd1331be016201', + '0x7166755492d46a1c22fdf7bd273848afee52b593', + '0x66666ad6b459f54a68419363385316abb8a857ff', + '0x95cdbc58a013024d9149d5050c26cfa6109d5db6', + '0x5e6429493ee91b7a781be18a4e58f6cf96a31f7c', + '0xa6ffd0c2bf29efc1b4ce9af3359ede190e5b9634', + '0x88f1706c20d94a4d1551c5f799c9e3380a24c3ac', + '0x145ca5302130becfcaeba9ad93de2f4db4d3a72e', + '0x6d319e903198bc5c7d5d247f804787f4821923cd', + '0x2f7c53d9610167d869d9ae59d75350e0f536b6e7', + '0xd714dd60e22bbb1cbafd0e40de5cfa7bbdd3f3c8', + '0x03118e02ce007a0f0d1c9d806c2a7d5ae2f26995', + '0x9c059c76f695fc71731c43f0afdca61624192abb', + '0x42fc353027cbf1a0b4b1b72ab79d3e74bd04f01d', + '0xeae62eac295c78500ed9bf227eeec6fc9a2116b8', + '0x9221e53a5e8c3073f923a5655172d760fd38a1f5', + '0x880814d04c48344e490cd5a8dea1288e939878fc', + '0x1ff350b74c73b28f745473be1ebd7639fc7e1be6', + '0xeb70fe2e2a0146fa7a5ca1f88c6ac5c93ed1cd8e', + '0x506c3d1029dd58009ee6fd6488de912fb5e8d911', + '0x601091af1314491f4e3088f8f0fff80d31fb0e1e', + '0x8bee0043b5f369367eb694489305962e72b453b2', + '0xc4e9e087a811be812f85e49f2a41603d9a0991a9', + '0x8ca24021e3ee3b5c241bbfcee0712554d7dc38a1', + '0x0ef276dff8847dfe54db263b9889968daf5ac3e0', + '0x87956abc4078a0cc3b89b419928b857b8af826ed', + '0x5660a09c50387f49a1554acf90aff5453565f62b', + '0x2f1a5c8523839c2d0692f7c89116fb067b77a532', + '0xbf1c92051b1be78753ee7b47301de06c67b90f1a', + '0x6238b78fbb072a4721b9cd9bddb1a093a7c97431', + '0x59693ebba325f592d858c30998d7c68ee29a4cb1', + '0xfd9ce79fd7f62ca88ace958cd2716f4cce25e2df', + '0x895be97bdb9f8a244c472b18ea96dee39ddf8fe5', + '0xcb15649d7b7a1eb01fb1acd14809de6cf82aa1a0', + '0xd434276ad656c193c5e8ef37f211c1ef9628ca44', + '0xaa59e8186e5c31e507ee1d429981c10138a32e38', + '0x55e7b1f29bbd994e429d11362f9f7373903dee09', + '0xb3abc96cb9a61576c03c955d75b703a890a14aa0', + '0x8d52201cb62766fbdcaa6dded248f7fd73a85c97', + '0x7b4f11f64da52ce0a8f7bcfc776bc50fc94aaca0', + '0xc2ae0852930d7e633c4fc635503850d980ed3f62', + '0x4df32be58c1390d1fa16dc71799ada140872b4bf', + '0xba45b15e1349b6405e43b70fe18c112f1fec7f59', + '0x840b0c891a9e5dd0868946e26c1e290567b7d962', + '0xde0a3b29d6a0b7835b9191a89241f0814c0eea0a', + '0x424a52eea75886992088a5b2b9cdc49adf4e1d3f', + '0xbcb1d22e5667964aec911dc4772d200436d8f023', + '0xd0ed4ee0c4e5c6a697afc2c5cfacb4c8221bf371', + '0x3491b165b4d38d70d2c66a560248e729066d4cb8', + '0xadb2df2675786f2e70bcfb590233d6bb38da0dba', + '0x737fb0d6e539938f05d826da91b664b66e3c9606', + '0x78269edb0c25e8599aabfb80beb75ca0f57de1b6', + '0xa479050576ad284901cf64a805245a1a1b391a03', + '0x20651c0078191498199ac5f1581a6c6b9076a233', + '0x00a73c4e596bec4c4068a9152da71e45480b5450', + '0x2fe9d42e1037d4785fc5e3ee7f57b34bf0140aa1', + '0x648aa14e4424e0825a5ce739c8c68610e143fb79', + '0x7f361aa96041eb143ec27f65620dbd7a0ea32554', + '0x0d0b52f22dd33091aa39b48165c0f3e07f9a2ad1', + '0x7b82ea36fcfb6c4501114e8028a88d90a0dbca11', + '0x082aa068e76e73e5dea46e4993614c5a29dae2e9', + '0xe2ac0fc8d6e1041bddd90bd1c2156785bb5dcf4d', + '0xd117658923d9c5e319cd149efbb5108bcd732635', + '0x9d7ba953587b87c474a10beb65809ea489f026bd', + '0x95fa3122c4672717eb768e9f49e40dc4478c4258', + '0x2b82cb88db8fff6ddd1b1e683f83e21c43d11de5', + '0x29eee8f0139573ddd4b41839a4fdca58ccc06254', + '0x18e6b15cff87db31d1173aaf84f7b429fa57b98c', + '0xc9e52a623a6a19f16bde2cd0aa16df7bc2acc1ee', + '0xebd9374d22050b979eb4fcc27c8a01ca9d49b86e', + '0xed0c647095c52d21857932d49e414f9fc4dc759d', + '0x42f9134e9d3bf7eee1f8a5ac2a4328b059e7468c', + '0xbb01152f06d3f6a2a1767d1135b77865f914c555', + '0x156bbe5c1cc60232df6e1f8ad5fa670fe38670c8', + '0x65813baedfd68029af5382672b0e4dd2e6f27952', + '0xb6d19afe6de6c1ab49b964e202ebbf6b8e590a33', + '0x71b9a7ac238a3d2dd20e5fada5c9fd3bfed058a6', + '0xb036eaeffe323649a0f51c7d97b0493670517cc2', + '0x637797a442af01cc79cdb63632ee9de3fdc7d47a', + '0x458075b1aaa3a9e24503786091090547116b5f81', + '0x61be14477ca25571e197ecc6addb895c67618010', + '0x020ca66c30bec2c4fe3861a94e4db4a498a35872', + '0x4a423ca6ab6b02822f7c62af82fd0267ed55521f', + '0xe994c06b5a860ac296dc364d189ed9331c3bcb9c', + '0xd53510e1977bd81aa69c042b7f24aa11a076f83e', + '0x245cc372c84b3645bf0ffe6538620b04a217988b', + '0x31f3ecf9ca812f773bd2afe836cc52df522c8e11', + '0xc6a83c18e0d874a9c76b85b98d5ca6b310c0efc6', + '0xe61673dce30003c68b6f7a0c0d034433af09bf68', + '0xb7637542279e38fadbcdf7298aa381aafd157795', + '0x080c4303c73aa9a063026d67a97a88d1e7a9c6d1', + '0x4b351427dc7826e5dc0091647d21af5ee0fafa5f', + '0x0a9412550204eed92b68e0ae9251c30b2b184624', + '0x5a1bd9dcf079d07e6ae02cba6818c2520226eb53', + '0x365bb0a8bb54e603b83742f80991b19e2a460de7', + '0xbe7eaf40699e6852188030d09e11fcef9d3cbab4', + '0x1f2b0633bb0623dccebe57932d6731ae93f5213e', + '0x518d0f7a7432fe475ca36f3eb6a4a7f408a8bd61', + '0xbec9b6ac6c8a909d68691d359113376f7dd15ecf', + '0x544c0d4fe12355b673d33ca4146d74c2a4118142', + '0x60b54e614947e4978aa3a6ef92a30eb45e5f5bb7', + '0x69968a65eb8e03f98bb5530992dadef9fac3abd6', + '0xefb30a1443a5886acbc6ff432305d2d5cc9c3cc9', + '0xac7318049ff9087c77a71bd7a9a08d81c427c462', + '0x9e0e9d25a5ed9bc773f91691f0b45599255257b1', + '0x610c92c70eb55dfeafe8970513d13771da79f2e0', + '0xd4b56f77d174d7d981b48dc29873918a70b1084d', + '0xc2877b05cfe462e585fe3de8046f7528998af6f1', + '0xf12ec382c04e0a989b852e89ce01ab720e406600', + '0xab8e23220bfd1d5414bd4fad2a36132dc186d4d6', + '0x2409e95953e229a431d6c277d5408f48c3149be4', + '0x0f4ce592795eeb497fd7fb4cc25844b4865904a0', + '0x7ae109a63ff4dc852e063a673b40bed85d22e585', + '0x11099ac9cc097d0c9759635b8e16c6a91ecc43da', + '0xc5200d72e6d3cbb471a6692d7425abe3a0c781af', + '0x877444579532453050720ced6a8a66c0c60b04c8', + '0x936b7e1d2bc5b6d7d62f696193e6d4d338b0d69b', + '0xbfeb1cb7ec1f9e70c2ba12555300319214b6b874', + '0x449e8424e765a04b6b10e10c13ef941a9bf0d48a', + '0x87a89626be393803e4235ff3e0ffe2d55af7b2a0', + '0xc703805318962e761f68133eda6bf816c1e70a92', + '0xbdb8903d2e99cd58f548d432c0a6895c9c16878d', + '0xe3abac3bc452a44b98bd215c62693d715230ffb6', + '0x888e00ac046ead3aca03a0e1b8abbf0c032d39da', + '0xa4b73b39f73f73655e9fdc5d167c21b3fa4a1ed6', + '0xf5fb27b912d987b5b6e02a1b1be0c1f0740e2c6f', + '0x7aaaae8cd46ab71e1e5084d55d9c6b3ea4d970a0', + '0x529abbc74405db95ee0ae48d9b1bc19c3d0d9d95', + '0x9757c71cde5c15be87de4fb2ce6888d3618d296b', + '0x7fc11241f0ea0804d3f5e78d1cb376a627a10102', + '0xcff3a953a80533339d222ce9c18e11d6dd2c661f', + '0x03b40776af5a364ffbaea3d2e293df4cceab4f98', + '0x740dccb5bf8a00c0d3ccf8139a01fda2a370aeff', + '0xa0be0c8c405c488d002c4d1d9186c87dce27e102', + '0x2daac0b65e080b404f16acfb60ec94a11af952a2', + '0xc4947286fec9f5a5a3fcf213de67d13aaa520c07', + '0x3f1e4a5352cd1487ab7901e77b575f4a44d23f96', + '0x36c5a180ea8ce271491e2119d9f6e325434e76d6', + '0xe1c29724b7be8ec00b6f05618d18a28a08759fc9', + '0x317ad090e2a44b9cc617c4e8680dbcb61b75b98b', + '0x3765240be64af984bc5bb3b6a2988e431d668f6b', + '0x74b5378a22333193bb8fad0c3eb4a190a9d504b4', + '0x566666666cb98fb6eb703291831175e6003f4bc4', + '0x477b88378c2d6801029718a8e56f44d626195e4e', + '0x1d90a311499e705d2b0f46f33c496275ba0d4386', + '0x4d71fd5e7b080172befff76ceedae1edbce8e32f', + '0x6a44d3a2d6f40c6d928564c58e9e838ffb970474', + '0x1861974f32eacdcced0f81b0f8eccfed58153a9d', + '0xdd09297fbdb6259b4c0af463f1935a6bfc9692a9', + '0xa697c106f153ba7fa3801ba2afd6273559c7b105', + '0x9260d7f0ab32fed1e25b7b1e02ab2dba2fe858fc', + '0x2cf63cc7ccee738ced034c9df02ecae2beb20677', + '0x9b54d1714f85a192723a36f1e8de9e81dbcbbb1f', + '0x0a8928e9cede470bf74fd1ffb7f220ddbc7344af', + '0xed11e5ea95a5a3440fbaadc4cc404c56d0a5bb04', + '0x93713bcbe5d637f5dab950825b4c8c3965fae60a', + '0xc299ef8cda6f1ae6c6134668ef24eb20ff250a88', + '0x98b83cdd50520501cf45db95e42ecb10445bbefa', + '0x334f12afb7d8740868be04719639616533075234', + '0xfb4a4f4d1384e50173bf647ea2748720f0743092', + '0xcc9bab7d49956748659a466d9af8434db49d9021', + '0x32adc15c1864a11348daa283f7bacdab661c0524', + '0x1177ba1e2fa6dbf1c9753c4e3405410173af1e83', + '0xeec0723a0af783f4fae753d17ee642aa7d5f28df', + '0x3ef90ea80ced403891c5dfd029ddd980ef0ee8ad', + '0xabaf3841fe57ed06ecfa94cc8882c9f6f64797e6', + '0x7a1057e6e9093da9c1d4c1d049609b6889fc4c67', + '0x342f316df796f9ab361ae3aec2f3e5b33aa5b00c', + '0xb7ebd0467d892cffc7e511df23c005cd91f1a1c0', + '0x6aeb8fcc0e4fd7f4625dfd356a8b25aaec12b574', + '0xb3197cad2032899ef2f33bf0e8a26f3ac5b48b03', + '0xa1b9b33aa2c318ea67d280cff079aac2d4784a13', + '0xd017ba31edcb9afc6462f0814a0608a3e5ade0bd', + '0x21a22b4a0cdc44560995325992000460e645c92b', + '0x314a565c67c841ef46569998412bbe810332ec77', + '0x8b51c1ba09ee33e7649cac62ccb6d0f410f5647a', + '0x9d78eaa53cf87ee531518daaeaaca88209828791', + '0x33ae445490c9b75c67952013a7dbcaee9ce3b36d', + '0xce9933bdaf3e6cdf553235b95e4c1b56412d8e99', + '0x66aa8bee5366b6b48811ae0dac9fe5e1eefe1621', + '0xf1a79209f4d4149c6e8f7e989c093d00ebbe55b5', + '0x0f47425534bcf0b326d9dca8655dc95dd4f5c341', + '0x8cbf7a00de4327f173c2a83ff8a6ff63ddadbcf2', + '0x30dacd98447955bdfb3a6004781905e9f661b74f', + '0x131f723e3e8f460104226bb6ef948ea649e5b0f7', + '0x7b0b80919af26b7a4193a560fa0fa713db7e0187', + '0x41a7fe0adfc98b8b9267e837057a7540affa3910', + '0x9395579eee9b622a6c29eb552d044b24721a3db2', + '0x97e637b51cc1537017dfe83d6595e232aa4d7e20', + '0xd26691f8ef4db9f7e5e5f31ca9d82465dc7da0db', + '0x78ff2ed0c62a25503f059df8620e12122a5a7d82', + '0x05d2528a9ae093a20e379f27927ff421caa47a32', + '0x96852393c0aeead1fe7ecad90c24e8267b82c12c', + '0xf4e5d5cee605b4a24de753cd45f74387f38fdc8b', + '0x4e73e24314446800d1361df363825ef8da7021e6', + '0x8f842799ae515fbd1470b08ec7571f6e1567eb98', + '0x8ab0fe3d61e372a0caa2b2acf6d1ffdefd1c645a', + '0xa14c0a53ff311a466f5cb84401cac24e4e8c1a41', + '0xde8a79f5d4fd192d0a8dcd3bca7a7a5eb05a0262', + '0xcabd7395635fb2df2bb6a6f6768709d70d6a9ac9', + '0x6a759f49172fe708fedcafda6142ac90846b6f54', + '0xbcc599587aa0c97f7ceeee9c3bb2db2b33f835e4', + '0x6a72e2a8c95031bc2cc2755e5a30a145645e024a', + '0x848ff2a5179c96167b271673f7bb6597233f5f9e', + '0x9ffd0a5b5438b95861167422e745d34d151bcc3b', + '0x6a42527918fd57911f442761a1c4157a1c059ae3', + '0xb2f6be1d6c18514eabdc352b97b63273608af8fe', + '0x739d102209c83f2713755d6b15d849d788e9b3fa', + '0xaf68308e1454eb452e69ead59b0d45e00d886322', + '0xd37628069493fb3abf6e14c38176e4857910def3', + '0xcbd5acd74e9e92624f4dcd1f65e9d8566234dfdd', + '0x072fdf2a609ab82c40f41804eeec48a5b1dd7583', + '0x904bc15358c40ba6c1e45f10e65d052001e9edd2', + '0xb15d1673d286a4f520acbe6a7541f59eb6dc0947', + '0x48888db73eb818dec38fed2c8d4d08252177de0d', + '0xacd66384ae7e7cf81c4c7e86cdbee94a3e6e6a0c', + '0x1a171a91b4aa1a669e2397d6670746ddcdd4fbbe', + '0x9381741a8ada2b21ccacc5a920a65e8c35d0fa94', + '0x5f7670321668e6db551e39e7a5dff443d42dc97f', + '0x7e62dcfc6d33a42c8f0f333e7a73d4d0197dfe5d', + '0x44620ae3b21ef2143a0e59041d7acc4bf817d781', + '0xb25205ca60f964d45b30e969dc3f10a5de4ec3bc', + '0xdce7b58aa945c8c738abc18230915f88b7675c85', + '0x63a133ced53555ed70e9ac606ec2611d3526f0ef', + '0x9f8af0bef30d33811aedb08f5e642d7b0a176c32', + '0x4b689505e560a7d0e59d75df291382c47b9df531', + '0x16f3813b675bd7ac25ef16913d5ae2c2a26f3423', + '0xcd08d1f2f083f96edd4fa8143c99bf2bc2166fc3', + '0x0b5654c15f1f8200083c2d9298ae9ac08fcad2a4', + '0xec8b791c0c2989983f6d8427fd18a722ee049af5', + '0xbc4429d476fbc50c59b1c7ba7973137d308ae5a1', + '0xed3fc8e5e1719e4926efe93bc1ba5bdd77334011', + '0xe55945473935470fafdc34dde353c3d251dfadc1', + '0xe965484ba4250c446779d4703f1598dc2ea00d12', + '0xc4916b8a736db8b9819ccc4729240f1d8a88c5f6', + '0x2617377809427b497b89b4659ad6e1aa92a51d04', + '0xf5a701d13be654a534d14de8cd6a328293712405', + '0xa736bf77ecc2598a1299c45d8283a27cf006d51b', + '0x3b550a96915c1b6008bcbeac23f9195690ef343d', + '0x3ecff81a9a181826db15b1163b9448314fc1134d', + '0x338e4d22b039468ed06b02c268e826628f0aa7fd', + '0x44a61e402a0528feacc6694ea9c9c2be125d09f2', + '0xab35d3476251c6b614dc2eb36380d7af1232d822', + '0xdf0259238271427c469abc18a2cb3047d5c12466', + '0xee1fb7e04d44ab0d413d67c6a04ac402c601f31a', + '0xa12ed27478a53871cd88a9d388da4975486c3122', + '0x29a82e07b96c405ac99a8023f767d2971546de70', + '0xb6d14aba015d1218863bda8d38e7c401139bb459', + '0x3bd8c80b52e843e02e4cb3ffe0561c98eb607121', + '0x0a41fc2ced00a23bbe7311347a9cef387a52e758', + '0x509c76c59e86e18cdcae958b8fb7776dce03e6f8', + '0xe9a562c5fb4d7247d660ec10da29e1d7991e42d9', + '0x27c48787eb1d6b5c3f5c32ed8b0ba61ec7e1d536', + '0x004256d86d7c2b4460a533ca05b521bf83e973ac', + '0x68047134f0c42275456d99a546f260e5fb587ec2', + '0x97064993a5ef8cc0977e2194f484d4965efb808d', + '0x4e1c5fd0c198bcd7689ec701ddce1e4b3804ffd3', + '0x5120b5440821a7213f2beefafe5faa8278ef80da', + '0x73aa447a8fbb316ba2572e992552eef99fd51e5d', + '0xf30e02d077c4a2a2b30c58387af201d8fb834ddb', + '0x8061636660a6eacff709446c5e2a7e178976ad69', + '0x31567db93d9af6efc09d6043734bcb4baef362b3', + '0x94ea5b1fe6817e5a05f8c1c340a7639deb780743', + '0xf4b195ee08dc60ed1c60464e2be29f7511f2ec5c', + '0x4bdcb61458ba319e0fb288f502f49915af29d8de', + '0xd4d439dfcf33e4c187bda504240581d9ee759caa', + '0x2c08cb81ccc8070121a0b3c1e8c8ab37fba75566', + '0x5f32bb3289803798e0027ed47604d94899c22698', + '0xe89069529689849588cd65344c034a35289f44ea', + '0xee10cfb43fb78ff64117af3dc4e24f4925e985a0', + '0x30c7f4f7504d6366916f669cd8e731ed4df6c702', + '0x999474ddf3495a9d2ae2581cc9c79c40d3240986', + '0x52bc4fa1165b8fbfd8747e7eb2973c262634ef51', + '0x589855dd123971871a7a0f9796e273718fdf26d8', + '0x9d54050cdba29ce15a499391dcd762034c4a7b03', + '0xb655cc4572114987117e54f677e988373650d637', + '0xbaab6ae44a02221fcff0749701ff7c7e4c70a2f3', + '0xe3a8ef86b0b1d496b1f7e123eb5060b5993de1b4', + '0x56d8f61c6d2364375ab69f666bf219e3db99f024', + '0xc28531bdf80a349d35ba5ed98519c7cbb423ccdc', + '0xe2474983c4fb6951ee9a7923ef8ff10119454bdf', + '0xc2f41b3a1ff28fd2a6eee76ee12e51482fcfd11f', + '0xe4299fc6acef8ca3da8a6c26db8d473378c9a4e2', + '0xef7a834a3e7748a6985898bade117d4d9ab6c177', + '0x7c5412b761ab74e3686165af5049568fc1b7784a', + '0x2cef036e948859eb7383386eb589ebd8480b6ff1', + '0x136bbec3b1b182ae3136423448e3d5b111a8a7da', + '0x7e79b18e0577b9ee5ef0495adc7aa6f6603c2383', + '0x758b621a786850c9ba25b1db8bd4c67ddf6d41ce', + '0x912d69c7e38273fa28e75275e440b6c74bd12646', + '0x5ad3330aebdd74d7dda641d37273ac1835ee9330', + '0x81a7730af39020c0f23f41ea8f91d39670fbc46a', + '0xcc83f1790556508351ae447587e59054c96410d1', + '0x92a93805eef9e123a1668562a382da5d0ad1f2a5', + '0xee0e9a9519bd3138e338a748af99d1fe1bceae5f', + '0x0e7a95438becc07885a65ae662467616a9d4f7d7', + '0xc93c7f71581dfeaab59bed908888dac5689f312a', + '0x972eebcb30252640c60c7e4821b15118f03b267e', + '0x127d0a3d36eb5cf1fb73bd829df93e84adced213', + '0xe0e37cd3990e545f3c7d09a4e4a3eaa5444218a0', + '0xffbdc115f419abed23888812f00d10f12ef6da3e', + '0x3fbb1742c5364239164b8bef4c386f38ceba80d3', + '0xabbef42e6967033789d065629a64b51a1863bc5d', + '0x48c29eeee1dbc30ade4040e1e0110d82461d13ea', + '0x4b8c142c1c1afc2e1bbf4c3513c46b5c088aa055', + '0x8acebd78b02875c9cce77c40141186da76965cc3', + '0x8b700c7640faa64a2c800f594cbb21e4ff64dada', + '0x02d6824e540664f95b657c0c9c12f8bbe466ab6c', + '0x6b306e9741270cfa228767ed26b89cd859faa66d', + '0x105495d87dbb25292ac8c2a713a8d32c67b824fd', + '0x9eeaf68b5370f36d5bc7dff2ea0112935132ff5a', + '0x105ae604b7c0859941bd8ab2455b5e89ef3e8970', + '0xa76e4e20772f075b76472a1449e8461a1ccefbc0', + '0x341a99e162fd976606db5f56a07990d8ad33d1e3', + '0xb248140d89ee4a1feabdd28f2f3ef23e2bd4b469', + '0x4e7c76f695515e87e469032b4082ba11f56a1bd1', + '0x79b95af13cede53422c656ae407368d8098645df', + '0x6fe1a56c978c1b66e97c2ae9b0cfd29e6483d040', + '0x06870beb1fd22c3a00c40da9b659ceb2c1ea4ca4', + '0xa7429f2c7a748e17810c0ccd2979f72a09d5ab3a', + '0xcc2e5565abfc3b457e284d84e87a56583833afef', + '0x9ad7a1ffeedf85a087b9af9f30666a8685280b1d', + '0xc978f4364c03a00352e8c7d9619b42e26b6424ab', + '0x1e824c86dceb7439ae02c0f6e5dc40e1cc284ff2', + '0x35fa139a452ce5d98e19d68e42876a7a058acb69', + '0xb36a2cb5b2b4f7e9d0f7d018a82fb5694dad4f8d', + '0x39dc1c08c0efdd39ae86ae402a8b8ee2cdcb45df', + '0xda46892a65820d354d670e3666528595ba03025d', + '0x4ddb82a25164f22ebe556ccd9c51fd78ffaf4eb0', + '0x8ae19e8e3091a5fe19dcb6de5f12bca5e94f7978', + '0x0eb1f3facd2c33e9d5d1ee7a99b898240e6ac827', + '0xc0d62cb44b51e17d3f17c25cf3537257807de44e', + '0xc20b4ad1e1b2792ca88e6aeff2d91e726192f3d0', + '0x618f67d64891c9c2c0de5c026dddf2b0973b7d60', + '0x65632601797f24fd3ca11944fb96c660e907c2d9', + '0x7bc86bd5e77d7b28e34253a630912f631534762a', + '0x3032ebdefed1a65b95a1f6cda088dad55602e9e4', + '0x70b8b68620041e6076544247545b5eaaf61e10d1', + '0x3a7249b510add84a2196fb0fad9d8b745d807286', + '0x3d92ede2ee89264ae5a079fca6f8ef5c1eabb621', + '0x4286f42d354441590959345bd121fe464b204116', + '0x011e0be1128af8c51646181368589ccfbddf746a', + '0xf9d4d006217141ab80f0e15d626416d0f49c8512', + '0x5028d77b91a3754fb38b2fbb726af02d1fe44db6', + '0x0654ef514655e94e32defc219c906eb90fb76b29', + '0xcf9cd29590221d227cdaab52e376a45624698329', + '0xf89733692fff06db317e410d6ba6ea26cd4a4647', + '0x7efa979645ef9860eb44a4543cc1112188888888', + '0xae09159c02c7dd954f42edec25c602da2776256b', + '0xe2be94b59a3a4aef2f66eb0dd73079da00315bf0', + '0xa63fba933ef79e46bc6971777feb289e9603d70b', + '0x54815ed6eaa280e6c65cf79bc9f0f641c5cdb54b', + '0x604ae0d02b4ab2c4bede20c68abcc4290d8fc77f', + '0xff3327cc139449fa111ad87351bb300e9cc7607c', + '0xa50ecb238bfa1b1c9050c58cf3e99c99260c4ed1', + '0x50498427b5947d8e5931ddf15b5143dbd015e5ae', + '0x808a023b72260170c95d831f589a1ae0dca1e43e', + '0x0ea81dbd6f7a76a17c1e0e8a08587513a33cbe2b', + '0xd9b1d215a1880248d36e90608daffa449543c0fd', + '0x2abadddc9faaffebcaa2702ef56a1989d2bfd91a', + '0xe4aaac3a9daaa52fabe45947c8db71b1ae74df76', + '0xa75c86521514ff4873e5524a2579b249403c9a21', + '0xafe5f35d14ee9abdac14bd2d0af575cabaf7d9e0', + '0x2b888954421b424c5d3d9ce9bb67c9bd47537d12', + '0x0403ae49513e03765b403b2e8d1d16d7b37cb8d5', + '0x346790c85882719d3806c1a7933dd7455a4f5b09', + '0xce73904422880604e78591fd6c758b0d5106dd50', + '0x026815624ac76c88ac92ab490035dc539558275d', + '0x0743faadd766df6687f32b68f1bb608f7c1eef28', + '0xfda462548ce04282f4b6d6619823a7c64fdc0185', + '0x2972584996ca225451a7a845cda2486bcb611c2a', + '0x49907511bdf0351daa417a87d349060876a42544', + '0x3efba11e19379bd1ec58b796ded837accef7b71c', + '0x0af8c8f1045be77272a09d2513a56a3d4002de6e', + '0xa06067164e76285cef0ac6c42b3ad3ce9be5039a', + '0xf3059770b573b28fc3f1fcfb8c31f4912e9963b4', + '0x926163468df9ed0efc44970b3687706115630cdd', + '0xbd7dbab9aeb52d6c8d0e80fcebde3af4cc86204a', + '0x69e0dcb6741e44061dc3bfce92a5c5db3fb185f3', + '0xbfdc403a22a073b36489aa0255784442ee8ba450', + '0x6610681a0f9566efa372eed51e3857f06aff38d0', + '0xa56dfbe8010a8830a9fe5b56e8eff7236e277120', + '0xe5cc01210888790d688a157885dfad50251d212a', + '0x41e8874ac24abd3fb1a1b4b00c964be7f580b360', + '0xd3240c65544d673f67c8bdff487f936778e2e640', + '0x352adad7fd62b768153ac3f577024750bceb2dc5', + '0x85a56dbdae92610b711b8d5d771692d267c93dcd', + '0x49a4d4e6f60d1af83325e9231531c2289e19412a', + '0x1bf9e46b06cfdfbbdb1e0c76d0a13b20ff08bae9', + '0xe6f2ad3ae201f8672a5860c352eee5fc20efd748', + '0xe9039a93d0d4994d79224e6e11749163440a4a83', + '0x84a1495edf1d5915da0fc7c7b770d5d591dd32c5', + '0x83300ff9b0dd70778a296740269947c7be2e8308', + '0x724ec6d9b800de28657520acff418f5ffe55b770', + '0x1f4341e7b8ac0d3c4f2228f2a5503c2338a4d6c1', + '0xc59c313500c9aab020773b4bbc260d4fc5fbfeab', + '0xf7b2b44066170cf1e44bc3eb4437cb3c4ded0518', + '0xcc6660ca5ffa1d7f20c6613188a46e3398f44ca2', + '0xefa4b83a9e8b4cc3b2939e0794df524e122180db', + '0x6da074c23543144d865061efc6fd1bc72afce82d', + '0x46abfe1c972fca43766d6ad70e1c1df72f4bb4d1', + '0x48193168a19164c6f50c2fef223ebcd3cce803c9', + '0x1188c274fcffe973f01dee1b01ecb39ffbf06b02', + '0xc8af50428848b28ec5168037b54b7c7d83e168ee', + '0x044fd039d5c219103d31a19bcfafbce7e8e65275', + '0xeeaa36420519d85efab3b7120ac5afa5a5825bfb', + '0x419859e599ede9f4f130b9aeaa7b2d5cc342e7fb', + '0x39a3ae037b702f7080cce53c39ff2d3c25e0a777', + '0x6ed0baf6b69da7d48499b7796901a5b939b16078', + '0x7b7f60489e1d39c2a9c1527514c9126c9395e84e', + '0x77f4f0da890739ea78d30985a865105aea4d1500', + '0x881e69d5d8470f24370d15eb320411b69a2ebc24', + '0x262a6a9bf9f02ae2a881a46cd3e462ab9bce3317', + '0x188319c06bad2d261aeabae21b700b01670ca9b5', + '0xe7e621f8d2c924eea1f1e5678ea19b6cda8fc00c', + '0x4d60b58cb924e2b4eaf229f6ac6c9bd52805a963', + '0xacdecf79986db9d509e4f3ff6d55eba2f4acbcb0', + '0x336395f561c2cc577da91c1e399ea4a50e27fc1a', + '0x83ffa883ce6cc63be4b7535fdb9ef4e9130f1dda', + '0x38d1a45c31e8e7078de05f3a21165a9955cfd3f2', + '0x3c288e057376cc31680c3a0c8e57e2bcb2967982', + '0x437930df02e1b01b25dc43545512006528d76d6a', + '0x3ec6732676db7996c1b34e64b0503f941025cb63', + '0x2d7636963cc7ac07dfef65040e1f9b510e317439', + '0xb7f6ae084aa5915142e978c229ca8c641574caee', + '0x6c2e99e086d4cd1c760dc3b979fce5846968509c', + '0x72b2a07ea578cc92f9024be2501c7f295f227ec2', + '0x50c8f0ab4e2a1aeb34ebbad261f6af28995ad3c6', + '0xbb93a3027ae3855827945b2d895a2bd205eef53a', + '0x29825bf65ad0ee73c79dfa2814815291f1fb2bfd', + '0x5a98fcbea516cf06857215779fd812ca3bef1b32', + '0x76282a2d0371118ec586c6c203005e090f365cdd', + '0x30c136becb8b1180612af1300575f6c2d26becfe', + '0x04ecaede106078c2948534c5fdf128941c7fb638', + '0xc20cd61e87596ea1d7ecb4066315054477728044', + '0x4d04eb67a2d1e01c71fad0366e0c200207a75487', + '0xb0fb25c8fc9fb6c8dbd34432efc39a32c8c05351', + '0x619bbd8a9c3fd504435f6c45b63376676b83a708', + '0x97242b533bbbf6375d33c0d6a11cbdd55970ebad', + '0x2df6417348f2631dd480d22897d4f95ec5f246b1', + '0x7632abf23cbe29f964054f310175bc3e34a92df4', + '0x03e7e8e7dddfb341e60e4d54dfb2800566f42dce', + '0xab376e789dfdf8b456aee79e65c999aa8d5c6f7c', + '0xbbc43cf94ad648d6e5c547485f67d0cbb8ad7420', + '0x1f51221d0a6a2fd1ca80712f941185bbcbc24e1e', + '0x62cbc40ca9cca21501687a759d21a5a49d25e914', + '0x67e1d1f93ed5177142e39ec897e5d104ee27af8e', + '0xa61c06a018de450321dce198664205a9c375755f', + '0x547cd10972eb44365905ff25d44cd004c16fa9b0', + '0x482d455a64f604fc9b7db7a1eff361a28c951053', + '0x1b9d39da4aab19dccfbc17a16f876effcc73eafd', + '0xa6d11d6eadb010edfffdc0017c5ff1c832f55e4f', + '0xe88ace70252f2480419ea8b050eb1d3176e87489', + '0x23f65e02084d7a9c90c616488d84874aea484c8c', + '0xae25ad6cba120fc1497fea5b516c8e80a6b69726', + '0x4632105acee0f4e11a1c5672da9c839dfd5857c9', + '0xd2163e324e46832b8542bdec04a789b94116a192', + '0x2187ff76adc046fb5e4bbd640054b27c254702fd', + '0xdb76092038b2e3bf3de50e658f92558f6603d8ee', + '0x002a5dc50bbb8d5808e418aeeb9f060a2ca17346', + '0x3a46a54225da7255adfd7115d157861d1f16a3c3', + '0x0d298f3220eadf02d10c9feff537b50787725418', + '0xc9c888fc1c00bff0ff4d136b34f439727a4729a5', + '0x60e7357de5ec8c3b07f8efb3a8c1325811eb7db0', + '0x5e0d5d56fff1265082d7f1a0504eec886fff8b80', + '0x727b7565a8169699755e39b8b100eefe423aef90', + '0xd56c6e89da9f6ceab903878b98b1d91cfe1024d9', + '0x02250178cc6d3b55751482e5d7c04e2c2759c234', + '0xdaf514bb28d343a2655f00beede9042a44be1849', + '0xcd02c8b722c8e286fbb353fd7bf814bd38490c27', + '0x7b55d264e7c58d14379cf49d93d028b65efbc490', + '0xaf1aa0722e87a6f2bbf6e866f99db1d6cbf37e96', + '0xcaefb6af0295540e1fd62c877b770ba5e6dc4088', + '0xdffe214273bc77397b7a449dc1c76df00613669b', + '0xc6dc654b5aa7969a24c7e4442a52e61fb8b24827', + '0xab68de366b763e65d55c840b929fe3e66c80aeae', + '0x3af19e2cd5ac30eb6e660d8e514233fadc702963', + '0x7e4a8391c728fed9069b2962699ab416628b19fa', + '0x27f7a24da1feb46093c0a9cbf3297fe2f1c7aa44', + '0xaa4237995a8ddb6fc30c3c5bc4cb9c0c15ee7c4f', + '0xabaccecf664cf3898c2aa29e7409de7a46ebaba1', + '0xb4fd4309513fa7989deb3e79b99101df33e9a6ee', + '0xff6d917a46f3071e9dc83a57aba7e1c6e46b991c', + '0x80dfa8751208175c5ee55aff291a90826891e091', + '0x3fdc2814ca7a6aa4a54cd896c93574ae06d3c467', + '0xfa893e0326bc79aa30d72d64359e784770376d90', + '0x73e657de143e4784e187d395518f7ef84e0b654b', + '0x14129d1f673a38f2c88fc19f46138419ffafd20c', + '0x1dda0041df7222c2da97b38e5ca2babff4ead061', + '0x439cd1791bbd86a12607ce634f559a1a6a3375af', + '0xd3830fdff1f4da6546456e4a775428dbbe200239', + '0x3b4001168fcf6302250d8564afb0d2efd81cadf8', + '0x0181a6648d73f1cf4f956859f8158f4c28f51a67', + '0x163447e025d07f906fa42707ecc6df7847621472', + '0xe0e61b4a39f0cb349172228eae4273459c1c34b6', + '0xd0cd01f30183d2bebf0b5b6eff3376e3841770e7', + '0x415fce36e2dc12421f20b93dbad1dd68bd2f6db6', + '0x239f4b81f1b54ee89a506c98b34a4ff6b012f8e7', + '0x1301383453a218332b9e0fd203f1bdc8af93f23c', + '0x7f70f5fc9537dc90dc97dce7d7d921b5149c0db0', + '0x4097cfe0daffeb631181706c5ade6f12c4c8f267', + '0xf7748b4f60a8d36dcd6ccb3d30244baecb1429cf', + '0xeab9916101791c84bef3ccc349427d96b9766643', + '0xff162ec6f0f5b1384c29c32ab2d15056286d3f8f', + '0xd5a41bfe8e373c94434eab2fc81034ec00572b09', + '0x02f077064e807240e1f3808e9ce912b6027dfcf4', + '0x00b5ade4ac1fe9ccc08addc2c10070642335117f', + '0x7edb74a70adcaac6b739b5610ea311d44c628015', + '0xea3f5d7134eac21e14e1e38b705466f7d4de180e', + '0xcf9ae38d1580a2d5d72f85081911748159f5ad8e', + '0x6f1acc3e8facd3e8ae52319e7e4efe1a2b035f4b', + '0x3118bccdb201111062b1e5d13c720503fc1319e2', + '0x09a5eb2e20a4e93acd011475ac797cbeb9111af1', + '0xafd5f60aa8eb4f488eaa0ef98c1c5b0645d9a0a0', + '0x87a04752e516548b0d5d4df97384c0b22b649179', + '0xda69fc3be70623d487d095469c637d06392b07d0', + '0x07c867770c43b1c6b715aa8ac3a55dfd7f835a82' + ] + } +}; + +const provider = snapshot.utils.getProvider(scoreAPIObj.params.network); +snapshot.utils + .getScoresDirect( + scoreAPIObj.params.space, + scoreAPIObj.params.strategies, + scoreAPIObj.params.network, + provider, + scoreAPIObj.params.addresses, + scoreAPIObj.params.snapshot + ) + .then(console.log) + .catch(console.error); From 81358b4ed8f5aa2aecaa819a6e38cfe1b83770fb Mon Sep 17 00:00:00 2001 From: Daniel <25051234+dasanra@users.noreply.github.com> Date: Wed, 26 Oct 2022 16:19:11 +0200 Subject: [PATCH 182/815] Add claimDateLimit parameter to safe-vested strategy [safe-vested] (#907) * Add claimDateLimit parameter to safe-vested strategy * Set v0.2.0 to safe-vested --- src/strategies/safe-vested/README.md | 19 ++++++++++++- src/strategies/safe-vested/examples.json | 7 +++-- src/strategies/safe-vested/index.ts | 35 +++++++++++++++++++----- 3 files changed, 50 insertions(+), 11 deletions(-) diff --git a/src/strategies/safe-vested/README.md b/src/strategies/safe-vested/README.md index 027d9718b..be8d5ba03 100644 --- a/src/strategies/safe-vested/README.md +++ b/src/strategies/safe-vested/README.md @@ -1,6 +1,14 @@ # safe-vested -Custom strategy to compute voting power from vested tokens. Strategy is configurable accepting a JSON using the following structure. +Custom strategy to compute voting power from vested tokens. Originally created for the Safe allocations. Vesting smart contract code can be found [here](https://github.com/safe-global/safe-token/blob/81e0f3548033ca9916f38444f2e62e5f3bb2d3e1/contracts/VestingPool.sol). + +## strategy parameters + +The following parameters can be used to configure the strategy. + +### allocationsSource + +This parameter is mandatory. It expects a JSON using the following structure providing at least the example parameters. ```json [ [ @@ -14,3 +22,12 @@ Custom strategy to compute voting power from vested tokens. Strategy is configur ] ``` +### claimDateLimit + +This is an optional parameter. A date limit to claim the vesting. Since that moment the vesting won't be considered unless the account already claimed some amount. + +Needs to follow [ISO Date format](https://www.w3schools.com/js/js_date_formats.asp). +```js +"2022-12-04T11:00:00Z" +``` + diff --git a/src/strategies/safe-vested/examples.json b/src/strategies/safe-vested/examples.json index ce9e3659f..7d6384558 100755 --- a/src/strategies/safe-vested/examples.json +++ b/src/strategies/safe-vested/examples.json @@ -4,11 +4,12 @@ "strategy": { "name": "safe-vested", "params": { - "allocationsSource": "https://raw.githubusercontent.com/5afe/claiming-app-data/7942c2b6757c02fadb32d58dde09a12a35f5a462/resources/data/snapshot-allocations-test.json" + "allocationsSource": "https://safe-claiming-app-data.gnosis-safe.io/allocations/1/snapshot-allocations-data.json", + "claimDateLimit": "2022-12-28T11:00:00Z" } }, - "network": "4", - "snapshot": 11250000, + "network": "1", + "snapshot": 15800000, "addresses": [ "0x9970dcab40e29a84D1020DeaEa443dCE1d8471b7", "0x1230B3d59858296A31053C1b8562Ecf89A2f888b", diff --git a/src/strategies/safe-vested/index.ts b/src/strategies/safe-vested/index.ts index 8ebd80211..f7bb077d0 100755 --- a/src/strategies/safe-vested/index.ts +++ b/src/strategies/safe-vested/index.ts @@ -4,9 +4,9 @@ import { formatUnits, parseUnits } from '@ethersproject/units'; import { Multicaller } from '../../utils'; export const author = 'dasanra'; -export const version = '0.1.0'; +export const version = '0.2.0'; -// https://github.com/safe-global/safe-token/blob/main/contracts/VestingPool.sol +// https://github.com/safe-global/safe-token/blob/81e0f3548033ca9916f38444f2e62e5f3bb2d3e1/contracts/VestingPool.sol const abi = [ 'function vestings(bytes32) view returns (address account, uint8 curveType, bool managed, uint16 durationWeeks, uint64 startDate, uint128 amount, uint128 amountClaimed, uint64 pausingDate, bool cancelled)' ]; @@ -20,6 +20,19 @@ type AllocationDetails = { type Options = { allocationsSource: string; + claimDateLimit: string | undefined; +}; + +const canStillClaim = (claimDateLimit: string | undefined): boolean => { + // if a claim date limit is set we check if it's still possible to claim + if (claimDateLimit) { + const now = new Date(); + const limitDate = new Date(claimDateLimit); + return now.getTime() < limitDate.getTime(); + } + + // if not date limit is set can always claim. + return true; }; export async function strategy( @@ -65,11 +78,19 @@ export async function strategy( ) as AllocationDetails; const hasAlreadyClaimed = vestings[key].account === account; - // If account already claimed only count the pending amount - // Else nothing claimed yet so consider the full allocation - const currentVestingAmount = hasAlreadyClaimed - ? vestings[key].amount.sub(vestings[key].amountClaimed) - : amount; + let currentVestingAmount; + if (hasAlreadyClaimed) { + // If account already claimed only count the pending amount + currentVestingAmount = vestings[key].amount.sub( + vestings[key].amountClaimed + ); + } else { + // Else nothing claimed yet so consider the full allocation + // or none if the claim date limit was set and reached. + currentVestingAmount = canStillClaim(options.claimDateLimit) + ? amount + : '0'; + } const previousAmount = acc[account]; // If account received multiple allocations sum them From a74b0dde978c26dfa2683a3f1f2683cb5a38d5f6 Mon Sep 17 00:00:00 2001 From: Andy Espagnolo Date: Wed, 26 Oct 2022 15:15:23 -0300 Subject: [PATCH 183/815] [decentraland-wearable-rarity] fix: decentraland strategies with too many addresses (#910) * fix: decentraland strategies with too many addresses * Update src/strategies/decentraland-wearable-rarity/index.ts * remove console.log * change limit to 1000 addresses * Apply suggestions from code review Co-authored-by: Chaitanya --- .../decentraland-estate-size/index.ts | 81 +++++++----- .../decentraland-wearable-rarity/index.ts | 117 ++++++++++-------- 2 files changed, 113 insertions(+), 85 deletions(-) diff --git a/src/strategies/decentraland-estate-size/index.ts b/src/strategies/decentraland-estate-size/index.ts index a95339f83..57b6956ac 100644 --- a/src/strategies/decentraland-estate-size/index.ts +++ b/src/strategies/decentraland-estate-size/index.ts @@ -4,11 +4,20 @@ import { subgraphRequest } from '../../utils'; export const author = '2fd'; export const version = '0.1.0'; +const SUBGRAPH_QUERY_ADDRESSES_LIMIT = 2000; const DECENTRALAND_MARKETPLACE_SUBGRAPH_URL = { '1': 'https://api.thegraph.com/subgraphs/name/decentraland/marketplace', '3': 'https://api.thegraph.com/subgraphs/name/decentraland/marketplaceropsten' }; +function chunk(_array: string[], pageSize: number): string[][] { + const chunks: string[][] = []; + for (let i = 0; i < _array.length; i += pageSize) { + chunks.push(_array.slice(i, i + pageSize)); + } + return chunks; +} + export async function strategy( space, network, @@ -23,51 +32,55 @@ export async function strategy( scores[getAddress(address)] = 0; } - // if graph doesn't exists return automaticaly + // if graph doesn't exist return automatically if (!DECENTRALAND_MARKETPLACE_SUBGRAPH_URL[network]) { return scores; } + const chunks = chunk(addresses, SUBGRAPH_QUERY_ADDRESSES_LIMIT); const multipler = options.multiplier || 1; - const params = { - nfts: { - __args: { - where: { - owner_in: addresses.map((address) => address.toLowerCase()), - category: 'estate', - searchEstateSize_gt: 0 + + for (const chunk of chunks) { + const params = { + nfts: { + __args: { + where: { + owner_in: chunk.map((address) => address.toLowerCase()), + category: 'estate', + searchEstateSize_gt: 0 + }, + first: 1000, + skip: 0 }, - first: 1000, - skip: 0 - }, - owner: { - id: true - }, - searchEstateSize: true + owner: { + id: true + }, + searchEstateSize: true + } + }; + + if (snapshot !== 'latest') { + // @ts-ignore + params.nfts.__args.block = { number: snapshot }; } - }; - if (snapshot !== 'latest') { - // @ts-ignore - params.nfts.__args.block = { number: snapshot }; - } + let hasNext = true; + while (hasNext) { + const result = await subgraphRequest( + DECENTRALAND_MARKETPLACE_SUBGRAPH_URL[network], + params + ); - let hasNext = true; - while (hasNext) { - const result = await subgraphRequest( - DECENTRALAND_MARKETPLACE_SUBGRAPH_URL[network], - params - ); + const nfts = result && result.nfts ? result.nfts : []; + for (const estate of nfts) { + const userAddress = getAddress(estate.owner.id); + scores[userAddress] = + (scores[userAddress] || 0) + estate.searchEstateSize * multipler; + } - const nfts = result && result.nfts ? result.nfts : []; - for (const estate of nfts) { - const userAddress = getAddress(estate.owner.id); - scores[userAddress] = - (scores[userAddress] || 0) + estate.searchEstateSize * multipler; + params.nfts.__args.skip += params.nfts.__args.first; + hasNext = nfts.length === params.nfts.__args.first; } - - params.nfts.__args.skip += params.nfts.__args.first; - hasNext = nfts.length === params.nfts.__args.first; } return scores; diff --git a/src/strategies/decentraland-wearable-rarity/index.ts b/src/strategies/decentraland-wearable-rarity/index.ts index 9ef09182a..4baaf43d5 100644 --- a/src/strategies/decentraland-wearable-rarity/index.ts +++ b/src/strategies/decentraland-wearable-rarity/index.ts @@ -4,6 +4,7 @@ import { subgraphRequest } from '../../utils'; export const author = '2fd'; export const version = '0.1.0'; +const SUBGRAPH_QUERY_ADDRESSES_LIMIT = 2000; const DECENTRALAND_COLLECTIONS_SUBGRAPH_URL = { '1': 'https://api.thegraph.com/subgraphs/name/decentraland/collections-ethereum-mainnet', '3': 'https://api.thegraph.com/subgraphs/name/decentraland/collections-ethereum-ropsten', @@ -13,6 +14,14 @@ const DECENTRALAND_COLLECTIONS_SUBGRAPH_URL = { 'https://api.thegraph.com/subgraphs/name/decentraland/collections-matic-mumbai' }; +function chunk(_array: string[], pageSize: number): string[][] { + const chunks: string[][] = []; + for (let i = 0; i < _array.length; i += pageSize) { + chunks.push(_array.slice(i, i + pageSize)); + } + return chunks; +} + export async function strategy( space, network, @@ -27,68 +36,74 @@ export async function strategy( scores[getAddress(address)] = 0; } - // if graph doesn't exists return automaticaly + // if graph doesn't exist return automatically if (!DECENTRALAND_COLLECTIONS_SUBGRAPH_URL[network]) { return scores; } - // initialize multiplers and params + const chunks = chunk(addresses, SUBGRAPH_QUERY_ADDRESSES_LIMIT); + // initialize multipliers and params const multiplers = options.multipliers || {}; - const params = { - nfts: { - __args: { - where: { - itemType_in: [ - 'wearable_v1', - 'wearable_v2', - 'smart_wearable_v1', - 'emote_v1' - ], - owner_in: addresses.map((address) => address.toLowerCase()), - id_gt: '' + + for (const chunk of chunks) { + const params = { + nfts: { + __args: { + where: { + itemType_in: [ + 'wearable_v1', + 'wearable_v2', + 'smart_wearable_v1', + 'emote_v1' + ], + owner_in: chunk.map((address) => address.toLowerCase()), + id_gt: '' + }, + orderBy: 'id', + orderDirection: 'asc', + first: 1000 }, - orderBy: 'id', - orderDirection: 'asc', - first: 1000 - }, - id: true, - owner: { - id: true - }, - searchWearableRarity: true - } - }; + id: true, + owner: { + id: true + }, + searchWearableRarity: true + } + }; - if (options.collections) { - // @ts-ignore - params.nfts.__args.where.collection_in = options.collections; - } + if (options.collections) { + // @ts-ignore + params.nfts.__args.where.collection_in = options.collections; + } - if (snapshot !== 'latest') { - // @ts-ignore - params.nfts.__args.block = { number: snapshot }; - } + if (snapshot !== 'latest') { + // @ts-ignore + params.nfts.__args.block = { number: snapshot }; + } - // load and add each wearable by rarity - let hasNext = true; - while (hasNext) { - const result = await subgraphRequest( - DECENTRALAND_COLLECTIONS_SUBGRAPH_URL[network], - params - ); + // load and add each wearable by rarity + let hasNext = true; + while (hasNext) { + const result = await subgraphRequest( + DECENTRALAND_COLLECTIONS_SUBGRAPH_URL[network], + params + ); - const nfts = result && result.nfts ? result.nfts : []; - const latest = nfts[nfts.length - 1]; - for (const wearable of nfts) { - const userAddress = getAddress(wearable.owner.id); - const rarity = String(wearable.searchWearableRarity).toLowerCase().trim(); - scores[userAddress] = - (scores[userAddress] ?? 0) + (multiplers[rarity] ?? 0); - } + const nfts = result && result.nfts ? result.nfts : []; + const latest = nfts[nfts.length - 1]; + for (const wearable of nfts) { + const userAddress = getAddress(wearable.owner.id); + const rarity = String(wearable.searchWearableRarity) + .toLowerCase() + .trim(); + scores[userAddress] = + (scores[userAddress] ?? 0) + (multiplers[rarity] ?? 0); + } - hasNext = nfts.length === params.nfts.__args.first; - if (hasNext) { - params.nfts.__args.where.id_gt = latest?.id || ''; + hasNext = nfts.length === params.nfts.__args.first; + if (hasNext) { + params.nfts.__args.where.id_gt = latest?.id || ''; + } } } From 986f54c7645febd1cdd81995d0bd7c6cc2cd4d48 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 26 Oct 2022 23:49:38 +0530 Subject: [PATCH 184/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.43 (#909) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 2440de90c..d10ff88b1 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.42", + "@snapshot-labs/snapshot.js": "^0.4.43", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index cb1022c7b..32bb1ab41 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.42": - version "0.4.42" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.42.tgz#2439708bd97c2eb2fc3fa1f747f5644c19d15a00" - integrity sha512-2LA4tFpd5EWRgltM0b8VLW+ii14s7BoRjj96FJQQAMreViK3Wl9Y/lu8T+A1Mm3lYnaInoQ3Xb4q/AqFYq10DA== +"@snapshot-labs/snapshot.js@^0.4.43": + version "0.4.43" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.43.tgz#0263d08ac4f621200377ba7d81084d214c08fbc9" + integrity sha512-H279y596WTUOaRbirgnDAGSqVsIhCuDfB9Obt2hmVmnFVgUSmGzXHY83a3i2B8osSvdFKV0VxozikWlvu/V/mw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 1e1f913568e4c4f88b415597af099ecf875d1b76 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Thu, 27 Oct 2022 01:38:18 +0530 Subject: [PATCH 185/815] Fix lowercase address issue with getvp (#912) * Fix lowercase address issue with getvp * Fix * Revert --- src/utils/vp.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/utils/vp.ts b/src/utils/vp.ts index 3eff86e14..6bd74f2af 100644 --- a/src/utils/vp.ts +++ b/src/utils/vp.ts @@ -54,6 +54,7 @@ export async function getVp( if (addresses.length === 0) return {}; } + addresses = addresses.map(getAddress); return _strategies[strategy.name].strategy( space, n, @@ -75,6 +76,7 @@ export async function getVp( addresses = [...new Set(addresses)]; } + addresses = addresses.map(getAddress); return addresses.reduce((a, b) => a + (score[b] || 0), 0); }); const vp = vpByStrategy.reduce((a, b) => a + b, 0); From 9e4e19cc71529aca156c2682129018ceb958372e Mon Sep 17 00:00:00 2001 From: Dan Wu Date: Wed, 26 Oct 2022 15:25:57 -0500 Subject: [PATCH 186/815] Add Metropolis Pod strategy [metropolis-pod] (#911) * add Metropolis strategy * update readme * Update src/strategies/metropolis-pod/index.ts Co-authored-by: Chaitanya --- src/strategies/index.ts | 2 ++ src/strategies/metropolis-pod/README.md | 20 ++++++++++++++ src/strategies/metropolis-pod/examples.json | 16 +++++++++++ src/strategies/metropolis-pod/index.ts | 28 +++++++++++++++++++ src/strategies/metropolis-pod/schema.json | 30 +++++++++++++++++++++ 5 files changed, 96 insertions(+) create mode 100644 src/strategies/metropolis-pod/README.md create mode 100644 src/strategies/metropolis-pod/examples.json create mode 100644 src/strategies/metropolis-pod/index.ts create mode 100644 src/strategies/metropolis-pod/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index d8719ad8c..778a22c0c 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -363,6 +363,7 @@ import * as erc721PairWeights from './erc721-pair-weights'; import * as harmonyStaking from './harmony-staking'; import * as echelonCachedErc1155Decay from './echelon-cached-erc1155-decay'; import * as orcaPod from './orca-pod'; +import * as metropolisPod from './metropolis-pod'; import * as proxyProtocolErc20BalanceOf from './proxyprotocol-erc20-balance-of'; import * as proxyProtocolErc721BalanceOf from './proxyprotocol-erc721-balance-of'; import * as proxyProtocolErc1155BalanceOf from './proxyprotocol-erc1155-balance-of'; @@ -755,6 +756,7 @@ const strategies = { 'echelon-cached-erc1155-decay': echelonCachedErc1155Decay, 'erc3525-flexible-voucher': erc3525FlexibleVoucher, 'orca-pod': orcaPod, + 'metropolis-pod': metropolisPod, 'proxyprotocol-erc20-balance-of': proxyProtocolErc20BalanceOf, 'proxyprotocol-erc721-balance-of': proxyProtocolErc721BalanceOf, 'proxyprotocol-erc1155-balance-of': proxyProtocolErc1155BalanceOf, diff --git a/src/strategies/metropolis-pod/README.md b/src/strategies/metropolis-pod/README.md new file mode 100644 index 000000000..7bacb4349 --- /dev/null +++ b/src/strategies/metropolis-pod/README.md @@ -0,0 +1,20 @@ +# metropolis-pod + +This strategy gives one voting power to each member of a specific Metropolis Pod NFT, specified by the ERC1155 Token ID - which can be found in the [Metropolis web app](https://pod.xyz) or in your wallet. + +## Parameters + +| Param Name | Description | +| ----------- | ----------- | +| id | Token ID of the pod | +| weight (optional) | Multiplier of the voting power - Default is `1` | + +Here is an example of the parameters: + +```json +{ + "symbol": "METRO", + "id": "1", + "weight": 100 +} +``` diff --git a/src/strategies/metropolis-pod/examples.json b/src/strategies/metropolis-pod/examples.json new file mode 100644 index 000000000..90e960d66 --- /dev/null +++ b/src/strategies/metropolis-pod/examples.json @@ -0,0 +1,16 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "metropolis-pod", + "params": { + "symbol": "METRO", + "id": "1", + "weight": 100 + } + }, + "network": "1", + "addresses": ["0x094a473985464098b59660b37162a284b5132753","0x4B4C43F66ec007D1dBE28f03dAC975AAB5fbb888","0x403f69b1092cf1cB82487CD137F96E8200f03BD5"], + "snapshot": 15188155 + } +] diff --git a/src/strategies/metropolis-pod/index.ts b/src/strategies/metropolis-pod/index.ts new file mode 100644 index 000000000..c6371ea05 --- /dev/null +++ b/src/strategies/metropolis-pod/index.ts @@ -0,0 +1,28 @@ +import { strategy as erc1155BalanceOfIdsWeightedStrategy } from '../erc1155-balance-of-ids-weighted'; + +export const author = 'itsdanwu'; +export const version = '0.1.0'; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const score = await erc1155BalanceOfIdsWeightedStrategy( + space, + network, + provider, + addresses, + { + address: '0x0762aa185b6ed2dca77945ebe92de705e0c37ae3', + ids: [options.id], + weight: parseFloat(options.weight || 1) + }, + snapshot + ); + + return Object.fromEntries(Object.entries(score).map((a) => [a[0], a[1]])); +} diff --git a/src/strategies/metropolis-pod/schema.json b/src/strategies/metropolis-pod/schema.json new file mode 100644 index 000000000..91cc5fcb4 --- /dev/null +++ b/src/strategies/metropolis-pod/schema.json @@ -0,0 +1,30 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. METRO"], + "maxLength": 16 + }, + "id": { + "type": "string", + "title": "Token ID", + "examples": ["1"] + }, + "weight": { + "type": "number", + "title": "Weight", + "examples": ["e.g. 100"] + } + }, + "required": ["id"], + "additionalProperties": false + } + } +} From aa504bb4b174af72c2481f08fbbfa39641e043df Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 27 Oct 2022 17:44:02 +0530 Subject: [PATCH 187/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.44 (#913) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index d10ff88b1..f2ecc891b 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.43", + "@snapshot-labs/snapshot.js": "^0.4.44", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 32bb1ab41..491d5d841 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.43": - version "0.4.43" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.43.tgz#0263d08ac4f621200377ba7d81084d214c08fbc9" - integrity sha512-H279y596WTUOaRbirgnDAGSqVsIhCuDfB9Obt2hmVmnFVgUSmGzXHY83a3i2B8osSvdFKV0VxozikWlvu/V/mw== +"@snapshot-labs/snapshot.js@^0.4.44": + version "0.4.44" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.44.tgz#2e305a3b39d6046c7f4559aec8dd9bfb4cdb7e7b" + integrity sha512-hF8vjlXEuACxn2Esk+vNK0IZSyglaQ3r/3ILbOIM6ScJZA9kVWJngaIUQklNsfgKILERQ30OW+GQrDYJYSz1mQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From f8f47f8c1dc2a5942b7cba5f3504a478725a4f84 Mon Sep 17 00:00:00 2001 From: Timan Rebel Date: Fri, 28 Oct 2022 14:26:27 +0200 Subject: [PATCH 188/815] DefiPlaza strategy: Added an API call to our backend to enable additional voting power [defiplaza] (#915) * feat(defiplaza): update defiplaza strategy to include StablePlaza pool * feat: add querying our backend for additional voting power * Update src/strategies/defiplaza/index.ts Co-authored-by: Chaitanya * Update src/strategies/defiplaza/index.ts Co-authored-by: Chaitanya Co-authored-by: Trebel Co-authored-by: Chaitanya --- src/strategies/defiplaza/examples.json | 4 ++-- src/strategies/defiplaza/index.ts | 22 ++++++++++++++++++---- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/strategies/defiplaza/examples.json b/src/strategies/defiplaza/examples.json index f2e5e9b54..6124eeb10 100644 --- a/src/strategies/defiplaza/examples.json +++ b/src/strategies/defiplaza/examples.json @@ -29,8 +29,8 @@ "0x5fa483d02a78fcf0e5dd0670b5d4b60a0be1de33", "0x40d0440af173578d0ce4e959f822fca215cad7bb", "0x27f2be297489e813dae3895a30c9ac72b01bf57a", - "0xb4185c5e29a9b415efc405ec5d1eae51b65059ff" + "0x1eA44f3176B480cD03a8c9B7e924B2bB9a49a9cA" ], - "snapshot": 15202927 + "snapshot": 15839572 } ] diff --git a/src/strategies/defiplaza/index.ts b/src/strategies/defiplaza/index.ts index 91a2dddf0..cd1e0870c 100644 --- a/src/strategies/defiplaza/index.ts +++ b/src/strategies/defiplaza/index.ts @@ -1,8 +1,9 @@ import { formatUnits } from '@ethersproject/units'; -import { Multicaller } from '../../utils'; +import { Multicaller, customFetch } from '../../utils'; -export const author = 'trebel-defiplaza'; -export const version = '0.1.0'; + +export const author = 'timanrebel'; +export const version = '0.1.1'; const abi = [ 'function balanceOf(address account) external view returns (uint256)', @@ -30,6 +31,7 @@ export async function strategy( address ]); + // request balance of staked tokens on StablePlaza if (options.stableplaza) { multi.call(`stableplaza.${address}`, options.stableplaza, 'stakerData', [ address @@ -38,7 +40,7 @@ export async function strategy( }); const result = await multi.execute(); - const returnObject = {}; + let returnObject = {}; addresses.forEach((address) => { if (!returnObject.hasOwnProperty(address)) { @@ -62,5 +64,17 @@ export async function strategy( } }); + // request balance on Radix + const res = await customFetch(`https://radix.defiplaza.net/voting/${snapshot}`, {}, 8000); + const radixLinks = await res.json(); + + for (let wallet of radixLinks) { + if (!returnObject.hasOwnProperty(wallet.address)) { + returnObject[wallet.address] = 0; + } + + returnObject[wallet.address] += parseFloat(formatUnits(wallet.balance, options.decimals)); + } + return returnObject; } From ba3d5ab76d9d8dca354169a8004b43e622b27af3 Mon Sep 17 00:00:00 2001 From: Swen Mun Date: Fri, 28 Oct 2022 21:35:46 +0900 Subject: [PATCH 189/815] Revise ninechronicles-staked-and-dcc [ninechronicles-staked-and-dcc] (#914) * Use staked wNCG instead of LP token * Fix docs Co-authored-by: Chaitanya --- .../ninechronicles-staked-and-dcc/README.md | 43 ++++++++++++++----- .../examples.json | 9 ++-- .../ninechronicles-staked-and-dcc/index.ts | 42 +++++++++++++----- 3 files changed, 69 insertions(+), 25 deletions(-) diff --git a/src/strategies/ninechronicles-staked-and-dcc/README.md b/src/strategies/ninechronicles-staked-and-dcc/README.md index 9e4003923..48b9c65e6 100644 --- a/src/strategies/ninechronicles-staked-and-dcc/README.md +++ b/src/strategies/ninechronicles-staked-and-dcc/README.md @@ -1,36 +1,53 @@ # Nine Chronicles DAO voting strategy (by staked assets and D:CC) -This strategy returns calculated score based on staked assets ([Nine Chronicles Gold (NCG)][NCG], [LP Token for [wNCG](20WETH-80WNCG)][20WETH-80WNCG] and [D:CC]) of given accounts. +This strategy returns calculated score based on staked assets ([Nine Chronicles Gold (NCG)][NCG], [Wrapped Nine Chronicles Gold (wNCG)][wNCG] and [D:CC]) of given accounts. [NCG]: https://docs.nine-chronicles.com/introduction/intro/nine-chronicles-gold-ncg -[20WETH-80WNCG]: https://etherscan.io/token/0xe8cc7E765647625B95F59C15848379D10B9AB4af [wNCG]: https://etherscan.io/token/0xf203ca1769ca8e9e8fe1da9d147db68b6c919817 [D:CC]: https://dcc.nine-chronicles.com/ ## Calculation +The `score` representing the account's voting power will be calculated with: + ``` -score = (w1 * staked_ncg) + (w2 * staked_lp_tokens) + (w3 * dcc_balance) +score = (w1 * staked_ncg) + (w2 * staked_wncg) + (w3 * dcc_balance) ``` - `staked_ncg`: The staked NCG amounts of given account. (on Nine Chronicles mainnet) -- `staked_lp_tokens`: The staked LP token amounts in the staking contract of given account. (on Ethereum mainnet) - - This value only refer staking contract from [Planetarium] and staked value on its backeed pool will be ignored. +- `staked_wncg`: The staked wNCG amounts of given account. (on Ethereum mainnet) - `w1`, `w2`, `w3`: Weights for each amounts. it can be configured by parameters. +Also, the `staked_wncg` of the account will be calculated with: + +``` +staked_wncg = (wncg_in_vault / total_lp_supply) * staked_lp_tokens +``` + +- `wncg_in_vault`: The total wNCG amounts that [Balancer] Vault held. +- `total_lp_supply`: The total supply of LP token that Balancer pool issued. +- `staked_lp_tokens`: The staked LP token amounts in the staking contract of given account. + - This value only refers staking contract from [Planetarium] and staked value on its backed pool (from Balancer) will be ignored. + +[Balancer]: https://balancer.fi/ +[Planetarium]: https://planetariumhq.com/ + ## Parameters - `symbol` - (**Optional**, `string`): The symbol of voting score. - `ethLPTokenStakingAddress` - (**Required**, `string`): The address of staking contract on Ethereum. +- `ethLPTokenAddres` - (**Required**, `string`): The address of LP token contract on Ethereum. +- `ethWNCGAddress` - (**Required**, `string`): The address of wNCG token contract on Ethereum. +- `ethBalancerVaultAddress` - (**Required**, `string`): The address of Balancer Vault contract on Ethereum. - `ethDccAddress` - (**Required**, `string`): The address of D:CC token contract on Ethereum. - `ncGraphQLEndpoint` - (**Required**, `string`): The GraphQL endpoint of Nine Chronicles to query. - `ncBlockHash` - (**Required**, `string`): The target Block Hash of Nine Chronicles. -- `lpTokenDecimal` - (**Optional**, `number`): The decimal precision for staked token. default is 18. +- `wNCGDecimal` - (**Optional**, `number`): The decimal precision for wNCG. default is 18. - `weights` - (**Optional**, `number`): Weight values for the fomular . these values must be integers without decimal parts. - `stakedNCG`: Weight for staked NCG. (`w1`) - - `stakedLPToken`: Weight for staked LP token. (`w2`) + - `stakedWNCG`: Weight for staked wNCG. (`w2`) - `dcc`: Weight for D:CC. (`w3`) @@ -39,14 +56,18 @@ score = (w1 * staked_ncg) + (w2 * staked_lp_tokens) + (w3 * dcc_balance) ```json { "symbol": "Staked 9c assets + DCC", - "ethLPTokenStakingAddress": "0xcc2db561d149a6d2f071a2809492d72e07838f69", + "ethLPTokenStakingAddress": "0xc53b567a70db04e928fb96d6a417971aa88fda38", + "ethLPTokenAddress": "0xe8cc7e765647625b95f59c15848379d10b9ab4af", + "ethWNCGAddress": "0xf203ca1769ca8e9e8fe1da9d147db68b6c919817", + "ethBalancerVaultAddress": "0xba12222222228d8ba445958a75a0704d566bf2c8", "ethDccAddress": "0xcea65a86195c911912ce48b6636ddd365c208130", - "ncGraphQLEndpoint": "http://9c-main-rpc-31.nine-chronicles.com/graphql", + "ncGraphQLEndpoint": "http://rpc-for-snapshot.nine-chronicles.com/graphql", "ncBlockHash": "711ce4bcdc0fb5264577876f217a794b2448ccce24e3c7ea0fb9794e420863e4", - "lpTokenDecimal": 18, + "wNCGDecimals": 18, "weights": { - "stakedToken": 1, + "stakedWNCG": 1, "stakedNCG": 1, "dcc": 999 + } } ``` diff --git a/src/strategies/ninechronicles-staked-and-dcc/examples.json b/src/strategies/ninechronicles-staked-and-dcc/examples.json index e689a732e..e2fc45bf4 100644 --- a/src/strategies/ninechronicles-staked-and-dcc/examples.json +++ b/src/strategies/ninechronicles-staked-and-dcc/examples.json @@ -6,12 +6,15 @@ "params": { "symbol": "Staked 9c assets + DCC", "ethLPTokenStakingAddress": "0xc53b567A70dB04E928FB96D6A417971aa88fdA38", + "ethLPTokenAddress": "0xe8cc7e765647625b95f59c15848379d10b9ab4af", + "ethWNCGAddress": "0xf203ca1769ca8e9e8fe1da9d147db68b6c919817", + "ethBalancerVaultAddress": "0xba12222222228d8ba445958a75a0704d566bf2c8", "ethDccAddress": "0xcea65a86195c911912ce48b6636ddd365c208130", - "ncGraphQLEndpoint": "http://9c-main-rpc-31.nine-chronicles.com/graphql", + "ncGraphQLEndpoint": "http://rpc-for-snapshot.nine-chronicles.com/graphql", "ncBlockHash": "711ce4bcdc0fb5264577876f217a794b2448ccce24e3c7ea0fb9794e420863e4", - "lpTokenDecimal": 18, + "wNCGDecimals": 18, "weights": { - "stakedLPToken": 1, + "stakedWNCG": 1, "stakedNCG": 1, "dcc": 999 } diff --git a/src/strategies/ninechronicles-staked-and-dcc/index.ts b/src/strategies/ninechronicles-staked-and-dcc/index.ts index a7b8bf0b0..bf94d151a 100644 --- a/src/strategies/ninechronicles-staked-and-dcc/index.ts +++ b/src/strategies/ninechronicles-staked-and-dcc/index.ts @@ -5,21 +5,29 @@ import { strategy as erc721BalanceOfStrategy } from '../erc721'; import { Multicaller, subgraphRequest } from '../../utils'; export const author = 'longfin'; -export const version = '1.0.0'; +export const version = '1.1.0'; export const dependOnOtherAddress = false; const lpStakingABI = [ 'function stakedTokenBalance(address account) view returns (uint256)', -] +]; + +const erc20ABI = [ + 'function totalSupply() view returns (uint256)', + 'function balanceOf(address account) view returns (uint256)', +]; interface Options { ethLPTokenStakingAddress: string, + ethLPTokenAddress: string, + ethWNCGAddress: string, + ethBalancerVaultAddress: string, ethDccAddress: string, ncBlockHash: string, ncGraphQLEndpoint: string, - lpTokenDecimal: number, + wncgDecimals: number, weights: { - stakedLPToken: number, + stakedWNCG: number, dcc: number, stakedNCG: number } @@ -35,12 +43,15 @@ export async function strategy( ): Promise> { const { ethLPTokenStakingAddress, + ethLPTokenAddress, + ethWNCGAddress, + ethBalancerVaultAddress, ethDccAddress, ncBlockHash, ncGraphQLEndpoint, - lpTokenDecimal = 18, + wncgDecimals = 18, weights: { - stakedLPToken: stakedLpTokenWeight = 1, + stakedWNCG: stakedWNCGWeight = 1, dcc: dccWeight = 999, stakedNCG: stakedNCGWeight = 1, }, @@ -63,14 +74,23 @@ export async function strategy( }); const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - const multiCaller = new Multicaller(network, provider, lpStakingABI, { blockTag }); + const { + wNCGInVault, + totalLPSupply, + }: Record = await new Multicaller(network, provider, erc20ABI, { blockTag }) + .call("wNCGInVault", ethWNCGAddress, 'balanceOf', [ethBalancerVaultAddress]) + .call("totalLPSupply", ethLPTokenAddress, 'totalSupply', []) + .execute(); + + const lpStakingChecker = new Multicaller(network, provider, lpStakingABI, { blockTag }); addresses.forEach((address) => - multiCaller.call(address, ethLPTokenStakingAddress, 'stakedTokenBalance', [address]) + lpStakingChecker.call(address, ethLPTokenStakingAddress, 'stakedTokenBalance', [address]) ); - const stakedTokenScores = multiCaller.execute().then((rawScores: Record) => { + const stakedWNCGScores = lpStakingChecker.execute().then((rawScores: Record) => { const scores = {}; Object.keys(rawScores).forEach(addr => { - scores[addr] = parseFloat(formatUnits(rawScores[addr].mul(stakedLpTokenWeight), lpTokenDecimal)); + const amount = rawScores[addr].mul(wNCGInVault).mul(stakedWNCGWeight).div(totalLPSupply); + scores[addr] = parseFloat(formatUnits(amount, wncgDecimals)); }); return scores; @@ -103,7 +123,7 @@ export async function strategy( const allScores = await Promise.all([ dccScores, - stakedTokenScores, + stakedWNCGScores, stakedNCGScores, ]); From 1999da52e608e120ea234caedbe9dbf924ee72e6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 28 Oct 2022 18:22:38 +0530 Subject: [PATCH 190/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.45 (#917) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f2ecc891b..2cee357ab 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.44", + "@snapshot-labs/snapshot.js": "^0.4.45", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 491d5d841..1835fa988 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.44": - version "0.4.44" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.44.tgz#2e305a3b39d6046c7f4559aec8dd9bfb4cdb7e7b" - integrity sha512-hF8vjlXEuACxn2Esk+vNK0IZSyglaQ3r/3ILbOIM6ScJZA9kVWJngaIUQklNsfgKILERQ30OW+GQrDYJYSz1mQ== +"@snapshot-labs/snapshot.js@^0.4.45": + version "0.4.45" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.45.tgz#89721ac87c190a0b7b01df1684a982f7796359bb" + integrity sha512-GsBQSEu9qVEl2xiXjIOR8BP5oU2pPsYfrdA1svL7ZuRbTmX+E2Kcm0nZ0Jy/CaWYUqWSFPa5DiMVze/osFo39w== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From e8fb8d1e5c0773203348cc306b2b66d7cfcbdc4a Mon Sep 17 00:00:00 2001 From: Onigiri <35141155+onigiri-x@users.noreply.github.com> Date: Fri, 28 Oct 2022 15:52:09 -0300 Subject: [PATCH 191/815] Ens all club digit strategy [ens-all-club-digits] (#900) * Ens all club digit strategy * Use 4 digits and add accounts with high volumes of ens names, test up to 7 digits support * Update src/strategies/ens-all-club-digits/index.ts Co-authored-by: Chaitanya * Update src/strategies/ens-all-club-digits/examples.json * Alot better model without legacy 10k club memory issues * Cleanup Co-authored-by: Chaitanya --- src/strategies/ens-all-club-digits/README.md | 16 ++++ .../ens-all-club-digits/examples.json | 20 +++++ src/strategies/ens-all-club-digits/index.ts | 87 +++++++++++++++++++ src/strategies/index.ts | 2 + 4 files changed, 125 insertions(+) create mode 100644 src/strategies/ens-all-club-digits/README.md create mode 100644 src/strategies/ens-all-club-digits/examples.json create mode 100644 src/strategies/ens-all-club-digits/index.ts diff --git a/src/strategies/ens-all-club-digits/README.md b/src/strategies/ens-all-club-digits/README.md new file mode 100644 index 000000000..14ed3264c --- /dev/null +++ b/src/strategies/ens-all-club-digits/README.md @@ -0,0 +1,16 @@ +# ens-all-club-digits + +This strategy is for All Club Digits members, holders of ENS names 000.eth - 999.eth, 0000.eth - 9999.eth, 00000.eth to 99999.eth and beyond +This script queries The Graph for all ENS names owned by voter and checks for 10K Club names. +Pass the number of digits as the requirement + + +Here is an example of parameters, we want 999 so we put numberOfDigits set to 3: + +```json +{ + "address": "0x57f1887a8BF19b14fC0dF6Fd9B2acc9Af147eA85", + "symbol": "DIGITS", + "numberOfDigits": 3 +} +``` diff --git a/src/strategies/ens-all-club-digits/examples.json b/src/strategies/ens-all-club-digits/examples.json new file mode 100644 index 000000000..1931a5ff5 --- /dev/null +++ b/src/strategies/ens-all-club-digits/examples.json @@ -0,0 +1,20 @@ +[ + { + "name": "ENS ALL Club Digits", + "strategy": { + "name": "ens-all-club-digits", + "params": { + "address": "0x57f1887a8BF19b14fC0dF6Fd9B2acc9Af147eA85", + "symbol": "NUMS", + "numberOfDigits": 7 + } + }, + "network": "1", + "addresses": [ + "0xa2e87bf4e4edc28922736887772c351de5554b77", + "0xf8ebe2b23ed74bee2b35da9de63c2380902b7cb5", + "0xae099ada728a5abf8b31f2b126cc5bf8e70fbc2c" + ], + "snapshot": 15818456 + } +] diff --git a/src/strategies/ens-all-club-digits/index.ts b/src/strategies/ens-all-club-digits/index.ts new file mode 100644 index 000000000..4776d3d78 --- /dev/null +++ b/src/strategies/ens-all-club-digits/index.ts @@ -0,0 +1,87 @@ +import { subgraphRequest } from '../../utils'; +import { getAddress } from '@ethersproject/address'; + +const ENS_SUBGRAPH_URL = { + '1': 'https://api.thegraph.com/subgraphs/name/ensdomains/ens', + '3': 'https://api.thegraph.com/subgraphs/name/ensdomains/ensropsten', + '4': 'https://api.thegraph.com/subgraphs/name/ensdomains/ensrinkeby', + '5': 'https://api.thegraph.com/subgraphs/name/ensdomains/ensgoerli' +}; + +export const author = 'onigiri-x'; +export const version = '0.1.0'; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + // 999 Club = 3 , 10k club = 4, 100k club = 5, etc + const { numberOfDigits } = options; + + const max = 10; + const count = Math.ceil(addresses.length / max); + const pages = Array.from(Array(count)).map((x, i) => + addresses.slice(max * i, max * (i + 1)) + ); + let page = 0; + const votes = {}; + // This will iterate until there are no more full pages (1000 domains being returned), + while (true) { + const params = Object.fromEntries( + pages + .map((page, i) => `_${i}`) + .map((q, i) => [ + q, + { + __aliasFor: 'registrations', + __args: { + block: snapshot !== 'latest' ? { number: snapshot } : null, + where: { + registrant_in: pages[i].map((address) => address.toLowerCase()) + }, + first: 1000, + skip: page*1000, + orderBy: 'registrationDate', + orderDirection: 'desc' + }, + registrant: { + id: true + }, + domain: { + // labelhash: true, + labelName: true + } + } + ]) + ); + + let result = await subgraphRequest(ENS_SUBGRAPH_URL[network], params); + result = [].concat.apply([], Object.values(result)); + + if (result) { + result.forEach((registration) => { + const owner = getAddress(registration.registrant.id); + const label = registration.domain.labelName; + if (!votes[owner]) { + votes[owner] = 0; + } + const reg = new RegExp('^[0-9]*$'); // only number 0 to 9 + if (label && label.length === numberOfDigits && reg.test(label)) { + votes[owner] = votes[owner] + 1; + } + }); + if (result.length >= 1000) { + page++; + } else { + break; + } + } else { + break; + } + } + return votes; +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 778a22c0c..d8ff7f421 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -18,6 +18,7 @@ import * as vDfynVault from './balance-in-vdfyn-vault'; import * as ensDomainsOwned from './ens-domains-owned'; import * as ensReverseRecord from './ens-reverse-record'; import * as ens10kClub from './ens-10k-club'; +import * as ensAllClubDigits from './ens-all-club-digits'; import * as governorDelegator from './governor-delegator'; import * as erc20BalanceOf from './erc20-balance-of'; import * as erc20BalanceOfCoeff from './erc20-balance-of-coeff'; @@ -417,6 +418,7 @@ const strategies = { 'ens-domains-owned': ensDomainsOwned, 'ens-reverse-record': ensReverseRecord, 'ens-10k-club': ens10kClub, + 'ens-all-club-digits': ensAllClubDigits, 'governor-delegator': governorDelegator, 'erc20-balance-of': erc20BalanceOf, 'erc20-votes': erc20Votes, From e755633fbc40a08d0201cdd1a9e770f4553462ac Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Sun, 30 Oct 2022 14:11:07 +0530 Subject: [PATCH 192/815] Passport validation - check with snapshot block (#918) * Passport validation - check with snapshot block * Typo --- src/validations/passport/helper.ts | 21 ++++++++++++++++++--- src/validations/passport/index.ts | 28 ++++++++++++++++++++++------ 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/src/validations/passport/helper.ts b/src/validations/passport/helper.ts index c4ca2cba7..b30a1e637 100644 --- a/src/validations/passport/helper.ts +++ b/src/validations/passport/helper.ts @@ -22,9 +22,11 @@ export const getPassport = async (address) => { return false; }; -export const getVerifiedStamps = async (passport, address, stampsRequired) => { - if (!passport) return false; - +export const getVerifiedStamps = async ( + passport, + address, + stampsRequired +): Promise => { const stamps = passport.stamps || []; // filter out stamps with stampsRequired @@ -79,3 +81,16 @@ const verifyCredential = async (credential) => { } return false; }; + +export const hasValidIssuanceAndExpiration = (credential, proposalTs) => { + const issuanceDate = Number( + new Date(credential.issuanceDate).getTime() / 1000 + ).toFixed(0); + const expirationDate = Number( + new Date(credential.expirationDate).getTime() / 1000 + ).toFixed(0); + if (issuanceDate <= proposalTs && expirationDate >= proposalTs) { + return true; + } + return false; +}; diff --git a/src/validations/passport/index.ts b/src/validations/passport/index.ts index 91331009f..b27bef9c6 100644 --- a/src/validations/passport/index.ts +++ b/src/validations/passport/index.ts @@ -1,5 +1,10 @@ +import snapshot from '@snapshot-labs/snapshot.js'; import Validation from '../validation'; -import { getPassport, getVerifiedStamps } from './helper'; +import { + getPassport, + getVerifiedStamps, + hasValidIssuanceAndExpiration +} from './helper'; export default class extends Validation { public id = 'passport'; @@ -9,19 +14,30 @@ export default class extends Validation { async validate(): Promise { const passport: any = await getPassport(this.author); if (!passport) return false; - if (!passport.stamps || !this.params.stamps) return false; + if (!passport.stamps?.length || !this.params.stamps?.length) return false; - const verifiedStamps: false | any[] = await getVerifiedStamps( + const verifiedStamps: any[] = await getVerifiedStamps( passport, this.author, this.params.stamps ); - if (!verifiedStamps) return false; + if (!verifiedStamps.length) return false; + + const provider = snapshot.utils.getProvider(this.network); + const proposalTs = (await provider.getBlock(this.snapshot)).timestamp; let weight = 0; this.params.stamps.forEach((stamp: any) => { - const found = verifiedStamps.find((s: any) => s.provider === stamp.id); - if (found?.verified) weight += stamp.weight; + const verifiedStamp = verifiedStamps.find( + (s: any) => s.provider === stamp.id + ); + + // check that the credential is still valid (created before snapshot block and not expired) + if ( + verifiedStamp && + hasValidIssuanceAndExpiration(verifiedStamp.credential, proposalTs) + ) + weight += stamp.weight; }); return weight >= this.params.min_weight; From 4ee9304fab23804d7feb49c8efceba8ad1ac41a8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 30 Oct 2022 17:21:15 +0530 Subject: [PATCH 193/815] Automated lint (#920) Co-authored-by: ChaituVR --- src/strategies/defiplaza/index.ts | 15 ++- src/strategies/ens-all-club-digits/index.ts | 2 +- src/strategies/index.ts | 5 +- src/strategies/metropolis-pod/examples.json | 6 +- .../ninechronicles-staked-and-dcc/index.ts | 108 +++++++++++------- src/strategies/safe-vested/examples.json | 4 +- 6 files changed, 84 insertions(+), 56 deletions(-) diff --git a/src/strategies/defiplaza/index.ts b/src/strategies/defiplaza/index.ts index cd1e0870c..8fcf80cf8 100644 --- a/src/strategies/defiplaza/index.ts +++ b/src/strategies/defiplaza/index.ts @@ -1,7 +1,6 @@ import { formatUnits } from '@ethersproject/units'; import { Multicaller, customFetch } from '../../utils'; - export const author = 'timanrebel'; export const version = '0.1.1'; @@ -40,7 +39,7 @@ export async function strategy( }); const result = await multi.execute(); - let returnObject = {}; + const returnObject = {}; addresses.forEach((address) => { if (!returnObject.hasOwnProperty(address)) { @@ -65,15 +64,21 @@ export async function strategy( }); // request balance on Radix - const res = await customFetch(`https://radix.defiplaza.net/voting/${snapshot}`, {}, 8000); + const res = await customFetch( + `https://radix.defiplaza.net/voting/${snapshot}`, + {}, + 8000 + ); const radixLinks = await res.json(); - for (let wallet of radixLinks) { + for (const wallet of radixLinks) { if (!returnObject.hasOwnProperty(wallet.address)) { returnObject[wallet.address] = 0; } - returnObject[wallet.address] += parseFloat(formatUnits(wallet.balance, options.decimals)); + returnObject[wallet.address] += parseFloat( + formatUnits(wallet.balance, options.decimals) + ); } return returnObject; diff --git a/src/strategies/ens-all-club-digits/index.ts b/src/strategies/ens-all-club-digits/index.ts index 4776d3d78..d1885ba41 100644 --- a/src/strategies/ens-all-club-digits/index.ts +++ b/src/strategies/ens-all-club-digits/index.ts @@ -44,7 +44,7 @@ export async function strategy( registrant_in: pages[i].map((address) => address.toLowerCase()) }, first: 1000, - skip: page*1000, + skip: page * 1000, orderBy: 'registrationDate', orderDirection: 'desc' }, diff --git a/src/strategies/index.ts b/src/strategies/index.ts index d8ff7f421..e427bcfbb 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -390,7 +390,6 @@ import * as ninechroniclesStakedAndDcc from './ninechronicles-staked-and-dcc'; import * as spreadsheet from './spreadsheet'; import * as anchorage from './anchorage'; - const strategies = { 'forta-shares': fortaShares, 'ethermon-erc721': ethermon721, @@ -758,7 +757,7 @@ const strategies = { 'echelon-cached-erc1155-decay': echelonCachedErc1155Decay, 'erc3525-flexible-voucher': erc3525FlexibleVoucher, 'orca-pod': orcaPod, - 'metropolis-pod': metropolisPod, + 'metropolis-pod': metropolisPod, 'proxyprotocol-erc20-balance-of': proxyProtocolErc20BalanceOf, 'proxyprotocol-erc721-balance-of': proxyProtocolErc721BalanceOf, 'proxyprotocol-erc1155-balance-of': proxyProtocolErc1155BalanceOf, @@ -783,7 +782,7 @@ const strategies = { 'clqdr-balance-with-lp': clqdrBalanceWithLp, spreadsheet, anchorage, - 'ninechronicles-staked-and-dcc': ninechroniclesStakedAndDcc, + 'ninechronicles-staked-and-dcc': ninechroniclesStakedAndDcc }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/metropolis-pod/examples.json b/src/strategies/metropolis-pod/examples.json index 90e960d66..0e6c78934 100644 --- a/src/strategies/metropolis-pod/examples.json +++ b/src/strategies/metropolis-pod/examples.json @@ -10,7 +10,11 @@ } }, "network": "1", - "addresses": ["0x094a473985464098b59660b37162a284b5132753","0x4B4C43F66ec007D1dBE28f03dAC975AAB5fbb888","0x403f69b1092cf1cB82487CD137F96E8200f03BD5"], + "addresses": [ + "0x094a473985464098b59660b37162a284b5132753", + "0x4B4C43F66ec007D1dBE28f03dAC975AAB5fbb888", + "0x403f69b1092cf1cB82487CD137F96E8200f03BD5" + ], "snapshot": 15188155 } ] diff --git a/src/strategies/ninechronicles-staked-and-dcc/index.ts b/src/strategies/ninechronicles-staked-and-dcc/index.ts index bf94d151a..4d42e497f 100644 --- a/src/strategies/ninechronicles-staked-and-dcc/index.ts +++ b/src/strategies/ninechronicles-staked-and-dcc/index.ts @@ -9,28 +9,28 @@ export const version = '1.1.0'; export const dependOnOtherAddress = false; const lpStakingABI = [ - 'function stakedTokenBalance(address account) view returns (uint256)', + 'function stakedTokenBalance(address account) view returns (uint256)' ]; const erc20ABI = [ 'function totalSupply() view returns (uint256)', - 'function balanceOf(address account) view returns (uint256)', + 'function balanceOf(address account) view returns (uint256)' ]; interface Options { - ethLPTokenStakingAddress: string, - ethLPTokenAddress: string, - ethWNCGAddress: string, - ethBalancerVaultAddress: string, - ethDccAddress: string, - ncBlockHash: string, - ncGraphQLEndpoint: string, - wncgDecimals: number, + ethLPTokenStakingAddress: string; + ethLPTokenAddress: string; + ethWNCGAddress: string; + ethBalancerVaultAddress: string; + ethDccAddress: string; + ncBlockHash: string; + ncGraphQLEndpoint: string; + wncgDecimals: number; weights: { - stakedWNCG: number, - dcc: number, - stakedNCG: number - } + stakedWNCG: number; + dcc: number; + stakedNCG: number; + }; } export async function strategy( @@ -53,9 +53,9 @@ export async function strategy( weights: { stakedWNCG: stakedWNCGWeight = 1, dcc: dccWeight = 999, - stakedNCG: stakedNCGWeight = 1, - }, - } : Options = options; + stakedNCG: stakedNCGWeight = 1 + } + }: Options = options; addresses = addresses.map(formatEthAddress); @@ -66,56 +66,76 @@ export async function strategy( addresses, { address: ethDccAddress }, snapshot - ).then(scores => { - Object.keys(scores).forEach(addr => { + ).then((scores) => { + Object.keys(scores).forEach((addr) => { scores[addr] *= dccWeight; }); - return scores + return scores; }); const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - const { - wNCGInVault, - totalLPSupply, - }: Record = await new Multicaller(network, provider, erc20ABI, { blockTag }) - .call("wNCGInVault", ethWNCGAddress, 'balanceOf', [ethBalancerVaultAddress]) - .call("totalLPSupply", ethLPTokenAddress, 'totalSupply', []) - .execute(); - - const lpStakingChecker = new Multicaller(network, provider, lpStakingABI, { blockTag }); + const { wNCGInVault, totalLPSupply }: Record = + await new Multicaller(network, provider, erc20ABI, { blockTag }) + .call('wNCGInVault', ethWNCGAddress, 'balanceOf', [ + ethBalancerVaultAddress + ]) + .call('totalLPSupply', ethLPTokenAddress, 'totalSupply', []) + .execute(); + + const lpStakingChecker = new Multicaller(network, provider, lpStakingABI, { + blockTag + }); addresses.forEach((address) => - lpStakingChecker.call(address, ethLPTokenStakingAddress, 'stakedTokenBalance', [address]) + lpStakingChecker.call( + address, + ethLPTokenStakingAddress, + 'stakedTokenBalance', + [address] + ) ); - const stakedWNCGScores = lpStakingChecker.execute().then((rawScores: Record) => { - const scores = {}; - Object.keys(rawScores).forEach(addr => { - const amount = rawScores[addr].mul(wNCGInVault).mul(stakedWNCGWeight).div(totalLPSupply); - scores[addr] = parseFloat(formatUnits(amount, wncgDecimals)); + const stakedWNCGScores = lpStakingChecker + .execute() + .then((rawScores: Record) => { + const scores = {}; + Object.keys(rawScores).forEach((addr) => { + const amount = rawScores[addr] + .mul(wNCGInVault) + .mul(stakedWNCGWeight) + .div(totalLPSupply); + scores[addr] = parseFloat(formatUnits(amount, wncgDecimals)); + }); + + return scores; }); - - return scores; - }); const stakedNCGQuery = { stateQuery: { __args: { - hash: ncBlockHash, + hash: ncBlockHash }, stakeStates: { __args: { - addresses: addresses, + addresses: addresses }, - deposit: true, + deposit: true } } }; - const stakedNCGScores = subgraphRequest(ncGraphQLEndpoint, stakedNCGQuery).then(resp => { + const stakedNCGScores = subgraphRequest( + ncGraphQLEndpoint, + stakedNCGQuery + ).then((resp) => { const scores: Record = {}; addresses.forEach((addr, i) => { const stakeState = resp.stateQuery.stakeStates[i]; - scores[addr] = parseFloat(formatUnits(parseUnits(stakeState?.deposit ?? "0.00", 2).mul(stakedNCGWeight), 2)); + scores[addr] = parseFloat( + formatUnits( + parseUnits(stakeState?.deposit ?? '0.00', 2).mul(stakedNCGWeight), + 2 + ) + ); }); return scores; @@ -124,7 +144,7 @@ export async function strategy( const allScores = await Promise.all([ dccScores, stakedWNCGScores, - stakedNCGScores, + stakedNCGScores ]); return allScores.reduce((total, scores) => { diff --git a/src/strategies/safe-vested/examples.json b/src/strategies/safe-vested/examples.json index 7d6384558..3924bb74b 100755 --- a/src/strategies/safe-vested/examples.json +++ b/src/strategies/safe-vested/examples.json @@ -4,8 +4,8 @@ "strategy": { "name": "safe-vested", "params": { - "allocationsSource": "https://safe-claiming-app-data.gnosis-safe.io/allocations/1/snapshot-allocations-data.json", - "claimDateLimit": "2022-12-28T11:00:00Z" + "allocationsSource": "https://safe-claiming-app-data.gnosis-safe.io/allocations/1/snapshot-allocations-data.json", + "claimDateLimit": "2022-12-28T11:00:00Z" } }, "network": "1", From 7ab708518e5e4209740ce86c3162d8eb3de7718f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 31 Oct 2022 12:21:37 +0530 Subject: [PATCH 194/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.46 (#922) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 2cee357ab..9224c1d11 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.45", + "@snapshot-labs/snapshot.js": "^0.4.46", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 1835fa988..b99781f4a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.45": - version "0.4.45" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.45.tgz#89721ac87c190a0b7b01df1684a982f7796359bb" - integrity sha512-GsBQSEu9qVEl2xiXjIOR8BP5oU2pPsYfrdA1svL7ZuRbTmX+E2Kcm0nZ0Jy/CaWYUqWSFPa5DiMVze/osFo39w== +"@snapshot-labs/snapshot.js@^0.4.46": + version "0.4.46" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.46.tgz#33d4e2e2212441ee9fee40b18cd1e7db587c7a4a" + integrity sha512-/1klfof9/mS5GGxgI+fh8mgGCdGeD9h4krFsjK/Y1YFTRvKPAIjoZW22PbVmHeXH1FWkoqc2vIh6mzQygKNq2Q== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 960bd42c6a2d60ddc75820de8e0d243edfc57459 Mon Sep 17 00:00:00 2001 From: defininja <91393134+defininja@users.noreply.github.com> Date: Mon, 31 Oct 2022 21:21:47 +0530 Subject: [PATCH 195/815] score updations for new farm and infinity vault updations [planet-finance-v2] (#921) * score updations for new farm and infinity vault updations * Update index.ts * Update src/strategies/planet-finance-v2/index.ts * name of author changed to defininja * author change to defininja * Update src/strategies/planet-finance-v2/index.ts Co-authored-by: defininja Co-authored-by: Chaitanya --- .../planet-finance-v2/examples.json | 4 +- src/strategies/planet-finance-v2/index.ts | 46 +++++++++---------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/strategies/planet-finance-v2/examples.json b/src/strategies/planet-finance-v2/examples.json index 14393b3c6..bc5d3cd3a 100644 --- a/src/strategies/planet-finance-v2/examples.json +++ b/src/strategies/planet-finance-v2/examples.json @@ -10,7 +10,7 @@ } }, "network": "56", - "addresses": ["0xc358615Fb090Db0284a73Ac690B264BFDCa141f0"], - "snapshot": 16110697 + "addresses": ["0xc358615Fb090Db0284a73Ac690B264BFDCa141f0", "0x19d4051F7740e6AA4494EBCc655a70f524878346", "0xa14EdA7b66Fa8B030905A57D97Da57553c56Ec0D"], + "snapshot": 22001625 } ] diff --git a/src/strategies/planet-finance-v2/index.ts b/src/strategies/planet-finance-v2/index.ts index 18eca0333..622c8cbbd 100644 --- a/src/strategies/planet-finance-v2/index.ts +++ b/src/strategies/planet-finance-v2/index.ts @@ -3,12 +3,11 @@ import { multicall } from '../../utils'; import { Multicaller } from '../../utils'; import { strategy as erc20BalanceOfStrategy } from '../erc20-balance-of'; -export const author = 'planet-finance'; -export const version = '0.0.1'; +export const author = 'defininja'; +export const version = '0.0.2'; const planetFinanceFarmAbi = [ - 'function poolInfo(uint256) returns (address want,uint256 allocPoint,uint256 lastRewardBlock,uint256 accAQUAPerShare,address strat)', - 'function stakedWantTokens(uint256 _pid, address _user) returns (uint256)' + 'function userInfo(uint256, address) view returns (uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256)' ]; const bep20Abi: any = [ @@ -24,15 +23,15 @@ const aquaLendingAbi = [ 'function getAccountSnapshot(address) view returns (uint256,uint256,uint256,uint256)' ]; -const gammaFarmAddress = '0xB87F7016585510505478D1d160BDf76c1f41b53d'; +const gammaFarmAddress = '0x9EBce8B8d535247b2a0dfC0494Bc8aeEd7640cF9'; const aquaAddress = '0x72B7D61E8fC8cF971960DD9cfA59B8C829D91991'; const aquaBnbLpTokenAddress = '0x03028D2F8B275695A1c6AFB69A4765e3666e36d9'; -const aquaLendingAddress = '0xb7eD4A5AF620B52022fb26035C565277035d4FD7'; +const aquaLendingAddress = '0x2f5d7A9D8D32c16e41aF811744DB9f15d853E0A5'; -const aquaInfinityAddress = '0x6E7a174836b2Df12599ecB2Dc64C1F9e1576aC45'; +const aquaInfinityAddress = '0xddd0626BB795BdF9CfA925da5102eFA5E7008114'; const increase_in_voting = 5; //increase 5 times @@ -73,15 +72,15 @@ export async function strategy( { blockTag } ); - // returns user's aqua balance in aqua-bnb vault + // returns user's aqua balance in aqua-bnb pool let usersNewAquaBnbVaultBalances: any = multicall( network, provider, planetFinanceFarmAbi, addresses.map((address: any) => [ gammaFarmAddress, - 'stakedWantTokens', - ['1', address] + 'userInfo', + ['2', address] ]), { blockTag } ); @@ -102,7 +101,7 @@ export async function strategy( const result = await Promise.all([ score, usergAquaBalInAquaInfinityVault, - usersNewAquaBnbVaultBalances, // new pool aqua bnb + usersNewAquaBnbVaultBalances, usersAquaInLending ]); @@ -112,8 +111,10 @@ export async function strategy( usersAquaInLending = result[3]; //AQUA-BNB + // total supply of aqua bnb lp token erc20Multi.call('aquaBnbTotalSupply', aquaBnbLpTokenAddress, 'totalSupply'); + // aqua balance of aqua bnb lp erc20Multi.call('aquaBnbAquaBal', aquaAddress, 'balanceOf', [ aquaBnbLpTokenAddress ]); @@ -130,18 +131,17 @@ export async function strategy( address[0], address[1] + - (parseFloat( - formatUnits(usersNewAquaBnbVaultBalances[index].toString(), 18) - ) / - parseFloat(formatUnits(totalSupply, 18))) * - parseFloat(formatUnits(contractAquaBalance, 18)) + - parseFloat( - formatUnits(usergAquaBalInAquaInfinityVault[index].toString(), 18) - ) * - parseFloat(formatUnits(usersAquaInLending[index]['3'], 18)) * - increase_in_voting + - parseFloat(formatUnits(usersAquaInLending[index]['1'], 18)) * - parseFloat(formatUnits(usersAquaInLending[index]['3'], 18)) + + parseFloat( + formatUnits(usersNewAquaBnbVaultBalances[index]['0'].toString(), 18) + ) / parseFloat(formatUnits(totalSupply, 18)) * parseFloat(formatUnits(contractAquaBalance, 18)) + + + parseFloat(formatUnits( usergAquaBalInAquaInfinityVault[index].toString(), 18 )) * + parseFloat(formatUnits( usersAquaInLending[index]['3'], 18 )) * + increase_in_voting + + + parseFloat(formatUnits(usersAquaInLending[index]['1'], 18)) * + parseFloat(formatUnits( usersAquaInLending[index]['3'], 18 ) ) ]; }) ); From f4c81808c78b8b1f801d27abd61e579e3c1645f6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 31 Oct 2022 22:08:59 +0530 Subject: [PATCH 196/815] Automated lint (#924) Co-authored-by: ChaituVR --- .../planet-finance-v2/examples.json | 8 ++++-- src/strategies/planet-finance-v2/index.ts | 25 ++++++++++--------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/strategies/planet-finance-v2/examples.json b/src/strategies/planet-finance-v2/examples.json index bc5d3cd3a..bfefc7469 100644 --- a/src/strategies/planet-finance-v2/examples.json +++ b/src/strategies/planet-finance-v2/examples.json @@ -10,7 +10,11 @@ } }, "network": "56", - "addresses": ["0xc358615Fb090Db0284a73Ac690B264BFDCa141f0", "0x19d4051F7740e6AA4494EBCc655a70f524878346", "0xa14EdA7b66Fa8B030905A57D97Da57553c56Ec0D"], - "snapshot": 22001625 + "addresses": [ + "0xc358615Fb090Db0284a73Ac690B264BFDCa141f0", + "0x19d4051F7740e6AA4494EBCc655a70f524878346", + "0xa14EdA7b66Fa8B030905A57D97Da57553c56Ec0D" + ], + "snapshot": 22001625 } ] diff --git a/src/strategies/planet-finance-v2/index.ts b/src/strategies/planet-finance-v2/index.ts index 622c8cbbd..637fe0927 100644 --- a/src/strategies/planet-finance-v2/index.ts +++ b/src/strategies/planet-finance-v2/index.ts @@ -114,7 +114,7 @@ export async function strategy( // total supply of aqua bnb lp token erc20Multi.call('aquaBnbTotalSupply', aquaBnbLpTokenAddress, 'totalSupply'); - // aqua balance of aqua bnb lp + // aqua balance of aqua bnb lp erc20Multi.call('aquaBnbAquaBal', aquaAddress, 'balanceOf', [ aquaBnbLpTokenAddress ]); @@ -131,17 +131,18 @@ export async function strategy( address[0], address[1] + - - parseFloat( - formatUnits(usersNewAquaBnbVaultBalances[index]['0'].toString(), 18) - ) / parseFloat(formatUnits(totalSupply, 18)) * parseFloat(formatUnits(contractAquaBalance, 18)) + - - parseFloat(formatUnits( usergAquaBalInAquaInfinityVault[index].toString(), 18 )) * - parseFloat(formatUnits( usersAquaInLending[index]['3'], 18 )) * - increase_in_voting + - - parseFloat(formatUnits(usersAquaInLending[index]['1'], 18)) * - parseFloat(formatUnits( usersAquaInLending[index]['3'], 18 ) ) + (parseFloat( + formatUnits(usersNewAquaBnbVaultBalances[index]['0'].toString(), 18) + ) / + parseFloat(formatUnits(totalSupply, 18))) * + parseFloat(formatUnits(contractAquaBalance, 18)) + + parseFloat( + formatUnits(usergAquaBalInAquaInfinityVault[index].toString(), 18) + ) * + parseFloat(formatUnits(usersAquaInLending[index]['3'], 18)) * + increase_in_voting + + parseFloat(formatUnits(usersAquaInLending[index]['1'], 18)) * + parseFloat(formatUnits(usersAquaInLending[index]['3'], 18)) ]; }) ); From cf00eabc62e20f2a87089353dc8bacf12c83df3a Mon Sep 17 00:00:00 2001 From: Danny Willis <102543677+dannyposi@users.noreply.github.com> Date: Tue, 1 Nov 2022 14:53:01 +0700 Subject: [PATCH 197/815] [posichain-staking] Add posichain-staking strategy (#925) * Add posichain-staking strategy * Enable posichain-staking strategy * Add more address example * Update author * Add more comment --- src/strategies/index.ts | 2 + .../posichain-staking/examples.json | 18 ++++++++ src/strategies/posichain-staking/index.ts | 41 +++++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 src/strategies/posichain-staking/examples.json create mode 100644 src/strategies/posichain-staking/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index e427bcfbb..13c99bf7b 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -381,6 +381,7 @@ import * as echelonWalletPrimeAndCachedKey from './echelon-wallet-prime-and-cach import * as nation3VotesWIthDelegations from './nation3-votes-with-delegations'; import * as aavegotchiAgip37WapGhst from './aavegotchi-agip-37-wap-ghst'; import * as aavegotchiAgip37GltrStakedLp from './aavegotchi-agip-37-gltr-staked-lp'; +import * as posichainStaking from './posichain-staking'; import * as erc20TokensPerUni from './erc20-tokens-per-uni'; import * as bancorStandardRewardsUnderlyingBalance from './bancor-standard-rewards-underlying-balance'; import * as sdVoteBoost from './sd-vote-boost'; @@ -761,6 +762,7 @@ const strategies = { 'proxyprotocol-erc20-balance-of': proxyProtocolErc20BalanceOf, 'proxyprotocol-erc721-balance-of': proxyProtocolErc721BalanceOf, 'proxyprotocol-erc1155-balance-of': proxyProtocolErc1155BalanceOf, + 'posichain-staking': posichainStaking, 'arrow-vesting': arrowVesting, 'tutellus-protocol': tutellusProtocol, 'fight-club': fightClub, diff --git a/src/strategies/posichain-staking/examples.json b/src/strategies/posichain-staking/examples.json new file mode 100644 index 000000000..33a3de460 --- /dev/null +++ b/src/strategies/posichain-staking/examples.json @@ -0,0 +1,18 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "posichain-staking", + "params": { + "symbol": "POSI" + } + }, + "network": "900000", + "addresses": [ + "0xD3Ee1d798eCea22Fde4D29590eFF0c77bA7e6b9e", + "0xb065c1a5BC1B3c1b1dF8781D369cffc534B65731", + "0x7fd592690ec6A7300289B059ee8711f4f9BBfD8a" + ], + "snapshot": 3989273 + } +] diff --git a/src/strategies/posichain-staking/index.ts b/src/strategies/posichain-staking/index.ts new file mode 100644 index 000000000..7562ebf4b --- /dev/null +++ b/src/strategies/posichain-staking/index.ts @@ -0,0 +1,41 @@ +import { StaticJsonRpcProvider } from '@ethersproject/providers'; +import { formatUnits } from '@ethersproject/units'; +import { BigNumber } from '@ethersproject/bignumber'; + +export const author = 'dannyposi'; +export const version = '0.0.1'; + +type Params = { + symbol: string; + decimals: number; +}; + +export async function strategy( + _space: string, + _network: string, + provider: StaticJsonRpcProvider, + // adding a 0 value for addresses not in the result is not needed + // since they are dropped anyway in utils.ts + // https://github.com/snapshot-labs/snapshot-strategies/blob/02439eb120ed7c4cc0c493924b78d92d22006b40/src/utils.ts#L26 + _addresses: Array, + options: Params, + snapshot: number | string +) { + const blockTag: number | string = + typeof snapshot === 'number' ? snapshot : 'latest'; + const response: Record = await provider.send( + 'hmyv2_getValidatorsStakeByBlockNumber', + [blockTag] + ); + return Object.fromEntries( + Object.entries(response).map(([address, balance]) => [ + address, + parseFloat( + formatUnits( + BigNumber.from('0x' + balance.toString(16)), + options && options.decimals ? options.decimals : 18 + ) + ) + ]) + ); +} From 1ade2a2dd3ca24593aed9a604cb8cca45eff2b5e Mon Sep 17 00:00:00 2001 From: bonustrack Date: Tue, 1 Nov 2022 16:59:15 +0700 Subject: [PATCH 198/815] Add schema for Passport validation --- src/validations/passport/schema.json | 45 ++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 src/validations/passport/schema.json diff --git a/src/validations/passport/schema.json b/src/validations/passport/schema.json new file mode 100644 index 000000000..50b2662c1 --- /dev/null +++ b/src/validations/passport/schema.json @@ -0,0 +1,45 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Validation", + "definitions": { + "Validation": { + "title": "Validation", + "type": "object", + "properties": { + "stamps": { + "type": "array", + "title": "Stamps", + "minItems": 1, + "maxItems": 32, + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "title": "Id" + }, + "weight": { + "type": "number", + "title": "Weight" + } + }, + "required": [ + "id", + "weight" + ], + "additionalProperties": false + } + }, + "min_weight": { + "type": "number", + "title": "Min. weight" + } + }, + "required": [ + "stamps", + "min_weight" + ], + "additionalProperties": false + } + } +} From 4c4e2f1f5246bf9c5a7a561b6d308da4e42a2cb6 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Tue, 1 Nov 2022 16:37:20 +0530 Subject: [PATCH 199/815] Export examples and schema for validations (#926) --- src/validations/index.ts | 43 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/src/validations/index.ts b/src/validations/index.ts index 6fbd4764b..b37697f60 100644 --- a/src/validations/index.ts +++ b/src/validations/index.ts @@ -3,11 +3,52 @@ import aave from './aave'; import nouns from './nouns'; import timeperiod from './timeperiod'; import passport from './passport'; +import { readFileSync } from 'fs'; +import path from 'path'; -export default { +const validations = { basic, aave, nouns, timeperiod, passport }; + +Object.keys(validations).forEach(function (validationName) { + let examples = null; + let schema = null; + let about = ''; + + try { + examples = JSON.parse( + readFileSync( + path.join(__dirname, validationName, 'examples.json'), + 'utf8' + ) + ); + } catch (error) { + examples = null; + } + + try { + schema = JSON.parse( + readFileSync(path.join(__dirname, validationName, 'schema.json'), 'utf8') + ); + } catch (error) { + schema = null; + } + + try { + about = readFileSync( + path.join(__dirname, validationName, 'README.md'), + 'utf8' + ); + } catch (error) { + about = ''; + } + validations[validationName].examples = examples; + validations[validationName].schema = schema; + validations[validationName].about = about; +}); + +export default validations; From f8dae058d40e03b0138925a67d73eb580b76f5fd Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Tue, 1 Nov 2022 17:04:05 +0530 Subject: [PATCH 200/815] Revert "Export examples and schema for validations (#926)" (#927) This reverts commit 4c4e2f1f5246bf9c5a7a561b6d308da4e42a2cb6. --- src/validations/index.ts | 43 +--------------------------------------- 1 file changed, 1 insertion(+), 42 deletions(-) diff --git a/src/validations/index.ts b/src/validations/index.ts index b37697f60..6fbd4764b 100644 --- a/src/validations/index.ts +++ b/src/validations/index.ts @@ -3,52 +3,11 @@ import aave from './aave'; import nouns from './nouns'; import timeperiod from './timeperiod'; import passport from './passport'; -import { readFileSync } from 'fs'; -import path from 'path'; -const validations = { +export default { basic, aave, nouns, timeperiod, passport }; - -Object.keys(validations).forEach(function (validationName) { - let examples = null; - let schema = null; - let about = ''; - - try { - examples = JSON.parse( - readFileSync( - path.join(__dirname, validationName, 'examples.json'), - 'utf8' - ) - ); - } catch (error) { - examples = null; - } - - try { - schema = JSON.parse( - readFileSync(path.join(__dirname, validationName, 'schema.json'), 'utf8') - ); - } catch (error) { - schema = null; - } - - try { - about = readFileSync( - path.join(__dirname, validationName, 'README.md'), - 'utf8' - ); - } catch (error) { - about = ''; - } - validations[validationName].examples = examples; - validations[validationName].schema = schema; - validations[validationName].about = about; -}); - -export default validations; From 5f596a48c1e2dac3068bfb66554cf05e75b29f69 Mon Sep 17 00:00:00 2001 From: gmtesla <50935419+gmtesla@users.noreply.github.com> Date: Tue, 1 Nov 2022 22:09:35 +1000 Subject: [PATCH 201/815] feat: add dsla staking strategy (#928) --- src/strategies/dsla/README.md | 15 +++++++ src/strategies/dsla/examples.json | 37 +++++++++++++++ src/strategies/dsla/index.ts | 75 +++++++++++++++++++++++++++++++ src/strategies/dsla/schema.json | 67 +++++++++++++++++++++++++++ src/strategies/index.ts | 4 +- 5 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 src/strategies/dsla/README.md create mode 100644 src/strategies/dsla/examples.json create mode 100644 src/strategies/dsla/index.ts create mode 100644 src/strategies/dsla/schema.json diff --git a/src/strategies/dsla/README.md b/src/strategies/dsla/README.md new file mode 100644 index 000000000..ec8724192 --- /dev/null +++ b/src/strategies/dsla/README.md @@ -0,0 +1,15 @@ +# dsla + +DSLA's custom snapshot strategy, calculates voting score based of the staked balances of the voters for users/provider pools of Staking SLA. + +Here is an example of parameters: + +```json +{ + "LP_TOKEN": "0xAC104C0438A7bb15C714503537c6FA271FDB284E", + "SP_TOKEN": "0xcf4ea46eba95fe3643b6c954d29516d7376913dc", + "DSLA": "0x3aFfCCa64c2A6f4e3B6Bd9c64CD2C969EFd1ECBe", + "StakingSLA": "0x091ee4d4D8FfD00698c003C21F1ba69EA6310241", + "decimals": 18 +} +``` diff --git a/src/strategies/dsla/examples.json b/src/strategies/dsla/examples.json new file mode 100644 index 000000000..be925545b --- /dev/null +++ b/src/strategies/dsla/examples.json @@ -0,0 +1,37 @@ +[ + { + "name": "Example query of DSLA Staking", + "strategy": { + "name": "dsla", + "params": { + "LP_TOKEN": "0xAC104C0438A7bb15C714503537c6FA271FDB284E", + "SP_TOKEN": "0xcf4ea46eba95fe3643b6c954d29516d7376913dc", + "DSLA": "0x3aFfCCa64c2A6f4e3B6Bd9c64CD2C969EFd1ECBe", + "StakingSLA": "0x091ee4d4D8FfD00698c003C21F1ba69EA6310241", + "decimals": 18 + } + }, + "network": "1", + "addresses": [ + "0x8b0049beb72893c290a026398571a26ea4a03892", + "0x4d5c314adac838d1906992d83894fe47d6931165", + "0xe7a3b897fa52fe3e7f7d0e9803bea00fab78d12f", + "0xb6d568233e81442ded126fad8e8230ed02b6be3e", + "0x5d64d4c35345e9588f3f2233cf6e93978763012c", + "0x9e1b10bf75f339805ed3b266070001100bf87a85", + "0x57a43c9bc2b4d4447bfc1cf4e050bc6dcb72d753", + "0xb44b476a7f6a83b5e0559433b0d3ad374a0c1682", + "0x4baac6507bdcb0c9d059284c539bcf35d433d22e", + "0x66fc061aa4d8d3809876f5a6ddb3506d2d16168f", + "0x443a391e33241798d69295149cdf018e543049ea", + "0x645b28857b19c0046b10caa3bd93fcd31ce15905", + "0x20850bcea7476a0623e276c2cb9ec2e3024dcb0c", + "0xce049d2afc746f96d2ca2b6425efcbf9d44fda2c", + "0x397ef1462cf750ae2e4c387a70474c1f1c5a1637", + "0xb270814532f90969b62b37ccd04dfadfadcd3267", + "0x12b50bdab12a633d992ebfecff6eb9785aa5a09a", + "0x88c0356a46823938bcb233be05d7634aab7f40d9" + ], + "snapshot": 15825878 + } +] diff --git a/src/strategies/dsla/index.ts b/src/strategies/dsla/index.ts new file mode 100644 index 000000000..b4bc72e8f --- /dev/null +++ b/src/strategies/dsla/index.ts @@ -0,0 +1,75 @@ +import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'gmtesla'; +export const version = '0.1.1'; + +// const DSLA = '0x3aFfCCa64c2A6f4e3B6Bd9c64CD2C969EFd1ECBe'; +// const StakingSLA = '0x091ee4d4D8FfD00698c003C21F1ba69EA6310241'; +// const LP_TOKEN = '0xAC104C0438A7bb15C714503537c6FA271FDB284E'; // dpToken +// const SP_TOKEN = '0xcf4ea46eba95fe3643b6c954d29516d7376913dc' // duToken + +const abi = [ + 'function balanceOf(address account) external view returns (uint256)', + 'function totalSupply() external view returns (uint256)', + 'function usersPool(address token) external view returns (uint256)', + 'function providersPool(address token) external view returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + // Get dpToken Balances + const multi = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => + multi.call(address, options.LP_TOKEN, 'balanceOf', [address]) + ); + const dpTokenBalances: Record = await multi.execute(); + + // Get duToken Balances + addresses.forEach((address) => + multi.call(address, options.SP_TOKEN, 'balanceOf', [address]) + ); + const duTokenBalances: Record = await multi.execute(); + + // Get totalSupply of user/provider pools + const multi2 = new Multicaller(network, provider, abi, { blockTag }); + multi2.call('userTotalSupply', options.LP_TOKEN, 'totalSupply', []); + multi2.call('providerTotalSupply', options.SP_TOKEN, 'totalSupply', []); + multi2.call('usersPool', options.StakingSLA, 'usersPool', [options.DSLA]); + multi2.call('providersPool', options.StakingSLA, 'providersPool', [options.DSLA]); + const res2: Record = await multi2.execute(); + + // Sum up duTokenBalance and dpTokenBalances + // dTokenBalance = staked amount * total supply / (userPools or providerPools) + // staked amount = dTokenBalance * (userPools or providerPools) / total supply + const balances = Object.fromEntries( + Object.entries(dpTokenBalances).map(([address, balance]) => [ + address, + BigNumber.from(balance).mul(res2.providersPool).div(res2.providerTotalSupply) + ]) + ); + Object.entries(duTokenBalances).forEach(([address, balance]) => { + const prevBal = BigNumber.from(balances[address]); + balances[address] = prevBal.add( + BigNumber.from(balance).mul(res2.usersPool).div(res2.userTotalSupply) + ); + }) + + const result = Object.fromEntries( + Object.entries(balances).map(([address, balance]) => [ + address, + parseFloat(formatUnits(balance, options.decimals)) + ]) + ); + + return result; +} diff --git a/src/strategies/dsla/schema.json b/src/strategies/dsla/schema.json new file mode 100644 index 000000000..c4de2f966 --- /dev/null +++ b/src/strategies/dsla/schema.json @@ -0,0 +1,67 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "DSLA", + "type": "object", + "properties": { + "LP_TOKEN": { + "type": "string", + "title": "LP_TOKEN", + "examples": [ + "e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984" + ], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "SP_TOKEN": { + "type": "string", + "title": "SP_TOKEN", + "examples": [ + "e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984" + ], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "DSLA": { + "type": "string", + "title": "DSLA", + "examples": [ + "e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984" + ], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "StakingSLA": { + "type": "string", + "title": "StakingSLA", + "examples": [ + "e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984" + ], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": [ + "e.g. 18" + ] + } + }, + "required": [ + "LP_TOKEN", + "SP_TOKEN", + "StakingSLA", + "DSLA", + "decimals" + ], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 13c99bf7b..ec7d28194 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -390,6 +390,7 @@ import * as clqdrBalanceWithLp from './clqdr-balance-with-lp'; import * as ninechroniclesStakedAndDcc from './ninechronicles-staked-and-dcc'; import * as spreadsheet from './spreadsheet'; import * as anchorage from './anchorage'; +import * as dsla from './dsla'; const strategies = { 'forta-shares': fortaShares, @@ -784,7 +785,8 @@ const strategies = { 'clqdr-balance-with-lp': clqdrBalanceWithLp, spreadsheet, anchorage, - 'ninechronicles-staked-and-dcc': ninechroniclesStakedAndDcc + 'ninechronicles-staked-and-dcc': ninechroniclesStakedAndDcc, + dsla }; Object.keys(strategies).forEach(function (strategyName) { From 22a599619325ba947836dffd7d3f3256e69ec5b7 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Wed, 2 Nov 2022 12:42:43 +0530 Subject: [PATCH 202/815] Validation examples and schema (#932) --- src/validations/index.ts | 47 +++++++++++++++++++++++++++++- src/validations/passport/README.md | 1 + 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 src/validations/passport/README.md diff --git a/src/validations/index.ts b/src/validations/index.ts index 6fbd4764b..5f116ea4f 100644 --- a/src/validations/index.ts +++ b/src/validations/index.ts @@ -1,13 +1,58 @@ +import { readFileSync } from 'fs'; +import path from 'path'; import basic from './basic'; import aave from './aave'; import nouns from './nouns'; import timeperiod from './timeperiod'; import passport from './passport'; -export default { +const validationClasses = { basic, aave, nouns, timeperiod, passport }; + +const validations = {}; +Object.keys(validationClasses).forEach(function (validationName) { + let examples = null; + let schema = null; + let about = ''; + + try { + examples = JSON.parse( + readFileSync( + path.join(__dirname, validationName, 'examples.json'), + 'utf8' + ) + ); + } catch (error) { + examples = null; + } + + try { + schema = JSON.parse( + readFileSync(path.join(__dirname, validationName, 'schema.json'), 'utf8') + ); + } catch (error) { + schema = null; + } + + try { + about = readFileSync( + path.join(__dirname, validationName, 'README.md'), + 'utf8' + ); + } catch (error) { + about = ''; + } + validations[validationName] = { + validation: validationClasses[validationName], + examples, + schema, + about + }; +}); + +export default validations; diff --git a/src/validations/passport/README.md b/src/validations/passport/README.md new file mode 100644 index 000000000..8c66ea370 --- /dev/null +++ b/src/validations/passport/README.md @@ -0,0 +1 @@ +# Gitcoin passport validation From f896333fc65e87e873d99bffebbe9f2509c04ae3 Mon Sep 17 00:00:00 2001 From: Julien THOMAS <61523188+julien-devatom@users.noreply.github.com> Date: Wed, 2 Nov 2022 08:43:40 +0100 Subject: [PATCH 203/815] New strategy: linear-vesting-power [linear-vesting-power] (#923) * feat(vesting-power): add new strategy * test(vesting-power): mock date to pass test which are comparing 2 distributions * refactor(vesting-power): run lint * fix(vesting-power): use only cliff duration as params * fix(vesting-power): use of block timestamp instead of `Date` * fix(vesting-power): reduce the number of queries --- .../index.ts | 11 +- src/strategies/index.ts | 2 + .../linear-vesting-power/examples.json | 22 ++++ src/strategies/linear-vesting-power/index.ts | 121 ++++++++++++++++++ 4 files changed, 153 insertions(+), 3 deletions(-) create mode 100644 src/strategies/linear-vesting-power/examples.json create mode 100644 src/strategies/linear-vesting-power/index.ts diff --git a/src/strategies/balance-of-with-linear-vesting-power/index.ts b/src/strategies/balance-of-with-linear-vesting-power/index.ts index a504ec5e0..504eb900b 100644 --- a/src/strategies/balance-of-with-linear-vesting-power/index.ts +++ b/src/strategies/balance-of-with-linear-vesting-power/index.ts @@ -18,10 +18,12 @@ const ERC20abi = [ const vestedAmountPower = ( totalVestedNotClaimed: BigNumberish, startDate: BigNumberish, - period: BigNumberish + period: BigNumberish, + now: BigNumberish ) => { + now = BigNumber.from(now); const amount = BigNumber.from(totalVestedNotClaimed); - const now = BigNumber.from(Math.round(Date.now() / 1000)); + if (now.lte(startDate)) return BigNumber.from(0); if (now.gt(BigNumber.from(startDate).add(period))) return totalVestedNotClaimed; @@ -41,6 +43,8 @@ export async function strategy( ) { const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const block = await provider.getBlock(blockTag); + const now = block.timestamp; // fetch the number of vesting accounts const maxId: BigNumber = await call( provider, @@ -122,7 +126,8 @@ export async function strategy( vestedAmountPower( BigNumber.from(totalVested).sub(totalAccrued), options.startVesting, - options.vestingDuration + options.vestingDuration, + now ) ); return [address, parseFloat(formatUnits(votingPower, options.decimals))]; diff --git a/src/strategies/index.ts b/src/strategies/index.ts index ec7d28194..8b5147a62 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -37,6 +37,7 @@ import * as erc20Price from './erc20-price'; import * as balanceOfWithMin from './balance-of-with-min'; import * as balanceOfWithThresholds from './balance-of-with-thresholds'; import * as balanceOfWithLinearVestingPower from './balance-of-with-linear-vesting-power'; +import * as linearVestingPower from './linear-vesting-power'; import * as thresholds from './thresholds'; import * as ethBalance from './eth-balance'; import * as ethWithBalance from './eth-with-balance'; @@ -739,6 +740,7 @@ const strategies = { 'unipilot-vault-pilot-balance': unipilotVaultPilotBalance, 'solv-voucher-claimable': solvVoucherClaimable, 'balance-of-with-linear-vesting-power': balanceOfWithLinearVestingPower, + 'linear-vesting-power': linearVestingPower, apeswap, h2o, dopamine, diff --git a/src/strategies/linear-vesting-power/examples.json b/src/strategies/linear-vesting-power/examples.json new file mode 100644 index 000000000..243968115 --- /dev/null +++ b/src/strategies/linear-vesting-power/examples.json @@ -0,0 +1,22 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "linear-vesting-power", + "params": { + "DSSVestAddress": "0x6017dd61f4d0C8123f160F99058Adc5671dF6447", + "decimals": 18, + "vestingNetwork": 1, + "cliffDuration": 15768000 + } + }, + "network": "1", + "addresses": [ + "0xd9286ab8Ac06a428Bbb45Bfd785f9A22FD0ef0Bd", + "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", + "0x9B8e8dD9151260c21CB6D7cc59067cd8DF306D58", + "0x38C0039247A31F3939baE65e953612125cB88268" + ], + "snapshot": 15076584 + } +] diff --git a/src/strategies/linear-vesting-power/index.ts b/src/strategies/linear-vesting-power/index.ts new file mode 100644 index 000000000..22dd6780f --- /dev/null +++ b/src/strategies/linear-vesting-power/index.ts @@ -0,0 +1,121 @@ +import { call, Multicaller } from '../../utils'; +import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; + +export const author = 'morpho-labs'; +export const version = '0.1.0'; + +const DSSVestAbi = [ + 'function usr(uint256 _id) external view returns (address)', + 'function tot(uint256 _id) external view returns (uint256)', + 'function accrued(uint256 _id) external view returns (uint256)', + 'function bgn(uint256 _id) external view returns (uint256)', + 'function fin(uint256 _id) external view returns (uint256)', + 'function ids() external view returns (uint256)' +]; + +const vestedAmountPower = ( + totalVestedNotClaimed: BigNumberish, + startDate: BigNumberish, + period: BigNumberish, + now: BigNumberish +) => { + now = BigNumber.from(now); + const amount = BigNumber.from(totalVestedNotClaimed); + if (now.lte(startDate)) return BigNumber.from(0); + if (now.gt(BigNumber.from(startDate).add(period))) + return totalVestedNotClaimed; + return now.sub(startDate).mul(amount).div(period); +}; + +const idsArray = (maxId: number) => + Array.from({ length: maxId }, (_, i) => i + 1); + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const block = await provider.getBlock(blockTag); + const now = block.timestamp; + // fetch the number of vesting accounts + const maxId: BigNumber = await call( + provider, + DSSVestAbi, + [options.DSSVestAddress, 'ids', []], + { + blockTag + } + ); + + // create an array of each vesting ID: [1:maxId] + const ids = idsArray(maxId.toNumber()); + + // And then, we fetch the vesting data for each vesting ID + // 1. vester address + const multiVest = new Multicaller( + options.vestingNetwork, + provider, + DSSVestAbi, + { + blockTag + } + ); + + ids.forEach((id) => multiVest.call(id, options.DSSVestAddress, 'usr', [id])); + const vestedAddresses: Record = await multiVest.execute(); + + // 1. total vested + // 2. total claimed + // 3. beginning time (after cliff period: bgn = startVesting + cliff) + // 4. end time (with cliff period: end = startVesting + cliff + duration = bgn + duration) + + const multiVestCaller = new Multicaller( + options.vestingNetwork, + provider, + DSSVestAbi, + { blockTag } + ); + ids.forEach((id) => { + multiVestCaller.call('tot' + id, options.DSSVestAddress, 'tot', [id]); + multiVestCaller.call('accrued' + id, options.DSSVestAddress, 'accrued', [ + id + ]); + multiVestCaller.call('bgn' + id, options.DSSVestAddress, 'bgn', [id]); + multiVestCaller.call('fin' + id, options.DSSVestAddress, 'fin', [id]); + }); + + const multiVestResult: Record = + await multiVestCaller.execute(); + + return Object.fromEntries( + addresses.map((address) => { + const initialVotingPower = [address, 0]; + // fetch vested users data + const [id] = + Object.entries(vestedAddresses).find( + ([, _address]) => _address === address + ) ?? []; + if (id === undefined) return initialVotingPower; + const totalVested = multiVestResult['tot' + id]; + const totalAccrued = multiVestResult['accrued' + id]; + + const bgn = multiVestResult['bgn' + id]; + const fin = multiVestResult['fin' + id]; + if (!(id && totalAccrued && totalVested && bgn && fin)) + return initialVotingPower; + const votingPower = vestedAmountPower( + BigNumber.from(totalVested).sub(totalAccrued), + BigNumber.from(bgn).sub(options.cliffDuration), + BigNumber.from(fin).sub(bgn).add(options.cliffDuration), + now + ); + return [address, parseFloat(formatUnits(votingPower, options.decimals))]; + }) + ); +} From db0541418ce27884ffa0cf3318ab8d4032be5a28 Mon Sep 17 00:00:00 2001 From: Jashan Shetty <43118727+eth-jashan@users.noreply.github.com> Date: Wed, 2 Nov 2022 13:37:02 +0530 Subject: [PATCH 204/815] Add strategy [rep3-badges] (#930) * rep3 strategy setup * Update README.md * ERC20 condition update * subgraph call change * Update scores.ts --- src/strategies/index.ts | 4 +- src/strategies/rep3-badges/README.md | 52 ++++++ src/strategies/rep3-badges/examples.json | 105 +++++++++++ src/strategies/rep3-badges/index.ts | 222 +++++++++++++++++++++++ 4 files changed, 382 insertions(+), 1 deletion(-) create mode 100644 src/strategies/rep3-badges/README.md create mode 100644 src/strategies/rep3-badges/examples.json create mode 100644 src/strategies/rep3-badges/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 8b5147a62..f0a989fca 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -392,6 +392,7 @@ import * as ninechroniclesStakedAndDcc from './ninechronicles-staked-and-dcc'; import * as spreadsheet from './spreadsheet'; import * as anchorage from './anchorage'; import * as dsla from './dsla'; +import * as rep3Badges from './rep3-badges'; const strategies = { 'forta-shares': fortaShares, @@ -788,7 +789,8 @@ const strategies = { spreadsheet, anchorage, 'ninechronicles-staked-and-dcc': ninechroniclesStakedAndDcc, - dsla + dsla, + 'rep3-badges': rep3Badges }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/rep3-badges/README.md b/src/strategies/rep3-badges/README.md new file mode 100644 index 000000000..2924af733 --- /dev/null +++ b/src/strategies/rep3-badges/README.md @@ -0,0 +1,52 @@ +# REP3 Badges + +The Proof of Contribution Protocol (or PoCP) is the beta version of rep3's credentialing protocol. The rep3 DAO tool (live at https://app.rep3.gg/) is one possible implementation of the protocol to facilitate better member and contribution management for DAOs. + +Using the protocol, DAOs can give various types of badges to their members. These badges are organised in a parent-child relationship -- first, all members receive a membership badge (which is the parent badge), and then members can receive contribution badges (representing their work) or any other type of badge as designed by the community (for example, one-off badges to acknowledge exemplary work). The contribution badges and the custom badges are children to the membership badge. + +This architecture lets communities track and visualise their member activity and, on the other hand, lets community members build their portfolio of work through on-chain credentials. These naturally have a higher signalling value than more traditional types of portfolios like resumés. + +Badges given through the rep3 platform are also fully interoperable with several web3 tools, especially those that are used for gating resources behind a token. These badges, at a contract level, are custom implmentations of ERC-721 tokens. This is a deliberate decision to balance the trade-off between maintaining the integrity of these badges (w.r.t. the work they represent) and permitting key rotation by users. + +The rest of this document details the technical specifications and integration process of our protocol. Please note that this document might be confusing to understand or even have some outdated parts. We are in the process of updating these as we begin to focus on protocol-level integrations in addition to focussing on tool adoption. + +As always, do not hesitate at all to reach out to any team member in case you have a question. We usually reply within 12h and will be more than happy to address any questions you may have. + +Have a great day ahead! + +```json +{ + "symbol": "REP-3", + "rep3ContractAddress": "0x959a3e7e2ea1ea56c9127ae9ed271ede495d145f", + "erc20Token": "0x6b175474e89094c44da98b954eedeac495271d0f", + "erc20Symbol": "DAI", + "erc20Decimal": 18, + "subgraphNetwork": 80001, + "specs": [ + { + "type": 0, + "level": 1, + "weight": 5 + }, + { + "type": 0, + "level": 2, + "weight": 10 + }, + { + "type": 0, + "level": 3, + "weight": 15 + }, + { + "type": 0, + "level": 4, + "weight": 20 + }, + { + "type": 1, + "weight": 2 + } + ] +} +``` diff --git a/src/strategies/rep3-badges/examples.json b/src/strategies/rep3-badges/examples.json new file mode 100644 index 000000000..bda5d22fd --- /dev/null +++ b/src/strategies/rep3-badges/examples.json @@ -0,0 +1,105 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "rep3-badges", + "params": { + "symbol": "REP-3", + "rep3ContractAddress": "0x959a3e7e2ea1ea56c9127ae9ed271ede495d145f", + "erc20Token": "0x6b175474e89094c44da98b954eedeac495271d0f", + "erc20Symbol": "DAI", + "erc20Decimal": 18, + "subgraphNetwork": 80001, + "specs": [ + { + "type": 0, + "level": 1, + "weight": 5 + }, + { + "type": 0, + "level": 2, + "weight": 10 + }, + { + "type": 0, + "level": 3, + "weight": 15 + }, + { + "type": 0, + "level": 4, + "weight": 20 + }, + { + "type": 1, + "weight": 2 + } + ] + } + }, + "network": "1", + "addresses": [ + "0x565CBd65Cb3e65445AfD14169003A528C985e9C7", + "0xD1fe5790AD50C9E8d2e9F03f4f42A09a9F59dec3", + "0x56d0b5ed3d525332f00c9bc938f93598ab16aaa7", + "0x49e4dbff86a2e5da27c540c9a9e8d2c3726e278f", + "0x4757ce43dc5429b8f1a132dc29ef970e55ae722b", + "0xd7539FCdC0aB79a7B688b04387cb128E75cb77Dc", + "0x6E33e22f7aC5A4b58A93C7f6D8Da8b46c50A3E20", + "0xC9dA7343583fA8Bb380A6F04A208C612F86C7701", + "0x2AC89522CB415AC333E64F52a1a5693218cEBD58" + ], + "snapshot": 15874502 + }, + { + "name": "Example query", + "strategy": { + "name": "rep3-badges", + "params": { + "symbol": "REP-3", + "rep3ContractAddress": "0x959a3e7e2ea1ea56c9127ae9ed271ede495d145f", + "subgraphNetwork": 80001, + "specs": [ + { + "type": 0, + "level": 1, + "weight": 5 + }, + { + "type": 0, + "level": 2, + "weight": 10 + }, + { + "type": 0, + "level": 3, + "weight": 15 + }, + { + "type": 0, + "level": 4, + "weight": 20 + }, + { + "type": 1, + "weight": 2 + } + ] + } + }, + "network": "1", + "addresses": [ + "0x565CBd65Cb3e65445AfD14169003A528C985e9C7", + "0xD1fe5790AD50C9E8d2e9F03f4f42A09a9F59dec3", + "0x56d0b5ed3d525332f00c9bc938f93598ab16aaa7", + "0x49e4dbff86a2e5da27c540c9a9e8d2c3726e278f", + "0x4757ce43dc5429b8f1a132dc29ef970e55ae722b", + "0xd7539FCdC0aB79a7B688b04387cb128E75cb77Dc", + "0x6E33e22f7aC5A4b58A93C7f6D8Da8b46c50A3E20", + "0xC9dA7343583fA8Bb380A6F04A208C612F86C7701", + "0x2AC89522CB415AC333E64F52a1a5693218cEBD58" + ], + "snapshot": 15864502 + } +] diff --git a/src/strategies/rep3-badges/index.ts b/src/strategies/rep3-badges/index.ts new file mode 100644 index 000000000..b36ed2d28 --- /dev/null +++ b/src/strategies/rep3-badges/index.ts @@ -0,0 +1,222 @@ +import { error } from 'console'; +import { subgraphRequest } from '../../utils'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; +import { getAddress } from '@ethersproject/address'; + +export const author = 'eth-jashan'; +export const version = '1.0.0'; + +const REP3_SUBGRAPH_API_URLS_BY_CHAIN_ID = { + '80001': 'https://api.thegraph.com/subgraphs/name/eth-jashan/rep3-mumbai', + '137': 'https://api.thegraph.com/subgraphs/name/eth-jashan/rep3-matic' +}; + +const abi = [ + 'function balanceOf(address account) external view returns (uint256)' +]; + +// subgraph helper function to get Membership Badges +function fetchMembershipsForAddress( + network: string, + contractAddress: string, + + blockTag: number | string +): Promise { + const url = REP3_SUBGRAPH_API_URLS_BY_CHAIN_ID[network]; + + if (url == undefined) { + throw new error(`Unsupported network with id: ${network}`); + } + + const query = { + membershipNFTs: { + __args: { + where: { + contractAddress: contractAddress + }, + block: blockTag != 'latest' ? { number: blockTag } : null + }, + time: true, + level: true, + tokenID: true, + claimer: true + } + }; + + return subgraphRequest(url, query); +} + +// subgraph helper function to get Association Badges + +function fetchAssociationBadgesForAddress( + network: string, + contractAddress: string, + blockTag: number | string +): Promise { + const url = REP3_SUBGRAPH_API_URLS_BY_CHAIN_ID[network]; + + if (url == undefined) { + throw new error(`Unsupported network with id: ${network}`); + } + + const query = { + associationBadges: { + __args: { + where: { + contractAddress: contractAddress + }, + block: blockTag != 'latest' ? { number: blockTag } : null + }, + type: true, + tokenID: true, + claimer: true + } + }; + + return subgraphRequest(url, query); +} + +// Combining ERC20 Balances and Weights from Rep3 Badges + +function applyBadgeWeights(badges: any[], erc20Balance: any, options: any) { + const badgeWeights = {}; + badges.forEach((badge: any) => { + if (badge?.level) { + const levelWeight = options.specs.find( + (spec) => spec.level === parseInt(badge?.level) + ); + if (badgeWeights[getAddress(badge.claimer)]) { + badgeWeights[getAddress(badge.claimer)] = + badgeWeights[getAddress(badge.claimer)] + levelWeight.weight; + } else { + badgeWeights[getAddress(badge.claimer)] = levelWeight.weight; + } + } else if (badge?.type) { + const levelWeight = options.specs.find( + (spec) => spec.type === parseInt(badge?.type) + ); + if (badgeWeights[getAddress(badge.claimer)]) { + badgeWeights[getAddress(badge.claimer)] = + badgeWeights[getAddress(badge.claimer)] + levelWeight.weight; + } else { + badgeWeights[getAddress(badge.claimer)] = levelWeight.weight; + } + } + }); + if (options?.erc20Token) { + Object.keys(erc20Balance).forEach((key) => { + if (badgeWeights[key]) { + if (erc20Balance[key]) { + erc20Balance[key] = erc20Balance[key] * badgeWeights[key]; + } else { + erc20Balance[key] = badgeWeights[key]; + } + } + }); + } + + return options?.erc20Token ? erc20Balance : badgeWeights; +} + +// helper function to get ERC20 balances for addresses +async function getErc20Balance( + network, + provider, + abi, + blockTag, + addresses, + options +): Promise { + if (options.erc20Token) { + const multi = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => + multi.call(address, options.erc20Token, 'balanceOf', [address]) + ); + try { + const result: any = await multi.execute(); + Object.keys(result).forEach((key) => { + result[key] = parseFloat( + formatUnits(result[key], options.erc20Decimal) + ); + }); + + return result; + } catch (error: any) { + return {}; + } + } else { + return {}; + } +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const erc20BalanceOf: any = await getErc20Balance( + network, + provider, + abi, + blockTag, + addresses, + options + ); + + let associationBadges: any[] = []; + + const allMembershipbadges = await fetchMembershipsForAddress( + options.subgraphNetwork, + options.rep3ContractAddress, + 'latest' + ); + const allAssociationBadges = await fetchAssociationBadgesForAddress( + options.subgraphNetwork, + options.rep3ContractAddress, + + 'latest' + ); + + const validMembershipNft: any[] = addresses.map((address: string) => { + const membershipNftForAddress = allMembershipbadges.membershipNFTs.filter( + (x) => getAddress(x.claimer) === address + ); + const associationBadgeForAddress = + allAssociationBadges.associationBadges.filter( + (x) => getAddress(x.claimer) === address + ); + if (associationBadgeForAddress.length > 0) { + associationBadges = associationBadges.concat(associationBadgeForAddress); + } + if (membershipNftForAddress.length > 1) { + const latestMembership = allMembershipbadges.membershipNFTs.sort( + (p1, p2) => (p1.time < p2.time ? 1 : p1.time > p2.time ? -1 : 0) + ); + return latestMembership[0]; + } else if (membershipNftForAddress.length === 1) { + return membershipNftForAddress[0]; + } + }); + + let allWeightableBadges = validMembershipNft.concat(associationBadges); + allWeightableBadges = allWeightableBadges.filter((x) => x !== undefined); + let badgeWeights = {}; + if (!allWeightableBadges) return badgeWeights; + + badgeWeights = applyBadgeWeights( + allWeightableBadges, + erc20BalanceOf, + options + ); + + return Object.fromEntries( + addresses.map((address: string) => [address, badgeWeights[address] || 0]) + ); +} From 0684517b86dbde43ccc831a8e33664857d29fe42 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 2 Nov 2022 17:15:33 +0530 Subject: [PATCH 205/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.47 (#933) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 9224c1d11..a963e3080 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.46", + "@snapshot-labs/snapshot.js": "^0.4.47", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index b99781f4a..a015f7772 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.46": - version "0.4.46" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.46.tgz#33d4e2e2212441ee9fee40b18cd1e7db587c7a4a" - integrity sha512-/1klfof9/mS5GGxgI+fh8mgGCdGeD9h4krFsjK/Y1YFTRvKPAIjoZW22PbVmHeXH1FWkoqc2vIh6mzQygKNq2Q== +"@snapshot-labs/snapshot.js@^0.4.47": + version "0.4.47" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.47.tgz#1b2e806bc26a71c4dc540f43b5bdf5d4d63488b7" + integrity sha512-f/zwBqZkeaF/YTt2Z/AtP9mRi7gT97vHFL8gVbIFLmpBTfGJ5N7DX6RFNjN0eY4/9VJJ1KFN0sq0fc0v3lCztw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From ca8ff80f8091576aa084696af7433f523f6dd71f Mon Sep 17 00:00:00 2001 From: Mateo Daza Date: Wed, 2 Nov 2022 12:40:50 -0500 Subject: [PATCH 206/815] Giveth xDAI / Gnosis strategy update [giveth-gnosis-balance-v2] (#931) * Updates subgraph to new version - considering GIVpower * makes a new strategy for giveth gnosis v2 * updates snapshot number * Update src/strategies/giveth-gnosis-balance-v2/index.ts Co-authored-by: Chaitanya --- .../giveth-gnosis-balance-v2/README.md | 12 +++ .../giveth-gnosis-balance-v2/examples.json | 19 ++++ .../giveth-gnosis-balance-v2/index.ts | 87 +++++++++++++++++++ src/strategies/index.ts | 2 + 4 files changed, 120 insertions(+) create mode 100644 src/strategies/giveth-gnosis-balance-v2/README.md create mode 100644 src/strategies/giveth-gnosis-balance-v2/examples.json create mode 100644 src/strategies/giveth-gnosis-balance-v2/index.ts diff --git a/src/strategies/giveth-gnosis-balance-v2/README.md b/src/strategies/giveth-gnosis-balance-v2/README.md new file mode 100644 index 000000000..34bbc6264 --- /dev/null +++ b/src/strategies/giveth-gnosis-balance-v2/README.md @@ -0,0 +1,12 @@ +# Giveth Gnosis balance + +This strategy sums up all the GIV on xDai, including the ones that are staked in Honeyswap pools, Sushiswap pools, and single staked on GIV pool. This version considers GIVpower + +Here is an example of parameters: + +```json +{ + "symbol": "GIV", + "decimals": 18 +} +``` diff --git a/src/strategies/giveth-gnosis-balance-v2/examples.json b/src/strategies/giveth-gnosis-balance-v2/examples.json new file mode 100644 index 000000000..ce772e79e --- /dev/null +++ b/src/strategies/giveth-gnosis-balance-v2/examples.json @@ -0,0 +1,19 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "giveth-gnosis-balance-v2", + "params": { + "symbol": "GIV", + "decimals": 18 + } + }, + "network": "100", + "addresses": [ + "0x839395e20bbb182fa440d08f850e6c7a8f6f0780", + "0x960a16c9070a9bbbb03e1bfd418982636d56d77d", + "0x00d18ca9782be1caef611017c2fbc1a39779a57c" + ], + "snapshot": 24831608 + } +] diff --git a/src/strategies/giveth-gnosis-balance-v2/index.ts b/src/strategies/giveth-gnosis-balance-v2/index.ts new file mode 100644 index 000000000..ca3efc5c3 --- /dev/null +++ b/src/strategies/giveth-gnosis-balance-v2/index.ts @@ -0,0 +1,87 @@ +import { subgraphRequest } from '../../utils'; +import { getAddress } from '@ethersproject/address'; +import { formatUnits } from '@ethersproject/units'; + +export const author = 'mateodaza'; +export const version = '0.1.0'; + +const GIVETH_SUBGRAPH_API = + 'https://api.thegraph.com/subgraphs/name/giveth/giveth-economy-second-xdai'; +const XDAI_BLOCKS_API = + 'https://api.thegraph.com/subgraphs/name/elkfinance/xdai-blocks'; + +const blockParams = { + blocks: { + __args: { + first: 1, + orderBy: 'timestamp', + orderDirection: 'desc', + where: { + timestamp_lte: '' + } + }, + number: true + } +}; + +const pairParams = { + pair: { + __args: { + id: '' + }, + reserve0: true, + totalSupply: true + } +}; + +const params = { + tokenBalances: { + __args: { + orderBy: 'id', + orderDirection: 'asc', + where: { + user_in: [] + } + }, + id: true, + balance: true, + token: true + } +}; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const block = await provider.getBlock(blockTag); + blockParams.blocks.__args.where.timestamp_lte = block.timestamp; + const xDaiBlock = await subgraphRequest(XDAI_BLOCKS_API, blockParams); + const blockNumber = Number(xDaiBlock.blocks[0].number); + // @ts-ignore + params.tokenBalances.__args.block = { number: blockNumber }; + if (snapshot !== 'latest') { + // @ts-ignore + pairParams.pair.__args.block = { number: blockNumber }; + } + + params.tokenBalances.__args.where.user_in = addresses.map((address) => + address.toLowerCase() + ); + + const data = await subgraphRequest(GIVETH_SUBGRAPH_API, params); + + const score = {}; + data.tokenBalances.map((addressBalance) => { + const id = addressBalance.id.split('-')[1]; + const prevScore = score[getAddress(id)] ? score[getAddress(id)] : 0; + score[getAddress(id)] = + prevScore + + parseFloat(formatUnits(addressBalance.balance, options.decimals)); + }); + return score; +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index f0a989fca..7aaf84c06 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -280,6 +280,7 @@ import * as balancerPoolid from './balancer-poolid'; import * as stakedBalancer from './staked-balancer'; import * as stakedUniswapModifiable from './staked-uniswap-modifiable'; import * as givethXdaiBalance from './giveth-xdai-balance'; +import * as givethGnosisBalanceV2 from './giveth-gnosis-balance-v2'; import * as givethBalancerBalance from './giveth-balancer-balance'; import * as erc1155BalanceOfIds from './erc1155-balance-of-ids'; import * as erc1155BalanceOfIdsWeighted from './erc1155-balance-of-ids-weighted'; @@ -401,6 +402,7 @@ const strategies = { 'landdao-token-tiers': landDaoTiers, 'giveth-balancer-balance': givethBalancerBalance, 'giveth-xdai-balance': givethXdaiBalance, + 'giveth-gnosis-balance-v2': givethGnosisBalanceV2, 'nouns-rfp-power': nounsPower, coordinape, 'anti-whale': antiWhale, From 9ef8b8f55e74eedb58dc6b84a6d51d9ace800e68 Mon Sep 17 00:00:00 2001 From: rsquare Date: Wed, 2 Nov 2022 18:48:23 +0100 Subject: [PATCH 207/815] Otterspace: Using updated graph model [otterspace-badges] (#896) * Using updated graph model * Added active badge logic --- src/strategies/otterspace-badges/examples.json | 10 ++++++++-- src/strategies/otterspace-badges/index.ts | 9 ++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/strategies/otterspace-badges/examples.json b/src/strategies/otterspace-badges/examples.json index df3be78f7..4d73e27f2 100644 --- a/src/strategies/otterspace-badges/examples.json +++ b/src/strategies/otterspace-badges/examples.json @@ -14,6 +14,10 @@ { "id": "bafyreihj2e3mxqwk24auglrfckk3eh2hzsq7eyghjpcprmopvok5wxz3bu", "weight": 10 + }, + { + "id": "bafyreiavo63i7sgb5dvjcj6nxfwkxd7thq37jj43l6f4mkorgdogqj2nni", + "weight": 7 } ] } @@ -22,7 +26,8 @@ "addresses": [ "0xbb9ecfd5685502977b5b7c1ac0cdff8c136a4da8", "0x33d0bbd05cf3c7e040d33bc1f338585a087e5dd9", - "0x0F1c502d4EF5b1940a7A77062e51353D8B366547" + "0x0F1c502d4EF5b1940a7A77062e51353D8B366547", + "0xeade2ceedea3b8d0d1d10537f507b9d262870748" ], "snapshot": 7509588 }, @@ -40,7 +45,8 @@ "addresses": [ "0xbb9ecfd5685502977b5b7c1ac0cdff8c136a4da8", "0x33d0bbd05cf3c7e040d33bc1f338585a087e5dd9", - "0x0F1c502d4EF5b1940a7A77062e51353D8B366547" + "0x0F1c502d4EF5b1940a7A77062e51353D8B366547", + "0xeade2ceedea3b8d0d1d10537f507b9d262870748" ], "snapshot": 7509588 }, diff --git a/src/strategies/otterspace-badges/index.ts b/src/strategies/otterspace-badges/index.ts index 1ba8314a5..731a97b41 100644 --- a/src/strategies/otterspace-badges/index.ts +++ b/src/strategies/otterspace-badges/index.ts @@ -52,7 +52,8 @@ function getBadgeWeight(specs: any[], badgeSpecID: string): number { if (specs && specs.length > 0) { const specConfig = specs.find((spec: any) => spec.id === badgeSpecID); badgeWeight = - specConfig && !isBadgeExpired(specConfig.expiresAt) + specConfig && + isBadgeActive(specConfig.status, specConfig.metadata?.expiresAt || null) ? specConfig.weight : 0; } else { @@ -62,8 +63,10 @@ function getBadgeWeight(specs: any[], badgeSpecID: string): number { return badgeWeight; } -function isBadgeExpired(expiresAt: string | null): boolean { - return expiresAt ? Date.now() - Number(new Date(expiresAt)) > 0 : false; +function isBadgeActive(status: string, expiresAt: string | null): boolean { + return !['REVOKED', 'BURNED'].includes(status) && expiresAt + ? Date.now() - Number(new Date(expiresAt)) <= 0 + : true; } function applyBadgeWeights(badges: [], options: any) { From 04683b32f6d902bca00096261117dc4e70e3438f Mon Sep 17 00:00:00 2001 From: gmtesla <50935419+gmtesla@users.noreply.github.com> Date: Thu, 3 Nov 2022 03:53:49 +1000 Subject: [PATCH 208/815] [dsla-parametric-staking-service-credits] Change Strategy Name: dsla -> dsla-parametric-staking-service-credits (#934) * feat: add dsla staking strategy * feat: rename dsla strategy to dsla-parametric-staking-service-credits * fix: lint * Delete src/strategies/dsla directory Co-authored-by: Chaitanya --- .../README.md | 0 .../examples.json | 6 +++--- .../index.ts | 18 +++++++++++------- .../schema.json | 12 ++++++------ src/strategies/index.ts | 5 +++-- 5 files changed, 23 insertions(+), 18 deletions(-) rename src/strategies/{dsla => dsla-parametric-staking-service-credits}/README.md (100%) rename src/strategies/{dsla => dsla-parametric-staking-service-credits}/examples.json (87%) rename src/strategies/{dsla => dsla-parametric-staking-service-credits}/index.ts (86%) rename src/strategies/{dsla => dsla-parametric-staking-service-credits}/schema.json (91%) diff --git a/src/strategies/dsla/README.md b/src/strategies/dsla-parametric-staking-service-credits/README.md similarity index 100% rename from src/strategies/dsla/README.md rename to src/strategies/dsla-parametric-staking-service-credits/README.md diff --git a/src/strategies/dsla/examples.json b/src/strategies/dsla-parametric-staking-service-credits/examples.json similarity index 87% rename from src/strategies/dsla/examples.json rename to src/strategies/dsla-parametric-staking-service-credits/examples.json index be925545b..bdf267123 100644 --- a/src/strategies/dsla/examples.json +++ b/src/strategies/dsla-parametric-staking-service-credits/examples.json @@ -2,10 +2,10 @@ { "name": "Example query of DSLA Staking", "strategy": { - "name": "dsla", + "name": "dsla-parametric-staking-service-credits", "params": { - "LP_TOKEN": "0xAC104C0438A7bb15C714503537c6FA271FDB284E", - "SP_TOKEN": "0xcf4ea46eba95fe3643b6c954d29516d7376913dc", + "xDSLA": "0xcf4ea46eba95fe3643b6c954d29516d7376913dc", + "xDSLA_LP": "0xAC104C0438A7bb15C714503537c6FA271FDB284E", "DSLA": "0x3aFfCCa64c2A6f4e3B6Bd9c64CD2C969EFd1ECBe", "StakingSLA": "0x091ee4d4D8FfD00698c003C21F1ba69EA6310241", "decimals": 18 diff --git a/src/strategies/dsla/index.ts b/src/strategies/dsla-parametric-staking-service-credits/index.ts similarity index 86% rename from src/strategies/dsla/index.ts rename to src/strategies/dsla-parametric-staking-service-credits/index.ts index b4bc72e8f..4e768ea62 100644 --- a/src/strategies/dsla/index.ts +++ b/src/strategies/dsla-parametric-staking-service-credits/index.ts @@ -30,22 +30,24 @@ export async function strategy( // Get dpToken Balances const multi = new Multicaller(network, provider, abi, { blockTag }); addresses.forEach((address) => - multi.call(address, options.LP_TOKEN, 'balanceOf', [address]) + multi.call(address, options.xDSLA_LP, 'balanceOf', [address]) ); const dpTokenBalances: Record = await multi.execute(); // Get duToken Balances addresses.forEach((address) => - multi.call(address, options.SP_TOKEN, 'balanceOf', [address]) + multi.call(address, options.xDSLA, 'balanceOf', [address]) ); const duTokenBalances: Record = await multi.execute(); // Get totalSupply of user/provider pools const multi2 = new Multicaller(network, provider, abi, { blockTag }); - multi2.call('userTotalSupply', options.LP_TOKEN, 'totalSupply', []); - multi2.call('providerTotalSupply', options.SP_TOKEN, 'totalSupply', []); + multi2.call('userTotalSupply', options.xDSLA, 'totalSupply', []); + multi2.call('providerTotalSupply', options.xDSLA_LP, 'totalSupply', []); multi2.call('usersPool', options.StakingSLA, 'usersPool', [options.DSLA]); - multi2.call('providersPool', options.StakingSLA, 'providersPool', [options.DSLA]); + multi2.call('providersPool', options.StakingSLA, 'providersPool', [ + options.DSLA + ]); const res2: Record = await multi2.execute(); // Sum up duTokenBalance and dpTokenBalances @@ -54,7 +56,9 @@ export async function strategy( const balances = Object.fromEntries( Object.entries(dpTokenBalances).map(([address, balance]) => [ address, - BigNumber.from(balance).mul(res2.providersPool).div(res2.providerTotalSupply) + BigNumber.from(balance) + .mul(res2.providersPool) + .div(res2.providerTotalSupply) ]) ); Object.entries(duTokenBalances).forEach(([address, balance]) => { @@ -62,7 +66,7 @@ export async function strategy( balances[address] = prevBal.add( BigNumber.from(balance).mul(res2.usersPool).div(res2.userTotalSupply) ); - }) + }); const result = Object.fromEntries( Object.entries(balances).map(([address, balance]) => [ diff --git a/src/strategies/dsla/schema.json b/src/strategies/dsla-parametric-staking-service-credits/schema.json similarity index 91% rename from src/strategies/dsla/schema.json rename to src/strategies/dsla-parametric-staking-service-credits/schema.json index c4de2f966..b8ae01f9e 100644 --- a/src/strategies/dsla/schema.json +++ b/src/strategies/dsla-parametric-staking-service-credits/schema.json @@ -6,9 +6,9 @@ "title": "DSLA", "type": "object", "properties": { - "LP_TOKEN": { + "xDSLA": { "type": "string", - "title": "LP_TOKEN", + "title": "xDSLA", "examples": [ "e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984" ], @@ -16,9 +16,9 @@ "minLength": 42, "maxLength": 42 }, - "SP_TOKEN": { + "xDSLA_LP": { "type": "string", - "title": "SP_TOKEN", + "title": "xDSLA_LP", "examples": [ "e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984" ], @@ -55,8 +55,8 @@ } }, "required": [ - "LP_TOKEN", - "SP_TOKEN", + "xDSLA", + "xDSLA_LP", "StakingSLA", "DSLA", "decimals" diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 7aaf84c06..e62cefbf4 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -392,7 +392,7 @@ import * as clqdrBalanceWithLp from './clqdr-balance-with-lp'; import * as ninechroniclesStakedAndDcc from './ninechronicles-staked-and-dcc'; import * as spreadsheet from './spreadsheet'; import * as anchorage from './anchorage'; -import * as dsla from './dsla'; +import * as dslaParametricStakingServiceCredits from './dsla-parametric-staking-service-credits'; import * as rep3Badges from './rep3-badges'; const strategies = { @@ -791,7 +791,8 @@ const strategies = { spreadsheet, anchorage, 'ninechronicles-staked-and-dcc': ninechroniclesStakedAndDcc, - dsla, + 'dsla-parametric-staking-service-credits': + dslaParametricStakingServiceCredits, 'rep3-badges': rep3Badges }; From 7bcc60ea61e64f888b27cd9f29ae311a76bd20de Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Thu, 3 Nov 2022 13:30:14 +0530 Subject: [PATCH 209/815] [offchain-delegation] new strategy rename (#935) * [offchain-delegation] new strategy rename * Fixes * Fixes * Change addresses * Fixes * Fix for test cases --- src/strategies/anchorage/README.md | 3 -- src/strategies/anchorage/examples.json | 26 ------------- src/strategies/index.ts | 4 +- src/strategies/offchain-delegation/README.md | 37 +++++++++++++++++++ .../offchain-delegation/examples.json | 33 +++++++++++++++++ .../index.ts | 11 +++--- 6 files changed, 78 insertions(+), 36 deletions(-) delete mode 100644 src/strategies/anchorage/README.md delete mode 100644 src/strategies/anchorage/examples.json create mode 100644 src/strategies/offchain-delegation/README.md create mode 100644 src/strategies/offchain-delegation/examples.json rename src/strategies/{anchorage => offchain-delegation}/index.ts (87%) diff --git a/src/strategies/anchorage/README.md b/src/strategies/anchorage/README.md deleted file mode 100644 index c33a04bf3..000000000 --- a/src/strategies/anchorage/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Anchorage delegation - -This strategy is managed by Anchorage team to handle delegations. diff --git a/src/strategies/anchorage/examples.json b/src/strategies/anchorage/examples.json deleted file mode 100644 index 9cfdf6210..000000000 --- a/src/strategies/anchorage/examples.json +++ /dev/null @@ -1,26 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "anchorage", - "params": { - "symbol": "DAI (anchorage)", - "strategies": [ - { - "name": "erc20-balance-of", - "params": { - "address": "0x6B175474E89094C44Da98b954EedeAC495271d0F", - "decimals": 18 - } - } - ] - } - }, - "network": "1", - "addresses": [ - "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", - "0x4C7909d6F029b3a5798143C843F4f8e5341a3473" - ], - "snapshot": 15820600 - } -] diff --git a/src/strategies/index.ts b/src/strategies/index.ts index e62cefbf4..5f18f007b 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -391,7 +391,7 @@ import * as sdVoteBoostTWAVP from './sd-vote-boost-twavp'; import * as clqdrBalanceWithLp from './clqdr-balance-with-lp'; import * as ninechroniclesStakedAndDcc from './ninechronicles-staked-and-dcc'; import * as spreadsheet from './spreadsheet'; -import * as anchorage from './anchorage'; +import * as offchainDelegation from './offchain-delegation'; import * as dslaParametricStakingServiceCredits from './dsla-parametric-staking-service-credits'; import * as rep3Badges from './rep3-badges'; @@ -789,7 +789,7 @@ const strategies = { 'sd-vote-boost-twavp': sdVoteBoostTWAVP, 'clqdr-balance-with-lp': clqdrBalanceWithLp, spreadsheet, - anchorage, + 'offchain-delegation': offchainDelegation, 'ninechronicles-staked-and-dcc': ninechroniclesStakedAndDcc, 'dsla-parametric-staking-service-credits': dslaParametricStakingServiceCredits, diff --git a/src/strategies/offchain-delegation/README.md b/src/strategies/offchain-delegation/README.md new file mode 100644 index 000000000..e86a43634 --- /dev/null +++ b/src/strategies/offchain-delegation/README.md @@ -0,0 +1,37 @@ +# Offchain delegation + +This strategy is used to handle offchain delegations. + +## Getting started +- Check the template here: https://docs.google.com/spreadsheets/d/1IQDXROyxavyZ03ZtNW-2uuDjcI_oME-OmY1VFPTAO-M/edit?usp=sharing +- Select: File > Make a copy +- On the newly created file select: File > Share > Publish to web +- On the modal "Publish to web" click "Publish" button +- Copy the long id within the URL and use it as "sheetId" parameter for the strategy +- And use the id after "pub?gid=" as "gid" parameter +- You are ready! + + +## Parameters +- `sheetId`: The id of the spreadsheet +- `gid`: The id of the sheet +- `strategies`: The strategies to use, to calculate the score of the delegations +- `delegationSpace`: The space to use for the delegations (Optional, default: space of the proposal) + +Here is an example of the strategy parameters: + +```json +{ + "sheetId": "2PACX-1vTAo2yFq6GyBZcB3BOnIw_Rzub7KEEzqhhgFY5CD6eCW-Rfx9d4NaMJP8IP67G9YnV3PNPHKvgJeSNY", + "gid": "1557274211", + "strategies": [ + { + "name": "erc20-balance-of", + "params": { + "address": "0x6B175474E89094C44Da98b954EedeAC495271d0F", + "decimals": 18 + } + } + ] +} +``` diff --git a/src/strategies/offchain-delegation/examples.json b/src/strategies/offchain-delegation/examples.json new file mode 100644 index 000000000..d2a7dcb68 --- /dev/null +++ b/src/strategies/offchain-delegation/examples.json @@ -0,0 +1,33 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "offchain-delegation", + "params": { + "symbol": "DAI DELEGATEDW", + "sheetId": "2PACX-1vTAo2yFq6GyBZcB3BOnIw_Rzub7KEEzqhhgFY5CD6eCW-Rfx9d4NaMJP8IP67G9YnV3PNPHKvgJeSNY", + "gid": "1557274211", + "delegationSpace": "test7.shot.eth", + "strategies": [ + { + "name": "erc20-balance-of", + "params": { + "address": "0x6B175474E89094C44Da98b954EedeAC495271d0F", + "decimals": 18 + } + } + ] + } + }, + "network": "1", + "addresses": [ + "0x4C7909d6F029b3a5798143C843F4f8e5341a3473", + "0x47D5592606622D807F3B37E5e5C8268355E30925", + "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", + "0xdD36Aa96D9BD4b49DA6E6734fF18Cc69F90F9435", + "0x77EC061aC11df6b42Af3784BCE835A5feAF247Dd", + "0x3BAe6eb858837a9855CE7747feC3FC99a87A86e0" + ], + "snapshot": 15820600 + } +] diff --git a/src/strategies/anchorage/index.ts b/src/strategies/offchain-delegation/index.ts similarity index 87% rename from src/strategies/anchorage/index.ts rename to src/strategies/offchain-delegation/index.ts index fff4bcd22..80718b606 100644 --- a/src/strategies/anchorage/index.ts +++ b/src/strategies/offchain-delegation/index.ts @@ -6,9 +6,9 @@ export const author = 'bonustrack'; export const version = '0.1.0'; export const dependOnOtherAddress = true; -const SPREADSHEET_ID = +const DEFAULT_SPREADSHEET_ID = '2PACX-1vQsn8e6KQOwqfHoA4rWDke63jTwfcshHxcZwOzVharOoAARWy6aX0TvN-uzzgtmAn3F5vDbuDKnk5Jw'; -const GID = '506976679'; +const DEFAULT_GID = '506976679'; function csvToJson(csv) { const lines = csv.split('\n'); @@ -32,12 +32,13 @@ export async function strategy( ) { const block = await provider.getBlock(snapshot); const ts = block.timestamp; - + const SPREADSHEET_ID = options.sheetId ?? DEFAULT_SPREADSHEET_ID; + const GID = options.gid ?? DEFAULT_GID; const url = `https://docs.google.com/spreadsheets/d/e/${SPREADSHEET_ID}/pub?gid=${GID}&single=true&output=csv`; const res = await fetch(url); const text = await res.text(); const csv = csvToJson(text) || []; - + const delegationSpace = options.delegationSpace || space; const delegations = Object.fromEntries( csv .map((item) => ({ @@ -49,7 +50,7 @@ export async function strategy( .filter( (item) => item.ts <= ts && - item.space === space && + item.space === delegationSpace && !addresses.includes(item.delegator) ) .sort((a, b) => a.ts - b.ts) From 4555342b76f8271b8c700eaa7beba5bc77dfa0d8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 6 Nov 2022 19:25:10 +0530 Subject: [PATCH 210/815] Automated lint (#938) Co-authored-by: ChaituVR --- .../schema.json | 28 ++++--------------- src/validations/passport/schema.json | 10 ++----- 2 files changed, 8 insertions(+), 30 deletions(-) diff --git a/src/strategies/dsla-parametric-staking-service-credits/schema.json b/src/strategies/dsla-parametric-staking-service-credits/schema.json index b8ae01f9e..4b27e279c 100644 --- a/src/strategies/dsla-parametric-staking-service-credits/schema.json +++ b/src/strategies/dsla-parametric-staking-service-credits/schema.json @@ -9,9 +9,7 @@ "xDSLA": { "type": "string", "title": "xDSLA", - "examples": [ - "e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984" - ], + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], "pattern": "^0x[a-fA-F0-9]{40}$", "minLength": 42, "maxLength": 42 @@ -19,9 +17,7 @@ "xDSLA_LP": { "type": "string", "title": "xDSLA_LP", - "examples": [ - "e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984" - ], + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], "pattern": "^0x[a-fA-F0-9]{40}$", "minLength": 42, "maxLength": 42 @@ -29,9 +25,7 @@ "DSLA": { "type": "string", "title": "DSLA", - "examples": [ - "e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984" - ], + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], "pattern": "^0x[a-fA-F0-9]{40}$", "minLength": 42, "maxLength": 42 @@ -39,9 +33,7 @@ "StakingSLA": { "type": "string", "title": "StakingSLA", - "examples": [ - "e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984" - ], + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], "pattern": "^0x[a-fA-F0-9]{40}$", "minLength": 42, "maxLength": 42 @@ -49,18 +41,10 @@ "decimals": { "type": "number", "title": "Decimals", - "examples": [ - "e.g. 18" - ] + "examples": ["e.g. 18"] } }, - "required": [ - "xDSLA", - "xDSLA_LP", - "StakingSLA", - "DSLA", - "decimals" - ], + "required": ["xDSLA", "xDSLA_LP", "StakingSLA", "DSLA", "decimals"], "additionalProperties": false } } diff --git a/src/validations/passport/schema.json b/src/validations/passport/schema.json index 50b2662c1..bc6199277 100644 --- a/src/validations/passport/schema.json +++ b/src/validations/passport/schema.json @@ -23,10 +23,7 @@ "title": "Weight" } }, - "required": [ - "id", - "weight" - ], + "required": ["id", "weight"], "additionalProperties": false } }, @@ -35,10 +32,7 @@ "title": "Min. weight" } }, - "required": [ - "stamps", - "min_weight" - ], + "required": ["stamps", "min_weight"], "additionalProperties": false } } From 5de602c642e1293a5d5c619851188bb06e98bf3b Mon Sep 17 00:00:00 2001 From: etedwardelric Date: Mon, 7 Nov 2022 15:42:48 +0800 Subject: [PATCH 211/815] Add strategy [marsecosystem] (#937) * add marsecosystem strategy * add array limit * add lp multi --- src/strategies/index.ts | 4 +- src/strategies/marsecosystem/README.md | 69 ++++++++++ src/strategies/marsecosystem/examples.json | 92 +++++++++++++ src/strategies/marsecosystem/index.ts | 148 +++++++++++++++++++++ 4 files changed, 312 insertions(+), 1 deletion(-) create mode 100644 src/strategies/marsecosystem/README.md create mode 100644 src/strategies/marsecosystem/examples.json create mode 100644 src/strategies/marsecosystem/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 5f18f007b..265c21394 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -394,6 +394,7 @@ import * as spreadsheet from './spreadsheet'; import * as offchainDelegation from './offchain-delegation'; import * as dslaParametricStakingServiceCredits from './dsla-parametric-staking-service-credits'; import * as rep3Badges from './rep3-badges'; +import * as marsecosystem from './marsecosystem'; const strategies = { 'forta-shares': fortaShares, @@ -793,7 +794,8 @@ const strategies = { 'ninechronicles-staked-and-dcc': ninechroniclesStakedAndDcc, 'dsla-parametric-staking-service-credits': dslaParametricStakingServiceCredits, - 'rep3-badges': rep3Badges + 'rep3-badges': rep3Badges, + marsecosystem }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/marsecosystem/README.md b/src/strategies/marsecosystem/README.md new file mode 100644 index 000000000..043a10f13 --- /dev/null +++ b/src/strategies/marsecosystem/README.md @@ -0,0 +1,69 @@ +# marsecosystem + +This is the most common strategy, it returns the balances of the voters for a specific ERC20 token. + +Here is an example of parameters: + +```json +{ + "token": "0x7859B01BbF675d67Da8cD128a50D155cd881B576", + "miningMasters": [ + { "address": "0xc7B8285a9E099e8c21CA5516D23348D8dBADdE4a", "pid": 0 }, + { "address": "0x48C42579D98Aa768cde893F8214371ed607CABE3", "pid": 0 } + ], + "upMiningMasters": [ + { "address": "0x38823CB52d152e0fFe637D63F97f6F771a071Ea0", "pid": 0 }, + { "address": "0x38823CB52d152e0fFe637D63F97f6F771a071Ea0", "pid": 1 }, + { "address": "0x38823CB52d152e0fFe637D63F97f6F771a071Ea0", "pid": 2 }, + { "address": "0x38823CB52d152e0fFe637D63F97f6F771a071Ea0", "pid": 3 } + ], + "lps": [ + { + "lpToken": "0x40B605d8BeED09568E702Deadce90fb23cfd74d8", + "multi": 1500, + "miningMasters": [ + { + "address": "0xc7B8285a9E099e8c21CA5516D23348D8dBADdE4a", + "pid": 1 + }, + { + "address": "0x48C42579D98Aa768cde893F8214371ed607CABE3", + "pid": 1 + } + ], + "upMiningMasters": [ + { + "address": "0x38823CB52d152e0fFe637D63F97f6F771a071Ea0", + "pid": 4 + }, + { + "address": "0x38823CB52d152e0fFe637D63F97f6F771a071Ea0", + "pid": 5 + } + ] + }, + { + "lpToken": "0xe47cCE810174Ac2aCEaB936e6FF93690888bcF24", + "multi": 2000, + "miningMasters": [ + { + "address": "0xc7B8285a9E099e8c21CA5516D23348D8dBADdE4a", + "pid": 7 + }, + { + "address": "0x22D8d50454203bd5a41B49ef515891f1aD9f3e53", + "pid": 3 + } + ], + "upMiningMasters": [ + { + "address": "0x38823CB52d152e0fFe637D63F97f6F771a071Ea0", + "pid": 6 + } + ] + } + ], + "symbol": "XMS", + "decimals": 18 +} +``` diff --git a/src/strategies/marsecosystem/examples.json b/src/strategies/marsecosystem/examples.json new file mode 100644 index 000000000..bda9fca13 --- /dev/null +++ b/src/strategies/marsecosystem/examples.json @@ -0,0 +1,92 @@ +[ + { + "name": "Example", + "strategy": { + "name": "marsecosystem", + "params": { + "token": "0x7859B01BbF675d67Da8cD128a50D155cd881B576", + "miningMasters": [ + { "address": "0xc7B8285a9E099e8c21CA5516D23348D8dBADdE4a", "pid": 0 }, + { "address": "0x48C42579D98Aa768cde893F8214371ed607CABE3", "pid": 0 } + ], + "upMiningMasters": [ + { "address": "0x38823CB52d152e0fFe637D63F97f6F771a071Ea0", "pid": 0 }, + { "address": "0x38823CB52d152e0fFe637D63F97f6F771a071Ea0", "pid": 1 }, + { "address": "0x38823CB52d152e0fFe637D63F97f6F771a071Ea0", "pid": 2 }, + { "address": "0x38823CB52d152e0fFe637D63F97f6F771a071Ea0", "pid": 3 } + ], + "lps": [ + { + "lpToken": "0x40B605d8BeED09568E702Deadce90fb23cfd74d8", + "multi": 1500, + "miningMasters": [ + { + "address": "0xc7B8285a9E099e8c21CA5516D23348D8dBADdE4a", + "pid": 1 + }, + { + "address": "0x48C42579D98Aa768cde893F8214371ed607CABE3", + "pid": 1 + } + ], + "upMiningMasters": [ + { + "address": "0x38823CB52d152e0fFe637D63F97f6F771a071Ea0", + "pid": 4 + }, + { + "address": "0x38823CB52d152e0fFe637D63F97f6F771a071Ea0", + "pid": 5 + } + ] + }, + { + "lpToken": "0xe47cCE810174Ac2aCEaB936e6FF93690888bcF24", + "multi": 2000, + "miningMasters": [ + { + "address": "0xc7B8285a9E099e8c21CA5516D23348D8dBADdE4a", + "pid": 7 + }, + { + "address": "0x22D8d50454203bd5a41B49ef515891f1aD9f3e53", + "pid": 3 + } + ], + "upMiningMasters": [ + { + "address": "0x38823CB52d152e0fFe637D63F97f6F771a071Ea0", + "pid": 6 + } + ] + } + ], + "symbol": "XMS", + "decimals": 18 + } + }, + "network": "56", + "addresses": [ + "0x3139f8eb391f8bfb478b9c155e009c59a689d7e0", + "0xc03f7c895ae99bd63b2b9569d8465c1cb8f48807", + "0x74e3a06361b0c67d736020c3b09196aa84019bff", + "0xae2113de1cd10c5d626e902760638a4f5ae53d7a", + "0xa3abadcddf9c7194b7a9059ea76b5cfb6aa31c6f", + "0x1b983e23b541785e44fe1dae6e0d67d7d1ac4912", + "0xbc8da18ef4cfc2282487c0fba2daa8fa7623045f", + "0xbda6ba3ad624582495c55451a1840e563fc16389", + "0xdab35f3e690b005b6cec2ed692def81b9702186a", + "0x9a85032ce857d536784a6493273ba32e8562c6e2", + "0xbfb7746a642e4ac4549da3f203da3d110f0c4a4d", + "0xe1b7b6216cc1b73a35e651674d43a4aad495ac6c", + "0x1265a989b92bdcb9a5cb86d86f3701fca5514cb7", + "0xea013d2a1eaaf64808d6e1d2227564ec69d977fd", + "0xeaac9ebbdd62c7a7f3d881763dbb23770deb353b", + "0x1d9155f814a832af287bf6965bd66fbf12c69d4f", + "0x711cae85542082daf93a14403d148bb91299c6fb", + "0x75f9a46a78757d0ea1557abf6cb04499960ef951", + "0xbf329b00b533485987c957182bfb02bcee9c3994" + ], + "snapshot": 22704707 + } +] diff --git a/src/strategies/marsecosystem/index.ts b/src/strategies/marsecosystem/index.ts new file mode 100644 index 000000000..a75c4ef81 --- /dev/null +++ b/src/strategies/marsecosystem/index.ts @@ -0,0 +1,148 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'etedwardelric'; +export const version = '0.0.1'; + +const abi = [ + 'function balanceOf(address _owner) view returns (uint256 balance)', + 'function userInfo(uint256, address) view returns (uint256 amount, uint256 rewardDebt)', + 'function stakedWantTokens(uint256 _pid, address _user) view returns (uint256)', + 'function totalSupply() view returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multi = new Multicaller(network, provider, abi, { blockTag }); + + if (options.miningMasters) + options.miningMasters = options.miningMasters.slice(0, 20); + if (options.upMiningMasters) + options.upMiningMasters = options.upMiningMasters.slice(0, 20); + if (options.lps) { + options.lps = options.lps.slice(0, 5); + options.lps.forEach((lp) => { + if (lp.miningMasters) lp.miningMasters = lp.miningMasters.slice(0, 20); + if (lp.upMiningMasters) + lp.upMiningMasters = lp.upMiningMasters.slice(0, 20); + }); + } + + addresses.forEach((address) => { + multi.call(`${address}-${options.token}`, options.token, 'balanceOf', [ + address + ]); + if (options.miningMasters) + options.miningMasters.forEach((miningMaster) => + multi.call( + `${address}-${miningMaster.address}-${miningMaster.pid}`, + miningMaster.address, + 'userInfo', + [miningMaster.pid, address] + ) + ); + if (options.upMiningMasters) + options.upMiningMasters.forEach((upMiningMaster) => + multi.call( + `${address}-${upMiningMaster.address}-${upMiningMaster.pid}`, + upMiningMaster.address, + 'stakedWantTokens', + [upMiningMaster.pid, address] + ) + ); + }); + + addresses.forEach((address) => + options.lps.forEach((lp) => { + multi.call(`${lp.lpToken}-${options.token}`, options.token, 'balanceOf', [ + lp.lpToken + ]); + multi.call(`${lp.lpToken}`, lp.lpToken, 'totalSupply'); + multi.call(`${address}-${lp.lpToken}`, lp.lpToken, 'balanceOf', [ + address + ]); + if (lp.miningMasters) + lp.miningMasters.forEach((miningMaster) => + multi.call( + `${address}-${lp.lpToken}-${miningMaster.address}-${miningMaster.pid}`, + miningMaster.address, + 'userInfo', + [miningMaster.pid, address] + ) + ); + if (lp.upMiningMasters) + lp.upMiningMasters.forEach((upMiningMaster) => + multi.call( + `${address}-${lp.lpToken}-${upMiningMaster.address}-${upMiningMaster.pid}`, + upMiningMaster.address, + 'stakedWantTokens', + [upMiningMaster.pid, address] + ) + ); + }) + ); + + const result = await multi.execute(); + + return Object.fromEntries( + addresses.map((address) => { + let amount = BigNumber.from(0); + amount = amount.add(result[`${address}-${options.token}`]); + if (options.miningMasters) + for (let miningMaster of options.miningMasters) { + amount = amount.add( + result[`${address}-${miningMaster.address}-${miningMaster.pid}`][0] + ); + } + if (options.upMiningMasters) + for (let upMiningMaster of options.upMiningMasters) { + amount = amount.add( + result[`${address}-${upMiningMaster.address}-${upMiningMaster.pid}`] + ); + } + for (let lp of options.lps) { + amount = amount.add( + result[`${address}-${lp.lpToken}`] + .mul(result[`${lp.lpToken}-${options.token}`]) + .mul(lp.multi ?? 1000) + .div(result[`${lp.lpToken}`]) + .div(1000) + ); + if (lp.miningMasters) + for (let miningMaster of lp.miningMasters) { + amount = amount.add( + result[ + `${address}-${lp.lpToken}-${miningMaster.address}-${miningMaster.pid}` + ][0] + .mul(result[`${lp.lpToken}-${options.token}`]) + .mul(lp.multi ?? 1000) + .div(result[`${lp.lpToken}`]) + .div(1000) + ); + } + if (lp.upMiningMasters) + for (let upMiningMaster of lp.upMiningMasters) { + amount = amount.add( + result[ + `${address}-${lp.lpToken}-${upMiningMaster.address}-${upMiningMaster.pid}` + ] + .mul(result[`${lp.lpToken}-${options.token}`]) + .mul(lp.multi ?? 1000) + .div(result[`${lp.lpToken}`]) + .div(1000) + ); + } + } + return [address, parseFloat(formatUnits(amount))]; + }) + ); +} From 2637e3c9f8e17519dbf8f8ebec4a5890237bfb0f Mon Sep 17 00:00:00 2001 From: bonustrack Date: Tue, 8 Nov 2022 16:36:16 +0700 Subject: [PATCH 212/815] Clean offchain delegation --- src/strategies/marsecosystem/index.ts | 10 +++++----- src/strategies/offchain-delegation/README.md | 13 +++++-------- src/strategies/offchain-delegation/examples.json | 3 +-- src/strategies/offchain-delegation/index.ts | 8 +------- 4 files changed, 12 insertions(+), 22 deletions(-) diff --git a/src/strategies/marsecosystem/index.ts b/src/strategies/marsecosystem/index.ts index a75c4ef81..4238dea24 100644 --- a/src/strategies/marsecosystem/index.ts +++ b/src/strategies/marsecosystem/index.ts @@ -98,18 +98,18 @@ export async function strategy( let amount = BigNumber.from(0); amount = amount.add(result[`${address}-${options.token}`]); if (options.miningMasters) - for (let miningMaster of options.miningMasters) { + for (const miningMaster of options.miningMasters) { amount = amount.add( result[`${address}-${miningMaster.address}-${miningMaster.pid}`][0] ); } if (options.upMiningMasters) - for (let upMiningMaster of options.upMiningMasters) { + for (const upMiningMaster of options.upMiningMasters) { amount = amount.add( result[`${address}-${upMiningMaster.address}-${upMiningMaster.pid}`] ); } - for (let lp of options.lps) { + for (const lp of options.lps) { amount = amount.add( result[`${address}-${lp.lpToken}`] .mul(result[`${lp.lpToken}-${options.token}`]) @@ -118,7 +118,7 @@ export async function strategy( .div(1000) ); if (lp.miningMasters) - for (let miningMaster of lp.miningMasters) { + for (const miningMaster of lp.miningMasters) { amount = amount.add( result[ `${address}-${lp.lpToken}-${miningMaster.address}-${miningMaster.pid}` @@ -130,7 +130,7 @@ export async function strategy( ); } if (lp.upMiningMasters) - for (let upMiningMaster of lp.upMiningMasters) { + for (const upMiningMaster of lp.upMiningMasters) { amount = amount.add( result[ `${address}-${lp.lpToken}-${upMiningMaster.address}-${upMiningMaster.pid}` diff --git a/src/strategies/offchain-delegation/README.md b/src/strategies/offchain-delegation/README.md index e86a43634..5b5f2e714 100644 --- a/src/strategies/offchain-delegation/README.md +++ b/src/strategies/offchain-delegation/README.md @@ -11,26 +11,23 @@ This strategy is used to handle offchain delegations. - And use the id after "pub?gid=" as "gid" parameter - You are ready! - ## Parameters - `sheetId`: The id of the spreadsheet - `gid`: The id of the sheet - `strategies`: The strategies to use, to calculate the score of the delegations -- `delegationSpace`: The space to use for the delegations (Optional, default: space of the proposal) Here is an example of the strategy parameters: - ```json { "sheetId": "2PACX-1vTAo2yFq6GyBZcB3BOnIw_Rzub7KEEzqhhgFY5CD6eCW-Rfx9d4NaMJP8IP67G9YnV3PNPHKvgJeSNY", "gid": "1557274211", "strategies": [ { - "name": "erc20-balance-of", - "params": { - "address": "0x6B175474E89094C44Da98b954EedeAC495271d0F", - "decimals": 18 - } + "name": "erc20-balance-of", + "params": { + "address": "0x6B175474E89094C44Da98b954EedeAC495271d0F", + "decimals": 18 + } } ] } diff --git a/src/strategies/offchain-delegation/examples.json b/src/strategies/offchain-delegation/examples.json index d2a7dcb68..eab6e07cc 100644 --- a/src/strategies/offchain-delegation/examples.json +++ b/src/strategies/offchain-delegation/examples.json @@ -4,10 +4,9 @@ "strategy": { "name": "offchain-delegation", "params": { - "symbol": "DAI DELEGATEDW", + "symbol": "DAI (delegated)", "sheetId": "2PACX-1vTAo2yFq6GyBZcB3BOnIw_Rzub7KEEzqhhgFY5CD6eCW-Rfx9d4NaMJP8IP67G9YnV3PNPHKvgJeSNY", "gid": "1557274211", - "delegationSpace": "test7.shot.eth", "strategies": [ { "name": "erc20-balance-of", diff --git a/src/strategies/offchain-delegation/index.ts b/src/strategies/offchain-delegation/index.ts index 80718b606..c03fc1991 100644 --- a/src/strategies/offchain-delegation/index.ts +++ b/src/strategies/offchain-delegation/index.ts @@ -38,7 +38,6 @@ export async function strategy( const res = await fetch(url); const text = await res.text(); const csv = csvToJson(text) || []; - const delegationSpace = options.delegationSpace || space; const delegations = Object.fromEntries( csv .map((item) => ({ @@ -47,12 +46,7 @@ export async function strategy( delegate: getAddress(item.delegate), ts: parseInt(item.timestamp || '0') })) - .filter( - (item) => - item.ts <= ts && - item.space === delegationSpace && - !addresses.includes(item.delegator) - ) + .filter((item) => item.ts <= ts && !addresses.includes(item.delegator)) .sort((a, b) => a.ts - b.ts) .map((item) => [item.delegator, item.delegate]) ); From dc742ab6f5c83e98fb87413bdf0162c8dead7b28 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 10 Nov 2022 20:34:12 +0530 Subject: [PATCH 213/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.48 (#942) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index a963e3080..564a6a85b 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.47", + "@snapshot-labs/snapshot.js": "^0.4.48", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index a015f7772..2c19b41e9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,13 +1163,14 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.47": - version "0.4.47" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.47.tgz#1b2e806bc26a71c4dc540f43b5bdf5d4d63488b7" - integrity sha512-f/zwBqZkeaF/YTt2Z/AtP9mRi7gT97vHFL8gVbIFLmpBTfGJ5N7DX6RFNjN0eY4/9VJJ1KFN0sq0fc0v3lCztw== +"@snapshot-labs/snapshot.js@^0.4.48": + version "0.4.48" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.48.tgz#b16d788fab8dd5b9774baf65cfa374e620ff4cb7" + integrity sha512-c1hUJ2b+bxta8scdf3LiBzGdcWL/l3PWxLD0PEWZXQ4Yjd+O2mwF5+JL0YTUzi3Bzp0XiTzeSaxRw5+9JG8Pzw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" + "@ethersproject/address" "^5.6.1" "@ethersproject/bytes" "^5.6.1" "@ethersproject/contracts" "^5.6.2" "@ethersproject/hash" "^5.6.1" From c0946ae54af8c4c71ce39f2a14da2aa484ca9a6e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 11 Nov 2022 14:57:27 +0530 Subject: [PATCH 214/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.49 (#943) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 564a6a85b..e44f31328 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.48", + "@snapshot-labs/snapshot.js": "^0.4.49", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 2c19b41e9..b21256ebb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.48": - version "0.4.48" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.48.tgz#b16d788fab8dd5b9774baf65cfa374e620ff4cb7" - integrity sha512-c1hUJ2b+bxta8scdf3LiBzGdcWL/l3PWxLD0PEWZXQ4Yjd+O2mwF5+JL0YTUzi3Bzp0XiTzeSaxRw5+9JG8Pzw== +"@snapshot-labs/snapshot.js@^0.4.49": + version "0.4.49" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.49.tgz#b4da4a44aa7b400c8e4ea0b8c91d8894bb662ace" + integrity sha512-up1sl9d7BGx1DKUUpESP5MoadNtFhOA7jcsVR3vGEaDppFWWRpYGBBcjBm0hE1ThtsR5/l45Le0/WFGRsf8Fjw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 1f93bace20fe6f18522c5dbbbbc1a69b166f916d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 11 Nov 2022 20:49:09 +0530 Subject: [PATCH 215/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.50 (#944) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index e44f31328..0615174d2 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.49", + "@snapshot-labs/snapshot.js": "^0.4.50", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index b21256ebb..cd7d37163 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.49": - version "0.4.49" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.49.tgz#b4da4a44aa7b400c8e4ea0b8c91d8894bb662ace" - integrity sha512-up1sl9d7BGx1DKUUpESP5MoadNtFhOA7jcsVR3vGEaDppFWWRpYGBBcjBm0hE1ThtsR5/l45Le0/WFGRsf8Fjw== +"@snapshot-labs/snapshot.js@^0.4.50": + version "0.4.50" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.50.tgz#848b69b86b1a98ae477bbfa4be17a4b9b4c8472f" + integrity sha512-KGxOZ4SICZseNdKPFskZJcAInQVopJFi43M1nui0HUTDXdXJ/BxMTRj/ic1UhG8z4fJeHpoX2xzTZpucZ04qLg== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 22be69eaebe3695c562c8333c42ca0a0d29faa93 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Sun, 13 Nov 2022 23:05:10 +0530 Subject: [PATCH 216/815] Seperate passport validations (#940) --- src/validations/index.ts | 6 ++- src/validations/passport-gated/README.md | 1 + src/validations/passport-gated/examples.json | 19 ++++++++ src/validations/passport-gated/index.ts | 45 +++++++++++++++++++ src/validations/passport-gated/schema.json | 30 +++++++++++++ src/validations/passport-weighted/README.md | 1 + .../examples.json | 2 +- .../{passport => passport-weighted}/helper.ts | 0 .../{passport => passport-weighted}/index.ts | 2 +- .../schema.json | 10 ++++- src/validations/passport/README.md | 1 - test/validation.test.ts | 24 ++++++++-- 12 files changed, 131 insertions(+), 10 deletions(-) create mode 100644 src/validations/passport-gated/README.md create mode 100644 src/validations/passport-gated/examples.json create mode 100644 src/validations/passport-gated/index.ts create mode 100644 src/validations/passport-gated/schema.json create mode 100644 src/validations/passport-weighted/README.md rename src/validations/{passport => passport-weighted}/examples.json (86%) rename src/validations/{passport => passport-weighted}/helper.ts (100%) rename src/validations/{passport => passport-weighted}/index.ts (97%) rename src/validations/{passport => passport-weighted}/schema.json (84%) delete mode 100644 src/validations/passport/README.md diff --git a/src/validations/index.ts b/src/validations/index.ts index 5f116ea4f..b1c03b556 100644 --- a/src/validations/index.ts +++ b/src/validations/index.ts @@ -4,14 +4,16 @@ import basic from './basic'; import aave from './aave'; import nouns from './nouns'; import timeperiod from './timeperiod'; -import passport from './passport'; +import passportGated from './passport-gated'; +import passportWeighted from './passport-weighted'; const validationClasses = { basic, aave, nouns, timeperiod, - passport + 'passport-gated': passportGated, + 'passport-weighted': passportWeighted }; const validations = {}; diff --git a/src/validations/passport-gated/README.md b/src/validations/passport-gated/README.md new file mode 100644 index 000000000..0153ab360 --- /dev/null +++ b/src/validations/passport-gated/README.md @@ -0,0 +1 @@ +# Gitcoin passport gated validation diff --git a/src/validations/passport-gated/examples.json b/src/validations/passport-gated/examples.json new file mode 100644 index 000000000..d9f3d615a --- /dev/null +++ b/src/validations/passport-gated/examples.json @@ -0,0 +1,19 @@ +[ + { + "name": "Example of a passport gated proposal validation", + "author": "0x24F15402C6Bb870554489b2fd2049A85d75B982f", + "space": "fabien.eth", + "network": "1", + "snapshot": "latest", + "params": { + "stamps": [ + "Ens", + "Twitter", + "GitHub", + "POAP", + "SnapshotVotesProvider" + ], + "operand": "OR" + } + } +] diff --git a/src/validations/passport-gated/index.ts b/src/validations/passport-gated/index.ts new file mode 100644 index 000000000..649f59c26 --- /dev/null +++ b/src/validations/passport-gated/index.ts @@ -0,0 +1,45 @@ +import snapshot from '@snapshot-labs/snapshot.js'; +import Validation from '../validation'; +import { + getPassport, + getVerifiedStamps, + hasValidIssuanceAndExpiration +} from '../passport-weighted/helper'; + +export default class extends Validation { + public id = 'passport-gated'; + public github = 'snapshot-labs'; + public version = '0.1.0'; + + async validate(): Promise { + const passport: any = await getPassport(this.author); + if (!passport) return false; + if (!passport.stamps?.length || !this.params.stamps?.length) return false; + + const verifiedStamps: any[] = await getVerifiedStamps( + passport, + this.author, + this.params.stamps.map((stamp) => ({ + id: stamp + })) + ); + if (!verifiedStamps.length) return false; + + const provider = snapshot.utils.getProvider(this.network); + const proposalTs = (await provider.getBlock(this.snapshot)).timestamp; + + const operand = this.params.operand || 'AND'; + const validStamps = verifiedStamps.filter( + (stamp) => + hasValidIssuanceAndExpiration(stamp.credential, proposalTs) && + this.params.stamps.includes(stamp.provider) + ); + if (operand === 'AND') { + return validStamps.length === this.params.stamps.length; + } else if (operand === 'OR') { + return validStamps.length > 0; + } else { + return false; + } + } +} diff --git a/src/validations/passport-gated/schema.json b/src/validations/passport-gated/schema.json new file mode 100644 index 000000000..59f6dab62 --- /dev/null +++ b/src/validations/passport-gated/schema.json @@ -0,0 +1,30 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Validation", + "definitions": { + "Validation": { + "title": "Validation", + "type": "object", + "properties": { + "stamps": { + "type": "array", + "title": "Stamps", + "minItems": 1, + "maxItems": 32 + }, + "operand": { + "type": "string", + "title": "Operand", + "enum": [ + "AND", + "OR" + ] + } + }, + "required": [ + "stamps" + ], + "additionalProperties": false + } + } +} diff --git a/src/validations/passport-weighted/README.md b/src/validations/passport-weighted/README.md new file mode 100644 index 000000000..37bbf166f --- /dev/null +++ b/src/validations/passport-weighted/README.md @@ -0,0 +1 @@ +# Gitcoin passport weighted validation diff --git a/src/validations/passport/examples.json b/src/validations/passport-weighted/examples.json similarity index 86% rename from src/validations/passport/examples.json rename to src/validations/passport-weighted/examples.json index 23548fe9b..e070203e9 100644 --- a/src/validations/passport/examples.json +++ b/src/validations/passport-weighted/examples.json @@ -1,6 +1,6 @@ [ { - "name": "Example of a passport proposal validation", + "name": "Example of a passport-weighted proposal validation", "author": "0x24F15402C6Bb870554489b2fd2049A85d75B982f", "space": "fabien.eth", "network": "1", diff --git a/src/validations/passport/helper.ts b/src/validations/passport-weighted/helper.ts similarity index 100% rename from src/validations/passport/helper.ts rename to src/validations/passport-weighted/helper.ts diff --git a/src/validations/passport/index.ts b/src/validations/passport-weighted/index.ts similarity index 97% rename from src/validations/passport/index.ts rename to src/validations/passport-weighted/index.ts index b27bef9c6..901a2067a 100644 --- a/src/validations/passport/index.ts +++ b/src/validations/passport-weighted/index.ts @@ -7,7 +7,7 @@ import { } from './helper'; export default class extends Validation { - public id = 'passport'; + public id = 'passport-weighted'; public github = 'snapshot-labs'; public version = '0.1.0'; diff --git a/src/validations/passport/schema.json b/src/validations/passport-weighted/schema.json similarity index 84% rename from src/validations/passport/schema.json rename to src/validations/passport-weighted/schema.json index bc6199277..50b2662c1 100644 --- a/src/validations/passport/schema.json +++ b/src/validations/passport-weighted/schema.json @@ -23,7 +23,10 @@ "title": "Weight" } }, - "required": ["id", "weight"], + "required": [ + "id", + "weight" + ], "additionalProperties": false } }, @@ -32,7 +35,10 @@ "title": "Min. weight" } }, - "required": ["stamps", "min_weight"], + "required": [ + "stamps", + "min_weight" + ], "additionalProperties": false } } diff --git a/src/validations/passport/README.md b/src/validations/passport/README.md deleted file mode 100644 index 8c66ea370..000000000 --- a/src/validations/passport/README.md +++ /dev/null @@ -1 +0,0 @@ -# Gitcoin passport validation diff --git a/test/validation.test.ts b/test/validation.test.ts index c970880a7..1b269e927 100644 --- a/test/validation.test.ts +++ b/test/validation.test.ts @@ -1,12 +1,13 @@ import snapshot from '../src'; -import examples from '../src/validations/passport/examples.json'; +import examples from '../src/validations/passport-gated/examples.json'; +import snapshotjs from '@snapshot-labs/snapshot.js'; const [example] = examples; -const id = 'passport'; +const id = 'passport-gated'; describe('validation', () => { it(`validate: ${id} "${example.name}"`, async () => { - const validation = new snapshot.validations[id]( + const validation = new snapshot.validations[id].validation( example.author, example.space, example.network, @@ -15,4 +16,21 @@ describe('validation', () => { ); expect(await validation.validate()).toBe(true); }, 10e3); + + // Check schema is valid with examples.json + let schema; + try { + schema = require(`../src/validations/${id}/schema.json`); + } catch (error) { + schema = null; + } + (schema ? it : it.skip)( + 'Check schema (if available) is valid with examples.json', + async () => { + expect(typeof schema).toBe('object'); + expect(snapshotjs.utils.validateSchema(schema, example.params)).toBe( + true + ); + } + ); }); From 755dbb0809d4da25155eddbb2b493062b73870c4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 13 Nov 2022 23:15:29 +0530 Subject: [PATCH 217/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.51 (#945) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 0615174d2..653e0cc59 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.50", + "@snapshot-labs/snapshot.js": "^0.4.51", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index cd7d37163..a60d9b25a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.50": - version "0.4.50" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.50.tgz#848b69b86b1a98ae477bbfa4be17a4b9b4c8472f" - integrity sha512-KGxOZ4SICZseNdKPFskZJcAInQVopJFi43M1nui0HUTDXdXJ/BxMTRj/ic1UhG8z4fJeHpoX2xzTZpucZ04qLg== +"@snapshot-labs/snapshot.js@^0.4.51": + version "0.4.51" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.51.tgz#470dd2894298b576e90c0ffe1f68e49e70d194e7" + integrity sha512-Su8fO0Emu8JR8yzlUxpmNDmdYFhNWZ41HAJdi1KvM+5fh71lA0CWrYHCcFYzwaaZ65K4YGz/ILQmWxG/hhGhXg== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From b438efc9d6e7424a968655d88424e6349865f5e7 Mon Sep 17 00:00:00 2001 From: Fernando Zavalia <24811313+fzavalia@users.noreply.github.com> Date: Sun, 13 Nov 2022 15:20:30 -0300 Subject: [PATCH 218/815] New Strategy: Decentraland Rental Lessors [decentraland-rental-lessors] (#929) * feat: Rentals strategy (#1) * feat: Add rental lessors strategy to index * feat: WIP Create decentraland rental lessors strategy * chore: Update example file * feat: WIP Use options to configure strategy * fix: Addresses stored in scores map * feat: Refactor * feat: Refactor * feat: Update readme * chore: Update comment * feat: _in filters elements should be batched * chore: Update comment * feat: Add batchfy function * chore: Update comment * chore: Remove default in switch * chore: Add comments * chore: Update readme * chore: Add another address to example --- .../decentraland-rental-lessors/README.md | 30 +++ .../decentraland-rental-lessors/examples.json | 30 +++ .../decentraland-rental-lessors/index.ts | 223 ++++++++++++++++++ .../decentraland-rental-lessors/types.ts | 15 ++ src/strategies/index.ts | 2 + 5 files changed, 300 insertions(+) create mode 100644 src/strategies/decentraland-rental-lessors/README.md create mode 100644 src/strategies/decentraland-rental-lessors/examples.json create mode 100644 src/strategies/decentraland-rental-lessors/index.ts create mode 100644 src/strategies/decentraland-rental-lessors/types.ts diff --git a/src/strategies/decentraland-rental-lessors/README.md b/src/strategies/decentraland-rental-lessors/README.md new file mode 100644 index 000000000..678ec1e7f --- /dev/null +++ b/src/strategies/decentraland-rental-lessors/README.md @@ -0,0 +1,30 @@ +# Decentraland Rental Lessors + +This strategy allows calculating the VP of Land/Estate owners after ownership is transferred to the Rentals contract. + +Thanks to this, the VP that the user had before utilizing the rentals feature will not be lost. + +## Example + +The following example params are for obtaining the VP users have after sending their Lands/Estates to the Rentals contract in the Goerli network. + +```json +{ + "subgraphs": { + "rentals": "https://api.thegraph.com/subgraphs/name/decentraland/rentals-ethereum-goerli", + "marketplace": "https://api.thegraph.com/subgraphs/name/decentraland/marketplace-goerli" + }, + "addresses": { + "estate": "0xc9a46712e6913c24d15b46ff12221a79c4e251dc", + "land": "0x25b6b4bac4adb582a0abd475439da6730777fbf7" + }, + "multipliers": { + "estateSize": 2000, + "land": 2000 + } +} +``` + +The land multiplier determines how much VP is given by each Land the address possesses in the Rentals contract. For example, if the user has 5 Lands in the Rentals contract, it will be given 5 \* 2000 VP. + +The estateSize multiplier determines how much VP is given to the original owner according to the size of their Estates currently on the Rentals contract. For example, if the address has 1 Estate in the Rentals contract composed of 5 Lands, the user will be given 5 \* 2000 VP as well. diff --git a/src/strategies/decentraland-rental-lessors/examples.json b/src/strategies/decentraland-rental-lessors/examples.json new file mode 100644 index 000000000..e2f8512e8 --- /dev/null +++ b/src/strategies/decentraland-rental-lessors/examples.json @@ -0,0 +1,30 @@ +[ + { + "name": "Get VP of LAND and Estate owner's that have their assets locked in the Rentals contract", + "strategy": { + "name": "decentraland-rental-lessors", + "params": { + "subgraphs": { + "rentals": "https://api.thegraph.com/subgraphs/name/decentraland/rentals-ethereum-goerli", + "marketplace": "https://api.thegraph.com/subgraphs/name/decentraland/marketplace-goerli" + }, + "addresses": { + "estate": "0xc9a46712e6913c24d15b46ff12221a79c4e251dc", + "land": "0x25b6b4bac4adb582a0abd475439da6730777fbf7" + }, + "multipliers": { + "estateSize": 2000, + "land": 2000 + } + } + }, + "network": "5", + "addresses": [ + "0x747c6f502272129bf1ba872a1903045b837ee86c", + "0xbad79d832671d91b4bba85f600932faec0e5fd7c", + "0x24e5f44999c151f08609f8e27b2238c773c4d020", + "0x2f89ec84e0413950d9adf8e56dd56c2b2f5066cb" + ], + "snapshot": 7866054 + } +] diff --git a/src/strategies/decentraland-rental-lessors/index.ts b/src/strategies/decentraland-rental-lessors/index.ts new file mode 100644 index 000000000..72b77efee --- /dev/null +++ b/src/strategies/decentraland-rental-lessors/index.ts @@ -0,0 +1,223 @@ +import { getAddress } from '@ethersproject/address'; +import { subgraphRequest } from '../../utils'; +import { MarketplaceEstate, RentalsLandOrEstate, Scores } from './types'; + +export const author = 'fzavalia'; +export const version = '0.1.0'; + +const SUBGRAPH_QUERY_IN_FILTER_MAX_LENGTH = 500; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const scores: Scores = {}; + + // Initialize scores for every provided address as 0 + for (const address of addresses) { + scores[getAddress(address)] = 0; + } + + // For the provided addresses, fetch all their Lands and Estates that have been transferred to the rentals contract. + const rentalLandsAndEstates = await fetchLandsAndEstatesInRentalsContract( + addresses, + options, + snapshot + ); + + const rentalLands: RentalsLandOrEstate[] = []; + const rentalEstates: RentalsLandOrEstate[] = []; + + // Separate the assets into Lands and Estates + for (const rentalLandOrEstate of rentalLandsAndEstates) { + switch (rentalLandOrEstate.contractAddress) { + case options.addresses.land.toLowerCase(): + rentalLands.push(rentalLandOrEstate); + break; + case options.addresses.estate.toLowerCase(): + rentalEstates.push(rentalLandOrEstate); + } + } + + // For each Land, increase the score of the original owner by the land multiplier. + for (const land of rentalLands) { + scores[getAddress(land.lessor)] += options.multipliers.land; + } + + // Fetch and match Estates from the marketplace subgraph with the ones from the rentals subgraph. + const rentalAndMarketplaceEstates = + await fetchMarketplaceEstatesForProvidedRentalAssets( + rentalEstates, + options, + snapshot + ); + + // For each Estate, increase the score of the original owner by the size of the estate times the multiplier. + for (const [rentalEstate, marketplaceEstate] of rentalAndMarketplaceEstates) { + scores[getAddress(rentalEstate.lessor)] += + marketplaceEstate.size * options.multipliers.estateSize; + } + + return scores; +} + +// For a given list of addresses, fetch all the lands and estates that belonged to them before being transferred to the Rentals contract. +async function fetchLandsAndEstatesInRentalsContract( + addresses, + options, + snapshot +): Promise { + // Separate the addresses in batches to optimize the subgraph query. + const addressBatches = batchify( + addresses, + SUBGRAPH_QUERY_IN_FILTER_MAX_LENGTH + ); + + let finalRentalLandsAndEstates: RentalsLandOrEstate[] = []; + + for (const addressBatch of addressBatches) { + const query: any = { + rentalAssets: { + __args: { + where: { + contractAddress_in: [ + options.addresses.estate.toLowerCase(), + options.addresses.land.toLowerCase() + ], + lessor_in: addressBatch.map((address) => address.toLowerCase()), + isClaimed: false + }, + first: 1000, + skip: 0 + }, + id: true, + contractAddress: true, + tokenId: true, + lessor: true + } + }; + + // If a snapshot is provided, use it as another filter of the query. + if (typeof snapshot === 'number') { + query.rentalAssets.__args.block = { number: snapshot }; + } + + let hasMoreResults = true; + + while (hasMoreResults) { + const result = await subgraphRequest(options.subgraphs.rentals, query); + + const rentalLandsAndEstates: RentalsLandOrEstate[] = result.rentalAssets; + + // If the received length matches the requested length, there might be more results. + hasMoreResults = + rentalLandsAndEstates.length === query.rentalAssets.__args.first; + // If there are more results, skip the ones we already have on the next query. + query.rentalAssets.__args.skip += query.rentalAssets.__args.first; + + finalRentalLandsAndEstates = [ + ...finalRentalLandsAndEstates, + ...rentalLandsAndEstates + ]; + } + } + + return finalRentalLandsAndEstates; +} + +// For a given list of estates obtained from the rentals subgraph, fetch the estates that correspond to them in the marketplace subgraph. +async function fetchMarketplaceEstatesForProvidedRentalAssets( + rentalEstates: RentalsLandOrEstate[], + options, + snapshot +): Promise<[RentalsLandOrEstate, MarketplaceEstate][]> { + const rentalEstatesTokenIds: string[] = []; + + // Keep a map of rental estates to optimize the lookup later. + const rentalEstatesByTokenId = new Map(); + + for (const rentalEstate of rentalEstates) { + const tokenId = rentalEstate.tokenId; + rentalEstatesTokenIds.push(tokenId); + rentalEstatesByTokenId.set(tokenId, rentalEstate); + } + + // Separate the estate token ids in batches to optimize the subgraph query. + const rentalEstateTokenIdBatches = batchify( + rentalEstatesTokenIds, + SUBGRAPH_QUERY_IN_FILTER_MAX_LENGTH + ); + + const rentalAndMarketplaceEstates: [ + RentalsLandOrEstate, + MarketplaceEstate + ][] = []; + + for (const rentalEstateTokenIdBatch of rentalEstateTokenIdBatches) { + const query: any = { + estates: { + __args: { + where: { + tokenId_in: rentalEstateTokenIdBatch, + size_gt: 0 + }, + first: 1000, + skip: 0 + }, + tokenId: true, + size: true + } + }; + + // If a snapshot is provided, use it as another filter of the query. + if (typeof snapshot === 'number') { + query.estates.__args.block = { number: snapshot }; + } + + let hasMoreResults = true; + + while (hasMoreResults) { + const result = await subgraphRequest( + options.subgraphs.marketplace, + query + ); + + const marketplaceEstates: MarketplaceEstate[] = result.estates; + + // If the received length matches the requested length, there might be more results. + hasMoreResults = marketplaceEstates.length === query.estates.__args.first; + // If there are more results, skip the ones we already have on the next query. + query.estates.__args.skip += query.estates.__args.first; + + for (const marketplaceEstate of marketplaceEstates) { + const rentalEstate = rentalEstatesByTokenId.get( + marketplaceEstate.tokenId + ); + + if (rentalEstate) { + rentalAndMarketplaceEstates.push([rentalEstate, marketplaceEstate]); + } + } + } + } + + return rentalAndMarketplaceEstates; +} + +function batchify(elements: T[], batchSize: number): T[][] { + const batches: T[][] = []; + + for (let i = 0; i < elements.length; i++) { + if (i % batchSize === 0) { + batches.push([]); + } + + batches[batches.length - 1].push(elements[i]); + } + + return batches; +} diff --git a/src/strategies/decentraland-rental-lessors/types.ts b/src/strategies/decentraland-rental-lessors/types.ts new file mode 100644 index 000000000..412d22ed5 --- /dev/null +++ b/src/strategies/decentraland-rental-lessors/types.ts @@ -0,0 +1,15 @@ +export type Scores = { + [address: string]: number; +}; + +export type RentalsLandOrEstate = { + id: string; + contractAddress: string; + tokenId: string; + lessor: string; +}; + +export type MarketplaceEstate = { + tokenId: string; + size: number; +}; diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 265c21394..94a030270 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -152,6 +152,7 @@ import * as liftkitchen from './liftkitchen'; import * as coordinape from './coordinape'; import * as decentralandEstateSize from './decentraland-estate-size'; import * as decentralandWearableRariry from './decentraland-wearable-rarity'; +import * as decentralandRentalLessors from './decentraland-rental-lessors'; import * as iotexBalance from './iotex-balance'; import * as iotexStakedBalance from './iotex-staked-balance'; import * as xrc20BalanceOf from './xrc20-balance-of'; @@ -554,6 +555,7 @@ const strategies = { liftkitchen, 'decentraland-estate-size': decentralandEstateSize, 'decentraland-wearable-rarity': decentralandWearableRariry, + 'decentraland-rental-lessors': decentralandRentalLessors, brightid, 'inverse-xinv': inverseXINV, modefi, From 773012487f86cd32ddebed84219cd8567d839612 Mon Sep 17 00:00:00 2001 From: Danny Willis <102543677+dannyposi@users.noreply.github.com> Date: Mon, 14 Nov 2022 18:06:11 +0700 Subject: [PATCH 219/815] Add posichain total balance strategy [posichain-total-balance] (#946) * Add posichain-staking strategy * Enable posichain-staking strategy * Add more address example * Update author * Add more comment * Add posichain-staking readme * Add posichain-total-balance strategy --- src/strategies/index.ts | 2 + src/strategies/posichain-staking/README.md | 3 + .../posichain-total-balance/README.md | 3 + .../posichain-total-balance/examples.json | 18 +++++ .../posichain-total-balance/index.ts | 72 +++++++++++++++++++ 5 files changed, 98 insertions(+) create mode 100644 src/strategies/posichain-staking/README.md create mode 100644 src/strategies/posichain-total-balance/README.md create mode 100644 src/strategies/posichain-total-balance/examples.json create mode 100644 src/strategies/posichain-total-balance/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 94a030270..610b9304b 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -385,6 +385,7 @@ import * as nation3VotesWIthDelegations from './nation3-votes-with-delegations'; import * as aavegotchiAgip37WapGhst from './aavegotchi-agip-37-wap-ghst'; import * as aavegotchiAgip37GltrStakedLp from './aavegotchi-agip-37-gltr-staked-lp'; import * as posichainStaking from './posichain-staking'; +import * as posichainTotalBalance from './posichain-total-balance'; import * as erc20TokensPerUni from './erc20-tokens-per-uni'; import * as bancorStandardRewardsUnderlyingBalance from './bancor-standard-rewards-underlying-balance'; import * as sdVoteBoost from './sd-vote-boost'; @@ -772,6 +773,7 @@ const strategies = { 'proxyprotocol-erc721-balance-of': proxyProtocolErc721BalanceOf, 'proxyprotocol-erc1155-balance-of': proxyProtocolErc1155BalanceOf, 'posichain-staking': posichainStaking, + 'posichain-total-balance': posichainTotalBalance, 'arrow-vesting': arrowVesting, 'tutellus-protocol': tutellusProtocol, 'fight-club': fightClub, diff --git a/src/strategies/posichain-staking/README.md b/src/strategies/posichain-staking/README.md new file mode 100644 index 000000000..86d2c26cb --- /dev/null +++ b/src/strategies/posichain-staking/README.md @@ -0,0 +1,3 @@ +# Posichain Staking Strategy + +Calculates vote of validators based on the total staking (includes self stake and total balance delegated to them). diff --git a/src/strategies/posichain-total-balance/README.md b/src/strategies/posichain-total-balance/README.md new file mode 100644 index 000000000..6e0b441d3 --- /dev/null +++ b/src/strategies/posichain-total-balance/README.md @@ -0,0 +1,3 @@ +# Posichain Total Balance Strategy + +Calculates vote of validators based on their balance, plus total staking (includes self stake and total balance delegated to them). diff --git a/src/strategies/posichain-total-balance/examples.json b/src/strategies/posichain-total-balance/examples.json new file mode 100644 index 000000000..e89b2fb58 --- /dev/null +++ b/src/strategies/posichain-total-balance/examples.json @@ -0,0 +1,18 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "posichain-total-balance", + "params": { + "symbol": "POSI" + } + }, + "network": "900000", + "addresses": [ + "0xD3Ee1d798eCea22Fde4D29590eFF0c77bA7e6b9e", + "0xb065c1a5BC1B3c1b1dF8781D369cffc534B65731", + "0x7fd592690ec6A7300289B059ee8711f4f9BBfD8a" + ], + "snapshot": 3989273 + } +] diff --git a/src/strategies/posichain-total-balance/index.ts b/src/strategies/posichain-total-balance/index.ts new file mode 100644 index 000000000..3224bb33b --- /dev/null +++ b/src/strategies/posichain-total-balance/index.ts @@ -0,0 +1,72 @@ +import { StaticJsonRpcProvider } from '@ethersproject/providers'; +import { formatUnits } from '@ethersproject/units'; +import { BigNumber } from '@ethersproject/bignumber'; +import { multicall } from '../../utils'; +import networks from '@snapshot-labs/snapshot.js/src/networks.json'; + +export const author = 'dannyposi'; +export const version = '0.0.1'; + +const abi = [ + 'function getEthBalance(address addr) public view returns (uint256 balance)' +]; + +type Params = { + symbol: string; + decimals: number; +}; + +export async function strategy( + _space: string, + network: string, + provider: StaticJsonRpcProvider, + addresses: Array, + options: Params, + snapshot: number | string +) { + const blockTag: number | string = + typeof snapshot === 'number' ? snapshot : 'latest'; + + const stakingResponse: Record = await provider.send( + 'hmyv2_getValidatorsStakeByBlockNumber', + [blockTag] + ); + const stakingBalances = Object.fromEntries( + Object.entries(stakingResponse) + .filter(([address]) => addresses.includes(address)) + .map(([address, balance]) => [ + address, + parseFloat( + formatUnits( + BigNumber.from('0x' + balance.toString(16)), + options && options.decimals ? options.decimals : 18 + ) + ) + ]) + ); + + const balanceResponse = await multicall( + network, + provider, + abi, + addresses.map((address: any) => [ + networks[network].multicall, + 'getEthBalance', + [address] + ]), + { blockTag } + ); + const decimals = options.decimals || 18; + + const currentBalances = Object.fromEntries( + balanceResponse.map((value, i) => [ + addresses[i], + parseFloat(formatUnits(value.toString(), decimals)) + ]) + ); + + return Object.entries(currentBalances).reduce( + (acc, [key, value]) => ({ ...acc, [key]: (acc[key] || 0) + value }), + { ...stakingBalances } + ); +} From 0e77f3df8d88248ed5ad0bcc09697c52b718dcd7 Mon Sep 17 00:00:00 2001 From: G2 Date: Tue, 15 Nov 2022 11:40:51 -0500 Subject: [PATCH 220/815] Poap with weight v2 [poap-with-weight-v2] (#867) * Update to strategy network * v2 New POAP voting strategy that takes eventIDs * ReadME update * Minor change * Update src/strategies/poap-with-weight/examples.json * Update index.ts * tests update updates based on tests * Update src/strategies/poap-with-weight-v2/examples.json Co-authored-by: Alexander Greene * Update src/strategies/poap-with-weight-v2/examples.json Co-authored-by: Alexander Greene * Update src/strategies/poap-with-weight-v2/index.ts Co-authored-by: Alexander Greene * Update src/strategies/poap-with-weight-v2/README.md Co-authored-by: Alexander Greene * Update src/strategies/poap-with-weight-v2/index.ts Co-authored-by: Alexander Greene * Update src/strategies/poap-with-weight-v2/index.ts Co-authored-by: Alexander Greene * Update src/strategies/poap-with-weight-v2/index.ts EventID LIMIT Co-authored-by: Alexander Greene * Update src/strategies/poap-with-weight-v2/index.ts * Update src/strategies/poap-with-weight-v2/index.ts Co-authored-by: Chaitanya Co-authored-by: Alexander Greene --- src/strategies/index.ts | 2 + src/strategies/poap-with-weight-v2/README.md | 17 ++++ .../poap-with-weight-v2/examples.json | 23 +++++ src/strategies/poap-with-weight-v2/index.ts | 91 +++++++++++++++++++ 4 files changed, 133 insertions(+) create mode 100644 src/strategies/poap-with-weight-v2/README.md create mode 100644 src/strategies/poap-with-weight-v2/examples.json create mode 100644 src/strategies/poap-with-weight-v2/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 610b9304b..fe22a92aa 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -186,6 +186,7 @@ import * as unipoolSameToken from './unipool-same-token'; import * as unipoolUniv2Lp from './unipool-univ2-lp'; import * as unipoolXSushi from './unipool-xsushi'; import * as poapWithWeight from './poap-with-weight'; +import * as poapWithWeightV2 from './poap-with-weight-v2'; import * as uniswapV3 from './uniswap-v3'; import * as uniswapV3Staking from './uniswap-v3-staking'; import * as l2Deversifi from './l2-deversifi'; @@ -591,6 +592,7 @@ const strategies = { 'unipool-univ2-lp': unipoolUniv2Lp, 'unipool-xsushi': unipoolXSushi, 'poap-with-weight': poapWithWeight, + 'poap-with-weight-v2': poapWithWeightV2, 'uniswap-v3': uniswapV3, 'uniswap-v3-staking': uniswapV3Staking, 'l2-deversifi': l2Deversifi, diff --git a/src/strategies/poap-with-weight-v2/README.md b/src/strategies/poap-with-weight-v2/README.md new file mode 100644 index 000000000..83d8344aa --- /dev/null +++ b/src/strategies/poap-with-weight-v2/README.md @@ -0,0 +1,17 @@ +# POAP (erc721) eventId with weight + +Each POAP is implemented as an erc721 with a max supply tokens. + +This strategy weights the vote with a specific ERC721 NFT with a given EventId according to the holdings of each POAP and relative scarcity of each NFT. + +Here is an example of parameters: + +```json +{ + "symbol": "POAP", + "eventIds": [ + { "id": "1213", "weight": 10 }, + { "id": "1293", "weight": 1 } + ] +} +``` diff --git a/src/strategies/poap-with-weight-v2/examples.json b/src/strategies/poap-with-weight-v2/examples.json new file mode 100644 index 000000000..40724be29 --- /dev/null +++ b/src/strategies/poap-with-weight-v2/examples.json @@ -0,0 +1,23 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "poap-with-weight-v2", + "params": { + "network": "100", + "symbol": "POAP", + "eventIds": [ + { "id": "1213", "weight": 10 }, + { "id": "1293", "weight": 1 } + ] + } + }, + "network": "1", + "addresses": [ + "0xab6f255dac71103ea6d57b320eaf0eec901b05aa", + "0x878aac6eeaf3e3207d11723b820d6eb1105fa892", + "0x837d21cfda71e93e5257f95ce2c49751675ebcb1" + ], + "snapshot": 13040844 + } +] diff --git a/src/strategies/poap-with-weight-v2/index.ts b/src/strategies/poap-with-weight-v2/index.ts new file mode 100644 index 000000000..cf3572532 --- /dev/null +++ b/src/strategies/poap-with-weight-v2/index.ts @@ -0,0 +1,91 @@ +import { subgraphRequest } from '../../utils'; + +export const author = 'gawainb'; +export const version = '2.0.0'; + +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 EVENT_IDS_LIMIT = 500; +const MAX_TOKENS_PER_PAGE = 1000; + +export async function strategy( + space, + network, + provider, + addresses, + options, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + snapshot +) { + if (options.eventIds.length > EVENT_IDS_LIMIT) { + throw new Error(`Max number (${EVENT_IDS_LIMIT}) of event ids exceeded`); + } + + const eventIds = options.eventIds.map((eventId) => eventId.id); + const addressesMap = addresses.reduce((map, address) => { + map[address.toLowerCase()] = 0; + return map; + }, {}); + + const query = { + tokens: { + __args: { + where: { + event_: { + id_in: eventIds + }, + owner_in: addresses.map(a => a.toLowerCase()) + }, + first: MAX_TOKENS_PER_PAGE, + skip: 0 + }, + event: { + id: true, + tokenCount: true + }, + id: true, + owner: { + id: true + } + } + }; + + while (true) { + const supplyResponse = await subgraphRequest( + POAP_API_ENDPOINT_URL[network], + query + ); + + if (supplyResponse && supplyResponse.tokens) { + const eventIdsWeightMap = options.eventIds.reduce( + (map, { id, weight }) => { + map[id] = weight; + return map; + }, + {} + ); + + supplyResponse.tokens.forEach((token) => { + const tokenOwnerId = token.owner.id.toLowerCase(); + + if (addressesMap[tokenOwnerId] === undefined) return; + + addressesMap[tokenOwnerId] += + eventIdsWeightMap[token.event.id] * parseInt(token.event.tokenCount); + }); + } + + // if the number of tokens received is less than the max per page, + // then we have received all the tokens and can stop making requests + if (supplyResponse?.tokens?.length < MAX_TOKENS_PER_PAGE) { + break; + } + + query.tokens.__args.skip += MAX_TOKENS_PER_PAGE; + } + + return addressesMap; +} From d15be2b6d142d37c808907ab2077f20469b1e7b6 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Tue, 15 Nov 2022 22:40:39 +0530 Subject: [PATCH 221/815] Items type string and uniqueItems true --- src/validations/passport-gated/schema.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/validations/passport-gated/schema.json b/src/validations/passport-gated/schema.json index 59f6dab62..851c7514d 100644 --- a/src/validations/passport-gated/schema.json +++ b/src/validations/passport-gated/schema.json @@ -9,8 +9,12 @@ "stamps": { "type": "array", "title": "Stamps", + "uniqueItems": true, "minItems": 1, - "maxItems": 32 + "maxItems": 32, + "items": { + "type": "string" + } }, "operand": { "type": "string", From 413bec66a1d9d18a671bd8b5e21b2874a7084f09 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Tue, 15 Nov 2022 22:43:59 +0530 Subject: [PATCH 222/815] uniqueItems true for passport validation --- src/validations/passport-weighted/schema.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/validations/passport-weighted/schema.json b/src/validations/passport-weighted/schema.json index 50b2662c1..f728d12e0 100644 --- a/src/validations/passport-weighted/schema.json +++ b/src/validations/passport-weighted/schema.json @@ -9,6 +9,7 @@ "stamps": { "type": "array", "title": "Stamps", + "uniqueItems": true, "minItems": 1, "maxItems": 32, "items": { From ac4770c68a8482fedd3216e88c13930e5f8b53d0 Mon Sep 17 00:00:00 2001 From: G2 Date: Wed, 16 Nov 2022 10:57:42 -0500 Subject: [PATCH 223/815] Remove Network (#952) * Update to strategy network * Update Example.json Removed network parameter * Update examples.json Remove network param --- src/strategies/poap-with-weight-v2/examples.json | 1 - 1 file changed, 1 deletion(-) diff --git a/src/strategies/poap-with-weight-v2/examples.json b/src/strategies/poap-with-weight-v2/examples.json index 40724be29..5cdcc7a1d 100644 --- a/src/strategies/poap-with-weight-v2/examples.json +++ b/src/strategies/poap-with-weight-v2/examples.json @@ -4,7 +4,6 @@ "strategy": { "name": "poap-with-weight-v2", "params": { - "network": "100", "symbol": "POAP", "eventIds": [ { "id": "1213", "weight": 10 }, From eda7af36965cdebbcc69ef4feccbd232039f6c4e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 16 Nov 2022 23:01:58 +0530 Subject: [PATCH 224/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.52 (#953) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 653e0cc59..8643e7671 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.51", + "@snapshot-labs/snapshot.js": "^0.4.52", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index a60d9b25a..43f244646 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.51": - version "0.4.51" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.51.tgz#470dd2894298b576e90c0ffe1f68e49e70d194e7" - integrity sha512-Su8fO0Emu8JR8yzlUxpmNDmdYFhNWZ41HAJdi1KvM+5fh71lA0CWrYHCcFYzwaaZ65K4YGz/ILQmWxG/hhGhXg== +"@snapshot-labs/snapshot.js@^0.4.52": + version "0.4.52" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.52.tgz#cc222236d12ee519d2c46f35ac9b10012d54ca42" + integrity sha512-gm9tQL1FtpjSXf0jGVQgaf31KBMEjUe0ZQPzttu9GvRKCwBAEQosu7T3lcQvUpgIXz87aRAMzFQHouqoMg9rOw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 368130087e7824ba5f57e3a65ca50f6b38144a22 Mon Sep 17 00:00:00 2001 From: jigglyjams <83923290+jigglyjams@users.noreply.github.com> Date: Wed, 16 Nov 2022 23:01:31 -0800 Subject: [PATCH 225/815] feature: update juicebox strategy to support other protocol versions [juicebox] (#947) * feature: update juicebox strategy to support other protocol versions * cleanup: update JBTicketBooth to v2/v3 language, JBTokenStore * Update src/strategies/juicebox/index.ts Co-authored-by: Chaitanya * default: protocolVersion 3 Co-authored-by: Chaitanya --- src/strategies/juicebox/examples.json | 49 ++++++++++++++++++++++++--- src/strategies/juicebox/index.ts | 12 +++++-- 2 files changed, 54 insertions(+), 7 deletions(-) diff --git a/src/strategies/juicebox/examples.json b/src/strategies/juicebox/examples.json index f99cfeb93..2c7062d6b 100644 --- a/src/strategies/juicebox/examples.json +++ b/src/strategies/juicebox/examples.json @@ -5,14 +5,55 @@ "name": "juicebox", "params": { "projectId": "1", - "symbol": "JBX" + "symbol": "JBX", + "protocolVersion": "1" } }, "network": "1", "addresses": [ - "0x754F37225CE0E30639093Af47C16ef057B544b4f", - "0x6877be9E00d0bc5886c28419901E8cC98C1c2739" + "0x63A2368F4B509438ca90186cb1C15156713D5834", + "0x6877be9E00d0bc5886c28419901E8cC98C1c2739", + "0x823b92d6a4b2AED4b15675c7917c9f922ea8ADAD", + "0x1e54110DC48dD83F48187b846DF7E32bB76d0D0b" ], - "snapshot": 13714984 + "snapshot": 15971323 + }, + { + "name": "Juicebox Projects", + "strategy": { + "name": "juicebox", + "params": { + "projectId": "1", + "symbol": "JBX", + "protocolVersion": "2" + } + }, + "network": "1", + "addresses": [ + "0x63A2368F4B509438ca90186cb1C15156713D5834", + "0x6877be9E00d0bc5886c28419901E8cC98C1c2739", + "0x823b92d6a4b2AED4b15675c7917c9f922ea8ADAD", + "0x1e54110DC48dD83F48187b846DF7E32bB76d0D0b" + ], + "snapshot": 15971323 + }, + { + "name": "Juicebox Projects", + "strategy": { + "name": "juicebox", + "params": { + "projectId": "311", + "symbol": "GO", + "protocolVersion": "3" + } + }, + "network": "1", + "addresses": [ + "0x63A2368F4B509438ca90186cb1C15156713D5834", + "0x6877be9E00d0bc5886c28419901E8cC98C1c2739", + "0x823b92d6a4b2AED4b15675c7917c9f922ea8ADAD", + "0x1e54110DC48dD83F48187b846DF7E32bB76d0D0b" + ], + "snapshot": 15971421 } ] diff --git a/src/strategies/juicebox/index.ts b/src/strategies/juicebox/index.ts index f0c7c427a..0036ae46c 100644 --- a/src/strategies/juicebox/index.ts +++ b/src/strategies/juicebox/index.ts @@ -2,9 +2,13 @@ import { formatUnits } from '@ethersproject/units'; import { multicall } from '../../utils'; export const author = 'drgorillamd'; -export const version = '0.1.0'; +export const version = '0.2.0'; -const JBTicketBooth = '0xee2eBCcB7CDb34a8A822b589F9E8427C24351bfc'; +const JBTokenStore = { + 1: '0xee2eBCcB7CDb34a8A822b589F9E8427C24351bfc', + 2: '0xCBB8e16d998161AdB20465830107ca298995f371', + 3: '0x6FA996581D7edaABE62C15eaE19fEeD4F1DdDfE7' +}; const abi = ['function balanceOf(address, uint256) view returns (uint256)']; export async function strategy( @@ -22,7 +26,9 @@ export async function strategy( provider, abi, addresses.map((address: any) => [ - JBTicketBooth, + options.protocolVersion + ? JBTokenStore[options.protocolVersion] + : JBTokenStore['3'], 'balanceOf', [address, options.projectId] ]), From a91b0ed7a26d7f184b8dcb17cbc7b74d684cadef Mon Sep 17 00:00:00 2001 From: bonustrack Date: Fri, 18 Nov 2022 09:12:02 +0700 Subject: [PATCH 226/815] feat: Add multichain serie strategy --- src/strategies/index.ts | 4 +- src/strategies/multichain-serie/examples.json | 36 +++++++++++ src/strategies/multichain-serie/index.ts | 59 +++++++++++++++++++ 3 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 src/strategies/multichain-serie/examples.json create mode 100644 src/strategies/multichain-serie/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index fe22a92aa..7d4efe192 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -398,6 +398,7 @@ import * as offchainDelegation from './offchain-delegation'; import * as dslaParametricStakingServiceCredits from './dsla-parametric-staking-service-credits'; import * as rep3Badges from './rep3-badges'; import * as marsecosystem from './marsecosystem'; +import * as multichainSerie from './multichain-serie'; const strategies = { 'forta-shares': fortaShares, @@ -801,7 +802,8 @@ const strategies = { 'dsla-parametric-staking-service-credits': dslaParametricStakingServiceCredits, 'rep3-badges': rep3Badges, - marsecosystem + marsecosystem, + 'multichain-serie': multichainSerie }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/multichain-serie/examples.json b/src/strategies/multichain-serie/examples.json new file mode 100644 index 000000000..70aa3639e --- /dev/null +++ b/src/strategies/multichain-serie/examples.json @@ -0,0 +1,36 @@ +[ + { + "name": "Multichain serie", + "strategy": { + "name": "multichain-serie", + "params": { + "symbol": "MULTI", + "strategies": [ + { + "name": "erc20-balance-of", + "network": "137", + "params": { + "address": "0xB9638272aD6998708de56BBC0A290a1dE534a578", + "decimals": 18 + } + }, + { + "name": "erc20-balance-of", + "network": "56", + "params": { + "address": "0x0e37d70b51ffa2b98b4d34a5712c5291115464e3", + "decimals": 18 + } + } + ] + } + }, + "network": "1", + "addresses": [ + "0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5", + "0x9feab70f3c4a944b97b7565bac4991df5b7a69ff", + "0xaca39b187352d9805deced6e73a3d72abf86e7a0" + ], + "snapshot": 13035566 + } +] diff --git a/src/strategies/multichain-serie/index.ts b/src/strategies/multichain-serie/index.ts new file mode 100644 index 000000000..a4abd59d4 --- /dev/null +++ b/src/strategies/multichain-serie/index.ts @@ -0,0 +1,59 @@ +import { getProvider, getSnapshots } from '../../utils'; +import strategies from '..'; + +export const author = 'kesar'; +export const version = '1.1.0'; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const promises: any = []; + const blocks = await getSnapshots( + network, + snapshot, + provider, + options.strategies.map((s) => s.network || network) + ); + + for (const strategy of options.strategies) { + // If snapshot is taken before a network is activated then ignore its strategies + if ( + options.startBlocks && + blocks[strategy.network] < options.startBlocks[strategy.network] + ) { + continue; + } + + promises.push( + strategies[strategy.name].strategy( + space, + strategy.network, + getProvider(strategy.network), + addresses, + strategy.params, + blocks[strategy.network] + ) + ); + } + + const results: any = []; + for (const promise of promises) { + const result = await promise; + results.push(result); + } + + return results.reduce((finalResults: any, strategyResult: any) => { + for (const [address, value] of Object.entries(strategyResult)) { + if (!finalResults[address]) { + finalResults[address] = 0; + } + finalResults[address] += value; + } + return finalResults; + }, {}); +} From 4b7a133c9427a70615745569258447536eb93470 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Fri, 18 Nov 2022 16:34:07 +0530 Subject: [PATCH 227/815] passport-gated validation update (#949) * passport-gated validation update * Add default stamp to weighted * Update src/validations/passport-gated/schema.json * Update src/validations/passport-gated/schema.json * Update src/validations/passport-gated/schema.json * Update src/validations/passport-gated/schema.json Co-authored-by: Sam <51686767+samuveth@users.noreply.github.com> --- src/validations/passport-gated/examples.json | 4 ++-- src/validations/passport-gated/index.ts | 6 +++--- src/validations/passport-gated/schema.json | 19 +++++++++++++------ .../passport-weighted/examples.json | 2 +- src/validations/passport-weighted/schema.json | 4 +++- test/validation.test.ts | 4 ++-- 6 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/validations/passport-gated/examples.json b/src/validations/passport-gated/examples.json index d9f3d615a..ce52e78e0 100644 --- a/src/validations/passport-gated/examples.json +++ b/src/validations/passport-gated/examples.json @@ -9,11 +9,11 @@ "stamps": [ "Ens", "Twitter", - "GitHub", + "Github", "POAP", "SnapshotVotesProvider" ], - "operand": "OR" + "operator": "OR" } } ] diff --git a/src/validations/passport-gated/index.ts b/src/validations/passport-gated/index.ts index 649f59c26..55627fc03 100644 --- a/src/validations/passport-gated/index.ts +++ b/src/validations/passport-gated/index.ts @@ -28,15 +28,15 @@ export default class extends Validation { const provider = snapshot.utils.getProvider(this.network); const proposalTs = (await provider.getBlock(this.snapshot)).timestamp; - const operand = this.params.operand || 'AND'; + const operator = this.params.operator || 'AND'; const validStamps = verifiedStamps.filter( (stamp) => hasValidIssuanceAndExpiration(stamp.credential, proposalTs) && this.params.stamps.includes(stamp.provider) ); - if (operand === 'AND') { + if (operator === 'AND') { return validStamps.length === this.params.stamps.length; - } else if (operand === 'OR') { + } else if (operator === 'OR') { return validStamps.length > 0; } else { return false; diff --git a/src/validations/passport-gated/schema.json b/src/validations/passport-gated/schema.json index 851c7514d..4b2f5360c 100644 --- a/src/validations/passport-gated/schema.json +++ b/src/validations/passport-gated/schema.json @@ -13,15 +13,22 @@ "minItems": 1, "maxItems": 32, "items": { - "type": "string" + "type": "string", + "enum": ["Google", "Ens", "Poh", "Twitter", "TwitterTweetGT10", "TwitterFollowerGT100", "TwitterFollowerGT500", "TwitterFollowerGTE1000", "TwitterFollowerGT5000", "POAP", "Facebook", "FacebookFriends", "FacebookProfilePicture", "Brightid", "Github", "FiveOrMoreGithubRepos", "ForkedGithubRepoProvider", "StarredGithubRepoProvider", "TenOrMoreGithubFollowers", "FiftyOrMoreGithubFollowers", "GitcoinContributorStatistics#numGrantsContributeToGte#1", "GitcoinContributorStatistics#numGrantsContributeToGte#10", "GitcoinContributorStatistics#numGrantsContributeToGte#25", "GitcoinContributorStatistics#numGrantsContributeToGte#100", "GitcoinContributorStatistics#totalContributionAmountGte#10", "GitcoinContributorStatistics#totalContributionAmountGte#100", "GitcoinContributorStatistics#totalContributionAmountGte#1000", "GitcoinContributorStatistics#numGr14ContributionsGte#1", "GitcoinContributorStatistics#numRoundsContributedToGte#1", "GitcoinGranteeStatistics#numOwnedGrants#1", "GitcoinGranteeStatistics#numGrantContributors#10", "GitcoinGranteeStatistics#numGrantContributors#25", "GitcoinGranteeStatistics#numGrantContributors#100", "GitcoinGranteeStatistics#totalContributionAmount#100", "GitcoinGranteeStatistics#totalContributionAmount#1000", "GitcoinGranteeStatistics#totalContributionAmount#10000", "GitcoinGranteeStatistics#numGrantsInEcoAndCauseRound#1", "Linkedin", "Discord", "Signer", "GitPOAP", "SnapshotVotesProvider", "SnapshotProposalsProvider", "ethPossessionsGte#1", "ethPossessionsGte#10", "ethPossessionsGte#32", "FirstEthTxnProvider", "EthGTEOneTxnProvider", "EthGasProvider", "gtcPossessionsGte#10", "gtcPossessionsGte#100", "SelfStakingBronze", "SelfStakingSilver", "SelfStakingGold", "CommunityStakingBronze", "CommunityStakingSilver", "CommunityStakingGold", "NFT", "ZkSync", "Lens", "GnosisSafe"] } }, - "operand": { + "operator": { "type": "string", - "title": "Operand", - "enum": [ - "AND", - "OR" + "title": "Select approval operator", + "description": "Control how many or which stamps are required to vote.", + "anyOf": [{ + "const": "AND", + "title": "Require all stamps" + }, + { + "const": "OR", + "title": "Require at least one stamp" + } ] } }, diff --git a/src/validations/passport-weighted/examples.json b/src/validations/passport-weighted/examples.json index e070203e9..28fbb99d1 100644 --- a/src/validations/passport-weighted/examples.json +++ b/src/validations/passport-weighted/examples.json @@ -9,7 +9,7 @@ "stamps": [ { "id": "Ens", "weight": 2 }, { "id": "Twitter", "weight": 0.5 }, - { "id": "GitHub", "weight": 0.5 }, + { "id": "Github", "weight": 0.5 }, { "id": "POAP", "weight": 2 }, { "id": "SnapshotVotesProvider", "weight": 2 } ], diff --git a/src/validations/passport-weighted/schema.json b/src/validations/passport-weighted/schema.json index f728d12e0..da53f1cc2 100644 --- a/src/validations/passport-weighted/schema.json +++ b/src/validations/passport-weighted/schema.json @@ -17,13 +17,15 @@ "properties": { "id": { "type": "string", - "title": "Id" + "title": "Id", + "enum": ["Google", "Ens", "Poh", "Twitter", "TwitterTweetGT10", "TwitterFollowerGT100", "TwitterFollowerGT500", "TwitterFollowerGTE1000", "TwitterFollowerGT5000", "POAP", "Facebook", "FacebookFriends", "FacebookProfilePicture", "Brightid", "Github", "FiveOrMoreGithubRepos", "ForkedGithubRepoProvider", "StarredGithubRepoProvider", "TenOrMoreGithubFollowers", "FiftyOrMoreGithubFollowers", "GitcoinContributorStatistics#numGrantsContributeToGte#1", "GitcoinContributorStatistics#numGrantsContributeToGte#10", "GitcoinContributorStatistics#numGrantsContributeToGte#25", "GitcoinContributorStatistics#numGrantsContributeToGte#100", "GitcoinContributorStatistics#totalContributionAmountGte#10", "GitcoinContributorStatistics#totalContributionAmountGte#100", "GitcoinContributorStatistics#totalContributionAmountGte#1000", "GitcoinContributorStatistics#numGr14ContributionsGte#1", "GitcoinContributorStatistics#numRoundsContributedToGte#1", "GitcoinGranteeStatistics#numOwnedGrants#1", "GitcoinGranteeStatistics#numGrantContributors#10", "GitcoinGranteeStatistics#numGrantContributors#25", "GitcoinGranteeStatistics#numGrantContributors#100", "GitcoinGranteeStatistics#totalContributionAmount#100", "GitcoinGranteeStatistics#totalContributionAmount#1000", "GitcoinGranteeStatistics#totalContributionAmount#10000", "GitcoinGranteeStatistics#numGrantsInEcoAndCauseRound#1", "Linkedin", "Discord", "Signer", "GitPOAP", "SnapshotVotesProvider", "SnapshotProposalsProvider", "ethPossessionsGte#1", "ethPossessionsGte#10", "ethPossessionsGte#32", "FirstEthTxnProvider", "EthGTEOneTxnProvider", "EthGasProvider", "gtcPossessionsGte#10", "gtcPossessionsGte#100", "SelfStakingBronze", "SelfStakingSilver", "SelfStakingGold", "CommunityStakingBronze", "CommunityStakingSilver", "CommunityStakingGold", "NFT", "ZkSync", "Lens", "GnosisSafe"] }, "weight": { "type": "number", "title": "Weight" } }, + "default": { "id": "Ens", "weight": "1" }, "required": [ "id", "weight" diff --git a/test/validation.test.ts b/test/validation.test.ts index 1b269e927..0de09f2b3 100644 --- a/test/validation.test.ts +++ b/test/validation.test.ts @@ -1,6 +1,6 @@ +import snapshotjs from '@snapshot-labs/snapshot.js'; import snapshot from '../src'; import examples from '../src/validations/passport-gated/examples.json'; -import snapshotjs from '@snapshot-labs/snapshot.js'; const [example] = examples; const id = 'passport-gated'; @@ -11,7 +11,7 @@ describe('validation', () => { example.author, example.space, example.network, - 'latest', + example.snapshot, example.params ); expect(await validation.validate()).toBe(true); From 0b0fa300b234cfcb52781744dd56055d868f02b0 Mon Sep 17 00:00:00 2001 From: Danilo Tuler Date: Fri, 18 Nov 2022 09:11:06 -0300 Subject: [PATCH 228/815] [ctsi-staking] new strategy for CTSI Staking (#954) --- src/strategies/ctsi-staking/README.md | 23 +++ src/strategies/ctsi-staking/examples.json | 26 ++++ src/strategies/ctsi-staking/index.ts | 172 ++++++++++++++++++++++ src/strategies/ctsi-staking/schema.json | 23 +++ src/strategies/index.ts | 4 +- 5 files changed, 247 insertions(+), 1 deletion(-) create mode 100644 src/strategies/ctsi-staking/README.md create mode 100644 src/strategies/ctsi-staking/examples.json create mode 100644 src/strategies/ctsi-staking/index.ts create mode 100644 src/strategies/ctsi-staking/schema.json diff --git a/src/strategies/ctsi-staking/README.md b/src/strategies/ctsi-staking/README.md new file mode 100644 index 000000000..4281a8eaf --- /dev/null +++ b/src/strategies/ctsi-staking/README.md @@ -0,0 +1,23 @@ +# ctsi-staking + +This strategy implements the rules of CTSI Staking, returning the staked balance of the voters. It supports direct staking, as well as delegated staking through staking pools. + +There are no parameters to configure. + +The diagram below represents Cartesi Staking system: + +```mermaid +graph TD + U1[User 1] -->|stake| Staking{Staking} + U2[User 2] -->|operate| P1 + P1(Pool 1) -->|stake| Staking + U3[User 3] -->|stake| P1 +``` + +Cartesi staking system is primarily consolidated in the [StakingImpl contract](https://etherscan.io/address/0x9EdEAdFDE65BCfD0907db3AcdB3445229c764A69#readContract). Stakers to this contract can be EOA who stake directly, as the `User 1` above, or can be a [Staking Pool](https://github.com/cartesi/staking-pool), as the `Pool 1` above. + +Staking Pools are smart contracts, so in this case the voting power is delegated to its operator, given by the `owner` of the pool smart contract, represented by `User 2` above. + +Those users who do not wish to stake directly or operate a pool can stake to a pool instead, like the `User 3` represented in the diagram. As described above, pool operators accumulates the voting power of all its stakers. + +Note that an EOA can be at the same time a direct staker and a pool operator. Voting powers are accumulated. diff --git a/src/strategies/ctsi-staking/examples.json b/src/strategies/ctsi-staking/examples.json new file mode 100644 index 000000000..389209388 --- /dev/null +++ b/src/strategies/ctsi-staking/examples.json @@ -0,0 +1,26 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "ctsi-staking", + "params": { + "expectedResults": { + "scores": { + "0xf977814e90da44bfa03b6295a0616a897441acec": 51704200, + "0xc71c504d2a2938a173660ae71b3e97b563196bea": 36765082, + "0x2942aa4356783892c624125acfbbb80d29629a9d": 0, + "0xb5ba4a130f9e30036d1c1db11a8913caf3acdeba": 34404167.25798815 + } + } + } + }, + "network": "1", + "addresses": [ + "0xf977814e90da44bfa03b6295a0616a897441acec", + "0xc71c504d2a2938a173660ae71b3e97b563196bea", + "0x2942aa4356783892c624125acfbbb80d29629a9d", + "0xb5ba4a130f9e30036d1c1db11a8913caf3acdeba" + ], + "snapshot": 15951825 + } +] diff --git a/src/strategies/ctsi-staking/index.ts b/src/strategies/ctsi-staking/index.ts new file mode 100644 index 000000000..802c55ee5 --- /dev/null +++ b/src/strategies/ctsi-staking/index.ts @@ -0,0 +1,172 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { getAddress } from '@ethersproject/address'; +import { subgraphRequest } from '../../utils'; + +export const author = 'cartesi'; +export const version = '0.1.0'; + +const SUBGRAPH_URL_ROOT = 'https://api.thegraph.com/subgraphs/name/cartesi/pos'; + +const NETWORK_KEY = { + '1': '', + '5': '-goerli' +}; + +function buildSubgraphUrl(chainId) { + const networkString = NETWORK_KEY[chainId]; + return `${SUBGRAPH_URL_ROOT}${networkString}`; +} + +async function getStakingBalance( + url, + addresses, + options, + snapshot +): Promise> { + // query for direct stakers (no pools) + const query = { + users: { + __args: { + where: { + id_in: addresses, + pool: null + }, + first: 1000 + }, + id: true, + balance: true + } + }; + if (snapshot !== 'latest') { + // @ts-ignore + query.users.__args.block = { number: snapshot }; + } + const score: Record = {}; + const result = await subgraphRequest(url, query); + if (result && result.users) { + result.users.forEach((user) => { + const address = getAddress(user.id); + const balance = BigNumber.from(user.balance); + score[address] = balance; + }); + } + + return score; +} + +async function getStakingPoolOperatorBalance( + url, + addresses, + options, + snapshot +): Promise> { + // query for StakingPools by manager (pool operator) + const query = { + stakingPools: { + __args: { + where: { + manager_in: addresses + }, + first: 1000 + }, + manager: true, + user: { + balance: true + } + } + }; + if (snapshot !== 'latest') { + // @ts-ignore + query.stakingPools.__args.block = { number: snapshot }; + } + const score: Record = {}; + const result = await subgraphRequest(url, query); + if (result && result.stakingPools) { + result.stakingPools.forEach((pool) => { + const address = getAddress(pool.manager); + const balance = BigNumber.from(pool.user.balance); + // a pool operator can operate more than one pool, so we must add the value if there is already one + score[address] = score[address] ? score[address].add(balance) : balance; + }); + } + + return score; +} + +function combineBalanceScores( + records: Record[] +): Record { + return records.reduce((aggScore, currScore) => { + for (const [address, balance] of Object.entries(currScore)) { + if (!aggScore[address]) { + aggScore[address] = balance; + } else { + aggScore[address] = aggScore[address].add(balance); // sum(L1, L2) + } + } + return aggScore; + }, {}); +} + +function verifyResults( + results: Record, + expectedResults: Record +): void { + Object.entries(results).forEach(([address, score]) => { + const expectedScore = + expectedResults[address.toLowerCase()] ?? + expectedResults[getAddress(address)]; + if (score !== expectedScore) { + console.error( + `>>> ERROR: Score do not match for address ${address}, expected ${expectedScore}, got ${score}` + ); + } + }); +} + +export async function strategy( + _space, + network, + _provider, + addresses, + options, + snapshot +): Promise> { + // convert addresses to lowercase, as in subgraph they are all lowercase + addresses = addresses.map((address) => address.toLowerCase()); + + // build subgraph URL based on network, as we have one for mainnet and another for goerli + const url = buildSubgraphUrl(network); + + // get staking balance for all direct stakers as voters (no pools, no delegators) + const directStaking = await getStakingBalance( + url, + addresses, + options, + snapshot + ); + + // get balance of pools operated by voters + const operators = await getStakingPoolOperatorBalance( + url, + addresses, + options, + snapshot + ); + + const results = combineBalanceScores([directStaking, operators]); + const scores = Object.fromEntries( + Object.entries(results).map(([address, balance]) => [ + address, + parseFloat(formatUnits(balance, 18)) + ]) + ); + + if (options.expectedResults && snapshot !== 'latest') { + // validate testing expected results + verifyResults(scores, options.expectedResults.scores); + } + + return scores; +} diff --git a/src/strategies/ctsi-staking/schema.json b/src/strategies/ctsi-staking/schema.json new file mode 100644 index 000000000..006ba35fb --- /dev/null +++ b/src/strategies/ctsi-staking/schema.json @@ -0,0 +1,23 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "expectedResults": { + "type": "object", + "properties": { + "scores": { + "type": "object", + "additionalProperties": { "type": "number" } + } + } + } + }, + "required": [], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 7d4efe192..07605ac7f 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -399,6 +399,7 @@ import * as dslaParametricStakingServiceCredits from './dsla-parametric-staking- import * as rep3Badges from './rep3-badges'; import * as marsecosystem from './marsecosystem'; import * as multichainSerie from './multichain-serie'; +import * as ctsiStaking from './ctsi-staking'; const strategies = { 'forta-shares': fortaShares, @@ -803,7 +804,8 @@ const strategies = { dslaParametricStakingServiceCredits, 'rep3-badges': rep3Badges, marsecosystem, - 'multichain-serie': multichainSerie + 'multichain-serie': multichainSerie, + 'ctsi-staking': ctsiStaking }; Object.keys(strategies).forEach(function (strategyName) { From 640ca49d8eede608beba4b487d45438d0e01b4ff Mon Sep 17 00:00:00 2001 From: Sam <51686767+samuveth@users.noreply.github.com> Date: Sat, 19 Nov 2022 14:27:35 +0700 Subject: [PATCH 229/815] Add titles (#955) --- src/validations/passport-gated/schema.json | 242 ++++++++++++++++++++- 1 file changed, 236 insertions(+), 6 deletions(-) diff --git a/src/validations/passport-gated/schema.json b/src/validations/passport-gated/schema.json index 4b2f5360c..5e01f1962 100644 --- a/src/validations/passport-gated/schema.json +++ b/src/validations/passport-gated/schema.json @@ -14,14 +14,246 @@ "maxItems": 32, "items": { "type": "string", - "enum": ["Google", "Ens", "Poh", "Twitter", "TwitterTweetGT10", "TwitterFollowerGT100", "TwitterFollowerGT500", "TwitterFollowerGTE1000", "TwitterFollowerGT5000", "POAP", "Facebook", "FacebookFriends", "FacebookProfilePicture", "Brightid", "Github", "FiveOrMoreGithubRepos", "ForkedGithubRepoProvider", "StarredGithubRepoProvider", "TenOrMoreGithubFollowers", "FiftyOrMoreGithubFollowers", "GitcoinContributorStatistics#numGrantsContributeToGte#1", "GitcoinContributorStatistics#numGrantsContributeToGte#10", "GitcoinContributorStatistics#numGrantsContributeToGte#25", "GitcoinContributorStatistics#numGrantsContributeToGte#100", "GitcoinContributorStatistics#totalContributionAmountGte#10", "GitcoinContributorStatistics#totalContributionAmountGte#100", "GitcoinContributorStatistics#totalContributionAmountGte#1000", "GitcoinContributorStatistics#numGr14ContributionsGte#1", "GitcoinContributorStatistics#numRoundsContributedToGte#1", "GitcoinGranteeStatistics#numOwnedGrants#1", "GitcoinGranteeStatistics#numGrantContributors#10", "GitcoinGranteeStatistics#numGrantContributors#25", "GitcoinGranteeStatistics#numGrantContributors#100", "GitcoinGranteeStatistics#totalContributionAmount#100", "GitcoinGranteeStatistics#totalContributionAmount#1000", "GitcoinGranteeStatistics#totalContributionAmount#10000", "GitcoinGranteeStatistics#numGrantsInEcoAndCauseRound#1", "Linkedin", "Discord", "Signer", "GitPOAP", "SnapshotVotesProvider", "SnapshotProposalsProvider", "ethPossessionsGte#1", "ethPossessionsGte#10", "ethPossessionsGte#32", "FirstEthTxnProvider", "EthGTEOneTxnProvider", "EthGasProvider", "gtcPossessionsGte#10", "gtcPossessionsGte#100", "SelfStakingBronze", "SelfStakingSilver", "SelfStakingGold", "CommunityStakingBronze", "CommunityStakingSilver", "CommunityStakingGold", "NFT", "ZkSync", "Lens", "GnosisSafe"] + "anyOf": [ + { + "const": "Google", + "title": "Google account" + }, + { + "const": "Ens", + "title": "ENS owner" + }, + { + "const": "Poh", + "title": "Proof of humanity" + }, + { + "const": "Twitter", + "title": "Twitter account" + }, + { + "const": "TwitterTweetGT10", + "title": "Twitter followers > 10" + }, + { + "const": "TwitterFollowerGT100", + "title": "Twitter followers > 100" + }, + { + "const": "TwitterFollowerGT500", + "title": "Twitter followers > 500" + }, + { + "const": "TwitterFollowerGTE1000", + "title": "Twitter followers > 1000" + }, + { + "const": "TwitterFollowerGT5000", + "title": "Twitter followers > 5000" + }, + { + "const": "POAP", + "title": "POAP onwer" + }, + { + "const": "Facebook", + "title": "Facebook account" + }, + { + "const": "FacebookFriends", + "title": "Facebook friends > 100" + }, + { + "const": "FacebookProfilePicture", + "title": "Facebook profile picture" + }, + { + "const": "Brightid", + "title": "Brightid" + }, + { + "const": "Github", + "title": "Github account" + }, + { + "const": "FiveOrMoreGithubRepos", + "title": "Github repos > 4" + }, + { + "const": "ForkedGithubRepoProvider", + "title": "Github repo forked" + }, + { + "const": "StarredGithubRepoProvider", + "title": "Github repo starred" + }, + { + "const": "TenOrMoreGithubFollowers", + "title": "Github followers > 9" + }, + { + "const": "FiftyOrMoreGithubFollowers", + "title": "Github followers > 49" + }, + { + "const": "GitcoinContributorStatistics#numGrantsContributeToGte#1", + "title": "Grants contributed > 1" + }, + + { + "const": "GitcoinContributorStatistics#numGrantsContributeToGte#10", + "title": "Grants contributed > 10" + }, + { + "const": "GitcoinContributorStatistics#numGrantsContributeToGte#25", + "title": "Grants contributed > 25" + }, + { + "const": "GitcoinContributorStatistics#numGrantsContributeToGte#100", + "title": "Grants contributed > 100" + }, + { + "const": "GitcoinContributorStatistics#totalContributionAmountGte#10", + "title": "Grant contributions > $10" + }, + { + "const": "GitcoinContributorStatistics#totalContributionAmountGte#100", + "title": "Grant contributions > $100" + }, + { + "const": "GitcoinContributorStatistics#totalContributionAmountGte#1000", + "title": "Grant contributions > $1000" + }, + { + "const": "GitcoinGranteeStatistics#numOwnedGrants#1", + "title": "Grant owner > 1" + }, + { + "const": "GitcoinGranteeStatistics#numGrantContributors#10", + "title": "Grant contributors > 10" + }, + { + "const": "GitcoinGranteeStatistics#numGrantContributors#25", + "title": "Grant contributors > 25" + }, + + { + "const": "GitcoinGranteeStatistics#numGrantContributors#100", + "title": "Grant contributors > 100" + }, + { + "const": "GitcoinGranteeStatistics#totalContributionAmount#100", + "title": "Grant contributions > $100" + }, + { + "const": "GitcoinGranteeStatistics#totalContributionAmount#1000", + "title": "Grant contributions > $1000" + }, + { + "const": "GitcoinGranteeStatistics#totalContributionAmount#10000", + "title": "Grant contributions > $10000" + }, + { + "const": "GitcoinGranteeStatistics#numGrantsInEcoAndCauseRound#1", + "title": "Grant owner Eco & Cause" + }, + { + "const": "Linkedin", + "title": "Linkedin account" + }, + { + "const": "Discord", + "title": "Discord account" + }, + { + "const": "SnapshotVotesProvider", + "title": "Snapshot voter" + }, + { + "const": "SnapshotProposalsProvider", + "title": "Snapshot proposer" + }, + { + "const": "ethPossessionsGte#1", + "title": "ETH > 1" + }, + { + "const": "ethPossessionsGte#10", + "title": "ETH > 10" + }, + { + "const": "ethPossessionsGte#32", + "title": "ETH > 32" + }, + { + "const": "FirstEthTxnProvider", + "title": "First ETH > 30 days" + }, + { + "const": "EthGTEOneTxnProvider", + "title": "ETH tx > 1" + }, + { + "const": "EthGasProvider", + "title": "ETH gas > 0.5" + }, + { + "const": "gtcPossessionsGte#10", + "title": "Gitcoin GTC > 10" + }, + { + "const": "gtcPossessionsGte#100", + "title": "Gitcoin GTC > 100" + }, + { + "const": "SelfStakingBronze", + "title": "GTC staked > 1" + }, + { + "const": "SelfStakingSilver", + "title": "GTC staked > 10" + }, + { + "const": "SelfStakingGold", + "title": "GTC staked > 100" + }, + { + "const": "CommunityStakingBronze", + "title": "Comm GTC staked > 1" + }, + { + "const": "CommunityStakingSilver", + "title": "Comm GTC staked > 10" + }, + { + "const": "CommunityStakingGold", + "title": "Comm GTC staked > 100" + }, + { + "const": "NFT", + "title": "NFT holder" + }, + { + "const": "ZkSync", + "title": "ZkSync account" + }, + { + "const": "Lens", + "title": "Lens account" + }, + { + "const": "GnosisSafe", + "title": "GnosisSafe singer/owner" + } + ] } }, "operator": { "type": "string", - "title": "Select approval operator", + "title": "Approval operator", "description": "Control how many or which stamps are required to vote.", - "anyOf": [{ + "anyOf": [ + { "const": "AND", "title": "Require all stamps" }, @@ -32,9 +264,7 @@ ] } }, - "required": [ - "stamps" - ], + "required": ["stamps"], "additionalProperties": false } } From 293696bffeba12024dd4b5c3b4e70c2070c1560d Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Sun, 20 Nov 2022 01:11:31 +0530 Subject: [PATCH 230/815] Fix multichain-serie strategy memory issue --- src/strategies/multichain-serie/index.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/strategies/multichain-serie/index.ts b/src/strategies/multichain-serie/index.ts index a4abd59d4..98b3d9982 100644 --- a/src/strategies/multichain-serie/index.ts +++ b/src/strategies/multichain-serie/index.ts @@ -12,7 +12,7 @@ export async function strategy( options, snapshot ) { - const promises: any = []; + const results: any = []; const blocks = await getSnapshots( network, snapshot, @@ -29,8 +29,8 @@ export async function strategy( continue; } - promises.push( - strategies[strategy.name].strategy( + results.push( + await strategies[strategy.name].strategy( space, strategy.network, getProvider(strategy.network), @@ -41,12 +41,6 @@ export async function strategy( ); } - const results: any = []; - for (const promise of promises) { - const result = await promise; - results.push(result); - } - return results.reduce((finalResults: any, strategyResult: any) => { for (const [address, value] of Object.entries(strategyResult)) { if (!finalResults[address]) { From 4b4f6c820f2b46cbd81788350a4e5800853ef236 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 20 Nov 2022 16:17:23 +0530 Subject: [PATCH 231/815] Automated lint (#956) Co-authored-by: ChaituVR --- src/strategies/poap-with-weight-v2/index.ts | 2 +- src/validations/passport-gated/examples.json | 8 +- src/validations/passport-weighted/schema.json | 74 ++++++++++++++++--- 3 files changed, 67 insertions(+), 17 deletions(-) diff --git a/src/strategies/poap-with-weight-v2/index.ts b/src/strategies/poap-with-weight-v2/index.ts index cf3572532..3a8a0571b 100644 --- a/src/strategies/poap-with-weight-v2/index.ts +++ b/src/strategies/poap-with-weight-v2/index.ts @@ -37,7 +37,7 @@ export async function strategy( event_: { id_in: eventIds }, - owner_in: addresses.map(a => a.toLowerCase()) + owner_in: addresses.map((a) => a.toLowerCase()) }, first: MAX_TOKENS_PER_PAGE, skip: 0 diff --git a/src/validations/passport-gated/examples.json b/src/validations/passport-gated/examples.json index ce52e78e0..cb8e122df 100644 --- a/src/validations/passport-gated/examples.json +++ b/src/validations/passport-gated/examples.json @@ -6,13 +6,7 @@ "network": "1", "snapshot": "latest", "params": { - "stamps": [ - "Ens", - "Twitter", - "Github", - "POAP", - "SnapshotVotesProvider" - ], + "stamps": ["Ens", "Twitter", "Github", "POAP", "SnapshotVotesProvider"], "operator": "OR" } } diff --git a/src/validations/passport-weighted/schema.json b/src/validations/passport-weighted/schema.json index da53f1cc2..39cb04820 100644 --- a/src/validations/passport-weighted/schema.json +++ b/src/validations/passport-weighted/schema.json @@ -18,7 +18,69 @@ "id": { "type": "string", "title": "Id", - "enum": ["Google", "Ens", "Poh", "Twitter", "TwitterTweetGT10", "TwitterFollowerGT100", "TwitterFollowerGT500", "TwitterFollowerGTE1000", "TwitterFollowerGT5000", "POAP", "Facebook", "FacebookFriends", "FacebookProfilePicture", "Brightid", "Github", "FiveOrMoreGithubRepos", "ForkedGithubRepoProvider", "StarredGithubRepoProvider", "TenOrMoreGithubFollowers", "FiftyOrMoreGithubFollowers", "GitcoinContributorStatistics#numGrantsContributeToGte#1", "GitcoinContributorStatistics#numGrantsContributeToGte#10", "GitcoinContributorStatistics#numGrantsContributeToGte#25", "GitcoinContributorStatistics#numGrantsContributeToGte#100", "GitcoinContributorStatistics#totalContributionAmountGte#10", "GitcoinContributorStatistics#totalContributionAmountGte#100", "GitcoinContributorStatistics#totalContributionAmountGte#1000", "GitcoinContributorStatistics#numGr14ContributionsGte#1", "GitcoinContributorStatistics#numRoundsContributedToGte#1", "GitcoinGranteeStatistics#numOwnedGrants#1", "GitcoinGranteeStatistics#numGrantContributors#10", "GitcoinGranteeStatistics#numGrantContributors#25", "GitcoinGranteeStatistics#numGrantContributors#100", "GitcoinGranteeStatistics#totalContributionAmount#100", "GitcoinGranteeStatistics#totalContributionAmount#1000", "GitcoinGranteeStatistics#totalContributionAmount#10000", "GitcoinGranteeStatistics#numGrantsInEcoAndCauseRound#1", "Linkedin", "Discord", "Signer", "GitPOAP", "SnapshotVotesProvider", "SnapshotProposalsProvider", "ethPossessionsGte#1", "ethPossessionsGte#10", "ethPossessionsGte#32", "FirstEthTxnProvider", "EthGTEOneTxnProvider", "EthGasProvider", "gtcPossessionsGte#10", "gtcPossessionsGte#100", "SelfStakingBronze", "SelfStakingSilver", "SelfStakingGold", "CommunityStakingBronze", "CommunityStakingSilver", "CommunityStakingGold", "NFT", "ZkSync", "Lens", "GnosisSafe"] + "enum": [ + "Google", + "Ens", + "Poh", + "Twitter", + "TwitterTweetGT10", + "TwitterFollowerGT100", + "TwitterFollowerGT500", + "TwitterFollowerGTE1000", + "TwitterFollowerGT5000", + "POAP", + "Facebook", + "FacebookFriends", + "FacebookProfilePicture", + "Brightid", + "Github", + "FiveOrMoreGithubRepos", + "ForkedGithubRepoProvider", + "StarredGithubRepoProvider", + "TenOrMoreGithubFollowers", + "FiftyOrMoreGithubFollowers", + "GitcoinContributorStatistics#numGrantsContributeToGte#1", + "GitcoinContributorStatistics#numGrantsContributeToGte#10", + "GitcoinContributorStatistics#numGrantsContributeToGte#25", + "GitcoinContributorStatistics#numGrantsContributeToGte#100", + "GitcoinContributorStatistics#totalContributionAmountGte#10", + "GitcoinContributorStatistics#totalContributionAmountGte#100", + "GitcoinContributorStatistics#totalContributionAmountGte#1000", + "GitcoinContributorStatistics#numGr14ContributionsGte#1", + "GitcoinContributorStatistics#numRoundsContributedToGte#1", + "GitcoinGranteeStatistics#numOwnedGrants#1", + "GitcoinGranteeStatistics#numGrantContributors#10", + "GitcoinGranteeStatistics#numGrantContributors#25", + "GitcoinGranteeStatistics#numGrantContributors#100", + "GitcoinGranteeStatistics#totalContributionAmount#100", + "GitcoinGranteeStatistics#totalContributionAmount#1000", + "GitcoinGranteeStatistics#totalContributionAmount#10000", + "GitcoinGranteeStatistics#numGrantsInEcoAndCauseRound#1", + "Linkedin", + "Discord", + "Signer", + "GitPOAP", + "SnapshotVotesProvider", + "SnapshotProposalsProvider", + "ethPossessionsGte#1", + "ethPossessionsGte#10", + "ethPossessionsGte#32", + "FirstEthTxnProvider", + "EthGTEOneTxnProvider", + "EthGasProvider", + "gtcPossessionsGte#10", + "gtcPossessionsGte#100", + "SelfStakingBronze", + "SelfStakingSilver", + "SelfStakingGold", + "CommunityStakingBronze", + "CommunityStakingSilver", + "CommunityStakingGold", + "NFT", + "ZkSync", + "Lens", + "GnosisSafe" + ] }, "weight": { "type": "number", @@ -26,10 +88,7 @@ } }, "default": { "id": "Ens", "weight": "1" }, - "required": [ - "id", - "weight" - ], + "required": ["id", "weight"], "additionalProperties": false } }, @@ -38,10 +97,7 @@ "title": "Min. weight" } }, - "required": [ - "stamps", - "min_weight" - ], + "required": ["stamps", "min_weight"], "additionalProperties": false } } From b877e587a94edd98d74137f5b0e3a3ba875dc503 Mon Sep 17 00:00:00 2001 From: Dominik Opyd Date: Sun, 20 Nov 2022 19:00:05 +0100 Subject: [PATCH 232/815] feat(strategy): ari10 tokens locked in staking (#941) Co-authored-by: Chaitanya --- .../ari10-staking-locked/examples.json | 20 +++++++++ src/strategies/ari10-staking-locked/index.ts | 36 ++++++++++++++++ .../ari10-staking-locked/schema.json | 42 +++++++++++++++++++ src/strategies/index.ts | 2 + 4 files changed, 100 insertions(+) create mode 100644 src/strategies/ari10-staking-locked/examples.json create mode 100644 src/strategies/ari10-staking-locked/index.ts create mode 100644 src/strategies/ari10-staking-locked/schema.json diff --git a/src/strategies/ari10-staking-locked/examples.json b/src/strategies/ari10-staking-locked/examples.json new file mode 100644 index 000000000..313b53862 --- /dev/null +++ b/src/strategies/ari10-staking-locked/examples.json @@ -0,0 +1,20 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "ari10-staking-locked", + "params": { + "address": "0xBCC1b6477B52212fb62734D21bC0ecAE684B4970", + "input": "lockedAmount", + "weight": 1 + } + }, + "network": "56", + "addresses": [ + "0x6cb10a891e5713d34076bbecd16d898f26b84b33", + "0xab59182e57fd3e4a459c36b6473b82b0d91d840f", + "0xf58951274cf026db8277f898204f954e8d3e56a3" + ], + "snapshot": 22879530 + } +] diff --git a/src/strategies/ari10-staking-locked/index.ts b/src/strategies/ari10-staking-locked/index.ts new file mode 100644 index 000000000..2d817d947 --- /dev/null +++ b/src/strategies/ari10-staking-locked/index.ts @@ -0,0 +1,36 @@ +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'oritwoen'; +export const version = '0.1.0'; + +const abi = [ + 'function userInfo(uint256, address) external view returns (uint256 amount, uint256 lockedAmount)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multi = new Multicaller(network, provider, abi, { blockTag }); + + addresses.forEach((address) => + multi.call(address, options.address, 'userInfo', [0, address]) + ) + + const result: Record = await multi.execute(); + + return Object.fromEntries( + Object.entries(result).map(([address, info]) => [ + address, + parseFloat(formatUnits(info[options.input], 18)) * options.weight + ]) + ); +} diff --git a/src/strategies/ari10-staking-locked/schema.json b/src/strategies/ari10-staking-locked/schema.json new file mode 100644 index 000000000..a020d06b2 --- /dev/null +++ b/src/strategies/ari10-staking-locked/schema.json @@ -0,0 +1,42 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "address": { + "type": "string", + "title": "Contract address", + "examples": [ + "e.g. 0xBCC1b6477B52212fb62734D21bC0ecAE684B4970" + ], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "input": { + "type": "string", + "title": "Input", + "examples": [ + "e.g. lockedAmount" + ] + }, + "weight": { + "type": "number", + "title": "Weight", + "examples": [ + "e.g. 3" + ] + } + }, + "required": [ + "address", + "input", + "weight" + ], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 07605ac7f..fae161ae0 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -398,6 +398,7 @@ import * as offchainDelegation from './offchain-delegation'; import * as dslaParametricStakingServiceCredits from './dsla-parametric-staking-service-credits'; import * as rep3Badges from './rep3-badges'; import * as marsecosystem from './marsecosystem'; +import * as ari10StakingLocked from './ari10-staking-locked'; import * as multichainSerie from './multichain-serie'; import * as ctsiStaking from './ctsi-staking'; @@ -804,6 +805,7 @@ const strategies = { dslaParametricStakingServiceCredits, 'rep3-badges': rep3Badges, marsecosystem, + 'ari10-staking-locked': ari10StakingLocked, 'multichain-serie': multichainSerie, 'ctsi-staking': ctsiStaking }; From 135aa2abb292e52fe0b489c97183eb8f21937eca Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Sun, 20 Nov 2022 23:34:16 +0530 Subject: [PATCH 233/815] copy passport-gated items to passport-weighted --- src/validations/passport-weighted/schema.json | 293 ++++++++++++++---- 1 file changed, 231 insertions(+), 62 deletions(-) diff --git a/src/validations/passport-weighted/schema.json b/src/validations/passport-weighted/schema.json index 39cb04820..71eb7364c 100644 --- a/src/validations/passport-weighted/schema.json +++ b/src/validations/passport-weighted/schema.json @@ -18,68 +18,237 @@ "id": { "type": "string", "title": "Id", - "enum": [ - "Google", - "Ens", - "Poh", - "Twitter", - "TwitterTweetGT10", - "TwitterFollowerGT100", - "TwitterFollowerGT500", - "TwitterFollowerGTE1000", - "TwitterFollowerGT5000", - "POAP", - "Facebook", - "FacebookFriends", - "FacebookProfilePicture", - "Brightid", - "Github", - "FiveOrMoreGithubRepos", - "ForkedGithubRepoProvider", - "StarredGithubRepoProvider", - "TenOrMoreGithubFollowers", - "FiftyOrMoreGithubFollowers", - "GitcoinContributorStatistics#numGrantsContributeToGte#1", - "GitcoinContributorStatistics#numGrantsContributeToGte#10", - "GitcoinContributorStatistics#numGrantsContributeToGte#25", - "GitcoinContributorStatistics#numGrantsContributeToGte#100", - "GitcoinContributorStatistics#totalContributionAmountGte#10", - "GitcoinContributorStatistics#totalContributionAmountGte#100", - "GitcoinContributorStatistics#totalContributionAmountGte#1000", - "GitcoinContributorStatistics#numGr14ContributionsGte#1", - "GitcoinContributorStatistics#numRoundsContributedToGte#1", - "GitcoinGranteeStatistics#numOwnedGrants#1", - "GitcoinGranteeStatistics#numGrantContributors#10", - "GitcoinGranteeStatistics#numGrantContributors#25", - "GitcoinGranteeStatistics#numGrantContributors#100", - "GitcoinGranteeStatistics#totalContributionAmount#100", - "GitcoinGranteeStatistics#totalContributionAmount#1000", - "GitcoinGranteeStatistics#totalContributionAmount#10000", - "GitcoinGranteeStatistics#numGrantsInEcoAndCauseRound#1", - "Linkedin", - "Discord", - "Signer", - "GitPOAP", - "SnapshotVotesProvider", - "SnapshotProposalsProvider", - "ethPossessionsGte#1", - "ethPossessionsGte#10", - "ethPossessionsGte#32", - "FirstEthTxnProvider", - "EthGTEOneTxnProvider", - "EthGasProvider", - "gtcPossessionsGte#10", - "gtcPossessionsGte#100", - "SelfStakingBronze", - "SelfStakingSilver", - "SelfStakingGold", - "CommunityStakingBronze", - "CommunityStakingSilver", - "CommunityStakingGold", - "NFT", - "ZkSync", - "Lens", - "GnosisSafe" + "anyOf": [ + { + "const": "Google", + "title": "Google account" + }, + { + "const": "Ens", + "title": "ENS owner" + }, + { + "const": "Poh", + "title": "Proof of humanity" + }, + { + "const": "Twitter", + "title": "Twitter account" + }, + { + "const": "TwitterTweetGT10", + "title": "Twitter followers > 10" + }, + { + "const": "TwitterFollowerGT100", + "title": "Twitter followers > 100" + }, + { + "const": "TwitterFollowerGT500", + "title": "Twitter followers > 500" + }, + { + "const": "TwitterFollowerGTE1000", + "title": "Twitter followers > 1000" + }, + { + "const": "TwitterFollowerGT5000", + "title": "Twitter followers > 5000" + }, + { + "const": "POAP", + "title": "POAP onwer" + }, + { + "const": "Facebook", + "title": "Facebook account" + }, + { + "const": "FacebookFriends", + "title": "Facebook friends > 100" + }, + { + "const": "FacebookProfilePicture", + "title": "Facebook profile picture" + }, + { + "const": "Brightid", + "title": "Brightid" + }, + { + "const": "Github", + "title": "Github account" + }, + { + "const": "FiveOrMoreGithubRepos", + "title": "Github repos > 4" + }, + { + "const": "ForkedGithubRepoProvider", + "title": "Github repo forked" + }, + { + "const": "StarredGithubRepoProvider", + "title": "Github repo starred" + }, + { + "const": "TenOrMoreGithubFollowers", + "title": "Github followers > 9" + }, + { + "const": "FiftyOrMoreGithubFollowers", + "title": "Github followers > 49" + }, + { + "const": "GitcoinContributorStatistics#numGrantsContributeToGte#1", + "title": "Grants contributed > 1" + }, + + { + "const": "GitcoinContributorStatistics#numGrantsContributeToGte#10", + "title": "Grants contributed > 10" + }, + { + "const": "GitcoinContributorStatistics#numGrantsContributeToGte#25", + "title": "Grants contributed > 25" + }, + { + "const": "GitcoinContributorStatistics#numGrantsContributeToGte#100", + "title": "Grants contributed > 100" + }, + { + "const": "GitcoinContributorStatistics#totalContributionAmountGte#10", + "title": "Grant contributions > $10" + }, + { + "const": "GitcoinContributorStatistics#totalContributionAmountGte#100", + "title": "Grant contributions > $100" + }, + { + "const": "GitcoinContributorStatistics#totalContributionAmountGte#1000", + "title": "Grant contributions > $1000" + }, + { + "const": "GitcoinGranteeStatistics#numOwnedGrants#1", + "title": "Grant owner > 1" + }, + { + "const": "GitcoinGranteeStatistics#numGrantContributors#10", + "title": "Grant contributors > 10" + }, + { + "const": "GitcoinGranteeStatistics#numGrantContributors#25", + "title": "Grant contributors > 25" + }, + + { + "const": "GitcoinGranteeStatistics#numGrantContributors#100", + "title": "Grant contributors > 100" + }, + { + "const": "GitcoinGranteeStatistics#totalContributionAmount#100", + "title": "Grant contributions > $100" + }, + { + "const": "GitcoinGranteeStatistics#totalContributionAmount#1000", + "title": "Grant contributions > $1000" + }, + { + "const": "GitcoinGranteeStatistics#totalContributionAmount#10000", + "title": "Grant contributions > $10000" + }, + { + "const": "GitcoinGranteeStatistics#numGrantsInEcoAndCauseRound#1", + "title": "Grant owner Eco & Cause" + }, + { + "const": "Linkedin", + "title": "Linkedin account" + }, + { + "const": "Discord", + "title": "Discord account" + }, + { + "const": "SnapshotVotesProvider", + "title": "Snapshot voter" + }, + { + "const": "SnapshotProposalsProvider", + "title": "Snapshot proposer" + }, + { + "const": "ethPossessionsGte#1", + "title": "ETH > 1" + }, + { + "const": "ethPossessionsGte#10", + "title": "ETH > 10" + }, + { + "const": "ethPossessionsGte#32", + "title": "ETH > 32" + }, + { + "const": "FirstEthTxnProvider", + "title": "First ETH > 30 days" + }, + { + "const": "EthGTEOneTxnProvider", + "title": "ETH tx > 1" + }, + { + "const": "EthGasProvider", + "title": "ETH gas > 0.5" + }, + { + "const": "gtcPossessionsGte#10", + "title": "Gitcoin GTC > 10" + }, + { + "const": "gtcPossessionsGte#100", + "title": "Gitcoin GTC > 100" + }, + { + "const": "SelfStakingBronze", + "title": "GTC staked > 1" + }, + { + "const": "SelfStakingSilver", + "title": "GTC staked > 10" + }, + { + "const": "SelfStakingGold", + "title": "GTC staked > 100" + }, + { + "const": "CommunityStakingBronze", + "title": "Comm GTC staked > 1" + }, + { + "const": "CommunityStakingSilver", + "title": "Comm GTC staked > 10" + }, + { + "const": "CommunityStakingGold", + "title": "Comm GTC staked > 100" + }, + { + "const": "NFT", + "title": "NFT holder" + }, + { + "const": "ZkSync", + "title": "ZkSync account" + }, + { + "const": "Lens", + "title": "Lens account" + }, + { + "const": "GnosisSafe", + "title": "GnosisSafe singer/owner" + } ] }, "weight": { From 9b680698b2e3577b9a0ec90c3d914d4d5adfbcad Mon Sep 17 00:00:00 2001 From: Alexander Greene Date: Mon, 21 Nov 2022 11:20:49 -0600 Subject: [PATCH 234/815] fix: [poap-with-weight-v2] voting power (#958) * fix: poap with weight v2 voting power * the addressesMap addresses must be in valid format * convert lowercased address to valid address * Delete examples-vp.json * Delete voting-power.test.ts * Update src/strategies/poap-with-weight-v2/index.ts Co-authored-by: Chaitanya --- src/strategies/poap-with-weight-v2/index.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/strategies/poap-with-weight-v2/index.ts b/src/strategies/poap-with-weight-v2/index.ts index 3a8a0571b..44571c4c4 100644 --- a/src/strategies/poap-with-weight-v2/index.ts +++ b/src/strategies/poap-with-weight-v2/index.ts @@ -1,3 +1,4 @@ +import { getAddress } from '@ethersproject/address'; import { subgraphRequest } from '../../utils'; export const author = 'gawainb'; @@ -26,7 +27,7 @@ export async function strategy( const eventIds = options.eventIds.map((eventId) => eventId.id); const addressesMap = addresses.reduce((map, address) => { - map[address.toLowerCase()] = 0; + map[getAddress(address)] = 0; return map; }, {}); @@ -69,7 +70,7 @@ export async function strategy( ); supplyResponse.tokens.forEach((token) => { - const tokenOwnerId = token.owner.id.toLowerCase(); + const tokenOwnerId = getAddress(token.owner.id); if (addressesMap[tokenOwnerId] === undefined) return; From c6e52491315c4dc8b2b893dc22315e762deb2c0a Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Mon, 21 Nov 2022 22:57:34 +0530 Subject: [PATCH 235/815] Make sure returned addresses are checksum (#960) --- test/strategy.test.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/strategy.test.ts b/test/strategy.test.ts index b532c23e2..d16342365 100644 --- a/test/strategy.test.ts +++ b/test/strategy.test.ts @@ -106,12 +106,10 @@ describe.each(examples)( ); }); - it('Returned addresses should be either same case as input addresses or checksum addresses', () => { + it('Returned addresses should be checksum addresses', () => { expect( Object.keys(scores[0]).every( - (address) => - example.addresses.includes(address) || - getAddress(address) === address + (address) => getAddress(address) === address ) ).toBe(true); }); From a34990b65185cbc9f66cee3314bfc851bd8c1071 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Wed, 23 Nov 2022 18:59:29 +0530 Subject: [PATCH 236/815] Delegation strategies to ignore override (#961) * Delegation strategies to ignore override * Add own score if not delegated to anyone --- .../README.md | 12 ++++ .../examples.json | 21 ++++++ .../erc20-balance-of-with-delegation/index.ts | 33 +++++++++ src/strategies/index.ts | 4 ++ src/strategies/with-delegation/README.md | 42 ++++++++++++ src/strategies/with-delegation/examples.json | 28 ++++++++ src/strategies/with-delegation/index.ts | 67 +++++++++++++++++++ src/utils/delegation.ts | 30 +++++++++ 8 files changed, 237 insertions(+) create mode 100644 src/strategies/erc20-balance-of-with-delegation/README.md create mode 100644 src/strategies/erc20-balance-of-with-delegation/examples.json create mode 100644 src/strategies/erc20-balance-of-with-delegation/index.ts create mode 100644 src/strategies/with-delegation/README.md create mode 100644 src/strategies/with-delegation/examples.json create mode 100644 src/strategies/with-delegation/index.ts diff --git a/src/strategies/erc20-balance-of-with-delegation/README.md b/src/strategies/erc20-balance-of-with-delegation/README.md new file mode 100644 index 000000000..7c750a4eb --- /dev/null +++ b/src/strategies/erc20-balance-of-with-delegation/README.md @@ -0,0 +1,12 @@ +# erc20-balance-of-with-delegation + +Similar to `with-delegation` strategy, but it uses `erc20-balance-of` strategy to calculate voting power + +## Params + +| Param Name | Description | +| ---------- | ----------- | +| address | The address of the token contract | +| symbol | The symbol of the token | +| decimals | The number of decimals of the token | +| delegationSpace (optional) | Get delegations of a particular space (by default it take delegations of current space) | diff --git a/src/strategies/erc20-balance-of-with-delegation/examples.json b/src/strategies/erc20-balance-of-with-delegation/examples.json new file mode 100644 index 000000000..065aca672 --- /dev/null +++ b/src/strategies/erc20-balance-of-with-delegation/examples.json @@ -0,0 +1,21 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "erc20-balance-of-with-delegation", + "params": { + "symbol": "POHD", + "address": "0x1dAD862095d40d43c2109370121cf087632874dB", + "decimals": 0, + "delegationSpace": "poh.eth" + } + }, + "network": "1", + "addresses": [ + "0x3c13f2B56AF614aC6381265EcB3B619bA26CC641", + "0x048fee7c3279a24af0790b6b002ded42be021d2b", + "0x139a9032a46c3afe3456eb5f0a35183b5f189cae" + ], + "snapshot": 15705816 + } +] diff --git a/src/strategies/erc20-balance-of-with-delegation/index.ts b/src/strategies/erc20-balance-of-with-delegation/index.ts new file mode 100644 index 000000000..f4096b7d7 --- /dev/null +++ b/src/strategies/erc20-balance-of-with-delegation/index.ts @@ -0,0 +1,33 @@ +import { strategy as withDelegationStrategy } from '../with-delegation'; + +export const author = 'snapshot-labs'; +export const version = '0.1.0'; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + return await withDelegationStrategy( + space, + network, + provider, + addresses, + { + ...options, + strategies: [ + { + name: 'erc20-balance-of', + params: { + address: options.address, + decimals: options.decimals + } + } + ] + }, + snapshot + ); +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index fae161ae0..963482a9e 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -26,6 +26,7 @@ import * as erc20BalanceOfFixedTotal from './erc20-balance-of-fixed-total'; import * as erc20BalanceOfCv from './erc20-balance-of-cv'; import * as erc20WithBalance from './erc20-with-balance'; import * as erc20BalanceOfDelegation from './erc20-balance-of-delegation'; +import * as erc20BalanceOfWithDelegation from './erc20-balance-of-with-delegation'; import * as erc20BalanceOfQuadraticDelegation from './erc20-balance-of-quadratic-delegation'; import * as erc20BalanceOfWeighted from './erc20-balance-of-weighted'; import * as ethalendBalanceOf from './ethalend-balance-of'; @@ -89,6 +90,7 @@ import * as stakedKeep from './staked-keep'; import * as stakedDaomaker from './staked-daomaker'; import * as typhoon from './typhoon'; import * as delegation from './delegation'; +import * as withDelegation from './with-delegation'; import * as ticket from './ticket'; import * as work from './work'; import * as ticketValidity from './ticket-validity'; @@ -441,6 +443,7 @@ const strategies = { 'erc20-balance-of-coeff': erc20BalanceOfCoeff, 'erc20-with-balance': erc20WithBalance, 'erc20-balance-of-delegation': erc20BalanceOfDelegation, + 'erc20-balance-of-with-delegation': erc20BalanceOfWithDelegation, 'erc20-balance-of-quadratic-delegation': erc20BalanceOfQuadraticDelegation, 'erc20-balance-of-weighted': erc20BalanceOfWeighted, 'minto-balance-of-all': mintoBalanceAll, @@ -512,6 +515,7 @@ const strategies = { 'balancer-unipool': balancerUnipool, typhoon, delegation, + 'with-delegation': withDelegation, ticket, work, 'ticket-validity': ticketValidity, diff --git a/src/strategies/with-delegation/README.md b/src/strategies/with-delegation/README.md new file mode 100644 index 000000000..ccf3ca6fa --- /dev/null +++ b/src/strategies/with-delegation/README.md @@ -0,0 +1,42 @@ +# with-delegation + +If you want to delegate your voting power to another wallet address, +Unlike `delegation` strategy, delegator can't take back their voting power from the delegatee. and also delegate's voting power is added up. so no need to have an additional strategy + +```TEXT +Total VP = delegated VP + own VP (if not delegated to anyone) +``` + +The sub strategies defined in params are used to delegate vote from one address to another. + +| 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 take delegations of current space) | + +Here is an example of parameters: + +```json +{ + "symbol": "YFI (delegated)", + "strategies": [ + { + "name": "erc20-balance-of", + "params": { + "address": "0xBa37B002AbaFDd8E89a1995dA52740bbC013D992", + "symbol": "YFI", + "decimals": 18 + } + }, + { + "name": "yearn-vault", + "params": { + "address": "0xBA2E7Fed597fd0E3e70f5130BcDbbFE06bB94fe1", + "symbol": "YFI (yYFI)", + "decimals": 18 + } + } + ] +} + +``` \ No newline at end of file diff --git a/src/strategies/with-delegation/examples.json b/src/strategies/with-delegation/examples.json new file mode 100644 index 000000000..c9af9fe7e --- /dev/null +++ b/src/strategies/with-delegation/examples.json @@ -0,0 +1,28 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "with-delegation", + "params": { + "symbol": "POH (delegated)", + "delegationSpace": "poh.eth", + "strategies": [ + { + "name": "erc20-balance-of", + "params": { + "address": "0x1dAD862095d40d43c2109370121cf087632874dB", + "decimals": 0 + } + } + ] + } + }, + "network": "1", + "addresses": [ + "0x3c13f2B56AF614aC6381265EcB3B619bA26CC641", + "0x048fee7c3279a24af0790b6b002ded42be021d2b", + "0x139a9032a46c3afe3456eb5f0a35183b5f189cae" + ], + "snapshot": 15705816 + } +] diff --git a/src/strategies/with-delegation/index.ts b/src/strategies/with-delegation/index.ts new file mode 100644 index 000000000..f01e60503 --- /dev/null +++ b/src/strategies/with-delegation/index.ts @@ -0,0 +1,67 @@ +import { getAddress } from '@ethersproject/address'; +import { getDelegationsData } from '../../utils/delegation'; +import { getScoresDirect } from '../../utils'; + +export const author = 'snapshot-labs'; +export const version = '0.1.0'; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + addresses = addresses.map(getAddress); + const delegationSpace = options.delegationSpace || space; + const delegationsData = await getDelegationsData( + delegationSpace, + network, + addresses, + snapshot + ); + const delegations = delegationsData.delegations; + + // Get scores for all addresses and delegators + if (Object.keys(delegations).length === 0) return {}; + const allAddresses = Object.values(delegations).reduce( + (a: string[], b: string[]) => a.concat(b), + [] + ); + allAddresses.push(...addresses); + const scores = ( + await getScoresDirect( + space, + options.strategies, + network, + provider, + allAddresses, + snapshot + ) + ).filter((score) => Object.keys(score).length !== 0); + + const finalScore = Object.fromEntries( + addresses.map((address) => { + const addressScore = delegations[address] + ? delegations[address].reduce( + (a, b) => a + scores.reduce((x, y) => (y[b] ? x + y[b] : x), 0), + 0 + ) + : 0; + return [address, addressScore]; + }) + ); + + // Add own scores if not delegated to anyone + addresses.forEach((address) => { + if (!delegationsData.allDelegators.includes(address)) { + finalScore[address] += scores.reduce( + (a, b) => a + (b[address] ? b[address] : 0), + 0 + ); + } + }); + + return finalScore; +} diff --git a/src/utils/delegation.ts b/src/utils/delegation.ts index 251cc7702..2ad4522d9 100644 --- a/src/utils/delegation.ts +++ b/src/utils/delegation.ts @@ -1,6 +1,7 @@ import { getAddress } from '@ethersproject/address'; import { getDelegatesBySpace } from '../utils'; +// delegations with overrides export async function getDelegations(space, network, addresses, snapshot) { const addressesLc = addresses.map((addresses) => addresses.toLowerCase()); const delegatesBySpace = await getDelegatesBySpace(network, space, snapshot); @@ -33,3 +34,32 @@ export async function getDelegations(space, network, addresses, snapshot) { ]) ); } + +export async function getDelegationsData(space, network, addresses, snapshot) { + const delegatesBySpace = await getDelegatesBySpace(network, space, snapshot); + const delegationsReverse = {}; + delegatesBySpace.forEach( + (delegation: any) => + (delegationsReverse[delegation.delegator] = delegation.delegate) + ); + delegatesBySpace + .filter((delegation: any) => delegation.space !== '') + .forEach( + (delegation: any) => + (delegationsReverse[delegation.delegator] = delegation.delegate) + ); + + return { + delegations: Object.fromEntries( + addresses.map((address) => [ + address, + Object.entries(delegationsReverse) + .filter(([, delegate]) => address.toLowerCase() === delegate) + .map(([delegator]) => getAddress(delegator)) + ]) + ), + allDelegators: Object.keys(delegationsReverse).map((delegator) => + getAddress(delegator) + ) + }; +} From 4669111b180bd54a26f4fabddba39aa3233f696b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 23 Nov 2022 19:06:57 +0530 Subject: [PATCH 237/815] Automated lint (#962) Co-authored-by: ChaituVR --- .../ari10-staking-locked/examples.json | 36 +++++----- src/strategies/ari10-staking-locked/index.ts | 38 +++++------ .../ari10-staking-locked/schema.json | 66 ++++++++----------- 3 files changed, 65 insertions(+), 75 deletions(-) diff --git a/src/strategies/ari10-staking-locked/examples.json b/src/strategies/ari10-staking-locked/examples.json index 313b53862..328208711 100644 --- a/src/strategies/ari10-staking-locked/examples.json +++ b/src/strategies/ari10-staking-locked/examples.json @@ -1,20 +1,20 @@ [ - { - "name": "Example query", - "strategy": { - "name": "ari10-staking-locked", - "params": { - "address": "0xBCC1b6477B52212fb62734D21bC0ecAE684B4970", - "input": "lockedAmount", - "weight": 1 - } - }, - "network": "56", - "addresses": [ - "0x6cb10a891e5713d34076bbecd16d898f26b84b33", - "0xab59182e57fd3e4a459c36b6473b82b0d91d840f", - "0xf58951274cf026db8277f898204f954e8d3e56a3" - ], - "snapshot": 22879530 - } + { + "name": "Example query", + "strategy": { + "name": "ari10-staking-locked", + "params": { + "address": "0xBCC1b6477B52212fb62734D21bC0ecAE684B4970", + "input": "lockedAmount", + "weight": 1 + } + }, + "network": "56", + "addresses": [ + "0x6cb10a891e5713d34076bbecd16d898f26b84b33", + "0xab59182e57fd3e4a459c36b6473b82b0d91d840f", + "0xf58951274cf026db8277f898204f954e8d3e56a3" + ], + "snapshot": 22879530 + } ] diff --git a/src/strategies/ari10-staking-locked/index.ts b/src/strategies/ari10-staking-locked/index.ts index 2d817d947..3a865b4fa 100644 --- a/src/strategies/ari10-staking-locked/index.ts +++ b/src/strategies/ari10-staking-locked/index.ts @@ -6,31 +6,31 @@ export const author = 'oritwoen'; export const version = '0.1.0'; const abi = [ - 'function userInfo(uint256, address) external view returns (uint256 amount, uint256 lockedAmount)' + 'function userInfo(uint256, address) external view returns (uint256 amount, uint256 lockedAmount)' ]; export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot + space, + network, + provider, + addresses, + options, + snapshot ): Promise> { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - const multi = new Multicaller(network, provider, abi, { blockTag }); + const multi = new Multicaller(network, provider, abi, { blockTag }); - addresses.forEach((address) => - multi.call(address, options.address, 'userInfo', [0, address]) - ) + addresses.forEach((address) => + multi.call(address, options.address, 'userInfo', [0, address]) + ); - const result: Record = await multi.execute(); + const result: Record = await multi.execute(); - return Object.fromEntries( - Object.entries(result).map(([address, info]) => [ - address, - parseFloat(formatUnits(info[options.input], 18)) * options.weight - ]) - ); + return Object.fromEntries( + Object.entries(result).map(([address, info]) => [ + address, + parseFloat(formatUnits(info[options.input], 18)) * options.weight + ]) + ); } diff --git a/src/strategies/ari10-staking-locked/schema.json b/src/strategies/ari10-staking-locked/schema.json index a020d06b2..ed5c641e3 100644 --- a/src/strategies/ari10-staking-locked/schema.json +++ b/src/strategies/ari10-staking-locked/schema.json @@ -1,42 +1,32 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", - "$ref": "#/definitions/Strategy", - "definitions": { - "Strategy": { - "title": "Strategy", - "type": "object", - "properties": { - "address": { - "type": "string", - "title": "Contract address", - "examples": [ - "e.g. 0xBCC1b6477B52212fb62734D21bC0ecAE684B4970" - ], - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - }, - "input": { - "type": "string", - "title": "Input", - "examples": [ - "e.g. lockedAmount" - ] - }, - "weight": { - "type": "number", - "title": "Weight", - "examples": [ - "e.g. 3" - ] - } - }, - "required": [ - "address", - "input", - "weight" - ], - "additionalProperties": false + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "address": { + "type": "string", + "title": "Contract address", + "examples": ["e.g. 0xBCC1b6477B52212fb62734D21bC0ecAE684B4970"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "input": { + "type": "string", + "title": "Input", + "examples": ["e.g. lockedAmount"] + }, + "weight": { + "type": "number", + "title": "Weight", + "examples": ["e.g. 3"] } + }, + "required": ["address", "input", "weight"], + "additionalProperties": false } + } } From 75a2d38f477e4035ff89d65f72b7450794ea78f5 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Thu, 24 Nov 2022 02:00:12 +0530 Subject: [PATCH 238/815] Add delegationNetwork param (#963) * Add delegationNetwork param * Update README.md --- .../erc20-balance-of-with-delegation/README.md | 1 + src/strategies/with-delegation/README.md | 7 +++++-- src/strategies/with-delegation/index.ts | 15 ++++++++++++--- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/strategies/erc20-balance-of-with-delegation/README.md b/src/strategies/erc20-balance-of-with-delegation/README.md index 7c750a4eb..6c1014d5e 100644 --- a/src/strategies/erc20-balance-of-with-delegation/README.md +++ b/src/strategies/erc20-balance-of-with-delegation/README.md @@ -10,3 +10,4 @@ Similar to `with-delegation` strategy, but it uses `erc20-balance-of` strategy t | symbol | The symbol of the token | | decimals | The number of decimals of the token | | delegationSpace (optional) | Get delegations of a particular space (by default it take delegations of current space) | +| delegationNetwork (optional) | Get delegations of a particular network (by default it take delegations of current network) | diff --git a/src/strategies/with-delegation/README.md b/src/strategies/with-delegation/README.md index ccf3ca6fa..a63464cc2 100644 --- a/src/strategies/with-delegation/README.md +++ b/src/strategies/with-delegation/README.md @@ -7,12 +7,15 @@ Unlike `delegation` strategy, delegator can't take back their voting power from Total VP = delegated VP + own VP (if not delegated to anyone) ``` -The sub strategies defined in params are used to delegate vote from one address to another. +The sub strategies defined in params are used to delegate vote from one address to another. + +> Important Note: Don't pass strategies that need override | 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 take delegations of current space) | +| delegationNetwork (optional) | Get delegations of a particular network (by default it take delegations of current network) | Here is an example of parameters: @@ -39,4 +42,4 @@ Here is an example of parameters: ] } -``` \ No newline at end of file +``` diff --git a/src/strategies/with-delegation/index.ts b/src/strategies/with-delegation/index.ts index f01e60503..71ae7d6db 100644 --- a/src/strategies/with-delegation/index.ts +++ b/src/strategies/with-delegation/index.ts @@ -1,6 +1,6 @@ import { getAddress } from '@ethersproject/address'; import { getDelegationsData } from '../../utils/delegation'; -import { getScoresDirect } from '../../utils'; +import { getScoresDirect, getSnapshots } from '../../utils'; export const author = 'snapshot-labs'; export const version = '0.1.0'; @@ -15,11 +15,20 @@ export async function strategy( ) { addresses = addresses.map(getAddress); const delegationSpace = options.delegationSpace || space; + const delegationNetwork = options.delegationNetwork || network; + let delegationSnapshot = snapshot; + if (delegationNetwork !== network) { + const snapshots = await getSnapshots(network, snapshot, provider, [ + delegationNetwork + ]); + delegationSnapshot = snapshots[delegationNetwork]; + } + const delegationsData = await getDelegationsData( delegationSpace, - network, + delegationNetwork, addresses, - snapshot + delegationSnapshot ); const delegations = delegationsData.delegations; From 87ff2e2e0a89f3d8e04238d779654bac3170333c Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Thu, 24 Nov 2022 22:30:21 +0530 Subject: [PATCH 239/815] [spreadsheet] gid fix (#964) * [spreadsheet] gid fix * Update schema.json --- src/strategies/spreadsheet/index.ts | 2 +- src/strategies/spreadsheet/schema.json | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/strategies/spreadsheet/index.ts b/src/strategies/spreadsheet/index.ts index 3c0e375c9..dc7ef4f5b 100644 --- a/src/strategies/spreadsheet/index.ts +++ b/src/strategies/spreadsheet/index.ts @@ -28,7 +28,7 @@ export async function strategy( const ts = block.timestamp; const res = await fetch( - `https://docs.google.com/spreadsheets/d/e/${options.sheetId}/pub?gid=${options.gid}&single=true&output=csv` + `https://docs.google.com/spreadsheets/d/e/${options.sheetId}/pub?gid=${options.gid || "0"}&single=true&output=csv` ); const text = await res.text(); const csv = (csvToJson(text) || []).map((item) => ({ diff --git a/src/strategies/spreadsheet/schema.json b/src/strategies/spreadsheet/schema.json index 661725000..b8bfd544c 100644 --- a/src/strategies/spreadsheet/schema.json +++ b/src/strategies/spreadsheet/schema.json @@ -12,13 +12,18 @@ "examples": ["e.g. UNI"], "maxLength": 16 }, - "id": { + "sheetId": { "type": "string", "title": "Spreadsheet id", "examples": ["e.g. 2PACX-1vTmam7vShzrscND..."] + }, + "gid": { + "type": "string", + "title": "gid", + "examples": ["0"] } }, - "required": ["id"], + "required": ["sheetId"], "additionalProperties": false } } From 08c6febcad91661463da31ac7e1002c0dc46f1fd Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Fri, 25 Nov 2022 10:23:48 +0530 Subject: [PATCH 240/815] Multiquery to individual calls to get stamp streams (#965) --- src/validations/passport-gated/index.ts | 28 +++++--- src/validations/passport-gated/schema.json | 2 +- src/validations/passport-weighted/helper.ts | 69 ++++++++++++------- src/validations/passport-weighted/schema.json | 2 +- 4 files changed, 65 insertions(+), 36 deletions(-) diff --git a/src/validations/passport-gated/index.ts b/src/validations/passport-gated/index.ts index 55627fc03..7febbdc08 100644 --- a/src/validations/passport-gated/index.ts +++ b/src/validations/passport-gated/index.ts @@ -12,14 +12,15 @@ export default class extends Validation { public version = '0.1.0'; async validate(): Promise { + const requiredStamps = this.params.stamps; const passport: any = await getPassport(this.author); if (!passport) return false; - if (!passport.stamps?.length || !this.params.stamps?.length) return false; + if (!passport.stamps?.length || !requiredStamps?.length) return false; const verifiedStamps: any[] = await getVerifiedStamps( passport, this.author, - this.params.stamps.map((stamp) => ({ + requiredStamps.map((stamp) => ({ id: stamp })) ); @@ -28,16 +29,23 @@ export default class extends Validation { const provider = snapshot.utils.getProvider(this.network); const proposalTs = (await provider.getBlock(this.snapshot)).timestamp; - const operator = this.params.operator || 'AND'; - const validStamps = verifiedStamps.filter( - (stamp) => - hasValidIssuanceAndExpiration(stamp.credential, proposalTs) && - this.params.stamps.includes(stamp.provider) - ); + const operator = this.params.operator; + + // check issuance and expiration + const validStamps = verifiedStamps + .filter((stamp) => + hasValidIssuanceAndExpiration(stamp.credential, proposalTs) + ) + .map((stamp) => stamp.provider); + + // console.log('validStamps', validStamps); + // console.log('requiredStamps', requiredStamps); + // console.log('operator', operator); + if (operator === 'AND') { - return validStamps.length === this.params.stamps.length; + return requiredStamps.every((stamp) => validStamps.includes(stamp)); } else if (operator === 'OR') { - return validStamps.length > 0; + return requiredStamps.some((stamp) => validStamps.includes(stamp)); } else { return false; } diff --git a/src/validations/passport-gated/schema.json b/src/validations/passport-gated/schema.json index 5e01f1962..b70b94b1e 100644 --- a/src/validations/passport-gated/schema.json +++ b/src/validations/passport-gated/schema.json @@ -3,7 +3,7 @@ "$ref": "#/definitions/Validation", "definitions": { "Validation": { - "title": "Validation", + "title": "Gitcoin passport gated", "type": "object", "properties": { "stamps": { diff --git a/src/validations/passport-weighted/helper.ts b/src/validations/passport-weighted/helper.ts index b30a1e637..4b7b05c45 100644 --- a/src/validations/passport-weighted/helper.ts +++ b/src/validations/passport-weighted/helper.ts @@ -1,23 +1,48 @@ import DIDKit from '@spruceid/didkit-wasm-node/didkit_wasm'; import { Tulons } from 'tulons'; +import fetch from 'cross-fetch'; const CERAMIC_URL = 'https://ceramic.passport-iam.gitcoin.co'; const CERAMIC_NETWORK_ID = 1; +const CERAMIC_GITCOIN_PASSPORT_STREAM_ID = + 'kjzl6cwe1jw148h1e14jb5fkf55xmqhmyorp29r9cq356c7ou74ulowf8czjlzs'; +const IAM_ISSUER_DID = + 'did:key:z6MkghvGHLobLEdj1bgRLhS4LPGJAvbMA1tn2zcRyqmYU5LC'; export const getPassport = async (address) => { - // Ceramic connection details - - // Ceramic definition ids on the Ceramic account model - const CERAMIC_GITCOIN_PASSPORT_STREAM_ID = - 'kjzl6cwe1jw148h1e14jb5fkf55xmqhmyorp29r9cq356c7ou74ulowf8czjlzs'; const tulons = new Tulons(CERAMIC_URL, CERAMIC_NETWORK_ID); - // Ceramic data is stored as address -> DID -> Genesis/IDX Stream -> Data Stream const { streams } = await tulons.getGenesis(address); if (streams[CERAMIC_GITCOIN_PASSPORT_STREAM_ID]) { - return await tulons.getHydrated( - await tulons.getStream(streams[CERAMIC_GITCOIN_PASSPORT_STREAM_ID]) + const passport: any = await tulons.getStream( + streams[CERAMIC_GITCOIN_PASSPORT_STREAM_ID] ); + const streamIDs = passport.stamps.map((ceramicStamp) => { + return ceramicStamp.credential; + }); + // `stamps` is stored as ceramic URLs - must load actual VC data from URL + const stampsToLoad = passport.stamps.map(async (_stamp, idx) => { + const streamUrl = `${CERAMIC_URL}/api/v0/streams/${streamIDs[ + idx + ].substring(10)}`; + const response = await fetch(streamUrl); + const loadedCred = await response.json(); + const { provider } = _stamp; + + return { + provider, + credential: loadedCred.state.content, + streamId: streamIDs[idx] + }; + }); + // load all the stamps (unlike gitcoin UI, not ignoring any failing stamps) + const stamps = await Promise.all(stampsToLoad); + + return { + issuanceDate: new Date(passport.issuanceDate), + expiryDate: new Date(passport.expiryDate), + stamps + }; } return false; }; @@ -63,23 +88,19 @@ const verifyStamp = async (stamp, address) => { }; const verifyCredential = async (credential) => { - const { expirationDate, proof } = credential; - - // check that the credential is still valid (not expired) - if (new Date(expirationDate) > new Date()) { - try { - const verify = JSON.parse( - await DIDKit.verifyCredential( - JSON.stringify(credential), - `{"proofPurpose":"${proof.proofPurpose}"}` - ) - ) as { checks: string[]; warnings: string[]; errors: string[] }; - return verify.errors.length === 0; - } catch (e) { - return false; - } + const { proof } = credential; + try { + const verify = JSON.parse( + await DIDKit.verifyCredential( + JSON.stringify(credential), + `{"proofPurpose":"${proof.proofPurpose}"}` + ) + ) as { checks: string[]; warnings: string[]; errors: string[] }; + const has_correct_issuer = credential.issuer === IAM_ISSUER_DID; + return verify.errors.length === 0 && has_correct_issuer; + } catch (e) { + return false; } - return false; }; export const hasValidIssuanceAndExpiration = (credential, proposalTs) => { diff --git a/src/validations/passport-weighted/schema.json b/src/validations/passport-weighted/schema.json index 71eb7364c..b3d95ba5b 100644 --- a/src/validations/passport-weighted/schema.json +++ b/src/validations/passport-weighted/schema.json @@ -3,7 +3,7 @@ "$ref": "#/definitions/Validation", "definitions": { "Validation": { - "title": "Validation", + "title": "Gitcoin passport weighted", "type": "object", "properties": { "stamps": { From f8d458e9103c0d42e42fd0d414df9d59ff0c5a01 Mon Sep 17 00:00:00 2001 From: Artem Payvin Date: Sat, 26 Nov 2022 19:58:10 +0000 Subject: [PATCH 241/815] Add skale delegation weighted strategy [skale-delegation-weighted] (#966) * Add skale delegation weighted strategy * Change symbol in README --- src/strategies/index.ts | 4 +- .../skale-delegation-weighted/README.md | 16 +++++ .../skale-delegation-weighted/examples.json | 31 ++++++++ .../skale-delegation-weighted/index.ts | 72 +++++++++++++++++++ 4 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 src/strategies/skale-delegation-weighted/README.md create mode 100644 src/strategies/skale-delegation-weighted/examples.json create mode 100644 src/strategies/skale-delegation-weighted/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 963482a9e..4bccf876d 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -403,6 +403,7 @@ import * as marsecosystem from './marsecosystem'; import * as ari10StakingLocked from './ari10-staking-locked'; import * as multichainSerie from './multichain-serie'; import * as ctsiStaking from './ctsi-staking'; +import * as skaleDelegationWeighted from './skale-delegation-weighted'; const strategies = { 'forta-shares': fortaShares, @@ -811,7 +812,8 @@ const strategies = { marsecosystem, 'ari10-staking-locked': ari10StakingLocked, 'multichain-serie': multichainSerie, - 'ctsi-staking': ctsiStaking + 'ctsi-staking': ctsiStaking, + 'skale-delegation-weighted': skaleDelegationWeighted }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/skale-delegation-weighted/README.md b/src/strategies/skale-delegation-weighted/README.md new file mode 100644 index 000000000..c47b88c51 --- /dev/null +++ b/src/strategies/skale-delegation-weighted/README.md @@ -0,0 +1,16 @@ +# skale-delegation-weighted + +This strategy allow SKL tokens holders to participate in vote, where the weight of the vote is an amount of delegated tokens. +Holder can delegate directly or with Escrow contract(provided by SKALE) + +Required params in `example.json`: + - addressSKL - address of SKL token + - addressAllocator - address of Allocator contract + +```json +{ + "addressSKL": "0x6b175474e89094c44da98b954eedeac495271d0f", + "symbol": "SKL", + "decimals": 18 +} +``` diff --git a/src/strategies/skale-delegation-weighted/examples.json b/src/strategies/skale-delegation-weighted/examples.json new file mode 100644 index 000000000..bb63dd6a4 --- /dev/null +++ b/src/strategies/skale-delegation-weighted/examples.json @@ -0,0 +1,31 @@ +[ + { + "name": "Directly delegated amount of SKL token or delegated with Escrow ", + "strategy": { + "name": "skale-delegation-weighted", + "params": { + "addressSKL": "0x00c83aeCC790e8a4453e5dD3B0B4b3680501a7A7", + "addressAllocator": "0xB575c158399227b6ef4Dcfb05AA3bCa30E12a7ba", + "symbol": "SKL", + "decimals": 18 + } + }, + "network": "1", + "addresses": [ + "0xD6f4196EDe7a5e83e4819bf77784F8b24D9475BD", + "0xB4FA5AA4073E43C8b8E780df971856fc9e94F7c8", + "0x4AeD8A87544fFAe057354A4a762E70c38f5D6bc7", + "0x6A3B29FdfC7F4752851451fA20ECdCFeb1bA2Fd0", + "0xF2cCBcF4Ac3e021C4041F39F751A0b46b1C8aa14", + "0x9c738ed8D50B283B7884DA4e69400a178158e42e", + "0x2B3C7D1eF5FDfC0557934019c531d3E70D6200AE", + "0x80F41289795F122C82b83D8C3A760E01FDBF5C76", + "0x0BC34C33880a45d7Aa3bfDafE37Fd157E1Dca9bb", + "0x864521f4A31f1C893f8414697dFb6D3A2d949AC5", + "0xFdD2245Fa2B7881AB78C171Cc84F088e520450E2", + "0xd753854eA19B204E6Ee9b5544239Fcc7d40f932A", + "0xfFd22b84fB1d46ef74Ed6530b2635BE61340f347" + ], + "snapshot": 16048934 + } +] diff --git a/src/strategies/skale-delegation-weighted/index.ts b/src/strategies/skale-delegation-weighted/index.ts new file mode 100644 index 000000000..9ed2f69b3 --- /dev/null +++ b/src/strategies/skale-delegation-weighted/index.ts @@ -0,0 +1,72 @@ +import { BigNumberish, BigNumber } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller, multicall } from '../../utils'; + +export const author = 'payvint'; +export const version = '1.0.0'; + +const abi = [ + 'function getAndUpdateDelegatedAmount(address wallet) external returns (uint)', + 'function getEscrowAddress(address beneficiary) external view returns (address)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multi = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => { + multi.call(address, options.addressSKL, 'getAndUpdateDelegatedAmount', [ + address + ]); + }); + const resultAccounts: Record = await multi.execute(); + + console.log(resultAccounts); + + const escrowAddressCallsQuery = addresses.map((address: any) => [ + options.addressAllocator, + 'getEscrowAddress', + [address] + ]); + + const escrowAddressesFromAccount = await multicall( + network, + provider, + abi, + [...escrowAddressCallsQuery], + { + blockTag + } + ); + + const addressToEscrow = new Map(); + addresses.forEach((address: any, index: number) => { + addressToEscrow[address] = escrowAddressesFromAccount[index][0]; + }); + + addresses.forEach((address: any) => { + multi.call(address, options.addressSKL, 'getAndUpdateDelegatedAmount', [ + addressToEscrow[address] + ]); + }); + + const resultEscrows: Record = await multi.execute(); + + return Object.fromEntries( + Object.entries(resultAccounts).map(([address, balance]) => [ + address, + parseFloat( + formatUnits( + BigNumber.from(balance).add(BigNumber.from(resultEscrows[address])) + ) + ) + ]) + ); +} From 24a1d5ecfeb4d539641b77f1576a04d35a229ca3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 27 Nov 2022 23:41:08 +0530 Subject: [PATCH 242/815] Automated lint (#969) Co-authored-by: ChaituVR --- src/strategies/spreadsheet/index.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/strategies/spreadsheet/index.ts b/src/strategies/spreadsheet/index.ts index dc7ef4f5b..eb3ca106a 100644 --- a/src/strategies/spreadsheet/index.ts +++ b/src/strategies/spreadsheet/index.ts @@ -28,7 +28,9 @@ export async function strategy( const ts = block.timestamp; const res = await fetch( - `https://docs.google.com/spreadsheets/d/e/${options.sheetId}/pub?gid=${options.gid || "0"}&single=true&output=csv` + `https://docs.google.com/spreadsheets/d/e/${options.sheetId}/pub?gid=${ + options.gid || '0' + }&single=true&output=csv` ); const text = await res.text(); const csv = (csvToJson(text) || []).map((item) => ({ From 7a1357032ec1d917a21a53e95757c43064e70bb3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 28 Nov 2022 01:18:06 +0530 Subject: [PATCH 243/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.53 (#970) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 8643e7671..e7351ed8e 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.52", + "@snapshot-labs/snapshot.js": "^0.4.53", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 43f244646..983c33521 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.52": - version "0.4.52" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.52.tgz#cc222236d12ee519d2c46f35ac9b10012d54ca42" - integrity sha512-gm9tQL1FtpjSXf0jGVQgaf31KBMEjUe0ZQPzttu9GvRKCwBAEQosu7T3lcQvUpgIXz87aRAMzFQHouqoMg9rOw== +"@snapshot-labs/snapshot.js@^0.4.53": + version "0.4.53" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.53.tgz#9aa8d32d5ed2be51cdd373a05bd417e1bee8f938" + integrity sha512-fn/PPNuO6BzJxMZYSnLhH8gVyOX6mKbqftqSgKwAYAIfEfYJiEenZXhQRROi0aZ1JK2Qycf3pkqHv+ghy0YDEg== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 1470822c7c6e70af766be74cd42b0e6ce128e0c7 Mon Sep 17 00:00:00 2001 From: skly <91403802+0xSkly@users.noreply.github.com> Date: Tue, 29 Nov 2022 19:25:00 +0100 Subject: [PATCH 244/815] [reliquary] Add reqliquary strategy (#972) * Add reqliquary strategy Use levelOnUpdate to retrieve correct level Add improvements rename config param to multiplier add minimum voting level option Adjust voting power formula rename variable Add readme improve Improve readme & rename multiplier to strategy fix readme * Use abi string & fix author --- src/strategies/index.ts | 4 +- src/strategies/reliquary/README.md | 40 ++++++ src/strategies/reliquary/examples.json | 25 ++++ src/strategies/reliquary/index.ts | 166 +++++++++++++++++++++++++ 4 files changed, 234 insertions(+), 1 deletion(-) create mode 100644 src/strategies/reliquary/README.md create mode 100644 src/strategies/reliquary/examples.json create mode 100644 src/strategies/reliquary/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 4bccf876d..e8b23110c 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -404,6 +404,7 @@ import * as ari10StakingLocked from './ari10-staking-locked'; import * as multichainSerie from './multichain-serie'; import * as ctsiStaking from './ctsi-staking'; import * as skaleDelegationWeighted from './skale-delegation-weighted'; +import * as reliquary from './reliquary'; const strategies = { 'forta-shares': fortaShares, @@ -813,7 +814,8 @@ const strategies = { 'ari10-staking-locked': ari10StakingLocked, 'multichain-serie': multichainSerie, 'ctsi-staking': ctsiStaking, - 'skale-delegation-weighted': skaleDelegationWeighted + 'skale-delegation-weighted': skaleDelegationWeighted, + reliquary }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/reliquary/README.md b/src/strategies/reliquary/README.md new file mode 100644 index 000000000..511553005 --- /dev/null +++ b/src/strategies/reliquary/README.md @@ -0,0 +1,40 @@ +# reliquary + +This strategy utilizes Relic NFTs from Reliquary to calculate voting power. The strategy can be configured to either +use the level number to weight the voting power or the allocation points assigned to each level. + +If we use the levels strategy, the formula to calculate the voting power is + +`votingPower = level / maxVotingLevel * amount` + +or if we use allocation points + +`votingPower = levelAllocationPoint / maxLevelAllocationPoint * amount` + +In other words, if the nft has reached max voting level the voting power is equal to the amount deposited. + +Since Relic levels only update on an interaction, we have to chose if we want to use the current 'actual' level, or the level which the relic would +have after an update. This can be done using the `useLevelOnUpdate` flag. + +Configuration: +| property | type | value | description | +|------|---|---|---| +| reliquaryAddress | string | 0x12345... | address of reliquary contract +| poolId | number | 0...n | pool ID used for voting +| minVotingLevel | number | 0...n | min level required to vote +| maxVotingLevel | number | 0...n | max voting level +| decimals | number | 6..18 | number of decimals of the token deposited into this pool +| strategy | string | 'level' / 'allocation' | which strategy to use to weight voting power +| useLevelOnUpdate | boolean | true / false | use hypothetical level after update + +```json +{ + "reliquaryAddress": "0xb0fc43069089d0fa02baaa896ac2efcb596d7d05", + "poolId": 1, + "minVotingLevel": 1, + "maxVotingLevel": 7, + "decimals": 18, + "strategy": "allocation", + "useLevelOnUpdate": false +} +``` diff --git a/src/strategies/reliquary/examples.json b/src/strategies/reliquary/examples.json new file mode 100644 index 000000000..a8ea6205a --- /dev/null +++ b/src/strategies/reliquary/examples.json @@ -0,0 +1,25 @@ +[ + { + "name": "Example configuration", + "strategy": { + "name": "reliquary", + "params": { + "reliquaryAddress": "0xb0fc43069089d0fa02baaa896ac2efcb596d7d05", + "poolId": 1, + "minVotingLevel": 1, + "maxVotingLevel": 7, + "decimals": 18, + "strategy": "allocation", + "useLevelOnUpdate": false + } + }, + "network": "250", + "addresses": [ + "0x4fbe899d37fb7514adf2f41B0630E018Ec275a0C", + "0x945d88011cAC5FDc3eAF7DbA51592bfA98aEe91A", + "0x1E243A85822E2CD42C81359E0ea42033000D02a4", + "0xf7Ee8A9d014E9046D007bD448AaE7C667eF91E98" + ], + "snapshot": 50967176 + } +] diff --git a/src/strategies/reliquary/index.ts b/src/strategies/reliquary/index.ts new file mode 100644 index 000000000..dd88c1607 --- /dev/null +++ b/src/strategies/reliquary/index.ts @@ -0,0 +1,166 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import { StaticJsonRpcProvider } from '@ethersproject/providers'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller, call } from '../../utils'; + +export const author = '0xSkly'; +export const version = '0.1.0'; + +const abi = [ + 'function relicPositionsOfOwner(address owner) view returns (uint256[] relicIds, tuple(uint256 amount, uint256 rewardDebt, uint256 rewardCredit, uint256 entry, uint256 poolId, uint256 level, uint256 genesis, uint256 lastMaturityBonus)[] positionInfos)', + 'function getLevelInfo(uint256 pid) view returns (tuple(uint256[] requiredMaturity, uint256[] allocPoint, uint256[] balance) levelInfo)', + 'function levelOnUpdate(uint256 relicId) view returns (uint256 level)' +]; + +export async function strategy( + space: string, + network: string, + provider: StaticJsonRpcProvider, + addresses: string[], + options: { + reliquaryAddress: string; + poolId: number; + minVotingLevel: number; + maxVotingLevel: number; + decimals?: number; + strategy: 'level' | 'allocationPoints'; + useLevelOnUpdate?: boolean; + }, + snapshot?: number | string +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multi = new Multicaller(network, provider, abi, { blockTag }); + + for (let address of addresses) { + multi.call(address, options.reliquaryAddress, 'relicPositionsOfOwner', [ + address + ]); + } + + // first we get all relics for each voter + const relicPositionsByOwner: Record< + string, + [ + BigNumber[], //relicIds + { + amount: BigNumber; + rewardDebt: BigNumber; + rewardCredit: BigNumber; + entry: BigNumber; + poolId: BigNumber; + level: BigNumber; + genesis: BigNumber; + lastMaturityBonus: BigNumber; + }[] // correlating positions + ] + > = await multi.execute(); + + // then we filter by the configured pool ID + const relevantRelicPositions = Object.entries(relicPositionsByOwner).flatMap( + ([owner, [relicIds, positions]]) => + positions + .map((position, index) => ({ + owner, + relicId: relicIds[index].toNumber(), + poolId: position.poolId.toNumber(), + amount: position.amount, + level: position.level.toNumber() + })) + .filter((position) => position.poolId === options.poolId) + ); + + // if the strategy should use the level on update, we override the level + if (options.useLevelOnUpdate) { + for (let relicPosition of relevantRelicPositions) { + multi.call( + `${relicPosition.owner}.${relicPosition.relicId}.level`, + options.reliquaryAddress, + 'levelOnUpdate', + [relicPosition.relicId] + ); + } + + const relicLevelByVoterAndRelic: { + [owner: string]: { + [relicId: string]: { level: BigNumber }; + }; + } = await multi.execute(); + + for (let relicPosition of relevantRelicPositions) { + relicPosition.level = + relicLevelByVoterAndRelic[relicPosition.owner][ + relicPosition.relicId + ].level.toNumber(); + } + } + + const userVotingPower: Record = {}; + + /* + if we use the level strategy, we just add the level as a multiplier in relation to the max level. + So the formula used is: relicAmount * level / maxLevel + */ + if (options.strategy === 'level') { + for (let relicPosition of relevantRelicPositions) { + const multiplier = + relicPosition.level >= options.minVotingLevel + ? Math.min(options.maxVotingLevel, relicPosition.level) + : 0; + const votingPower = parseFloat( + formatUnits( + relicPosition.amount.mul(multiplier).div(options.maxVotingLevel), + options.decimals ?? 18 + ) + ); + + if (relicPosition.owner in userVotingPower) { + userVotingPower[relicPosition.owner] += votingPower; + } else { + userVotingPower[relicPosition.owner] = votingPower; + } + } + + return userVotingPower; + } + /* + otherwise we use the level allocations to weight the voting power. For this + we need to get the allocations for each level for the configured pool. + The formula used is: relicAmount * levelAllocation / maxAllocation + + */ + + const poolLevelInfo: { + requiredMaturity: BigNumber[]; + allocPoint: BigNumber[]; + balance: BigNumber[]; + } = await call( + provider, + abi, + [options.reliquaryAddress, 'getLevelInfo', [options.poolId]], + { blockTag } + ); + + const maxLevelAllocation = poolLevelInfo.allocPoint[options.maxVotingLevel]; + + for (let relicPosition of relevantRelicPositions) { + const multiplier = + poolLevelInfo.allocPoint[ + Math.min(options.maxVotingLevel, relicPosition.level) + ].toNumber(); + + const votingPower = parseFloat( + formatUnits( + relicPosition.amount.mul(multiplier).div(maxLevelAllocation), + options.decimals ?? 18 + ) + ); + + if (relicPosition.owner in userVotingPower) { + userVotingPower[relicPosition.owner] += votingPower; + } else { + userVotingPower[relicPosition.owner] = votingPower; + } + } + return userVotingPower; +} From c82d1531b8283b340e4dc88f2549b69806585de4 Mon Sep 17 00:00:00 2001 From: Danilo Tuler Date: Tue, 29 Nov 2022 16:24:21 -0300 Subject: [PATCH 245/815] [ctsi-staking-pool] new strategy for ctsi staking through pools (#967) --- src/strategies/ctsi-staking-pool/README.md | 7 + .../ctsi-staking-pool/examples.json | 24 ++++ src/strategies/ctsi-staking-pool/index.ts | 125 ++++++++++++++++++ src/strategies/ctsi-staking-pool/schema.json | 23 ++++ src/strategies/index.ts | 2 + 5 files changed, 181 insertions(+) create mode 100644 src/strategies/ctsi-staking-pool/README.md create mode 100644 src/strategies/ctsi-staking-pool/examples.json create mode 100644 src/strategies/ctsi-staking-pool/index.ts create mode 100644 src/strategies/ctsi-staking-pool/schema.json diff --git a/src/strategies/ctsi-staking-pool/README.md b/src/strategies/ctsi-staking-pool/README.md new file mode 100644 index 000000000..185b2b324 --- /dev/null +++ b/src/strategies/ctsi-staking-pool/README.md @@ -0,0 +1,7 @@ +# ctsi-staking-pool + +This strategy implements the rules of CTSI Staking through Staking Pools, returning the staked balance of the voters in all pools they stake to. + +There are no parameters to configure. + +Direct stakers or pool operators are not accounted in this strategy. For those use strategy `ctsi-staking`. diff --git a/src/strategies/ctsi-staking-pool/examples.json b/src/strategies/ctsi-staking-pool/examples.json new file mode 100644 index 000000000..75bd0e32a --- /dev/null +++ b/src/strategies/ctsi-staking-pool/examples.json @@ -0,0 +1,24 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "ctsi-staking-pool", + "params": { + "expectedResults": { + "scores": { + "0x4af926a219e09fe5dd1ee16d7039d82ecf979148": 1001.2293481992707, + "0x0b47fef7cb50ad5abbc10265152aacc3b4b5e6d1": 19243.216830099187, + "0xff26ccf9058b9bd8facfb6a8876864fec193285d": 4272385.58482901 + } + } + } + }, + "network": "1", + "addresses": [ + "0x4af926a219e09fe5dd1ee16d7039d82ecf979148", + "0x0b47fef7cb50ad5abbc10265152aacc3b4b5e6d1", + "0xff26ccf9058b9bd8facfb6a8876864fec193285d" + ], + "snapshot": 16053852 + } +] diff --git a/src/strategies/ctsi-staking-pool/index.ts b/src/strategies/ctsi-staking-pool/index.ts new file mode 100644 index 000000000..4e541dac7 --- /dev/null +++ b/src/strategies/ctsi-staking-pool/index.ts @@ -0,0 +1,125 @@ +import { BigNumber, FixedNumber } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { getAddress } from '@ethersproject/address'; +import { subgraphRequest } from '../../utils'; + +export const author = 'cartesi'; +export const version = '0.1.0'; + +const SUBGRAPH_URL_ROOT = 'https://api.thegraph.com/subgraphs/name/cartesi/pos'; + +const NETWORK_KEY = { + '1': '', + '5': '-goerli' +}; + +function buildSubgraphUrl(chainId) { + const networkString = NETWORK_KEY[chainId]; + return `${SUBGRAPH_URL_ROOT}${networkString}`; +} + +async function getStakingPoolDelegatorBalance( + url, + addresses, + options, + snapshot +): Promise> { + // query for StakingPool balance of voters + const query = { + poolBalances: { + __args: { + where: { + user_in: addresses + }, + first: 1000 + }, + pool: { + amount: true, + shares: true, + manager: true + }, + user: { + id: true + }, + shares: true + } + }; + if (snapshot !== 'latest') { + // @ts-ignore + query.poolBalances.__args.block = { number: snapshot }; + } + const score: Record = {}; + const result = await subgraphRequest(url, query); + if (result && result.poolBalances) { + result.poolBalances.forEach((poolBalance) => { + const address = getAddress(poolBalance.user.id); + const poolShares = FixedNumber.from(poolBalance.pool.shares); + const poolAmount = FixedNumber.from(poolBalance.pool.amount); + const shares = FixedNumber.from(poolBalance.shares); + const balance = BigNumber.from( + poolAmount + .mulUnsafe(shares.divUnsafe(poolShares)) + .floor() + .toFormat('ufixed128x0') + .toString() + ); + // a staker can stake to several pools, so we must add the value if there is already one + score[address] = score[address] ? score[address].add(balance) : balance; + }); + } + + return score; +} + +function verifyResults( + results: Record, + expectedResults: Record +): void { + Object.entries(results).forEach(([address, score]) => { + const expectedScore = + expectedResults[address.toLowerCase()] ?? + expectedResults[getAddress(address)]; + if (score !== expectedScore) { + console.error( + `>>> ERROR: Score do not match for address ${address}, expected ${expectedScore}, got ${score}` + ); + } + }); +} + +export async function strategy( + _space, + network, + _provider, + addresses, + options, + snapshot +): Promise> { + // convert addresses to lowercase, as in subgraph they are all lowercase + addresses = addresses.map((address) => address.toLowerCase()); + + // build subgraph URL based on network, as we have one for mainnet and another for goerli + const url = buildSubgraphUrl(network); + + // get balance staked in pools + const results = await getStakingPoolDelegatorBalance( + url, + addresses, + options, + snapshot + ); + + const scores = Object.fromEntries( + Object.entries(results).map(([address, balance]) => [ + address, + parseFloat(formatUnits(balance, 18)) + ]) + ); + + if (options.expectedResults && snapshot !== 'latest') { + // validate testing expected results + verifyResults(scores, options.expectedResults.scores); + } + + return scores; +} diff --git a/src/strategies/ctsi-staking-pool/schema.json b/src/strategies/ctsi-staking-pool/schema.json new file mode 100644 index 000000000..006ba35fb --- /dev/null +++ b/src/strategies/ctsi-staking-pool/schema.json @@ -0,0 +1,23 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "expectedResults": { + "type": "object", + "properties": { + "scores": { + "type": "object", + "additionalProperties": { "type": "number" } + } + } + } + }, + "required": [], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index e8b23110c..5c71c1a00 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -403,6 +403,7 @@ import * as marsecosystem from './marsecosystem'; import * as ari10StakingLocked from './ari10-staking-locked'; import * as multichainSerie from './multichain-serie'; import * as ctsiStaking from './ctsi-staking'; +import * as ctsiStakingPool from './ctsi-staking-pool'; import * as skaleDelegationWeighted from './skale-delegation-weighted'; import * as reliquary from './reliquary'; @@ -814,6 +815,7 @@ const strategies = { 'ari10-staking-locked': ari10StakingLocked, 'multichain-serie': multichainSerie, 'ctsi-staking': ctsiStaking, + 'ctsi-staking-pool': ctsiStakingPool, 'skale-delegation-weighted': skaleDelegationWeighted, reliquary }; From c30667d09fca07f6ef3cdde52ddaabeb194fd132 Mon Sep 17 00:00:00 2001 From: gregan Date: Wed, 30 Nov 2022 03:01:01 -0800 Subject: [PATCH 246/815] Setup MemberRewards for GoldfinchVotingPower [goldfinch-voting-power] (#973) * Setup MemberRewards for GoldfinchVotingPower * Fix address * Update block number * Fix address in example --- .../goldfinch-voting-power/examples.json | 4 ++-- .../goldfinch-voting-power/index.ts | 21 ++++++++++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/strategies/goldfinch-voting-power/examples.json b/src/strategies/goldfinch-voting-power/examples.json index 8d8d17f02..0a9f450cc 100644 --- a/src/strategies/goldfinch-voting-power/examples.json +++ b/src/strategies/goldfinch-voting-power/examples.json @@ -10,9 +10,9 @@ "0x526C7665C5dd9cD7102C6d42D407a0d9DC1e431d", "0x721931508df2764fd4f70c53da646cb8aed16ace", "0x4902b20bB3B8e7776CBcDCB6e3397E7F6b4e449E", - "0x8f4fc35cf5ad925bcc1cae81e5da62fca1c2dd2a", + "0x8F4fc35cF5ad925bCC1cAe81E5da62fCA1c2Dd2a", "0x6C3FB1A2A55fdcFb620Ae8f19b6fc332622050DD" ], - "snapshot": 15053050 + "snapshot": 16080167 } ] diff --git a/src/strategies/goldfinch-voting-power/index.ts b/src/strategies/goldfinch-voting-power/index.ts index 6433a9756..e0416c72b 100644 --- a/src/strategies/goldfinch-voting-power/index.ts +++ b/src/strategies/goldfinch-voting-power/index.ts @@ -8,6 +8,7 @@ export const version = '0.1.0'; const COMMUNITY_REWARDS = '0x0Cd73c18C085dEB287257ED2307eC713e9Af3460'; const STAKING_REWARDS = '0xFD6FF39DA508d281C2d255e9bBBfAb34B6be60c3'; const GFI = '0xdab396cCF3d84Cf2D07C4454e10C8A6F5b008D2b'; +const MEMBERSHIP_REWARDS = '0x4e5d9b093986d864331d88e0a13a616e1d508838'; const COMMUNITY_REWARDS_ABI = [ 'function totalUnclaimed(address owner) view returns (uint256)' @@ -15,6 +16,9 @@ const COMMUNITY_REWARDS_ABI = [ const STAKING_REWARDS_ABI = [ 'function totalOptimisticClaimable(address owner) view returns (uint256)' ]; +const MEMBERSHIP_REWARDS_ABI = [ + 'function votingPower(address addr) view returns (uint256)' +]; export async function strategy( space, @@ -64,6 +68,18 @@ export async function strategy( { blockTag } ); + const membershipRewards = await multicall( + network, + provider, + MEMBERSHIP_REWARDS_ABI, + addresses.map((address: any) => [ + MEMBERSHIP_REWARDS, + 'votingPower', + [address] + ]), + { blockTag } + ); + addresses.forEach((address, index) => { const parsedCommunityRewards = parseFloat( formatUnits(unclaimedCommunityRewards[index][0], options.decimals) @@ -71,8 +87,11 @@ export async function strategy( const parsedStakingRewards = parseFloat( formatUnits(unclaimedStakingRewards[index][0], options.decimals) ); + const parsedMembershipRewards = parseFloat( + formatUnits(membershipRewards[index][0], options.decimals) + ); gfiResult[address] = - gfiResult[address] + parsedCommunityRewards + parsedStakingRewards; + gfiResult[address] + parsedCommunityRewards + parsedStakingRewards + parsedMembershipRewards; }); return gfiResult; From a421fb95fd36723e34e46fabbe78146a3d43572a Mon Sep 17 00:00:00 2001 From: Julien THOMAS <61523188+julien-devatom@users.noreply.github.com> Date: Fri, 2 Dec 2022 03:43:01 +0100 Subject: [PATCH 247/815] [linear-vesting-power] Handle multiple vesting lines (#974) * fix(linear-vesting-power): handle multiple vesting lines * docs(linear-vesting-power): add some explanation about the strategy --- src/strategies/linear-vesting-power/index.ts | 52 +++++++++++++------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/src/strategies/linear-vesting-power/index.ts b/src/strategies/linear-vesting-power/index.ts index 22dd6780f..6c03e96ea 100644 --- a/src/strategies/linear-vesting-power/index.ts +++ b/src/strategies/linear-vesting-power/index.ts @@ -31,6 +31,20 @@ const vestedAmountPower = ( const idsArray = (maxId: number) => Array.from({ length: maxId }, (_, i) => i + 1); +/** + * @notice This strategy returns the total amount of vested tokens for a given user + * The particularity of this strategy is the ability to skip the cliff period for the voting power. + * So if Alice has a vesting line starting on August 2022, with a cliff period of 6 months, + * a vesting period of 3 years and a total amount of 1000 tokens, she is going to accumulate voting power from August 2022, + * and in January 2023, she will have 1/6 of the total voting power, i.e. 1000/6 = 166.66 voting power. + * As a consequence, any voter has its full voting power from the vesting contract 6 month before the end of the vesting period. + * + * @notice In order to handle claimed tokens, we are linearizing the amount accumulated and not claimed by the user from the beginning + * of the vesting power distribution (start - cliff) to the current date, at the rate of the vesting duration. + * So if Alice is claiming 166 tokens on August 2023 (6 months after the beginning of the distribution), whe are going to have + * 1000 - 166 = 834 tokens left to linearize from (start - cliff) to August 2023. This is an approximation of the voting power from + * the vesting amount. + */ export async function strategy( space, network, @@ -97,24 +111,28 @@ export async function strategy( addresses.map((address) => { const initialVotingPower = [address, 0]; // fetch vested users data - const [id] = - Object.entries(vestedAddresses).find( - ([, _address]) => _address === address - ) ?? []; - if (id === undefined) return initialVotingPower; - const totalVested = multiVestResult['tot' + id]; - const totalAccrued = multiVestResult['accrued' + id]; + const ids = Object.entries(vestedAddresses) + .filter(([, _address]) => _address === address) + .map(([id]) => id); - const bgn = multiVestResult['bgn' + id]; - const fin = multiVestResult['fin' + id]; - if (!(id && totalAccrued && totalVested && bgn && fin)) - return initialVotingPower; - const votingPower = vestedAmountPower( - BigNumber.from(totalVested).sub(totalAccrued), - BigNumber.from(bgn).sub(options.cliffDuration), - BigNumber.from(fin).sub(bgn).add(options.cliffDuration), - now - ); + if (!ids.length) return initialVotingPower; + const votingPower = ids.reduce((vp, id) => { + const totalVested = multiVestResult['tot' + id]; + const totalAccrued = multiVestResult['accrued' + id]; + + const bgn = multiVestResult['bgn' + id]; + const fin = multiVestResult['fin' + id]; + if (!(id && totalAccrued && totalVested && bgn && fin)) return vp; + return vp.add( + vestedAmountPower( + BigNumber.from(totalVested).sub(totalAccrued), + // Here, we are slicing the start to start minus cliff duration, in order to skip the cliff for the voting power calculation + BigNumber.from(bgn).sub(options.cliffDuration), + BigNumber.from(fin).sub(bgn).add(options.cliffDuration), + now + ) + ); + }, BigNumber.from(0)); return [address, parseFloat(formatUnits(votingPower, options.decimals))]; }) ); From 072d04b89fe9739909c6e4ac493979cabe9c30c1 Mon Sep 17 00:00:00 2001 From: mib-hashflow <113477247+mib-hashflow@users.noreply.github.com> Date: Sat, 3 Dec 2022 20:16:07 -0800 Subject: [PATCH 248/815] Add new snapshot strategy for Hashflow which allows HFT LPs to vote using their deposited tokens [hashflow-governance-power] (#975) * Add new snapshot strategy for Hashflow which allows HFT LPs to vote using their deposited tokens * Fix autoformat Co-authored-by: Chaitanya --- .../hashflow-governance-power/README.md | 19 ++++++ .../hashflow-governance-power/examples.json | 68 +++++++++++++++++++ .../hashflow-governance-power/index.ts | 62 +++++++++++++++++ .../hashflow-governance-power/schema.json | 38 +++++++++++ src/strategies/index.ts | 2 + 5 files changed, 189 insertions(+) create mode 100644 src/strategies/hashflow-governance-power/README.md create mode 100644 src/strategies/hashflow-governance-power/examples.json create mode 100644 src/strategies/hashflow-governance-power/index.ts create mode 100644 src/strategies/hashflow-governance-power/schema.json diff --git a/src/strategies/hashflow-governance-power/README.md b/src/strategies/hashflow-governance-power/README.md new file mode 100644 index 000000000..6ff23c17c --- /dev/null +++ b/src/strategies/hashflow-governance-power/README.md @@ -0,0 +1,19 @@ +# hashflow-governance-power + +This strategy is used for the Hashflow DAO to consider both held HFT and LP'd HFT equally. + +It was implemented as a result of community proposal [#272](https://gov.hashflow.com/t/allow-hashgang-to-use-their-hft-lp-tokens-to-vote/272/20), which was passed via a [snapshot vote](https://snapshot.org/#/hashflowdao.eth/proposal/0x0fe602a533b10fab93a66b155770ba948ff23209412487ec1ba3c5a4d75357ef). + +It allows users who are LP'ing HFT in public HFT pools to use those for voting. This eliminates the need to withdraw from pools to participate in voting. + +The exact implementation uses the fact that the `payout` field of a pool's `function assetDetails()` call shares how many HFT are claimable in the pool. This can then be combined with the totalSupply of each pool's LP token to determine the HFT value of funds deposited by any given address. + +Here is an example of parameters: + +```json +{ + "hftContract": "0xb3999f658c0391d94a37f7ff328f3fec942bcadc", + "hftPool": "0x5afe266ab4e43c32bad5459fe8df116dd5541222", + "hToken": "0x8a96b94bee6636042f2019c60c43b4f1c8c177a9" +} +``` diff --git a/src/strategies/hashflow-governance-power/examples.json b/src/strategies/hashflow-governance-power/examples.json new file mode 100644 index 000000000..9220e982e --- /dev/null +++ b/src/strategies/hashflow-governance-power/examples.json @@ -0,0 +1,68 @@ +[ + { + "name": "Mainnet query", + "strategy": { + "name": "hashflow-governance-power", + "params": { + "hftContract": "0xb3999f658c0391d94a37f7ff328f3fec942bcadc", + "hftPool": "0x5afe266ab4e43c32bad5459fe8df116dd5541222", + "hToken": "0x8a96b94bee6636042f2019c60c43b4f1c8c177a9" + } + }, + "network": "1", + "addresses": [ + "0x5caf573a688f21bb7a73a5f1cbeac1dfd6b505ca", + "0x5f09807819ca23d2b55d418a1cda9758725b35c1", + "0xb719e6279c5a9b5aa2b7a47f9e0e6453fa405808", + "0xaac0643b2a9f8351113388d935ff0718dae07e56", + "0x5409630192a9adaaa9ffbd46a3c695386be04e9c", + "0xd36ebe8e232955a444b4ab9a9297549c99ff09a9", + "0xee6d0298496153a026678488673a39c6153ab7f6", + "0xcabe8da7ce365392970437c9f4edfb4c89560257", + "0x910c60c049d833a7fd2f5bda310bbea1c5fa3598", + "0x8b5ce16637225516e2af14962407ec5afb8b9b73", + "0x720d2dad9cf67988e5b09d1d0dc4ebe5843cd611", + "0x1bbae2d283f2c14f43147e53d4f1b69601a1eac3", + "0x1e377d026dbb28dff1662927b2cb836b7c9f06d3", + "0xd340c943ae137ea0bab682a286d1af65e4e39a6b", + "0x71311a0e6167efcf28eeab78f87c008d05760b0b", + "0xc4b86bd3d432bd0b55dcd0e4bd3db91e05de2c26" + ], + "snapshot": 16093501 + }, + { + "name": "BSC query", + "strategy": { + "name": "hashflow-governance-power", + "params": { + "hftContract": "0x44ec807ce2f4a6f2737a92e985f318d035883e47", + "hftPool": "0x7286f5be4e531f6ea7660c739108d95aa2fef959", + "hToken": "0x1ddc58822f0071bf6ab973c94a185a97d000d036" + } + }, + "network": "56", + "addresses": [ + "0x884d6fa3a4b349880486ad4d7c833ca968c785d8", + "0xc0b570dc0363b1d3c9714f1060e716696acd4034", + "0xf4a290d914592a7f482fccce09ad73762a5998ca", + "0xdb4d32ca46310b4079fef1d135c88c1d1def32d7", + "0xc479328e6254bf692a3b22f051245069b307647a", + "0x66633cc6b84cd127a0bb84864c1a4ea0172469a6", + "0x1e46348fba3e75fd3b609351adfc22612c20be54", + "0xf41939922947f7c93cfa77364b35c6e85e53aef3", + "0x34f0431bec239c0828fbcf96c32092e5c926df21", + "0x67bcd41adbf12d1ecffd86e17af2b14179b556a3", + "0xf6e1acdb0a18cb397dde6ec0cca024d875e3e6e2", + "0x4d37f2a705377ac4c0827b79a8a4b84267b03ea1", + "0x4e97283bac00e1be24474e0671a1457e55991d11", + "0x9448e95d67fbe5ee576eeddb2adc637bae141e10", + "0xbe7d87e410a5c880f7a8ee83d4ae9d3db26b0d84", + "0x9f9d3b1c793a367310ebe5d159c4599914abdbd5", + "0x7a43dc785ced8554478b2ba2e491347c0826adde", + "0x04d29d747aa0abda9144fc15d1546a1bb959c40a", + "0xbe18f84532d8f7fb6d7919401c0096f3e257db8b", + "0x672c3b982325be86e221fe5d0eb5391ffa9cc8fc" + ], + "snapshot": 23545695 + } +] diff --git a/src/strategies/hashflow-governance-power/index.ts b/src/strategies/hashflow-governance-power/index.ts new file mode 100644 index 000000000..cc53c4be7 --- /dev/null +++ b/src/strategies/hashflow-governance-power/index.ts @@ -0,0 +1,62 @@ +import { getAddress } from '@ethersproject/address'; +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { multicall, Multicaller } from '../../utils'; + +export const author = 'mib-hashflow'; +export const version = '0.1.1'; + +const abi = [ + 'function balanceOf(address account) external view returns (uint256)', + 'function assetDetails(address token) external view returns (uint128 withdrawalLimit, uint128 cap, uint128 netPayout, uint128 timestamp, address hToken, address hTokenXChain, bool listed)', + 'function totalSupply() external view returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const contractData = await multicall( + network, + provider, + abi, + [ + [options.hftPool, 'assetDetails', [options.hftContract]], + [options.hToken, 'totalSupply', []] + ], + { blockTag } + ); + + const netPayout: BigNumberish = contractData[0].netPayout; + const totalSupply: BigNumberish = contractData[1][0]; + + const lpTokenWeight = + parseFloat(formatUnits(netPayout, 18)) / + parseFloat(formatUnits(totalSupply, 18)); + + const hftMulti = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => + hftMulti.call(address, options.hftContract, 'balanceOf', [address]) + ); + const hftBalances: Record = await hftMulti.execute(); + + const lpMulti = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => + lpMulti.call(address, options.hToken, 'balanceOf', [address]) + ); + const lpBalances: Record = await lpMulti.execute(); + + return Object.fromEntries( + Object.entries(hftBalances).map(([address, balance]) => [ + getAddress(address), + parseFloat(formatUnits(balance, 18)) + + lpTokenWeight * parseFloat(formatUnits(lpBalances[address], 18)) + ]) + ); +} diff --git a/src/strategies/hashflow-governance-power/schema.json b/src/strategies/hashflow-governance-power/schema.json new file mode 100644 index 000000000..6e5b10b51 --- /dev/null +++ b/src/strategies/hashflow-governance-power/schema.json @@ -0,0 +1,38 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "hftContract": { + "type": "string", + "title": "HFT Contract address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "hftPool": { + "type": "string", + "title": "HFT Pool address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "hToken": { + "type": "string", + "title": "HFT Pool HFT-hToken address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } + }, + "required": ["hftContract", "hftPool", "hToken"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 5c71c1a00..94eac2ebf 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -225,6 +225,7 @@ import * as cyberkongzV3 from './cyberkongz-v3'; import * as compLikeVotesInclusive from './comp-like-votes-inclusive'; import * as mstable from './mstable'; import * as hashesVoting from './hashes-voting'; +import * as hashflowGovernancePower from './hashflow-governance-power'; import * as podLeader from './pod-leader'; import * as aavegotchiWagmiGuild from './aavegotchi-wagmi-guild'; import * as polisBalance from './polis-balance'; @@ -637,6 +638,7 @@ const strategies = { 'comp-like-votes-inclusive': compLikeVotesInclusive, mstable, 'hashes-voting': hashesVoting, + 'hashflow-governance-power': hashflowGovernancePower, 'pod-leader': podLeader, 'aavegotchi-wagmi-guild': aavegotchiWagmiGuild, 'polis-balance': polisBalance, From 5723f9e4c9f2e26e6f9c3be852ca7fa68d826d07 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 4 Dec 2022 16:04:50 +0530 Subject: [PATCH 249/815] Automated lint (#978) Co-authored-by: ChaituVR --- src/strategies/goldfinch-voting-power/index.ts | 5 ++++- src/strategies/reliquary/index.ts | 10 +++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/strategies/goldfinch-voting-power/index.ts b/src/strategies/goldfinch-voting-power/index.ts index e0416c72b..210c83001 100644 --- a/src/strategies/goldfinch-voting-power/index.ts +++ b/src/strategies/goldfinch-voting-power/index.ts @@ -91,7 +91,10 @@ export async function strategy( formatUnits(membershipRewards[index][0], options.decimals) ); gfiResult[address] = - gfiResult[address] + parsedCommunityRewards + parsedStakingRewards + parsedMembershipRewards; + gfiResult[address] + + parsedCommunityRewards + + parsedStakingRewards + + parsedMembershipRewards; }); return gfiResult; diff --git a/src/strategies/reliquary/index.ts b/src/strategies/reliquary/index.ts index dd88c1607..cfe3adf48 100644 --- a/src/strategies/reliquary/index.ts +++ b/src/strategies/reliquary/index.ts @@ -32,7 +32,7 @@ export async function strategy( const multi = new Multicaller(network, provider, abi, { blockTag }); - for (let address of addresses) { + for (const address of addresses) { multi.call(address, options.reliquaryAddress, 'relicPositionsOfOwner', [ address ]); @@ -72,7 +72,7 @@ export async function strategy( // if the strategy should use the level on update, we override the level if (options.useLevelOnUpdate) { - for (let relicPosition of relevantRelicPositions) { + for (const relicPosition of relevantRelicPositions) { multi.call( `${relicPosition.owner}.${relicPosition.relicId}.level`, options.reliquaryAddress, @@ -87,7 +87,7 @@ export async function strategy( }; } = await multi.execute(); - for (let relicPosition of relevantRelicPositions) { + for (const relicPosition of relevantRelicPositions) { relicPosition.level = relicLevelByVoterAndRelic[relicPosition.owner][ relicPosition.relicId @@ -102,7 +102,7 @@ export async function strategy( So the formula used is: relicAmount * level / maxLevel */ if (options.strategy === 'level') { - for (let relicPosition of relevantRelicPositions) { + for (const relicPosition of relevantRelicPositions) { const multiplier = relicPosition.level >= options.minVotingLevel ? Math.min(options.maxVotingLevel, relicPosition.level) @@ -143,7 +143,7 @@ export async function strategy( const maxLevelAllocation = poolLevelInfo.allocPoint[options.maxVotingLevel]; - for (let relicPosition of relevantRelicPositions) { + for (const relicPosition of relevantRelicPositions) { const multiplier = poolLevelInfo.allocPoint[ Math.min(options.maxVotingLevel, relicPosition.level) From e7a2964b530077b71415948cb90b9021c00484e9 Mon Sep 17 00:00:00 2001 From: shinitakunai <87251045+shinitakunai@users.noreply.github.com> Date: Wed, 7 Dec 2022 22:32:09 -0800 Subject: [PATCH 250/815] [vsta-pool-staking] Add VSTA-POOL-STAKING Strategy to account for VSTA lp holders staked to our Farm contract (#979) * Add strategies to count vesta lp farms * add readme * Update src/strategies/vsta-pool-staking/index.ts * Update index.ts Co-authored-by: Chaitanya --- src/strategies/index.ts | 4 +- src/strategies/vsta-pool-staking/README.md | 27 +++++++ .../vsta-pool-staking/examples.json | 24 ++++++ src/strategies/vsta-pool-staking/index.ts | 55 ++++++++++++++ src/strategies/vsta-pool-staking/schema.json | 73 +++++++++++++++++++ 5 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 src/strategies/vsta-pool-staking/README.md create mode 100644 src/strategies/vsta-pool-staking/examples.json create mode 100644 src/strategies/vsta-pool-staking/index.ts create mode 100644 src/strategies/vsta-pool-staking/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 94eac2ebf..17b3efc5c 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -407,6 +407,7 @@ import * as ctsiStaking from './ctsi-staking'; import * as ctsiStakingPool from './ctsi-staking-pool'; import * as skaleDelegationWeighted from './skale-delegation-weighted'; import * as reliquary from './reliquary'; +import * as vstaPoolStaking from './vsta-pool-staking'; const strategies = { 'forta-shares': fortaShares, @@ -819,7 +820,8 @@ const strategies = { 'ctsi-staking': ctsiStaking, 'ctsi-staking-pool': ctsiStakingPool, 'skale-delegation-weighted': skaleDelegationWeighted, - reliquary + reliquary, + 'vsta-pool-staking': vstaPoolStaking }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/vsta-pool-staking/README.md b/src/strategies/vsta-pool-staking/README.md new file mode 100644 index 000000000..189242083 --- /dev/null +++ b/src/strategies/vsta-pool-staking/README.md @@ -0,0 +1,27 @@ +# vsta-pool-staking + +This strategy returns voters underlying VSTA token balance for lping and staking to our reward farms + +## Params + +- `symbol` - (**Optional**, `string`) Symbol of ERC20 token +- `decimals` - (**Required**, `number`) Decimal precision for ERC20 token +- `balancerVaultAddress` - (**Required**, `string`) Address of Balancer Vault to get token balances of LPs +- `poolAddress` - (**Required**, `string`) Address of VSTA-TOKEN lp token +- `poolId` - (**Required**, `string`) Balancer pool ID of VSTA-TOKEN lp +- `farmAddress` - (**Required**, `string`) Vesta farm address +- `vstaAddress` - (**Required**, `string`) Vesta token address + +Here is an example of parameters: + +```json +{ + "balancerVaultAddress": "0xBA12222222228d8Ba445958a75a0704d566BF2C8", + "poolAddress": "0xC61ff48f94D801c1ceFaCE0289085197B5ec44F0", + "poolId": "0xc61ff48f94d801c1ceface0289085197b5ec44f000020000000000000000004d", + "farmAddress": "0x65207da01293C692a37f59D1D9b1624F0f21177c", + "vstaAddress": "0xa684cd057951541187f288294a1e1C2646aA2d24", + "symbol": "VSTA", + "decimals": 18 +} +``` diff --git a/src/strategies/vsta-pool-staking/examples.json b/src/strategies/vsta-pool-staking/examples.json new file mode 100644 index 000000000..8f74a71b5 --- /dev/null +++ b/src/strategies/vsta-pool-staking/examples.json @@ -0,0 +1,24 @@ +[ + { + "name": "VSTA pool staking strategy", + "strategy": { + "name": "vsta-pool-staking", + "params": { + "balancerVaultAddress": "0xBA12222222228d8Ba445958a75a0704d566BF2C8", + "poolAddress": "0xC61ff48f94D801c1ceFaCE0289085197B5ec44F0", + "poolId": "0xc61ff48f94d801c1ceface0289085197b5ec44f000020000000000000000004d", + "farmAddress": "0x65207da01293C692a37f59D1D9b1624F0f21177c", + "vstaAddress": "0xa684cd057951541187f288294a1e1C2646aA2d24", + "symbol": "VSTA", + "decimals": 18 + } + }, + "network": "42161", + "addresses": [ + "0x88684f6abb5dcd4d3195cc2c714dd79de5a76999", + "0x126824925a67f98dca1eb9d92d78d51c99f3a427", + "0x7a16e350ab5929a40cd9a6f51957d5a45a6e361b" + ], + "snapshot": 44025597 + } +] diff --git a/src/strategies/vsta-pool-staking/index.ts b/src/strategies/vsta-pool-staking/index.ts new file mode 100644 index 000000000..c4e3ca9f1 --- /dev/null +++ b/src/strategies/vsta-pool-staking/index.ts @@ -0,0 +1,55 @@ +import { formatUnits } from '@ethersproject/units'; +import { getAddress } from '@ethersproject/address'; +import { Multicaller } from '../../utils'; + +export const author = 'shinitakunai'; +export const version = '0.1.0'; + +const abi = [ + 'function getPoolTokens(bytes32 poolId) external view returns (address[], uint256[], uint256)', + 'function totalSupply() external view returns (uint256)', + 'function balances(address owner) external view returns (uint256)' +]; + +export async function strategy( + _space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multi = new Multicaller(network, provider, abi, { blockTag }); + multi.call('poolTokens', options.balancerVaultAddress, 'getPoolTokens', [ + options.poolId + ]); + multi.call('lpTokenTotalSupply', options.poolAddress, 'totalSupply', []); + addresses.forEach((address) => + multi.call(`userBalances.${address}`, options.farmAddress, 'balances', [ + address + ]) + ); + + const { + poolTokens: [tokens, balances], + lpTokenTotalSupply, + userBalances + } = await multi.execute(); + + const vstaIndex = tokens.findIndex( + (address) => address.toLowerCase() === options.vstaAddress.toLowerCase() + ); + + const vstaPerLp = balances[vstaIndex].div(lpTokenTotalSupply); + + const result = Object.fromEntries( + Object.entries(userBalances).map(([address, lpBalance]) => [ + getAddress(address), + parseFloat(formatUnits(vstaPerLp.mul(lpBalance), options.decimals)) + ]) + ); + + return result; +} diff --git a/src/strategies/vsta-pool-staking/schema.json b/src/strategies/vsta-pool-staking/schema.json new file mode 100644 index 000000000..a2d73368c --- /dev/null +++ b/src/strategies/vsta-pool-staking/schema.json @@ -0,0 +1,73 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "symbol", + "examples": ["e.g. VSTA"], + "maxLength": 16 + }, + "decimals": { + "type": "number", + "title": "decimals", + "examples": ["e.g. 18"] + }, + "balancerVaultAddress": { + "type": "string", + "title": "balancerVaultAddress", + "examples": ["e.g. 0x2d94AA3e47d9D5024503Ca8491fcE9A2fB4DA198"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "poolAddress": { + "type": "string", + "title": "poolAddress", + "examples": ["e.g. 0x472D0B0DDFE0BC02C27928b8BcbD67E65D07d48a"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "poolId": { + "type": "string", + "title": "poolId", + "examples": [ + "e.g. 0xc61ff48f94d801c1ceface0289085197b5ec44f000020000000000000000004d" + ], + "pattern": "^0x[a-fA-F0-9]{64}$", + "minLength": 66, + "maxLength": 66 + }, + "farmAddress": { + "type": "string", + "title": "farmAddress", + "examples": ["e.g. 0x472D0B0DDFE0BC02C27928b8BcbD67E65D07d48a"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "vstaAddress": { + "type": "string", + "title": "vstaAddress", + "examples": ["e.g. 0x472D0B0DDFE0BC02C27928b8BcbD67E65D07d48a"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } + }, + "required": [ + "decimals", + "balancerVaultAddress", + "poolAddress", + "farmAddress", + "vstaAddress" + ], + "additionalProperties": false + } + } +} From ea14aaa30e1a5560417d19b58a9953c7d483aece Mon Sep 17 00:00:00 2001 From: Tommy K <83377811+tklindt@users.noreply.github.com> Date: Thu, 8 Dec 2022 00:42:43 -0700 Subject: [PATCH 251/815] [erc20-balance-of-at] Add Strategy - erc20-balance-of-at (#980) * Add Strategy * Update src/strategies/erc20-balance-of-at/index.ts Co-authored-by: Chaitanya * Update src/strategies/erc20-balance-of-at/index.ts Co-authored-by: Chaitanya Co-authored-by: Chaitanya --- src/strategies/erc20-balance-of-at/README.md | 14 +++++++ .../erc20-balance-of-at/examples.json | 28 ++++++++++++++ src/strategies/erc20-balance-of-at/index.ts | 32 ++++++++++++++++ .../erc20-balance-of-at/schema.json | 38 +++++++++++++++++++ src/strategies/index.ts | 2 + 5 files changed, 114 insertions(+) create mode 100644 src/strategies/erc20-balance-of-at/README.md create mode 100644 src/strategies/erc20-balance-of-at/examples.json create mode 100644 src/strategies/erc20-balance-of-at/index.ts create mode 100644 src/strategies/erc20-balance-of-at/schema.json diff --git a/src/strategies/erc20-balance-of-at/README.md b/src/strategies/erc20-balance-of-at/README.md new file mode 100644 index 000000000..e54cc6d3f --- /dev/null +++ b/src/strategies/erc20-balance-of-at/README.md @@ -0,0 +1,14 @@ +# erc20-balance-of-at + +This strategy returns the balances of the voters for a specific ERC20 token at a specified snapshotID. The ERC20 token contract must implement ERC20 Snapshot (https://docs.openzeppelin.com/contracts/3.x/api/token/erc20#ERC20Snapshot) + +Here is an example of parameters: + +```json +{ + "address": "0xb4B486496469B3269c8907543706C377daAA4dD9", + "symbol": "PYE", + "decimals": 9, + "snapshotId": 1 +} +``` diff --git a/src/strategies/erc20-balance-of-at/examples.json b/src/strategies/erc20-balance-of-at/examples.json new file mode 100644 index 000000000..c0dcdd409 --- /dev/null +++ b/src/strategies/erc20-balance-of-at/examples.json @@ -0,0 +1,28 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "erc20-balance-of-at", + "params": { + "address": "0xb4B486496469B3269c8907543706C377daAA4dD9", + "symbol": "PYE", + "decimals": 9, + "snapshotId": 1 + } + }, + "network": "56", + "addresses": [ + "0x2E9012CeE533a78D822ed3cdb0fe5C6F3A76092F", + "0x848AE3318A798bA0354c4B817e4005a5DE72ca69", + "0xA4F971216d178C840F03cEcbe945811378aFb25d", + "0x76Cb562A83C71B8457c9705072201740A4463100", + "0x08386c3e469420Ed44522C3AF38fC91713D2Cbbf", + "0x7EFc2150058EB91B3DDd885f6a6991C28E0De39d", + "0x59444C2bfB8b5ef089d630701d467AB6656D05Bc", + "0xf6f2B0C7f0c806Fb27FD2b16DC298997B957E0B5", + "0xac0ebcd2f8ed5a56F9765EBB820D3C081a1030A4", + "0x595f6cf9086Bc85d574100962ac201cDA7e5315F" + ], + "snapshot": 23711285 + } +] diff --git a/src/strategies/erc20-balance-of-at/index.ts b/src/strategies/erc20-balance-of-at/index.ts new file mode 100644 index 000000000..cd6e0f411 --- /dev/null +++ b/src/strategies/erc20-balance-of-at/index.ts @@ -0,0 +1,32 @@ +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'OfficialDevTeamSix'; +export const version = '0.1.0'; + +const abi = [ + 'function balanceOfAt(address account, uint256 snapshotId) external view returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options +): Promise> { + + const multi = new Multicaller(network, provider, abi); + addresses.forEach((address) => + multi.call(address, options.address, 'balanceOfAt', [address, options.snapshotId]) + ); + const result: Record = await multi.execute(); + + return Object.fromEntries( + Object.entries(result).map(([address, balance]) => [ + address, + parseFloat(formatUnits(balance, options.decimals)) + ]) + ); +} diff --git a/src/strategies/erc20-balance-of-at/schema.json b/src/strategies/erc20-balance-of-at/schema.json new file mode 100644 index 000000000..094c42665 --- /dev/null +++ b/src/strategies/erc20-balance-of-at/schema.json @@ -0,0 +1,38 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. UNI"], + "maxLength": 16 + }, + "address": { + "type": "string", + "title": "Contract address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 18"] + }, + "snapshotId": { + "type": "number", + "title": "SnapshotID", + "examples": ["e.g. 5"] + } + }, + "required": ["address", "decimals", "snapshotId"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 17b3efc5c..719e7a04b 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -21,6 +21,7 @@ import * as ens10kClub from './ens-10k-club'; import * as ensAllClubDigits from './ens-all-club-digits'; import * as governorDelegator from './governor-delegator'; import * as erc20BalanceOf from './erc20-balance-of'; +import * as erc20BalanceOfAt from './erc20-balance-of-at'; import * as erc20BalanceOfCoeff from './erc20-balance-of-coeff'; import * as erc20BalanceOfFixedTotal from './erc20-balance-of-fixed-total'; import * as erc20BalanceOfCv from './erc20-balance-of-cv'; @@ -440,6 +441,7 @@ const strategies = { 'ens-all-club-digits': ensAllClubDigits, 'governor-delegator': governorDelegator, 'erc20-balance-of': erc20BalanceOf, + 'erc20-balance-of-at': erc20BalanceOfAt, 'erc20-votes': erc20Votes, 'erc20-votes-with-override': erc20VotesWithOverride, 'erc721-multi-registry-weighted': erc721MultiRegistryWeighted, From 436ddcc0056d01dd759200a009a086cd4598507e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 9 Dec 2022 13:37:21 +0530 Subject: [PATCH 252/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.54 (#982) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index e7351ed8e..d96c7a6b3 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.53", + "@snapshot-labs/snapshot.js": "^0.4.54", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 983c33521..a332b5a83 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.53": - version "0.4.53" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.53.tgz#9aa8d32d5ed2be51cdd373a05bd417e1bee8f938" - integrity sha512-fn/PPNuO6BzJxMZYSnLhH8gVyOX6mKbqftqSgKwAYAIfEfYJiEenZXhQRROi0aZ1JK2Qycf3pkqHv+ghy0YDEg== +"@snapshot-labs/snapshot.js@^0.4.54": + version "0.4.54" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.54.tgz#a8c5b5e432487fcd15a9ce4f4706f8c84a9509e3" + integrity sha512-Hv7kDr6xOJDZbQjmHEP9xFwksOcoWSv5ZeLIcwqPV2mscydCMNx3GmATSPAW0FykDc8f0L6ngUahU87X5wUC7Q== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 2d132d0354320d6495e2eb6a5dfb0378822bbf1a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 9 Dec 2022 19:27:26 +0530 Subject: [PATCH 253/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.55 (#983) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index d96c7a6b3..dd69bab00 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.54", + "@snapshot-labs/snapshot.js": "^0.4.55", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index a332b5a83..fdf58739c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.54": - version "0.4.54" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.54.tgz#a8c5b5e432487fcd15a9ce4f4706f8c84a9509e3" - integrity sha512-Hv7kDr6xOJDZbQjmHEP9xFwksOcoWSv5ZeLIcwqPV2mscydCMNx3GmATSPAW0FykDc8f0L6ngUahU87X5wUC7Q== +"@snapshot-labs/snapshot.js@^0.4.55": + version "0.4.55" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.55.tgz#e99b395edd796261b048b9e840278c39f50451dd" + integrity sha512-i941i4InG8yZoL1xhIJbT8zoK6XueDKBIKHvFQAF0i1P8iX8WlTmL1DfuqrkDt+oWLuLBS6ZPD30xm9QqI1/Uw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From b2d1af04141a996758fa499624f67904a9929cfb Mon Sep 17 00:00:00 2001 From: G2 Date: Sat, 10 Dec 2022 13:03:10 -0500 Subject: [PATCH 254/815] One-POAP-One-Vote [poap] (#977) * feat: poap 1:1 strategy * fix: grammar * refactor: some optimizations * fix: reorder imports * fix: use continue instead of return * fix: use erc721 strategy * fix: include snapshot for consistent results * fix: feedback * hardcode contract address * no need to lowercase addresses Co-authored-by: Alexander Greene --- src/strategies/index.ts | 2 ++ src/strategies/poap-with-weight-v2/index.ts | 10 +++--- src/strategies/poap-with-weight/index.ts | 37 ++++++++++++--------- src/strategies/poap/README.md | 13 ++++++++ src/strategies/poap/examples.json | 18 ++++++++++ src/strategies/poap/index.ts | 27 +++++++++++++++ 6 files changed, 87 insertions(+), 20 deletions(-) create mode 100644 src/strategies/poap/README.md create mode 100644 src/strategies/poap/examples.json create mode 100644 src/strategies/poap/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 719e7a04b..0dd1fb845 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -188,6 +188,7 @@ import * as trancheStakingSLICE from './tranche-staking-slice'; 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 poapWithWeight from './poap-with-weight'; import * as poapWithWeightV2 from './poap-with-weight-v2'; import * as uniswapV3 from './uniswap-v3'; @@ -605,6 +606,7 @@ const strategies = { 'unipool-same-token': unipoolSameToken, 'unipool-univ2-lp': unipoolUniv2Lp, 'unipool-xsushi': unipoolXSushi, + poap: poap, 'poap-with-weight': poapWithWeight, 'poap-with-weight-v2': poapWithWeightV2, 'uniswap-v3': uniswapV3, diff --git a/src/strategies/poap-with-weight-v2/index.ts b/src/strategies/poap-with-weight-v2/index.ts index 44571c4c4..74cc8a4a5 100644 --- a/src/strategies/poap-with-weight-v2/index.ts +++ b/src/strategies/poap-with-weight-v2/index.ts @@ -2,7 +2,7 @@ import { getAddress } from '@ethersproject/address'; import { subgraphRequest } from '../../utils'; export const author = 'gawainb'; -export const version = '2.0.0'; +export const version = '2.1.0'; const POAP_API_ENDPOINT_URL = { '1': 'https://api.thegraph.com/subgraphs/name/poap-xyz/poap', @@ -13,12 +13,11 @@ const EVENT_IDS_LIMIT = 500; const MAX_TOKENS_PER_PAGE = 1000; export async function strategy( - space, + _space, network, - provider, + _provider, addresses, options, - // eslint-disable-next-line @typescript-eslint/no-unused-vars snapshot ) { if (options.eventIds.length > EVENT_IDS_LIMIT) { @@ -53,6 +52,9 @@ export async function strategy( } } }; + if (snapshot !== 'latest') { + query.tokens.__args['block'] = { number: snapshot }; + } while (true) { const supplyResponse = await subgraphRequest( diff --git a/src/strategies/poap-with-weight/index.ts b/src/strategies/poap-with-weight/index.ts index bd01b91f8..3fca2933f 100644 --- a/src/strategies/poap-with-weight/index.ts +++ b/src/strategies/poap-with-weight/index.ts @@ -1,8 +1,9 @@ +import { getAddress } from '@ethersproject/address'; import { subgraphRequest } from '../../utils'; import examplesFile from './examples.json'; export const author = 'gawainb'; -export const version = '1.0.0'; +export const version = '1.1.0'; export const examples = examplesFile; const POAP_API_ENDPOINT_URL = { @@ -13,6 +14,7 @@ const POAP_API_ENDPOINT_URL = { const getTokenSupply = { tokens: { __args: { + block: undefined as undefined | { number: number }, where: { id_in: undefined } @@ -28,38 +30,41 @@ const getTokenSupply = { }; export async function strategy( - space, + _space, network, - provider, + _provider, addresses, options, - // eslint-disable-next-line @typescript-eslint/no-unused-vars snapshot ) { + const addressesMap = addresses.reduce((map, address) => { + map[getAddress(address)] = 0; + return map; + }, {}); // Set TokenIds as arguments for GQL query getTokenSupply.tokens.__args.where.id_in = options.tokenIds.map( (token) => token.id ); - const poapWeights = {}; + if (snapshot !== 'latest') { + getTokenSupply.tokens.__args.block = { number: snapshot }; + } const supplyResponse = await subgraphRequest( POAP_API_ENDPOINT_URL[network], getTokenSupply ); if (supplyResponse && supplyResponse.tokens) { + const tokenIdsWeightMap = options.tokenIds.reduce((map, { id, weight }) => { + map[id] = weight; + return map; + }, {}); supplyResponse.tokens.forEach((token: any) => { - if (!poapWeights[token.owner.id.toLowerCase()]) - poapWeights[token.owner.id.toLowerCase()] = 0; - poapWeights[token.owner.id.toLowerCase()] += - options.tokenIds.find((a) => a.id === token.id).weight * - parseInt(token.event.tokenCount); + const checksumAddress = getAddress(token.owner.id); + if (!addressesMap[checksumAddress]) addressesMap[checksumAddress] = 0; + addressesMap[checksumAddress] += + tokenIdsWeightMap[token.id] * parseInt(token.event.tokenCount); }); } - return Object.fromEntries( - addresses.map((address: any) => [ - address, - poapWeights[address.toLowerCase()] || 0 - ]) - ); + return addressesMap; } diff --git a/src/strategies/poap/README.md b/src/strategies/poap/README.md new file mode 100644 index 000000000..288a50990 --- /dev/null +++ b/src/strategies/poap/README.md @@ -0,0 +1,13 @@ +# POAP (erc721) + +Each POAP is implemented as an erc721 with a max supply tokens. + +This strategy returns the number of POAP ERC721 NFTs owned by each account. + +Here is an example of parameters: + +```json +{ + "symbol": "POAP" +} +``` diff --git a/src/strategies/poap/examples.json b/src/strategies/poap/examples.json new file mode 100644 index 000000000..406737427 --- /dev/null +++ b/src/strategies/poap/examples.json @@ -0,0 +1,18 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "poap", + "params": { + "symbol": "POAP" + } + }, + "network": "100", + "addresses": [ + "0x837d21cfda71e93e5257f95ce2c49751675ebcb1", + "0x00ac36c51500e900ab0f4e692fc1338cf70571b2", + "0xdd6f702c2907ce401888d993d7dc185e7a824466" + ], + "snapshot": 13040844 + } +] diff --git a/src/strategies/poap/index.ts b/src/strategies/poap/index.ts new file mode 100644 index 000000000..15ea3b07f --- /dev/null +++ b/src/strategies/poap/index.ts @@ -0,0 +1,27 @@ +import { getAddress } from '@ethersproject/address'; +import { strategy as erc721Strategy } from '../erc721'; + +export const author = 'greenealexander'; +export const version = '1.0.0'; + +export async function strategy( + space, + network, + provider, + addresses, + _options, + snapshot +) { + const results = await erc721Strategy( + space, + network, + provider, + addresses, + { address: '0x22C1f6050E56d2876009903609a2cC3fEf83B415' }, + snapshot + ); + return addresses.reduce((map, address) => { + map[getAddress(address)] = results[address] ?? 0; + return map; + }, {}); +} From 595f890c68b5c52774bcf74216c3aebb1c034635 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 11 Dec 2022 22:12:09 +0530 Subject: [PATCH 255/815] Automated lint (#985) Co-authored-by: ChaituVR --- src/strategies/erc20-balance-of-at/index.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/strategies/erc20-balance-of-at/index.ts b/src/strategies/erc20-balance-of-at/index.ts index cd6e0f411..34049d018 100644 --- a/src/strategies/erc20-balance-of-at/index.ts +++ b/src/strategies/erc20-balance-of-at/index.ts @@ -16,10 +16,12 @@ export async function strategy( addresses, options ): Promise> { - const multi = new Multicaller(network, provider, abi); addresses.forEach((address) => - multi.call(address, options.address, 'balanceOfAt', [address, options.snapshotId]) + multi.call(address, options.address, 'balanceOfAt', [ + address, + options.snapshotId + ]) ); const result: Record = await multi.execute(); From 1cbd1eddd96120a7454b77fd26a93591801abc74 Mon Sep 17 00:00:00 2001 From: Leez <94301129+0xleez@users.noreply.github.com> Date: Mon, 12 Dec 2022 19:25:54 +0100 Subject: [PATCH 256/815] [jpegd-locked-jpeg-of] Add Strategy to account for locked JPEG tokens for Trait or LTV Boosts (#984) * jpegd-boosts * rename * readme * switched from object to string abi * query subgraph at blockNumber --- src/strategies/index.ts | 4 +- src/strategies/jpegd-locked-jpeg-of/README.md | 24 +++++++ .../jpegd-locked-jpeg-of/examples.json | 28 ++++++++ src/strategies/jpegd-locked-jpeg-of/index.ts | 72 +++++++++++++++++++ 4 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 src/strategies/jpegd-locked-jpeg-of/README.md create mode 100644 src/strategies/jpegd-locked-jpeg-of/examples.json create mode 100644 src/strategies/jpegd-locked-jpeg-of/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 0dd1fb845..0023859a1 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -410,6 +410,7 @@ import * as ctsiStakingPool from './ctsi-staking-pool'; import * as skaleDelegationWeighted from './skale-delegation-weighted'; import * as reliquary from './reliquary'; import * as vstaPoolStaking from './vsta-pool-staking'; +import * as jpegdLockedJpegOf from './jpegd-locked-jpeg-of'; const strategies = { 'forta-shares': fortaShares, @@ -825,7 +826,8 @@ const strategies = { 'ctsi-staking-pool': ctsiStakingPool, 'skale-delegation-weighted': skaleDelegationWeighted, reliquary, - 'vsta-pool-staking': vstaPoolStaking + 'vsta-pool-staking': vstaPoolStaking, + 'jpegd-locked-jpeg-of': jpegdLockedJpegOf }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/jpegd-locked-jpeg-of/README.md b/src/strategies/jpegd-locked-jpeg-of/README.md new file mode 100644 index 000000000..6769b1e49 --- /dev/null +++ b/src/strategies/jpegd-locked-jpeg-of/README.md @@ -0,0 +1,24 @@ +# jpegd-locked-jpeg-of + +This strategy returns voters' aggregated locked JPEG token balance for Trait and LTV Boosts on the JPEG'd platform + +## Params + +- `collectionToProviderAddress` - (**Required**, `object`) Collection name (uppercase) to NftValueProvider address + +Here is an example of parameters: + +```json +{ + "collectionToProviderAddress": { + "CRYPTOPUNKS": "0xdf7806eaa13497efffdb1541d6b0fdd1a9566fd0", + "ETHERROCKS": "0x9921da2908cc59b13ddbcf45e64bfa91c78c4249", + "BAYC": "0x5b9cAA47A52e4BfbBce2f2A9f858c2A501B48C42", + "MAYC": "0xdEd112453BD8EA88CdaB214CFD92Ab06E232E9d7", + "DOODLES": "0xdd245B7823ee82D14419CE072Ef815868F0D1f1A", + "PUDGYPENGUINS": "0xd0bf9A40FebDfCA596fde589a343C6cDA37A7B90", + "AZUKI": "0xcaA0aa80637262fd3Ba6DD5b5598a2BAFAc27cE8", + "CLONEX": "0xb36B65400E13FF57dFDa29bBb7dC79eaA7ecA14C" + } +} +``` diff --git a/src/strategies/jpegd-locked-jpeg-of/examples.json b/src/strategies/jpegd-locked-jpeg-of/examples.json new file mode 100644 index 000000000..c6cecea2c --- /dev/null +++ b/src/strategies/jpegd-locked-jpeg-of/examples.json @@ -0,0 +1,28 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "jpegd-locked-jpeg-of", + "params": { + "collectionToProviderAddress": { + "CRYPTOPUNKS": "0xdf7806eaa13497efffdb1541d6b0fdd1a9566fd0", + "ETHERROCKS": "0x9921da2908cc59b13ddbcf45e64bfa91c78c4249", + "BAYC": "0x5b9cAA47A52e4BfbBce2f2A9f858c2A501B48C42", + "MAYC": "0xdEd112453BD8EA88CdaB214CFD92Ab06E232E9d7", + "DOODLES": "0xdd245B7823ee82D14419CE072Ef815868F0D1f1A", + "PUDGYPENGUINS": "0xd0bf9A40FebDfCA596fde589a343C6cDA37A7B90", + "AZUKI": "0xcaA0aa80637262fd3Ba6DD5b5598a2BAFAc27cE8", + "CLONEX": "0xb36B65400E13FF57dFDa29bBb7dC79eaA7ecA14C" + }, + "start": 15363080 + } + }, + "network": "1", + "addresses": [ + "0x9c5083dd4838e120dbeac44c052179692aa5dac5", + "0xB0dAfc466871c29662E5cbf4227322C96A8Ccbe9", + "0x0017dfe08bcc0dc9a323ca5d4831e371534e9320" + ], + "snapshot": 16119881 + } +] \ No newline at end of file diff --git a/src/strategies/jpegd-locked-jpeg-of/index.ts b/src/strategies/jpegd-locked-jpeg-of/index.ts new file mode 100644 index 000000000..ff34eeca7 --- /dev/null +++ b/src/strategies/jpegd-locked-jpeg-of/index.ts @@ -0,0 +1,72 @@ +import { formatUnits } from '@ethersproject/units'; +import { getAddress } from '@ethersproject/address'; +import { multicall } from '../../utils'; +import { subgraphRequest } from '../../utils'; + +export const author = '0xleez'; +export const version = '0.1.0'; + +const UNISWAP_SUBGRAPH_URL = { + '1': 'https://api.thegraph.com/subgraphs/name/jpegd/jpegd-core-mainnet' +}; + +const abi = [ + 'function traitBoostPositions(uint256 _nftIndex) view returns (address owner, uint256 unlockAt, uint256 lockedValue)', + 'function ltvBoostPositions(uint256 _nftIndex) view returns (address owner, uint256 unlockAt, uint256 lockedValue)' +]; + +export async function strategy( + _space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const { collectionToProviderAddress } = options; + + const params = { + jpeglocks: { + __args: { + where: { + owner_in: addresses.map((address) => address.toLowerCase()) + }, + block: blockTag != 'latest' ? { number: blockTag } : null + }, + owner: { id: true }, + collection: { id: true }, + type: true, + nftIndex: true, + amount: true, + unlockTime: true + } + }; + + const result = await subgraphRequest(UNISWAP_SUBGRAPH_URL[network], params); + const jpegLocks = result.jpeglocks ?? []; + + const responses = await multicall( + network, + provider, + abi, + jpegLocks.map((jpegLock: any) => [ + collectionToProviderAddress[jpegLock.collection.id], + jpegLock.type === 'LTV' ? 'ltvBoostPositions' : 'traitBoostPositions', + [jpegLock.nftIndex] + ]), + { blockTag } + ); + + return responses.reduce((acc, response, index) => { + const jpegLock = jpegLocks[index]; + const address = getAddress(jpegLock.owner.id); + + if (!acc[address]) acc[address] = 0; + + const lockedJpeg = Number(formatUnits(response.lockedValue.toString(), 18)); + acc[address] += lockedJpeg; + return acc; + }, {}); +} From fb45e501578681c75ecfb0e9085890b616e1173f Mon Sep 17 00:00:00 2001 From: nicholaspai <9457025+nicholaspai@users.noreply.github.com> Date: Tue, 13 Dec 2022 05:43:57 -0500 Subject: [PATCH 257/815] feat: Add ACX staking strategy [across-staked-acx] (#986) * feat: Add ACX staking strategy Signed-off-by: nicholaspai * Update index.ts * Update src/strategies/across-staked-acx/index.ts * Update src/strategies/across-staked-acx/index.ts Signed-off-by: nicholaspai Co-authored-by: Chaitanya --- src/strategies/across-staked-acx/README.md | 31 ++++ .../across-staked-acx/examples.json | 26 ++++ src/strategies/across-staked-acx/index.ts | 147 ++++++++++++++++++ src/strategies/index.ts | 2 + 4 files changed, 206 insertions(+) create mode 100644 src/strategies/across-staked-acx/README.md create mode 100644 src/strategies/across-staked-acx/examples.json create mode 100644 src/strategies/across-staked-acx/index.ts diff --git a/src/strategies/across-staked-acx/README.md b/src/strategies/across-staked-acx/README.md new file mode 100644 index 000000000..bc0d0d54a --- /dev/null +++ b/src/strategies/across-staked-acx/README.md @@ -0,0 +1,31 @@ +# across-staked-acx + +This strategy returns the voting power of an address that has staked any LP tokens in the [AcceleratingDistributor](https://etherscan.io/address/0x9040e41eF5E8b281535a96D9a48aCb8cfaBD9a48) +contract. The voting power is calculated as the amount of staked ACX-LP tokens multiplied by the current exchange +rate of ACX-LP to ACX. Finally, outstanding rewards for all staked LP positions denominated in ACX are then added to voting power. + +## Params + +- `acceleratingDistributorAddress` - (**Required**, `string`) Address of contract that emits ACX rewards for staked LP tokens. +- `acxLpTokenAddress` - (**Required**, `string`) Address of ACX-LP token. +- `wethLpTokenAddress` - (**Required**, `string`) Address of WETH-LP token. +- `usdcLpTokenAddress` - (**Required**, `string`) Address of USDC-LP token. +- `wbtcLpTokenAddress` - (**Required**, `string`) Address of WBTC-LP token. +- `daiLpTokenAddress` - (**Required**, `string`) Address of DAI-LP token. +- `hubPoolAddress` - (**Required**, `string`) Address of contract users can deposit tokens to receive LP tokens. +- `acxTokenAddress` - (**Required**, `string`) Address of token that is emitted to staked LP users in the AcceleratingDistributor. + +Here is an example of parameters that work for `"network": "1"` + +```json +{ + "acceleratingDistributorAddress": "0x9040e41eF5E8b281535a96D9a48aCb8cfaBD9a48", + "acxLpTokenAddress": "0xb0C8fEf534223B891D4A430e49537143829c4817", + "wethLpTokenAddress": "0x28F77208728B0A45cAb24c4868334581Fe86F95B", + "usdcLpTokenAddress": "0xC9b09405959f63F72725828b5d449488b02be1cA", + "wbtcLpTokenAddress": "0x59C1427c658E97a7d568541DaC780b2E5c8affb4", + "daiLpTokenAddress": "0x4fabacac8c41466117d6a38f46d08ddd4948a0cb", + "hubPoolAddress": "0xc186fa914353c44b2e33ebe05f21846f1048beda", + "acxTokenAddress": "0x44108f0223A3C3028F5Fe7AEC7f9bb2E66beF82F" +} +``` diff --git a/src/strategies/across-staked-acx/examples.json b/src/strategies/across-staked-acx/examples.json new file mode 100644 index 000000000..a00b52245 --- /dev/null +++ b/src/strategies/across-staked-acx/examples.json @@ -0,0 +1,26 @@ +[ + { + "name": "Example of Across Staked-ACX Strategy", + "strategy": { + "name": "across-staked-acx", + "params": { + "acceleratingDistributorAddress": "0x9040e41eF5E8b281535a96D9a48aCb8cfaBD9a48", + "acxLpTokenAddress": "0xb0C8fEf534223B891D4A430e49537143829c4817", + "wethLpTokenAddress": "0x28F77208728B0A45cAb24c4868334581Fe86F95B", + "usdcLpTokenAddress": "0xC9b09405959f63F72725828b5d449488b02be1cA", + "wbtcLpTokenAddress": "0x59C1427c658E97a7d568541DaC780b2E5c8affb4", + "daiLpTokenAddress": "0x4fabacac8c41466117d6a38f46d08ddd4948a0cb", + "hubPoolAddress": "0xc186fa914353c44b2e33ebe05f21846f1048beda", + "acxTokenAddress": "0x44108f0223A3C3028F5Fe7AEC7f9bb2E66beF82F" + } + }, + "network": "1", + "addresses": [ + "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D", + "0x718648C8c531F91b528A7757dD2bE813c3940608", + "0x996267d7d1B7f5046543feDe2c2Db473Ed4f65e9", + "0xbfb496ACb99299e9eCE84B3FD1B3fDd0f6CDDf49" + ], + "snapshot": 16171362 + } +] diff --git a/src/strategies/across-staked-acx/index.ts b/src/strategies/across-staked-acx/index.ts new file mode 100644 index 000000000..cb032a1c8 --- /dev/null +++ b/src/strategies/across-staked-acx/index.ts @@ -0,0 +1,147 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import { formatUnits, parseUnits } from '@ethersproject/units'; +import { multicall } from '../../utils'; + +export const author = 'nicholaspai'; +export const version = '0.1.0'; + +/** + * @notice This strategy returns the voting power of an address that has staked ACX-LP tokens in the + * AcceleratingDistributor contract. The voting power is calculated as the amount of staked ACX-LP + * tokens multiplied by the current exchange rate of ACX-LP to ACX. Outstanding rewards denominated + * in ACX are also added to voting power. + */ +const abi = [ + 'function getUserStake(address stakedToken, address account) view returns (tuple(uint256 cumulativeBalance, uint256 averageDepositTime, uint256 rewardsAccumulatedPerToken, uint256 rewardsOutstanding))', + 'function getOutstandingRewards(address stakedToken, address account) view returns (uint256)', + 'function pooledTokens(address) view returns (address lpToken, bool isEnabled, uint32 lastLpFeeUpdate, int256 utilizedReserves, uint256 liquidReserves, uint256 undistributedLpFees)', + 'function totalSupply() view returns (uint256)' +]; + +interface PooledToken { + lpToken: string; + isEnabled: boolean; + lastLpFeeUpdate: BigNumber; + utilizedReserves: BigNumber; + liquidReserves: BigNumber; + undistributedLpFees: BigNumber; +} + +const acxLpTokensDecimals = 18; +const oneUnitAcxLp = parseUnits('1', acxLpTokensDecimals); + +export async function strategy( + _space, + network, + provider, + addresses: string[], + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const response = await multicall( + network, + provider, + abi, + [ + [options.hubPoolAddress, 'pooledTokens', [options.acxTokenAddress]], + [options.acxLpTokenAddress, 'totalSupply', []], + ...addresses.map((address) => [ + options.acceleratingDistributorAddress, + 'getUserStake', + [options.acxLpTokenAddress, address] + ]), + ...addresses.map((address) => [ + options.acceleratingDistributorAddress, + 'getOutstandingRewards', + [options.acxLpTokenAddress, address] + ]), + ...addresses.map((address) => [ + options.acceleratingDistributorAddress, + 'getOutstandingRewards', + [options.wethLpTokenAddress, address] + ]), + ...addresses.map((address) => [ + options.acceleratingDistributorAddress, + 'getOutstandingRewards', + [options.usdcLpTokenAddress, address] + ]), + ...addresses.map((address) => [ + options.acceleratingDistributorAddress, + 'getOutstandingRewards', + [options.wbtcLpTokenAddress, address] + ]), + ...addresses.map((address) => [ + options.acceleratingDistributorAddress, + 'getOutstandingRewards', + [options.daiLpTokenAddress, address] + ]) + ], + { blockTag } + ); + + const pooledTokens: PooledToken = response[0]; + const acxLpTokenSupply: BigNumber = response[1][0]; + const userStake: BigNumber[][] = response.slice(2, 2 + addresses.length); + const outstandingAcxLpRewards = response.slice( + 2 + addresses.length, + 2 + addresses.length * 2 + ); + const outstandingWethLpRewards = response.slice( + 2 + addresses.length * 2, + 2 + addresses.length * 3 + ); + const outstandingUsdcLpRewards = response.slice( + 2 + addresses.length * 3, + 2 + addresses.length * 4 + ); + const outstandingWbtcLpRewards = response.slice( + 2 + addresses.length * 4, + 2 + addresses.length * 5 + ); + const outstandingDaiLpRewards = response.slice( + 2 + addresses.length * 5, + 2 + addresses.length * 6 + ); + + // This is the latest exchange rate as of the last HubPool._sync call. + // This computation is based off of this math: + // - https://github.com/across-protocol/contracts-v2/blob/e911cf59ad3469e19f04f5de1c92d6406c336042/contracts/HubPool.sol#L944 + // (liquidReserves + utilizedReserves - undistributedLpFees) / acxLpTokenSupply + const lastExchangeRate = pooledTokens.liquidReserves + .add(pooledTokens.utilizedReserves) + .sub(pooledTokens.undistributedLpFees) + .mul(oneUnitAcxLp) + .div(acxLpTokenSupply); + + // Convert staked ACX-LP balances to underlying by multiplying by ACX-LP:ACX token exchange rate. + // Note: Each UserStake object is stored on-chain as a tuple with the staked balance being the first element. + const stakedLpBalances = userStake.map((value) => + value[0][0].mul(lastExchangeRate).div(oneUnitAcxLp) + ); + // !!Note: This will break if the reward currency doesn't use same decimals as the staked LP token. + + // Add outstanding ACX rewards to staked balance values. This assumes that the reward + // currency ACX is the same unit as the staked ACX-LP's underlying. + const stakedBalancesPlusRewards = Object.fromEntries( + addresses.map((address, i) => [ + address, + parseFloat( + formatUnits( + stakedLpBalances[i] + .add(outstandingAcxLpRewards[i][0]) + .add(outstandingWethLpRewards[i][0]) + .add(outstandingUsdcLpRewards[i][0]) + .add(outstandingWbtcLpRewards[i][0]) + .add(outstandingDaiLpRewards[i][0]) + .toString(), + acxLpTokensDecimals + ) + ) + ]) + ); + + + return stakedBalancesPlusRewards; +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 0023859a1..ccf4182d2 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -409,11 +409,13 @@ import * as ctsiStaking from './ctsi-staking'; import * as ctsiStakingPool from './ctsi-staking-pool'; import * as skaleDelegationWeighted from './skale-delegation-weighted'; import * as reliquary from './reliquary'; +import * as acrossStakedAcx from './across-staked-acx'; import * as vstaPoolStaking from './vsta-pool-staking'; import * as jpegdLockedJpegOf from './jpegd-locked-jpeg-of'; const strategies = { 'forta-shares': fortaShares, + 'across-staked-acx': acrossStakedAcx, 'ethermon-erc721': ethermon721, 'recusal-list': recusalList, 'landdao-token-tiers': landDaoTiers, From 0de7d870cd04c9718dd756f1364f5f21feb0dbcf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 13 Dec 2022 23:38:01 +0530 Subject: [PATCH 258/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.56 (#987) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index dd69bab00..bd114da3e 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.55", + "@snapshot-labs/snapshot.js": "^0.4.56", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index fdf58739c..3c9b5d6ad 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.55": - version "0.4.55" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.55.tgz#e99b395edd796261b048b9e840278c39f50451dd" - integrity sha512-i941i4InG8yZoL1xhIJbT8zoK6XueDKBIKHvFQAF0i1P8iX8WlTmL1DfuqrkDt+oWLuLBS6ZPD30xm9QqI1/Uw== +"@snapshot-labs/snapshot.js@^0.4.56": + version "0.4.56" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.56.tgz#a7574329de9f6b17d8dc788634c8675ec5f29276" + integrity sha512-IyNoM67vByHMsxRNl1IImMeUJ5LWuSSs2/YR0LmstMPl1LAO+IZx6PQRGRyEGmgmUxcb8LbRjXWd/ev0Ho3mJg== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From bfc69f2ef16549074ddf52c53ccc894ca447875e Mon Sep 17 00:00:00 2001 From: millken Date: Thu, 15 Dec 2022 16:14:38 +0800 Subject: [PATCH 259/815] Update IoTeX API [xrc20-balance-of] (#990) * update api * fix tests --- src/strategies/xrc20-balance-of/examples.json | 1 + src/strategies/xrc20-balance-of/index.ts | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/strategies/xrc20-balance-of/examples.json b/src/strategies/xrc20-balance-of/examples.json index ba59768b0..aa74be298 100644 --- a/src/strategies/xrc20-balance-of/examples.json +++ b/src/strategies/xrc20-balance-of/examples.json @@ -11,6 +11,7 @@ }, "network": "4690", "addresses": [ + "0x0ddfc506136fb7c050cc2e9511eccd81b15e7426", "0x1904BFcb93EdC9BF961Eead2e5c0de81dCc1D37D", "0x87Eea07540789af85B64947aEA21A3f00400B597" ], diff --git a/src/strategies/xrc20-balance-of/index.ts b/src/strategies/xrc20-balance-of/index.ts index 68c6347d3..f78d9880c 100644 --- a/src/strategies/xrc20-balance-of/index.ts +++ b/src/strategies/xrc20-balance-of/index.ts @@ -5,11 +5,11 @@ interface ApiReturn { balance: string[]; } -export const author = 'iotex'; -export const version = '0.0.1'; +export const author = 'iotexproject'; +export const version = '0.0.2'; -const testNetUrl = 'https://testnet.iotexscout.io/apiproxy'; -const mainNetUrl = 'https://iotexscout.io/apiproxy'; +const testNetUrl = 'https://analyser-api.testnet.iotex.io'; +const mainNetUrl = 'https://analyser-api.iotex.io'; function getUrl(network) { return network == 4689 ? mainNetUrl : testNetUrl; @@ -36,7 +36,7 @@ export async function strategy( const apiUrl = getUrl(network); const response = await fetch( - `${apiUrl}/api.AccountService.GetErc20TokenBalanceByHeight`, + `${apiUrl}/api.AccountService.Erc20TokenBalanceByHeight`, { method: 'POST', headers: { From 9903f9671e94c41d8363c8016c16c1f5383bd427 Mon Sep 17 00:00:00 2001 From: gp6284 <90966492+gp6284@users.noreply.github.com> Date: Sun, 18 Dec 2022 16:58:35 +0800 Subject: [PATCH 260/815] Add babywealthyclub strategy [babywealthyclub] (#992) * Add babywealthyclub strategy * Add babywealthyclub strategy Co-authored-by: gp6284 <> --- src/strategies/babywealthyclub/examples.json | 23 ++++++++++ src/strategies/babywealthyclub/index.ts | 48 ++++++++++++++++++++ src/strategies/index.ts | 4 +- 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 src/strategies/babywealthyclub/examples.json create mode 100644 src/strategies/babywealthyclub/index.ts diff --git a/src/strategies/babywealthyclub/examples.json b/src/strategies/babywealthyclub/examples.json new file mode 100644 index 000000000..d77fe1f8a --- /dev/null +++ b/src/strategies/babywealthyclub/examples.json @@ -0,0 +1,23 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "babywealthyclub", + "params": { + "address": "0x1f9655c660B915b4344b71e2A6d3155C57AD1bB6", + "symbol": "BRC", + "decimals": "9", + "weighted": 20000000000 + } + }, + "network": "56", + "addresses": [ + "0x7F57612b01689a0E4f133730AE20cC19E3dF0208", + "0x4A7998DF2Cd16815271bb6b7d3aE7EB30f50a73a", + "0x08D816526BdC9d077DD685Bd9FA49F58A5Ab8e48", + "0x21fF20E7e1B820020415707298b92299CF0951fE", + "0xa7A01B93B889ff0639d5ec02914A77529924a46F" + ], + "snapshot": 23976608 + } +] diff --git a/src/strategies/babywealthyclub/index.ts b/src/strategies/babywealthyclub/index.ts new file mode 100644 index 000000000..aea541d04 --- /dev/null +++ b/src/strategies/babywealthyclub/index.ts @@ -0,0 +1,48 @@ +import { strategy as erc20BalanceOfStrategy } from '../erc20-balance-of'; +import { formatUnits } from '@ethersproject/units'; +import { multicall } from '../../utils'; + +export const author = 'gp6284'; +export const version = '0.1.0'; + +const abi = [ + 'function balanceOf(address account) external view returns (uint256)' +]; +const BWC_ADDRESS = '0xb7F7c7D91Ede27b019e265F8ba04c63333991e02'; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const erc20Balance = await erc20BalanceOfStrategy( + space, + network, + provider, + addresses, + options, + snapshot + ); + const response = await multicall( + network, + provider, + abi, + addresses.map((address: any) => [BWC_ADDRESS, 'balanceOf', [address]]), + { blockTag } + ); + + return Object.fromEntries( + addresses.map((address, i) => [ + address, + parseFloat(formatUnits(response[i].toString(), 0)) > 0 + ? Math.floor( + erc20Balance[addresses[i]] / (options.weighted || 10000000000) + ) + : 0 + ]) + ); +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index ccf4182d2..967817365 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -412,6 +412,7 @@ import * as reliquary from './reliquary'; import * as acrossStakedAcx from './across-staked-acx'; import * as vstaPoolStaking from './vsta-pool-staking'; import * as jpegdLockedJpegOf from './jpegd-locked-jpeg-of'; +import * as babywealthyclub from './babywealthyclub'; const strategies = { 'forta-shares': fortaShares, @@ -829,7 +830,8 @@ const strategies = { 'skale-delegation-weighted': skaleDelegationWeighted, reliquary, 'vsta-pool-staking': vstaPoolStaking, - 'jpegd-locked-jpeg-of': jpegdLockedJpegOf + 'jpegd-locked-jpeg-of': jpegdLockedJpegOf, + babywealthyclub }; Object.keys(strategies).forEach(function (strategyName) { From 3a93cc4c27ef6e89e77c4e27a0a8acbbf7b06401 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Sun, 18 Dec 2022 18:16:37 +0530 Subject: [PATCH 261/815] Remove unused validations (#993) Co-authored-by: Chaitanya S --- src/validations/aave/examples.json | 88 ------------------------ src/validations/aave/index.ts | 50 -------------- src/validations/index.ts | 6 -- src/validations/nouns/examples.json | 31 --------- src/validations/nouns/index.ts | 47 ------------- src/validations/timeperiod/examples.json | 13 ---- src/validations/timeperiod/index.ts | 21 ------ 7 files changed, 256 deletions(-) delete mode 100644 src/validations/aave/examples.json delete mode 100644 src/validations/aave/index.ts delete mode 100644 src/validations/nouns/examples.json delete mode 100644 src/validations/nouns/index.ts delete mode 100644 src/validations/timeperiod/examples.json delete mode 100644 src/validations/timeperiod/index.ts diff --git a/src/validations/aave/examples.json b/src/validations/aave/examples.json deleted file mode 100644 index 03c17b080..000000000 --- a/src/validations/aave/examples.json +++ /dev/null @@ -1,88 +0,0 @@ -[ - { - "name": "Example of Aave Proposition Power proposal validation", - "author": "0x5BC928BF0DAb1e4A2ddd9e347b0F22e88026D76c", - "space": "aave.eth", - "network": "1", - "snapshot": "latest", - "params": { - "minScore": 1, - "strategies": [ - { - "name": "erc20-balance-of", - "params": { - "symbol": "aAAVE", - "address": "0xffc97d72e13e01096502cb8eb52dee56f74dad7b", - "decimals": 18 - } - }, - { - "name": "aave-governance-power", - "params": { - "symbol": "AAVE+stkAAVE", - "decimals": 18, - "powerType": "vote", - "governanceStrategy": "0xb7e383ef9b1e9189fc0f71fb30af8aa14377429e" - } - }, - { - "name": "multichain", - "params": { - "graphs": { - "137": "https://api.thegraph.com/subgraphs/name/sameepsi/maticblocks" - }, - "symbol": "Matic AAVE+amAAVE", - "strategies": [ - { - "name": "erc20-balance-of", - "params": { - "symbol": "AAVE", - "address": "0xD6DF932A45C0f255f85145f286eA0b292B21C90B", - "decimals": 18 - }, - "network": "137" - }, - { - "name": "erc20-balance-of", - "params": { - "symbol": "amAAVE", - "address": "0x1d2a0E5EC8E5bBDCA5CB219e649B565d8e5c3360", - "decimals": 18 - }, - "network": 137 - } - ] - } - }, - { - "name": "contract-call", - "params": { - "args": ["%{address}"], - "symbol": "AAVE in stkBPT", - "address": "0xC0259c59D9f980E3b5e2574cD78C9A9Bc6A8E3fc", - "decimals": 18, - "methodABI": { - "name": "balanceOf", - "type": "function", - "inputs": [ - { - "name": "account", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "view" - } - } - } - ] - } - } -] diff --git a/src/validations/aave/index.ts b/src/validations/aave/index.ts deleted file mode 100644 index 4344d7147..000000000 --- a/src/validations/aave/index.ts +++ /dev/null @@ -1,50 +0,0 @@ -import Validation from '../validation'; -import { getProvider, getScoresDirect } from '../../utils'; - -export default class extends Validation { - public id = 'aave'; - public github = 'kartojal'; - public version = '0.2.0'; - - /** - * Aave Space Validation proposal validation uses: - * - Proposition power of GovernanceStrategy contract - * - Other active Aave Snapshot voting strategies - * - * The current validation implementation mutates the "strategies" field of the space - * to be able to use proposition power instead of voting power for "aave-governance-power". - * - */ - async validate(): Promise { - const minScore = this.params.minScore; - const strategies = this.params.strategies; - - const aaveGovernanceStrategyIndex = strategies.findIndex( - ({ name }) => name === 'aave-governance-power' - ); - - // Use the proposition power instead of voting power - if (aaveGovernanceStrategyIndex >= 0) { - strategies[aaveGovernanceStrategyIndex].params.powerType = 'proposition'; - } - - if (minScore) { - const scores = await getScoresDirect( - this.space, - strategies, - this.network, - getProvider(this.network), - [this.author], - this.snapshot || 'latest' - ); - const totalScore: any = scores - .map((score: any) => - Object.values(score).reduce((a, b: any) => a + b, 0) - ) - .reduce((a, b: any) => a + b, 0); - if (totalScore < minScore) return false; - } - - return true; - } -} diff --git a/src/validations/index.ts b/src/validations/index.ts index b1c03b556..31e93a17f 100644 --- a/src/validations/index.ts +++ b/src/validations/index.ts @@ -1,17 +1,11 @@ import { readFileSync } from 'fs'; import path from 'path'; import basic from './basic'; -import aave from './aave'; -import nouns from './nouns'; -import timeperiod from './timeperiod'; import passportGated from './passport-gated'; import passportWeighted from './passport-weighted'; const validationClasses = { basic, - aave, - nouns, - timeperiod, 'passport-gated': passportGated, 'passport-weighted': passportWeighted }; diff --git a/src/validations/nouns/examples.json b/src/validations/nouns/examples.json deleted file mode 100644 index 75c558f21..000000000 --- a/src/validations/nouns/examples.json +++ /dev/null @@ -1,31 +0,0 @@ -[ - { - "name": "Example of Nouns Proposition Power proposal validation", - "author": "0x03CD30Ab7b6eFaDfdc5D49Ec2B83DDD6a898e054", - "space": "nouns.eth", - "network": "4", - "snapshot": "latest", - "params": { - "minScore": 1, - "strategies": [ - { - "name": "erc20-balance-of", - "params": { - "symbol": "LINK", - "address": "0x01BE23585060835E02B77ef475b0Cc51aA1e0709", - "decimals": 18 - } - }, - { - "name": "nouns-rfp-power", - "params": { - "symbol": "NOUNS", - "decimals": 1, - "powerType": "vote", - "governanceStrategy": "0x50Acc1831E954fB5bB407d7A3CFe1e7769A41ab0" - } - } - ] - } - } -] diff --git a/src/validations/nouns/index.ts b/src/validations/nouns/index.ts deleted file mode 100644 index 3630c7ff7..000000000 --- a/src/validations/nouns/index.ts +++ /dev/null @@ -1,47 +0,0 @@ -import Validation from '../validation'; -import { getProvider, getScoresDirect } from '../../utils'; - -export default class extends Validation { - public id = 'nouns'; - public github = 'waterdrops'; - public version = '0.2.0'; - - /** - * Nouns Space Validation proposal validation uses: - * - * The current validation implementation mutates the "strategies" field of the space - * to be able to use proposition power instead of voting power for "nouns-rfp-power". - * - */ - async validate(): Promise { - const minScore = this.params.minScore; - const strategies = this.params.strategies; - - const nounsRFPStrategyIndex = strategies.findIndex( - ({ name }) => name === 'nouns-rfp-power' - ); - - // Use the proposition power instead of the voting power - if (nounsRFPStrategyIndex >= 0) - strategies[nounsRFPStrategyIndex].params.powerType = 'proposition'; - - if (minScore) { - const scores = await getScoresDirect( - this.space, - strategies, - this.network, - getProvider(this.network), - [this.author], - this.snapshot || 'latest' - ); - const totalScore: any = scores - .map((score: any) => - Object.values(score).reduce((a, b: any) => a + b, 0) - ) - .reduce((a, b: any) => a + b, 0); - if (totalScore < minScore) return false; - } - - return true; - } -} diff --git a/src/validations/timeperiod/examples.json b/src/validations/timeperiod/examples.json deleted file mode 100644 index 92e7d8c56..000000000 --- a/src/validations/timeperiod/examples.json +++ /dev/null @@ -1,13 +0,0 @@ -[ - { - "name": "Example of a prop entry time constrained validation", - "author": "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", - "space": "fabien.eth", - "network": "1", - "snapshot": "latest", - "params": { - "propEntryStart": 1659108444521, - "propEntryEnd": 1659194844521 - } - } -] diff --git a/src/validations/timeperiod/index.ts b/src/validations/timeperiod/index.ts deleted file mode 100644 index c31a95b4b..000000000 --- a/src/validations/timeperiod/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -import Validation from '../validation'; - -export default class extends Validation { - public id = 'timeperiod'; - public github = 'stevef'; - public version = '0.2.0'; - - async validate(): Promise { - const { propEntryStart = 0, propEntryEnd = 0 } = this.params; - - if (!propEntryStart || !propEntryEnd || propEntryStart >= propEntryEnd) - return false; - - const now = new Date().getTime(); - const startTime = new Date(propEntryStart).getTime(); - const endTime = new Date(propEntryEnd).getTime(); - - // Only allow proposals being submitted in this time window. - return now >= startTime && now <= endTime; - } -} From ee343fa0d6e25b13dc1b3f980cd26da0bf51b692 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 18 Dec 2022 18:25:55 +0530 Subject: [PATCH 262/815] Automated lint (#994) Co-authored-by: ChaituVR Co-authored-by: Chaitanya --- src/strategies/across-staked-acx/index.ts | 1 - .../jpegd-locked-jpeg-of/examples.json | 52 +++++++++---------- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/src/strategies/across-staked-acx/index.ts b/src/strategies/across-staked-acx/index.ts index cb032a1c8..43210089d 100644 --- a/src/strategies/across-staked-acx/index.ts +++ b/src/strategies/across-staked-acx/index.ts @@ -142,6 +142,5 @@ export async function strategy( ]) ); - return stakedBalancesPlusRewards; } diff --git a/src/strategies/jpegd-locked-jpeg-of/examples.json b/src/strategies/jpegd-locked-jpeg-of/examples.json index c6cecea2c..59b010597 100644 --- a/src/strategies/jpegd-locked-jpeg-of/examples.json +++ b/src/strategies/jpegd-locked-jpeg-of/examples.json @@ -1,28 +1,28 @@ [ - { - "name": "Example query", - "strategy": { - "name": "jpegd-locked-jpeg-of", - "params": { - "collectionToProviderAddress": { - "CRYPTOPUNKS": "0xdf7806eaa13497efffdb1541d6b0fdd1a9566fd0", - "ETHERROCKS": "0x9921da2908cc59b13ddbcf45e64bfa91c78c4249", - "BAYC": "0x5b9cAA47A52e4BfbBce2f2A9f858c2A501B48C42", - "MAYC": "0xdEd112453BD8EA88CdaB214CFD92Ab06E232E9d7", - "DOODLES": "0xdd245B7823ee82D14419CE072Ef815868F0D1f1A", - "PUDGYPENGUINS": "0xd0bf9A40FebDfCA596fde589a343C6cDA37A7B90", - "AZUKI": "0xcaA0aa80637262fd3Ba6DD5b5598a2BAFAc27cE8", - "CLONEX": "0xb36B65400E13FF57dFDa29bBb7dC79eaA7ecA14C" - }, - "start": 15363080 - } + { + "name": "Example query", + "strategy": { + "name": "jpegd-locked-jpeg-of", + "params": { + "collectionToProviderAddress": { + "CRYPTOPUNKS": "0xdf7806eaa13497efffdb1541d6b0fdd1a9566fd0", + "ETHERROCKS": "0x9921da2908cc59b13ddbcf45e64bfa91c78c4249", + "BAYC": "0x5b9cAA47A52e4BfbBce2f2A9f858c2A501B48C42", + "MAYC": "0xdEd112453BD8EA88CdaB214CFD92Ab06E232E9d7", + "DOODLES": "0xdd245B7823ee82D14419CE072Ef815868F0D1f1A", + "PUDGYPENGUINS": "0xd0bf9A40FebDfCA596fde589a343C6cDA37A7B90", + "AZUKI": "0xcaA0aa80637262fd3Ba6DD5b5598a2BAFAc27cE8", + "CLONEX": "0xb36B65400E13FF57dFDa29bBb7dC79eaA7ecA14C" }, - "network": "1", - "addresses": [ - "0x9c5083dd4838e120dbeac44c052179692aa5dac5", - "0xB0dAfc466871c29662E5cbf4227322C96A8Ccbe9", - "0x0017dfe08bcc0dc9a323ca5d4831e371534e9320" - ], - "snapshot": 16119881 - } -] \ No newline at end of file + "start": 15363080 + } + }, + "network": "1", + "addresses": [ + "0x9c5083dd4838e120dbeac44c052179692aa5dac5", + "0xB0dAfc466871c29662E5cbf4227322C96A8Ccbe9", + "0x0017dfe08bcc0dc9a323ca5d4831e371534e9320" + ], + "snapshot": 16119881 + } +] From 607a7928fd890522e893fd08d0494d5e8c14f5d7 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Wed, 21 Dec 2022 01:42:34 +0530 Subject: [PATCH 263/815] [erc721-with-metadata] Fix missing values in metadata (#998) --- src/strategies/erc721-with-metadata/index.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/strategies/erc721-with-metadata/index.ts b/src/strategies/erc721-with-metadata/index.ts index d866b0361..17c56c266 100644 --- a/src/strategies/erc721-with-metadata/index.ts +++ b/src/strategies/erc721-with-metadata/index.ts @@ -3,7 +3,7 @@ import { BigNumber } from '@ethersproject/bignumber'; import snapshots from '@snapshot-labs/snapshot.js'; export const author = 'allmysmarts'; -export const version = '0.1.0'; +export const version = '0.1.1'; const abi = [ 'function balanceOf(address account) external view returns (uint256)', @@ -58,7 +58,8 @@ export async function strategy( const walletToAttributeValue = {} as Record; for (const [walletId, tokenID] of Object.entries(walletIdToTokenID)) { const walletAddress = walletId.split('-')[0]; - const tokenData = metadata.find((x) => x[tokenID.toString()]); + const tokenData = metadata.find((x) => x[tokenID.toString()] > 0); + if (!tokenData) continue; walletToAttributeValue[walletAddress] = (walletToAttributeValue[walletAddress] || 0) + tokenData[tokenID.toString()]; From d26015e7f1a5368a6da1b173cc2da56a97f60c80 Mon Sep 17 00:00:00 2001 From: G2 Date: Tue, 27 Dec 2022 09:40:02 -0500 Subject: [PATCH 264/815] [poap] POAP Fixes (#988) * feat: poap 1:1 strategy * fix: grammar * refactor: some optimizations * fix: reorder imports * fix: use continue instead of return * fix: use erc721 strategy * fix: include snapshot for consistent results * fix: feedback * hardcode contract address * no need to lowercase addresses * fix: [poap] strategies - 1:1 strategy should also be capable of only counting specific tokens per their event id - with-weight block/snapshot param may not have been returning expected results * fix: grammar * revert: unnecessary changes Co-authored-by: Alexander Greene --- src/strategies/poap/README.md | 7 +- src/strategies/poap/examples.json | 5 +- src/strategies/poap/index.ts | 102 ++++++++++++++++++++++++++---- 3 files changed, 97 insertions(+), 17 deletions(-) diff --git a/src/strategies/poap/README.md b/src/strategies/poap/README.md index 288a50990..7b484eb22 100644 --- a/src/strategies/poap/README.md +++ b/src/strategies/poap/README.md @@ -2,12 +2,13 @@ Each POAP is implemented as an erc721 with a max supply tokens. -This strategy returns the number of POAP ERC721 NFTs owned by each account. +If no `eventIds` are passed, then this strategy returns the number of tokens owned by each account. Otherwise, it returns the number of tokens per account where the event id is included in `eventIds`. -Here is an example of parameters: +Here are some examples of parameters: ```json { - "symbol": "POAP" + "symbol": "POAP", + "eventIds": ["1213", "1293"] } ``` diff --git a/src/strategies/poap/examples.json b/src/strategies/poap/examples.json index 406737427..e790ab40f 100644 --- a/src/strategies/poap/examples.json +++ b/src/strategies/poap/examples.json @@ -4,7 +4,8 @@ "strategy": { "name": "poap", "params": { - "symbol": "POAP" + "symbol": "POAP", + "eventIds": ["1213", "1293"] } }, "network": "100", @@ -13,6 +14,6 @@ "0x00ac36c51500e900ab0f4e692fc1338cf70571b2", "0xdd6f702c2907ce401888d993d7dc185e7a824466" ], - "snapshot": 13040844 + "snapshot": 25283078 } ] diff --git a/src/strategies/poap/index.ts b/src/strategies/poap/index.ts index 15ea3b07f..f088b83d3 100644 --- a/src/strategies/poap/index.ts +++ b/src/strategies/poap/index.ts @@ -1,27 +1,105 @@ import { getAddress } from '@ethersproject/address'; +import { subgraphRequest } from '../../utils'; import { strategy as erc721Strategy } from '../erc721'; export const author = 'greenealexander'; -export const version = '1.0.0'; +export const version = '1.2.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, + options, snapshot ) { - const results = await erc721Strategy( - space, - network, - provider, - addresses, - { address: '0x22C1f6050E56d2876009903609a2cC3fEf83B415' }, - snapshot - ); - return addresses.reduce((map, address) => { - map[getAddress(address)] = results[address] ?? 0; + 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; + } + } + + return addressesMap; } From f7b33559c04e1e2eb22ed4ad8f92b379f26050be Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 6 Jan 2023 01:05:51 +0530 Subject: [PATCH 265/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.57 (#1004) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index bd114da3e..8a5bff1e4 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.56", + "@snapshot-labs/snapshot.js": "^0.4.57", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 3c9b5d6ad..8ab6f85fb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.56": - version "0.4.56" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.56.tgz#a7574329de9f6b17d8dc788634c8675ec5f29276" - integrity sha512-IyNoM67vByHMsxRNl1IImMeUJ5LWuSSs2/YR0LmstMPl1LAO+IZx6PQRGRyEGmgmUxcb8LbRjXWd/ev0Ho3mJg== +"@snapshot-labs/snapshot.js@^0.4.57": + version "0.4.57" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.57.tgz#e4182201bd3d1b227321c7915d1182f472f0e5cd" + integrity sha512-SYOp40YCK4p979sr2DqkvmfAtNXpXD+8Z1+NxszESS6CshTiOfnB9xuWhmEQl3wi5HhT0AgP4q0WlABLpW/18Q== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 032a2cf78a8bdfe01d019189b5ce004b05c6e804 Mon Sep 17 00:00:00 2001 From: Archethect Date: Tue, 10 Jan 2023 18:16:14 +0100 Subject: [PATCH 266/815] Battlefly DAO strategy [battlefly-vgfly-and-staked-gfly] (#1005) * battlefly dao voting * Add supported for LP weights + make sure claimable vgFLY is not counted towards score. --- .../battlefly-vgfly-and-staked-gfly/README.md | 22 +++ .../examples.json | 24 +++ .../battlefly-vgfly-and-staked-gfly/index.ts | 144 ++++++++++++++++++ src/strategies/index.ts | 4 +- 4 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 src/strategies/battlefly-vgfly-and-staked-gfly/README.md create mode 100644 src/strategies/battlefly-vgfly-and-staked-gfly/examples.json create mode 100644 src/strategies/battlefly-vgfly-and-staked-gfly/index.ts diff --git a/src/strategies/battlefly-vgfly-and-staked-gfly/README.md b/src/strategies/battlefly-vgfly-and-staked-gfly/README.md new file mode 100644 index 000000000..3c6f5026a --- /dev/null +++ b/src/strategies/battlefly-vgfly-and-staked-gfly/README.md @@ -0,0 +1,22 @@ +# battlefly-vgfly-and-staked-gfly + +This strategy calculates the voting power for addresses with one or more of the following requirements: + +* An amount of unvested tokens +* An amount of staked tokens +* An amount of staked LP tokens + +As input a graphUrl is required which will return those amounts for each queried address. +Additionally, the gFLY, magic vgFLY and LP token addresses are required for some on-chain calls that are not possible with Subgraph. + +```json +{ + "graphUrl": "https://api.thegraph.com/subgraphs/name/battlefly-game/gfly-main", + "gFLYAddress": "0x872bAD41CFc8BA731f811fEa8B2d0b9fd6369585", + "magicAddress": "0x539bdE0d7Dbd336b79148AA742883198BBF60342", + "lpAddress": "0x088F2Bd3667F385427d9289C28725D43d4b74AB4", + "vgFLYAddress": "0x86d643b7f4a2a6772A4B1bFBee5EcE46A1DE3dfD", + "symbol": "gFLY", + "decimals": 18 +} +``` diff --git a/src/strategies/battlefly-vgfly-and-staked-gfly/examples.json b/src/strategies/battlefly-vgfly-and-staked-gfly/examples.json new file mode 100644 index 000000000..7ecc45ad2 --- /dev/null +++ b/src/strategies/battlefly-vgfly-and-staked-gfly/examples.json @@ -0,0 +1,24 @@ +[ + { + "name": "Battlefly vgFLY holders and gFLY stakers", + "strategy": { + "name": "battlefly-vgfly-and-staked-gfly", + "params": { + "graphUrl": "https://api.thegraph.com/subgraphs/name/battlefly-game/gfly-main", + "gFLYAddress": "0x872bAD41CFc8BA731f811fEa8B2d0b9fd6369585", + "magicAddress": "0x539bdE0d7Dbd336b79148AA742883198BBF60342", + "lpAddress": "0x088F2Bd3667F385427d9289C28725D43d4b74AB4", + "vgFLYAddress": "0x86d643b7f4a2a6772A4B1bFBee5EcE46A1DE3dfD", + "symbol": "gFLY", + "decimals": 18 + } + }, + "network": "42161", + "addresses": [ + "0x0eB468F89E5bcFA4c933c8982D8d19554e101cfe", + "0x78063Ed58Edea4Ae4981946D6b4Cc63d8928CCBC", + "0x4026b3Da349C2952255Ca9db4F055ea57F4e037C" + ], + "snapshot": 47081042 + } +] diff --git a/src/strategies/battlefly-vgfly-and-staked-gfly/index.ts b/src/strategies/battlefly-vgfly-and-staked-gfly/index.ts new file mode 100644 index 000000000..478dccc72 --- /dev/null +++ b/src/strategies/battlefly-vgfly-and-staked-gfly/index.ts @@ -0,0 +1,144 @@ +import { multicall, Multicaller, subgraphRequest } from '../../utils'; +import { getAddress } from '@ethersproject/address'; +import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; + +export const author = 'Archethect'; +export const version = '0.0.1'; + +const abi = [ + 'function balanceOf(address account) external view returns (uint256)', + 'function decimals() external view returns (uint8)', + 'function token0() external view returns (address)', + 'function token1() external view returns (address)', + 'function totalSupply() external view returns (uint256)', + 'function getReserves() external view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast)', + 'function totalClaimableOf(address account) external view returns (uint256 total)' +]; + +const calcVotingPower = ( + stakedAsString: string, + stakedLPAsString: string, + vestingAsString: string, + claimableOf: BigNumberish, + decimals: number, + tokenWeight: number +) => { + const staked = parseFloat( + formatUnits(BigNumber.from(stakedAsString), decimals) + ); + const stakedLP = parseFloat( + formatUnits(BigNumber.from(stakedLPAsString), decimals) + ); + const vesting = parseFloat( + formatUnits(BigNumber.from(vestingAsString).sub(claimableOf), decimals) + ); + return staked + vesting + stakedLP * tokenWeight; +}; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const DF_SUBGRAPH_URL = options.graphUrl; + + // Setup subgraph query to fetch vgFLY and staked gFLY amounts (both normal and LP) per address + const params = { + _meta: { + block: { + number: true + } + }, + accounts: { + __args: { + where: { + id_in: addresses.map((addr: string) => addr.toLowerCase()) + }, + first: 1000 + }, + id: true, + staked: true, + stakedLP: true, + vesting: true + } + }; + + if (snapshot !== 'latest') { + // @ts-ignore + params.accounts.__args.block = { number: snapshot }; + } + + const result = await subgraphRequest(DF_SUBGRAPH_URL, { + ...params + }); + + // Take the same block number than from subgraph for consistency + const blockTag = + typeof snapshot === 'number' ? snapshot : result._meta.block.number; + + // fetch all token and lp contract data + + const fetchContractData = await multicall( + network, + provider, + abi, + [ + [options.lpAddress, 'token0', []], + [options.lpAddress, 'token1', []], + [options.lpAddress, 'getReserves', []], + [options.lpAddress, 'totalSupply', []], + [options.lpAddress, 'decimals', []] + ], + { blockTag } + ); + + // assign multicall data to variables + + const token0Address = fetchContractData[0][0]; + const token1Address = fetchContractData[1][0]; + const lpTokenReserves = fetchContractData[2]; + const lpTokenTotalSupply = fetchContractData[3][0]; + const lpTokenDecimals = fetchContractData[4][0]; + + // calculate single lp token weight + + let tokenWeight; + + //For token weight we only take the gFLY part into account + if (token0Address === options.gFLYAddress) { + tokenWeight = + parseFloat(formatUnits(lpTokenReserves._reserve0, options.decimals)) / + parseFloat(formatUnits(lpTokenTotalSupply, lpTokenDecimals)); + } else if (token1Address === options.gFLYAddress) { + tokenWeight = + parseFloat(formatUnits(lpTokenReserves._reserve1, options.decimals)) / + parseFloat(formatUnits(lpTokenTotalSupply, lpTokenDecimals)); + } else { + tokenWeight = 0; + } + + // Make sure vested vgFLY which is claimable is not counted + const multi = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => + multi.call(address, options.vgFLYAddress, 'totalClaimableOf', [address]) + ); + const claimableOfResult: Record = await multi.execute(); + + return Object.fromEntries( + result.accounts.map((a) => [ + getAddress(a.id), + calcVotingPower( + a.staked, + a.stakedLP, + a.vesting, + claimableOfResult[getAddress(a.id)], + options.decimals, + tokenWeight + ) + ]) + ); +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 967817365..c693125b9 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -413,6 +413,7 @@ import * as acrossStakedAcx from './across-staked-acx'; import * as vstaPoolStaking from './vsta-pool-staking'; import * as jpegdLockedJpegOf from './jpegd-locked-jpeg-of'; import * as babywealthyclub from './babywealthyclub'; +import * as battleflyVGFLYAndStakedGFLY from './battlefly-vgfly-and-staked-gfly'; const strategies = { 'forta-shares': fortaShares, @@ -831,7 +832,8 @@ const strategies = { reliquary, 'vsta-pool-staking': vstaPoolStaking, 'jpegd-locked-jpeg-of': jpegdLockedJpegOf, - babywealthyclub + babywealthyclub, + 'battlefly-vgfly-and-staked-gfly': battleflyVGFLYAndStakedGFLY }; Object.keys(strategies).forEach(function (strategyName) { From fee64550b00320ef892e8d3940f75a6e92a1e684 Mon Sep 17 00:00:00 2001 From: Victor Ionescu <113468466+gxmxni-hashflow@users.noreply.github.com> Date: Mon, 16 Jan 2023 02:41:26 -0800 Subject: [PATCH 267/815] Add Hashflow veHFT strategy. (#1011) --- src/strategies/hashflow-vehft/README.md | 23 ++++++++ src/strategies/hashflow-vehft/examples.json | 22 +++++++ src/strategies/hashflow-vehft/index.ts | 65 +++++++++++++++++++++ src/strategies/hashflow-vehft/schema.json | 30 ++++++++++ src/strategies/index.ts | 2 + 5 files changed, 142 insertions(+) create mode 100644 src/strategies/hashflow-vehft/README.md create mode 100644 src/strategies/hashflow-vehft/examples.json create mode 100644 src/strategies/hashflow-vehft/index.ts create mode 100644 src/strategies/hashflow-vehft/schema.json diff --git a/src/strategies/hashflow-vehft/README.md b/src/strategies/hashflow-vehft/README.md new file mode 100644 index 000000000..f3cea7d3f --- /dev/null +++ b/src/strategies/hashflow-vehft/README.md @@ -0,0 +1,23 @@ +# hashflow-vehft-v1 + +This strategy is used to account for the veHFT power that the Hashflow +staking vaults yield to the user. + +The voting power in the Hashflow DAO is a function of three parameters: + +- the amount of HFT staked +- the lock duration (normalized to 4 years between 0 and 1) +- ownership of a Creation's Coffer NFT + +The formula is as follows: + +[HFT amount] x [normalized time lock] x [1.1 if an NFT is owned] + +Here is an example of parameters: + +```json +{ + "hftVault": "0x15725391A37A5fFeB04F79cf25DA8460A3f068F6", + "nftContract": "0xb99E4E9b8Fd99c2C90aD5382dBC6ADfDfE3A33f3" +} +``` diff --git a/src/strategies/hashflow-vehft/examples.json b/src/strategies/hashflow-vehft/examples.json new file mode 100644 index 000000000..ad36c858d --- /dev/null +++ b/src/strategies/hashflow-vehft/examples.json @@ -0,0 +1,22 @@ +[ + { + "name": "Ethereum Query", + "strategy": { + "name": "hashflow-vehft", + "params": { + "hftVault": "0x15725391A37A5fFeB04F79cf25DA8460A3f068F6", + "nftContract": "0xb99E4E9b8Fd99c2C90aD5382dBC6ADfDfE3A33f3" + } + }, + "network": "1", + "addresses": [ + "0x602bcC6BF7cfd77048AB7cA4113382ef269362f2", + "0x2EE3300306c156948947a9c63959e89d9d60824F", + "0xAF8324Ab53229651E4C8Dea252a554AacA6f9577", + "0x6D2c2D57d49B015847a4A48ebB143138a5d7A455", + "0x41982604fDDce37bf04624A6F4A511f94043DEE0", + "0x34E1AE9a9b3F8e6B648A0e8952cf6C553d65fd62" + ], + "snapshot": 16402454 + } +] diff --git a/src/strategies/hashflow-vehft/index.ts b/src/strategies/hashflow-vehft/index.ts new file mode 100644 index 000000000..e3c0029df --- /dev/null +++ b/src/strategies/hashflow-vehft/index.ts @@ -0,0 +1,65 @@ +import { getAddress } from '@ethersproject/address'; +import { BigNumber } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { multicall } from '../../utils'; + +export const author = 'gxmxni-hashflow'; +export const version = '0.1.0'; + +const STAKES_ABI = + 'function stakes(address user) external returns (uint128 amount, uint64 lockExpiry)'; +const BALANCE_OF_ABI = + 'function balanceOf(address owner) external view returns (uint256 balance)'; + +const FOUR_YEARS_IN_SECONDS = 4 * 365 * 24 * 3_600; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const { timestamp } = await provider.getBlock(blockTag); + + const stakes = await multicall( + network, + provider, + [STAKES_ABI], + addresses.map((a) => [options.hftVault, 'stakes', [a]]), + { + blockTag + } + ); + + const rawVotingPower = stakes.map((s) => { + const timestampBN = BigNumber.from(timestamp); + const timeUntilExpiry = (s[1].gt(timestampBN) ? s[1] : timestampBN).sub( + timestampBN + ); + return timeUntilExpiry.mul(s[0]).div(FOUR_YEARS_IN_SECONDS); + }); + + const nftBalances = await multicall( + network, + provider, + [BALANCE_OF_ABI], + addresses.map((a) => [options.nftContract, 'balanceOf', [a]]), + { + blockTag + } + ); + + const votingPower = rawVotingPower.map((rvp, idx) => + parseFloat( + formatUnits(rvp.mul(nftBalances[idx][0].gt(0) ? 110 : 100).div(100), 18) + ) + ); + + return Object.fromEntries( + addresses.map((a, idx) => [getAddress(a), votingPower[idx]]) + ); +} diff --git a/src/strategies/hashflow-vehft/schema.json b/src/strategies/hashflow-vehft/schema.json new file mode 100644 index 000000000..82adaefd2 --- /dev/null +++ b/src/strategies/hashflow-vehft/schema.json @@ -0,0 +1,30 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "hftVault": { + "type": "string", + "title": "HFT Staking Vault Address", + "examples": ["e.g. 0x15725391A37A5fFeB04F79cf25DA8460A3f068F6"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "nftContract": { + "type": "string", + "title": "NFT Contract Address", + "examples": ["e.g. 0xb99E4E9b8Fd99c2C90aD5382dBC6ADfDfE3A33f3"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } + }, + "required": ["hftVault", "nftContract"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index c693125b9..239024c41 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -228,6 +228,7 @@ import * as compLikeVotesInclusive from './comp-like-votes-inclusive'; import * as mstable from './mstable'; import * as hashesVoting from './hashes-voting'; import * as hashflowGovernancePower from './hashflow-governance-power'; +import * as hashflowVeHft from './hashflow-vehft'; import * as podLeader from './pod-leader'; import * as aavegotchiWagmiGuild from './aavegotchi-wagmi-guild'; import * as polisBalance from './polis-balance'; @@ -649,6 +650,7 @@ const strategies = { mstable, 'hashes-voting': hashesVoting, 'hashflow-governance-power': hashflowGovernancePower, + 'hashflow-vehft': hashflowVeHft, 'pod-leader': podLeader, 'aavegotchi-wagmi-guild': aavegotchiWagmiGuild, 'polis-balance': polisBalance, From a697b147da2836511f6667aa9256cfcabdd120fb Mon Sep 17 00:00:00 2001 From: Xana Rahmani Date: Mon, 16 Jan 2023 14:15:16 +0330 Subject: [PATCH 268/815] Fix: fix erc20-balance-of strategy testcase (#1010) Co-authored-by: Chaitanya --- src/strategies/erc20-balance-of/examples.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategies/erc20-balance-of/examples.json b/src/strategies/erc20-balance-of/examples.json index 91c907bdd..a763c30b0 100644 --- a/src/strategies/erc20-balance-of/examples.json +++ b/src/strategies/erc20-balance-of/examples.json @@ -11,7 +11,7 @@ }, "network": "1", "addresses": [ - "0xa478c2975ab1ea89e8196811f51a7b7ade33eb11", + "0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11", "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", From dd424ce4a08fa7100a8bd15dc0a51c5b23b1bd07 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 16 Jan 2023 16:25:48 +0530 Subject: [PATCH 269/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.58 (#1013) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 8a5bff1e4..34bfe004e 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.57", + "@snapshot-labs/snapshot.js": "^0.4.58", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 8ab6f85fb..e74d9fa83 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.57": - version "0.4.57" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.57.tgz#e4182201bd3d1b227321c7915d1182f472f0e5cd" - integrity sha512-SYOp40YCK4p979sr2DqkvmfAtNXpXD+8Z1+NxszESS6CshTiOfnB9xuWhmEQl3wi5HhT0AgP4q0WlABLpW/18Q== +"@snapshot-labs/snapshot.js@^0.4.58": + version "0.4.58" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.58.tgz#011295a95a3ef0670ef91d89751abf06a5d1d7ea" + integrity sha512-dtfeiB0kEtpkQXKtc/MXrCj2cy3/CbbtNKMKudm/aLCTyK3DzYtQyvPLxQ1LwEvFcmf+1w3F6LAPENtmuj9obQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 61ce3f17b2ddc96c8e22148c00dc09094fc0f4cf Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Wed, 18 Jan 2023 23:43:44 +0530 Subject: [PATCH 270/815] Change nation3 strategy author to nation3 --- src/strategies/nation3-votes-with-delegations/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategies/nation3-votes-with-delegations/index.ts b/src/strategies/nation3-votes-with-delegations/index.ts index 05de39e7e..5d8976b13 100644 --- a/src/strategies/nation3-votes-with-delegations/index.ts +++ b/src/strategies/nation3-votes-with-delegations/index.ts @@ -3,7 +3,7 @@ import { formatUnits } from '@ethersproject/units'; import { Multicaller } from '../../utils'; import { getAddress } from '@ethersproject/address'; -export const author = 'caranell'; +export const author = 'nation3'; export const version = '0.1.0'; const DECIMALS = 18; From 1412df7870c248adb0f11fb5c0989beb78528dca Mon Sep 17 00:00:00 2001 From: wizardlabsxyz <103471804+wizardlabsxyz@users.noreply.github.com> Date: Thu, 19 Jan 2023 21:14:51 -0800 Subject: [PATCH 271/815] Lit Dao Governance Strategy (#1012) --- src/strategies/index.ts | 2 + src/strategies/lit-dao-governance/README.md | 5 + .../lit-dao-governance/examples.json | 18 ++++ src/strategies/lit-dao-governance/index.ts | 99 +++++++++++++++++++ src/strategies/lit-dao-governance/schema.json | 20 ++++ 5 files changed, 144 insertions(+) create mode 100644 src/strategies/lit-dao-governance/README.md create mode 100644 src/strategies/lit-dao-governance/examples.json create mode 100644 src/strategies/lit-dao-governance/index.ts create mode 100644 src/strategies/lit-dao-governance/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 239024c41..88efa9320 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -413,6 +413,7 @@ import * as reliquary from './reliquary'; import * as acrossStakedAcx from './across-staked-acx'; import * as vstaPoolStaking from './vsta-pool-staking'; import * as jpegdLockedJpegOf from './jpegd-locked-jpeg-of'; +import * as litDaoGovernance from './lit-dao-governance'; import * as babywealthyclub from './babywealthyclub'; import * as battleflyVGFLYAndStakedGFLY from './battlefly-vgfly-and-staked-gfly'; @@ -431,6 +432,7 @@ const strategies = { balancer, sunder, 'balancer-smart-pool': balancerSmartPool, + 'lit-dao-governance': litDaoGovernance, 'balancer-erc20-internal-balance-of': balancerErc20InternalBalanceOf, 'balance-in-vdfyn-vault': vDfynVault, 'erc20-received': erc20Received, diff --git a/src/strategies/lit-dao-governance/README.md b/src/strategies/lit-dao-governance/README.md new file mode 100644 index 000000000..316fc4405 --- /dev/null +++ b/src/strategies/lit-dao-governance/README.md @@ -0,0 +1,5 @@ +# lit-dao-governance + +This strategy is specific to lit-dao and should not be used in any context outside of the official LIT snapshot space. + +There are no parameters for this strategy diff --git a/src/strategies/lit-dao-governance/examples.json b/src/strategies/lit-dao-governance/examples.json new file mode 100644 index 000000000..76cdb8ad7 --- /dev/null +++ b/src/strategies/lit-dao-governance/examples.json @@ -0,0 +1,18 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "lit-dao-governance", + "params": { + "symbol": "LIT" + } + }, + "network": "1", + "addresses": [ + "0xc2e5e9Cc4F26Dc179C3f386e702283576B5157Fb", + "0x515fdd6f50cb6330399f5948f6422d8e27af012d", + "0xe129ed3b7Cb2AccE3A760bf66046ab53DF9D689d" + ], + "snapshot": 16388642 + } +] diff --git a/src/strategies/lit-dao-governance/index.ts b/src/strategies/lit-dao-governance/index.ts new file mode 100644 index 000000000..dce5d021c --- /dev/null +++ b/src/strategies/lit-dao-governance/index.ts @@ -0,0 +1,99 @@ +import { formatUnits } from '@ethersproject/units'; +import { getAddress } from '@ethersproject/address'; +import { multicall } from '../../utils'; +import { strategy as masterchefStrategy } from '../masterchef-pool-balance'; + +export const author = 'wizardlabsxyz'; +export const version = '0.1.0'; + +const abi = [ + 'function balanceOf(address account) external view returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const degenContract = "0x5f5541C618E76ab98361cdb10C67D1dE28740cC3"; + + // Use the existing masterchef strategy to get the staked lit balance + var stakedLitResults = await masterchefStrategy( + space, + network, + provider, + addresses, + { + "pid": "0", + "symbol": "Staked LIT", + "weight": 1, + "tokenIndex": null, + "chefAddress": "0x6c4f932a367ebbfef5528022459b47274618aaaf", + "uniPairAddress": null, + "weightDecimals": 0 + }, + snapshot); + + // Book + // LP2 + // LP2F + // Squiggle + // Degenaissance + const contracts: String[] = [ + "0x915bDf48e61fB3Cb39c8339Fb10108D9B596171C", + "0xFC0946B334B3bA133D239207a4d01Da1B75CF51B", + "0x76723D9524a743d8908458082FBdFAAf7F60B3eD", + "0x6F75bEAa3D3d8A15e08a9F499464C696fC4D4cde", + + // DEGEN HAS TO BE LAST FOR THE MULTIPLIER + degenContract + ]; + + const calls: any[] = []; + contracts.forEach((contract) => { + addresses.forEach((address: any) => { + calls.push([contract, 'balanceOf', [address]]); + }); + }); + + const response = await multicall(network, provider, abi, calls, { blockTag }); + + const merged = {}; + const degenOwnership = {}; + response.map((value: any, i: number) => { + const address = calls[i][2][0]; + merged[address] = (merged[address] || 0) as number; + + const parsedValue = parseFloat(formatUnits(value.toString(), 0)); + if (calls[i][0] == degenContract && parsedValue > 0) { + // Track degen ownership to apply multiplier to staked lit balance later + degenOwnership[address] = true; + + // Apply degen multiplier to NFT based voting power + merged[address] *= 2; + } else { + merged[address] += parsedValue + } + }); + + Object.keys(stakedLitResults).map((address: any) => { + const stakedLitVotingPower = Math.floor(stakedLitResults[address] / 3000000); + if (degenOwnership[address]) { + merged[address] += stakedLitVotingPower * 2; + } else { + merged[address] += stakedLitVotingPower; + } + }); + + return Object.fromEntries( + Object.entries(merged).map((address: any) => [ + getAddress(address[0]), + address[1] + ]) + ); +} diff --git a/src/strategies/lit-dao-governance/schema.json b/src/strategies/lit-dao-governance/schema.json new file mode 100644 index 000000000..2f5ed9c6b --- /dev/null +++ b/src/strategies/lit-dao-governance/schema.json @@ -0,0 +1,20 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. DOODLE"], + "maxLength": 16 + } + }, + "required": [], + "additionalProperties": false + } + } +} From c7fcddbf7f01a216967c935ed1c6ff3f8849d460 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 22 Jan 2023 23:34:17 +0530 Subject: [PATCH 272/815] Automated lint (#1017) Co-authored-by: ChaituVR --- src/strategies/lit-dao-governance/index.ts | 49 ++++++++++++---------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/src/strategies/lit-dao-governance/index.ts b/src/strategies/lit-dao-governance/index.ts index dce5d021c..55ba5f6fb 100644 --- a/src/strategies/lit-dao-governance/index.ts +++ b/src/strategies/lit-dao-governance/index.ts @@ -20,35 +20,36 @@ export async function strategy( ) { const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - const degenContract = "0x5f5541C618E76ab98361cdb10C67D1dE28740cC3"; + const degenContract = '0x5f5541C618E76ab98361cdb10C67D1dE28740cC3'; // Use the existing masterchef strategy to get the staked lit balance - var stakedLitResults = await masterchefStrategy( - space, - network, - provider, - addresses, - { - "pid": "0", - "symbol": "Staked LIT", - "weight": 1, - "tokenIndex": null, - "chefAddress": "0x6c4f932a367ebbfef5528022459b47274618aaaf", - "uniPairAddress": null, - "weightDecimals": 0 - }, - snapshot); + const stakedLitResults = await masterchefStrategy( + space, + network, + provider, + addresses, + { + pid: '0', + symbol: 'Staked LIT', + weight: 1, + tokenIndex: null, + chefAddress: '0x6c4f932a367ebbfef5528022459b47274618aaaf', + uniPairAddress: null, + weightDecimals: 0 + }, + snapshot + ); // Book // LP2 // LP2F // Squiggle // Degenaissance - const contracts: String[] = [ - "0x915bDf48e61fB3Cb39c8339Fb10108D9B596171C", - "0xFC0946B334B3bA133D239207a4d01Da1B75CF51B", - "0x76723D9524a743d8908458082FBdFAAf7F60B3eD", - "0x6F75bEAa3D3d8A15e08a9F499464C696fC4D4cde", + const contracts: string[] = [ + '0x915bDf48e61fB3Cb39c8339Fb10108D9B596171C', + '0xFC0946B334B3bA133D239207a4d01Da1B75CF51B', + '0x76723D9524a743d8908458082FBdFAAf7F60B3eD', + '0x6F75bEAa3D3d8A15e08a9F499464C696fC4D4cde', // DEGEN HAS TO BE LAST FOR THE MULTIPLIER degenContract @@ -77,12 +78,14 @@ export async function strategy( // Apply degen multiplier to NFT based voting power merged[address] *= 2; } else { - merged[address] += parsedValue + merged[address] += parsedValue; } }); Object.keys(stakedLitResults).map((address: any) => { - const stakedLitVotingPower = Math.floor(stakedLitResults[address] / 3000000); + const stakedLitVotingPower = Math.floor( + stakedLitResults[address] / 3000000 + ); if (degenOwnership[address]) { merged[address] += stakedLitVotingPower * 2; } else { From f4ec4cce11699cf8b4ef4d996865d02f8486e6a2 Mon Sep 17 00:00:00 2001 From: LookingForOwls <80638562+LookingForOwls@users.noreply.github.com> Date: Thu, 26 Jan 2023 14:36:10 -0500 Subject: [PATCH 273/815] [wagdie-subgraph] add: New vote weights if staked or seared. (#1018) * update WAGDIE character values * Update src/strategies/wagdie-subgraph/index.ts Co-authored-by: Chaitanya Co-authored-by: LookingForOwls Co-authored-by: Chaitanya --- src/strategies/wagdie-subgraph/examples.json | 4 ++-- src/strategies/wagdie-subgraph/index.ts | 18 ++++++++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/strategies/wagdie-subgraph/examples.json b/src/strategies/wagdie-subgraph/examples.json index a25028987..56fbe445c 100644 --- a/src/strategies/wagdie-subgraph/examples.json +++ b/src/strategies/wagdie-subgraph/examples.json @@ -14,8 +14,8 @@ "0xca8307d015aa664a186ad67da19ac6fc4b6c0198", "0x326937d5f4ad932db9d814ee7d852bc77b9d2e0d", "0x4F0EceDCd73dA0315134741d9D3830B08fE32e95", - "0xf36fc687c16f3021635b848a7d7450f5217240da" + "0xa027b41dc6fe7abec1b6ac69335383604766623c" ], - "snapshot": 15690081 + "snapshot": 16470969 } ] diff --git a/src/strategies/wagdie-subgraph/index.ts b/src/strategies/wagdie-subgraph/index.ts index 250c1bbe3..5c6023e2d 100644 --- a/src/strategies/wagdie-subgraph/index.ts +++ b/src/strategies/wagdie-subgraph/index.ts @@ -6,7 +6,7 @@ const SUBGRAPH_URL = { }; export const author = 'IcculusHerEmissary'; -export const version = '0.1.0'; +export const version = '0.2.0'; export async function strategy( _space, @@ -45,6 +45,9 @@ export async function strategy( }, location: { id: true + }, + searedConcord: { + id: true } } }; @@ -65,12 +68,23 @@ export async function strategy( for (const character of characters) { const userAddress = getAddress(character.owner.id); const charId = character?.location?.id; + let characterValue = options.scoreMultiplier; if ( options.location.includes('all') || options.location.includes(charId) ) { + // Staked character 1 bonus point + if (character.location?.id) + { + characterValue += 1 + } + // Seared character 4 bonus points + if (character.searedConcord?.id) + { + characterValue += 4 + } scores[userAddress] = - (scores[userAddress] ?? 0) + options.scoreMultiplier; + (scores[userAddress] ?? 0) + characterValue; } } From 3039a782bebe14115c6320bd9f2beff239796fd9 Mon Sep 17 00:00:00 2001 From: nexonfidev <98641861+nexonfidev@users.noreply.github.com> Date: Fri, 27 Jan 2023 01:13:39 +0530 Subject: [PATCH 274/815] Add Nexon Army NFT strategy. [nexon-army-nft] (#1022) * added nexon army nft strategy * updated strategy name * updated folder name Co-authored-by: Chaitanya --- src/strategies/index.ts | 4 +- src/strategies/nexon-army-nft/examples.json | 16 +++++ src/strategies/nexon-army-nft/index.ts | 67 +++++++++++++++++++++ 3 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 src/strategies/nexon-army-nft/examples.json create mode 100644 src/strategies/nexon-army-nft/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 88efa9320..d6a9fc735 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -416,6 +416,7 @@ import * as jpegdLockedJpegOf from './jpegd-locked-jpeg-of'; import * as litDaoGovernance from './lit-dao-governance'; import * as babywealthyclub from './babywealthyclub'; import * as battleflyVGFLYAndStakedGFLY from './battlefly-vgfly-and-staked-gfly'; +import * as nexonArmyNFT from './nexon-army-nft'; const strategies = { 'forta-shares': fortaShares, @@ -837,7 +838,8 @@ const strategies = { 'vsta-pool-staking': vstaPoolStaking, 'jpegd-locked-jpeg-of': jpegdLockedJpegOf, babywealthyclub, - 'battlefly-vgfly-and-staked-gfly': battleflyVGFLYAndStakedGFLY + 'battlefly-vgfly-and-staked-gfly': battleflyVGFLYAndStakedGFLY, + 'nexon-army-nft': nexonArmyNFT, }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/nexon-army-nft/examples.json b/src/strategies/nexon-army-nft/examples.json new file mode 100644 index 000000000..40647977a --- /dev/null +++ b/src/strategies/nexon-army-nft/examples.json @@ -0,0 +1,16 @@ +[ + { + "name": "Nexon Army NFT Holders", + "strategy": { + "name": "nexon-army-nft" + }, + "network": "137", + "addresses": [ + "0xd43BA4193920dA3A288AAf3400dcb5be62fB1dee", + "0x8966D8aCbb4b0d5830fca4b0Dd3b134e41049B19", + "0x6A6B81b62389ef53e201B855b30b1B92D73B1C4F", + "0xDb8D2DBB24A346b5b84981B1D5e741F67596009C" + ], + "snapshot": 38466628 + } +] diff --git a/src/strategies/nexon-army-nft/index.ts b/src/strategies/nexon-army-nft/index.ts new file mode 100644 index 000000000..6b9d072ae --- /dev/null +++ b/src/strategies/nexon-army-nft/index.ts @@ -0,0 +1,67 @@ +import { getAddress } from '@ethersproject/address'; +import { subgraphRequest } from '../../utils'; + +export const author = 'nexonfidev'; +export const version = '0.1.0'; + +const LIMIT = 1000; + +export const SUBGRAPH_URL = { + '137': 'https://api.thegraph.com/subgraphs/name/nexon-finance/nexon-army-nft' +}; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockNumber = typeof snapshot === 'number' + ? snapshot + : (await provider.getBlock('latest')).number; + + const _addresses = addresses.map((x) => x.toLowerCase()); + const addressSubsets = Array.apply( + null, + Array(Math.ceil(_addresses.length / LIMIT)) + ).map((_e, i) => _addresses.slice(i * LIMIT, (i + 1) * LIMIT)); + + const returnedFromSubgraph = await Promise.all( + addressSubsets.map((subset) => + subgraphRequest(SUBGRAPH_URL[network], makeQuery(blockNumber, subset)) + ) + ); + + const subgraphResult = returnedFromSubgraph.map((x) => x.votingWeights).flat(); + if (!subgraphResult) return; + + const score = {}; + subgraphResult.forEach((owner) => { + if (!score[getAddress(owner.address)]) { + score[getAddress(owner.address)] = parseFloat(owner.weight); + } + }); + + return score; +} + +function makeQuery(snapshot, addressSet) { + const query = { + votingWeights: { + __args: { + where: { + address_in: addressSet, + block_lte: snapshot + }, + orderBy: 'block', + orderDirection: 'desc', + first: LIMIT + }, + address: true, + weight: true + } + }; + return query; +} From c29f8ec13fe3e392b238161b5a226e4f041d9a1a Mon Sep 17 00:00:00 2001 From: johnmark13 Date: Thu, 26 Jan 2023 19:47:14 +0000 Subject: [PATCH 275/815] Circling around on the Nation3 strategy update [nation3-votes-with-delegations] (#1021) * Make sure we have all the ERc20 balances that we need. * I think this is more simple.... * Still not beautiful, but in testing I believe that this is simplified and covers our use cases * Update index.ts Bump version as requested! Co-authored-by: JohnMark13 Co-authored-by: Chaitanya --- .../examples.json | 8 +- .../nation3-votes-with-delegations/index.ts | 174 ++++++++++++------ 2 files changed, 119 insertions(+), 63 deletions(-) diff --git a/src/strategies/nation3-votes-with-delegations/examples.json b/src/strategies/nation3-votes-with-delegations/examples.json index b90731a69..602c1130c 100644 --- a/src/strategies/nation3-votes-with-delegations/examples.json +++ b/src/strategies/nation3-votes-with-delegations/examples.json @@ -10,11 +10,13 @@ }, "network": "1", "addresses": [ + "0xEdd000B7Db3cb8931d4E0cb1D0DBe6B947Ceb09A", "0x47d80912400ef8f8224531EBEB1ce8f2ACf4b75a", "0x636d65212C815b93B8E5b069f7082169cec851b7", - "0x327b0c1Ecd110651dC9994b6764b695c9cdC29bA", - "0x460AF11e497dc273fC163414943C6fd95d17B1fd" + "0x460AF11e497dc273fC163414943C6fd95d17B1fd", + "0x1512BB3b85696Fa4D85Cb4bbf78e9C4FE95DB90F", + "0x79438224Bc21b0E6B45ECF9F8caADfBdB874DedD" ], - "snapshot": 15638762 + "snapshot": 16399660 } ] diff --git a/src/strategies/nation3-votes-with-delegations/index.ts b/src/strategies/nation3-votes-with-delegations/index.ts index 5d8976b13..4843fa03c 100644 --- a/src/strategies/nation3-votes-with-delegations/index.ts +++ b/src/strategies/nation3-votes-with-delegations/index.ts @@ -4,7 +4,7 @@ import { Multicaller } from '../../utils'; import { getAddress } from '@ethersproject/address'; export const author = 'nation3'; -export const version = '0.1.0'; +export const version = '0.2.0'; const DECIMALS = 18; const balanceAbi = [ @@ -29,7 +29,7 @@ export async function strategy( ): Promise> { const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - const formattedAddresses = addresses.map((addr) => getAddress(addr)); + const formattedAddressesThatVoted = addresses.map((addr) => getAddress(addr)); const erc721OwnerCaller = new Multicaller(network, provider, ownerAbi, { blockTag @@ -50,18 +50,7 @@ export async function strategy( erc721LastTokenIdCaller.call('lastTokenId', options.erc721, 'getNextId'); - formattedAddresses.forEach((address) => { - erc20BalanceCaller.call(address, options.erc20, 'balanceOf', [address]); - }); - - const [erc20Balances, lastIndex]: [ - Record, - Record - ] = await Promise.all([ - erc20BalanceCaller.execute(), - erc721LastTokenIdCaller.execute() - ]); - + const lastIndex = await erc721LastTokenIdCaller.execute(); const lastTokenId = BigNumber.from(lastIndex.lastTokenId).toNumber(); for (let i = 0; i < lastTokenId; i++) { @@ -80,54 +69,119 @@ export async function strategy( const erc721OwnersArr = Object.entries(erc721Owners); const erc721SignersArr = Object.entries(erc721Signers); + //There is slightly confusing logic here, but ultimately the + //resultant Map below Maps the Voting Address to the list of + //addresses for which they are voting on behalf of. In the + //majority cases this will be a one to one mapping. + const votingAddressToOwnerAddressMap = buildPowerMap( + formattedAddressesThatVoted, + erc721OwnersArr, + erc721SignersArr + ); + + const erc20Balances: Record = + await getVEBalancesForAddressMap( + votingAddressToOwnerAddressMap, + erc20BalanceCaller, + options.erc20 + ); + + const agg = formattedAddressesThatVoted.map((addr) => { + const holderAddresses = votingAddressToOwnerAddressMap.get(addr); + const total = + holderAddresses?.reduce((sum, addr) => { + return sum.add(erc20Balances[addr] || 0); + }, BigNumber.from(0)) || 0; + return [addr, parseFloat(formatUnits(total, DECIMALS))]; + }); + const result = Object.fromEntries(agg); + return result; +} + +function buildPowerMap( + formattedAddressesThatVoted: string[], + erc721OwnersArr: [string, string][], + erc721SignersArr: [string, string][] +) { const delegatedTokens = erc721SignersArr.filter( - ([id, address]) => address !== erc721Owners[id] + ([id, address]) => address !== erc721OwnersArr[id] ); - const result = Object.fromEntries( - formattedAddresses.map((address) => { - // Getting ids of all tokens delegated to this address - const tokenDelegations = delegatedTokens - .filter(([, addr]) => addr === address) - .map(([id]) => id); - - if (tokenDelegations?.length) { - const realOwners = erc721OwnersArr.filter(([id]) => - tokenDelegations.includes(id) - ); - - if (!realOwners?.length) { - return [address, 0.0]; - } - - const ownerAddresses = realOwners.map(([, addr]) => addr); - - const erc20Balance = ownerAddresses.reduce((sum, addr) => { - return sum.add(erc20Balances[addr] || 0); - }, BigNumber.from(0)); - - return [address, parseFloat(formatUnits(erc20Balance, DECIMALS))]; - } else { - const erc20Balance = erc20Balances[address]; - const erc721Token = erc721OwnersArr.find( - ([, addr]) => addr === address - ); - - if (!erc721Token) { - return [address, 0.0]; - } - - const isUsersTokenDelegated = delegatedTokens.find( - ([id]) => id === erc721Token[0] - ); - - if (erc721Token && !isUsersTokenDelegated) { - return [address, parseFloat(formatUnits(erc20Balance, DECIMALS))]; - } - - return [address, 0.0]; - } - }) + const votingAddressToOwnerAddressMap = mapOwnersVotingPower( + formattedAddressesThatVoted, + erc721OwnersArr, + delegatedTokens ); - return result; + + addDelegatedVotingPowerToMap( + formattedAddressesThatVoted, + erc721OwnersArr, + erc721SignersArr, + delegatedTokens, + votingAddressToOwnerAddressMap + ); + + return votingAddressToOwnerAddressMap; +} + +function mapOwnersVotingPower( + formattedAddressesThatVoted: string[], + erc721OwnersArr: [string, string][], + delegatedTokens: [string, string][] +) { + return erc721OwnersArr.reduce((acc, [id, addr]) => { + if (!formattedAddressesThatVoted.includes(addr)) { + return acc; + } + //If the address that voted is the owner, but the owner has + //delegated their vote on this passport then they do not + //get any voting power from this passport. + if (delegatedTokens.some((delegated) => delegated[0] === id)) { + return acc; + } + acc.set(addr, [addr]); + return acc; + }, new Map()); +} + +function addDelegatedVotingPowerToMap( + formattedAddressesThatVoted: string[], + erc721OwnersArr: [string, string][], + erc721SignersArr: [string, string][], + delegatedTokens: [string, string][], + mapThatGetsUpdated: Map +) { + erc721SignersArr.reduce((acc, [id, addr]) => { + if (!formattedAddressesThatVoted.includes(addr)) { + return acc; + } + + //This works because the signerOf is defaulted to the ownerOf value + if (!delegatedTokens.some((delegated) => delegated[0] === id)) { + return acc; + } + + if (!mapThatGetsUpdated.has(addr)) { + acc.set(addr, []); + } + acc.get(addr)?.push(erc721OwnersArr[id][1]); + + return acc; + }, mapThatGetsUpdated); +} + +async function getVEBalancesForAddressMap( + votingAddressToOwnerAddressMap: Map, + erc20BalanceCaller, + veNationAddress: string +) { + votingAddressToOwnerAddressMap.forEach((addresses) => { + addresses.forEach((address) => { + erc20BalanceCaller.call(address, veNationAddress, 'balanceOf', [address]); + }); + }); + + const erc20Balances: Record = + await erc20BalanceCaller.execute(); + return erc20Balances; } From e96fb4f3611d3c8eaf34473cc09ada0579d4cb2a Mon Sep 17 00:00:00 2001 From: franzns <93920061+franzns@users.noreply.github.com> Date: Fri, 27 Jan 2023 12:10:42 +0100 Subject: [PATCH 276/815] [reliquary] Adapt strategy for new contract code (#1019) * adapt to new contract code * add coauther --- src/strategies/reliquary/README.md | 10 +++++----- src/strategies/reliquary/examples.json | 6 +++--- src/strategies/reliquary/index.ts | 26 ++++++++++++-------------- 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/strategies/reliquary/README.md b/src/strategies/reliquary/README.md index 511553005..10ded2c7a 100644 --- a/src/strategies/reliquary/README.md +++ b/src/strategies/reliquary/README.md @@ -1,15 +1,15 @@ # reliquary This strategy utilizes Relic NFTs from Reliquary to calculate voting power. The strategy can be configured to either -use the level number to weight the voting power or the allocation points assigned to each level. +use the level number to weight the voting power or the multiplier assigned to each level. If we use the levels strategy, the formula to calculate the voting power is `votingPower = level / maxVotingLevel * amount` -or if we use allocation points +or if we use multiplier -`votingPower = levelAllocationPoint / maxLevelAllocationPoint * amount` +`votingPower = levelMultiplier / maxLevelMultiplier * amount` In other words, if the nft has reached max voting level the voting power is equal to the amount deposited. @@ -24,7 +24,7 @@ Configuration: | minVotingLevel | number | 0...n | min level required to vote | maxVotingLevel | number | 0...n | max voting level | decimals | number | 6..18 | number of decimals of the token deposited into this pool -| strategy | string | 'level' / 'allocation' | which strategy to use to weight voting power +| strategy | string | 'level' / 'multiplier' | which strategy to use to weight voting power | useLevelOnUpdate | boolean | true / false | use hypothetical level after update ```json @@ -34,7 +34,7 @@ Configuration: "minVotingLevel": 1, "maxVotingLevel": 7, "decimals": 18, - "strategy": "allocation", + "strategy": "multiplier", "useLevelOnUpdate": false } ``` diff --git a/src/strategies/reliquary/examples.json b/src/strategies/reliquary/examples.json index a8ea6205a..d7a2b892b 100644 --- a/src/strategies/reliquary/examples.json +++ b/src/strategies/reliquary/examples.json @@ -4,12 +4,12 @@ "strategy": { "name": "reliquary", "params": { - "reliquaryAddress": "0xb0fc43069089d0fa02baaa896ac2efcb596d7d05", + "reliquaryAddress": "0x1ed6411670c709F4e163854654BD52c74E66D7eC", "poolId": 1, "minVotingLevel": 1, "maxVotingLevel": 7, "decimals": 18, - "strategy": "allocation", + "strategy": "multiplier", "useLevelOnUpdate": false } }, @@ -20,6 +20,6 @@ "0x1E243A85822E2CD42C81359E0ea42033000D02a4", "0xf7Ee8A9d014E9046D007bD448AaE7C667eF91E98" ], - "snapshot": 50967176 + "snapshot": 54393483 } ] diff --git a/src/strategies/reliquary/index.ts b/src/strategies/reliquary/index.ts index cfe3adf48..d288fb55a 100644 --- a/src/strategies/reliquary/index.ts +++ b/src/strategies/reliquary/index.ts @@ -3,12 +3,12 @@ import { StaticJsonRpcProvider } from '@ethersproject/providers'; import { formatUnits } from '@ethersproject/units'; import { Multicaller, call } from '../../utils'; -export const author = '0xSkly'; +export const author = '0xSkly'; // coAuthor = 'franzns' export const version = '0.1.0'; const abi = [ - 'function relicPositionsOfOwner(address owner) view returns (uint256[] relicIds, tuple(uint256 amount, uint256 rewardDebt, uint256 rewardCredit, uint256 entry, uint256 poolId, uint256 level, uint256 genesis, uint256 lastMaturityBonus)[] positionInfos)', - 'function getLevelInfo(uint256 pid) view returns (tuple(uint256[] requiredMaturity, uint256[] allocPoint, uint256[] balance) levelInfo)', + 'function relicPositionsOfOwner(address owner) view returns (uint256[] relicIds, tuple(uint256 amount, uint256 rewardDebt, uint256 rewardCredit, uint256 entry, uint256 poolId, uint256 level)[] positionInfos)', + 'function getLevelInfo(uint256 pid) view returns (tuple(uint256[] requiredMaturities, uint256[] multipliers, uint256[] balance) levelInfo)', 'function levelOnUpdate(uint256 relicId) view returns (uint256 level)' ]; @@ -23,7 +23,7 @@ export async function strategy( minVotingLevel: number; maxVotingLevel: number; decimals?: number; - strategy: 'level' | 'allocationPoints'; + strategy: 'level' | 'multiplier'; useLevelOnUpdate?: boolean; }, snapshot?: number | string @@ -50,8 +50,6 @@ export async function strategy( entry: BigNumber; poolId: BigNumber; level: BigNumber; - genesis: BigNumber; - lastMaturityBonus: BigNumber; }[] // correlating positions ] > = await multi.execute(); @@ -124,15 +122,15 @@ export async function strategy( return userVotingPower; } /* - otherwise we use the level allocations to weight the voting power. For this - we need to get the allocations for each level for the configured pool. - The formula used is: relicAmount * levelAllocation / maxAllocation + otherwise we use the level multiplier to weight the voting power. For this + we need to get the multipliers for each level for the configured pool. + The formula used is: relicAmount * levelMultiplier / maxMultiplier */ const poolLevelInfo: { - requiredMaturity: BigNumber[]; - allocPoint: BigNumber[]; + requiredMaturities: BigNumber[]; + multipliers: BigNumber[]; balance: BigNumber[]; } = await call( provider, @@ -141,17 +139,17 @@ export async function strategy( { blockTag } ); - const maxLevelAllocation = poolLevelInfo.allocPoint[options.maxVotingLevel]; + const maxMultiplier = poolLevelInfo.multipliers[options.maxVotingLevel]; for (const relicPosition of relevantRelicPositions) { const multiplier = - poolLevelInfo.allocPoint[ + poolLevelInfo.multipliers[ Math.min(options.maxVotingLevel, relicPosition.level) ].toNumber(); const votingPower = parseFloat( formatUnits( - relicPosition.amount.mul(multiplier).div(maxLevelAllocation), + relicPosition.amount.mul(multiplier).div(maxMultiplier), options.decimals ?? 18 ) ); From 566f5f35d7c9fd5bcf5fbe056fb2b78b7925d492 Mon Sep 17 00:00:00 2001 From: Jonny Huxtable Date: Sat, 28 Jan 2023 17:01:31 +0000 Subject: [PATCH 277/815] [stakedotlink-vesting] add strategy to calculate vesting tokens (#1020) * [stakedotlink-vesting] add strategy to calculate vesting tokens * [stakedotlink-vesting] add more context in README --- src/strategies/index.ts | 2 + src/strategies/stakedotlink-vesting/README.md | 19 +++++++++ .../stakedotlink-vesting/examples.json | 21 ++++++++++ src/strategies/stakedotlink-vesting/index.ts | 42 +++++++++++++++++++ .../stakedotlink-vesting/schema.json | 33 +++++++++++++++ 5 files changed, 117 insertions(+) create mode 100644 src/strategies/stakedotlink-vesting/README.md create mode 100644 src/strategies/stakedotlink-vesting/examples.json create mode 100644 src/strategies/stakedotlink-vesting/index.ts create mode 100644 src/strategies/stakedotlink-vesting/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index d6a9fc735..7b99b58ec 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -417,6 +417,7 @@ import * as litDaoGovernance from './lit-dao-governance'; import * as babywealthyclub from './babywealthyclub'; import * as battleflyVGFLYAndStakedGFLY from './battlefly-vgfly-and-staked-gfly'; import * as nexonArmyNFT from './nexon-army-nft'; +import * as stakedotlinkVesting from "./stakedotlink-vesting"; const strategies = { 'forta-shares': fortaShares, @@ -840,6 +841,7 @@ const strategies = { babywealthyclub, 'battlefly-vgfly-and-staked-gfly': battleflyVGFLYAndStakedGFLY, 'nexon-army-nft': nexonArmyNFT, + 'stakedotlink-vesting': stakedotlinkVesting }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/stakedotlink-vesting/README.md b/src/strategies/stakedotlink-vesting/README.md new file mode 100644 index 000000000..001c6ea2b --- /dev/null +++ b/src/strategies/stakedotlink-vesting/README.md @@ -0,0 +1,19 @@ +# stakedotlink-vesting + +Returns the vesting amount of tokens within a stake.link [DelegatorPool](https://github.com/stakedotlink/contracts/blob/main/contracts/core/DelegatorPool.sol). + +To calculate the amount of vesting tokens, the strategy will perform `totalBalanceOf - balanceOf`, returning the amount +tokens currently vesting at any given point in time. + +- `totalBalanceOf`: Total balance of account including vesting tokens as per `VestingSchedule` +- `balanceOf`: Balance of account excluding vesting tokens as per `VestingSchedule` + +Here is an example of parameters: + +```json +{ + "address": "0xAEF186611EC96427d161107fFE14bba8aA1C2284", + "symbol": "stSDL", + "decimals": 18 +} +``` diff --git a/src/strategies/stakedotlink-vesting/examples.json b/src/strategies/stakedotlink-vesting/examples.json new file mode 100644 index 000000000..39d1080a6 --- /dev/null +++ b/src/strategies/stakedotlink-vesting/examples.json @@ -0,0 +1,21 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "stakedotlink-vesting", + "params": { + "address": "0xAEF186611EC96427d161107fFE14bba8aA1C2284", + "symbol": "stSDL", + "decimals": 18 + } + }, + "network": "1", + "addresses": [ + "0x427a9957d3a131EE969a3BB5537070C6aEf03Ea4", + "0xF2aD781cFf42E1f506b78553DA89090C65b1A847", + "0xc316276f87019e5adbc3185A03e23ABF948A732D", + "0xE2b7cBA5E48445f9bD17193A29D7fDEb4Effb078" + ], + "snapshot": 16478298 + } +] diff --git a/src/strategies/stakedotlink-vesting/index.ts b/src/strategies/stakedotlink-vesting/index.ts new file mode 100644 index 000000000..dd1922768 --- /dev/null +++ b/src/strategies/stakedotlink-vesting/index.ts @@ -0,0 +1,42 @@ +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'stakedotlink'; +export const version = '0.0.1'; + +const abi = [ + 'function balanceOf(address _account) public view returns (uint256)', + 'function totalBalanceOf(address _account) public view returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multi = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => + multi.call(address, options.address, 'balanceOf', [address]) + ); + const balanceResult: Record = await multi.execute(); + addresses.forEach((address) => + multi.call(address, options.address, 'totalBalanceOf', [address]) + ); + const totalBalanceResult: Record = + await multi.execute(); + + return Object.fromEntries( + Object.entries(balanceResult).map(([address, balance]) => { + const vestingBalance = + parseFloat(formatUnits(totalBalanceResult[address], options.decimals)) - + parseFloat(formatUnits(balance, options.decimals)); + return [address, vestingBalance]; + }) + ); +} diff --git a/src/strategies/stakedotlink-vesting/schema.json b/src/strategies/stakedotlink-vesting/schema.json new file mode 100644 index 000000000..2113da8b8 --- /dev/null +++ b/src/strategies/stakedotlink-vesting/schema.json @@ -0,0 +1,33 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. UNI"], + "maxLength": 16 + }, + "address": { + "type": "string", + "title": "Contract address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 18"] + } + }, + "required": ["address", "decimals"], + "additionalProperties": false + } + } +} From 2d30289edcf59954c6f64d239c83263f76decb30 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 28 Jan 2023 22:53:43 +0530 Subject: [PATCH 278/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.59 (#1025) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 34bfe004e..68794bc55 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.58", + "@snapshot-labs/snapshot.js": "^0.4.59", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index e74d9fa83..ef4bbd037 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.58": - version "0.4.58" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.58.tgz#011295a95a3ef0670ef91d89751abf06a5d1d7ea" - integrity sha512-dtfeiB0kEtpkQXKtc/MXrCj2cy3/CbbtNKMKudm/aLCTyK3DzYtQyvPLxQ1LwEvFcmf+1w3F6LAPENtmuj9obQ== +"@snapshot-labs/snapshot.js@^0.4.59": + version "0.4.59" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.59.tgz#1bda092fd56f061bae0867daa0a9cb0680c7a5b5" + integrity sha512-6oXjzozrl7g7mP2zfd5YEXDg+9XElDYrfgENMsXEj4YNXZCa58TA7QbQwpGEE66tmvTveBg+DXQ528nUR//xOg== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From ca527c1398dc82c75364a4a3485e3492a338918b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 29 Jan 2023 17:01:54 +0530 Subject: [PATCH 279/815] Automated lint (#1027) Co-authored-by: ChaituVR --- src/strategies/index.ts | 2 +- src/strategies/nexon-army-nft/index.ts | 93 ++++++++++---------- src/strategies/wagdie-subgraph/examples.json | 2 +- src/strategies/wagdie-subgraph/index.ts | 13 ++- 4 files changed, 55 insertions(+), 55 deletions(-) diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 7b99b58ec..a9d8d78a3 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -417,7 +417,7 @@ import * as litDaoGovernance from './lit-dao-governance'; import * as babywealthyclub from './babywealthyclub'; import * as battleflyVGFLYAndStakedGFLY from './battlefly-vgfly-and-staked-gfly'; import * as nexonArmyNFT from './nexon-army-nft'; -import * as stakedotlinkVesting from "./stakedotlink-vesting"; +import * as stakedotlinkVesting from './stakedotlink-vesting'; const strategies = { 'forta-shares': fortaShares, diff --git a/src/strategies/nexon-army-nft/index.ts b/src/strategies/nexon-army-nft/index.ts index 6b9d072ae..ae91b0741 100644 --- a/src/strategies/nexon-army-nft/index.ts +++ b/src/strategies/nexon-army-nft/index.ts @@ -7,61 +7,64 @@ export const version = '0.1.0'; const LIMIT = 1000; export const SUBGRAPH_URL = { - '137': 'https://api.thegraph.com/subgraphs/name/nexon-finance/nexon-army-nft' + '137': 'https://api.thegraph.com/subgraphs/name/nexon-finance/nexon-army-nft' }; export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot + space, + network, + provider, + addresses, + options, + snapshot ) { - const blockNumber = typeof snapshot === 'number' - ? snapshot - : (await provider.getBlock('latest')).number; + const blockNumber = + typeof snapshot === 'number' + ? snapshot + : (await provider.getBlock('latest')).number; - const _addresses = addresses.map((x) => x.toLowerCase()); - const addressSubsets = Array.apply( - null, - Array(Math.ceil(_addresses.length / LIMIT)) - ).map((_e, i) => _addresses.slice(i * LIMIT, (i + 1) * LIMIT)); + const _addresses = addresses.map((x) => x.toLowerCase()); + const addressSubsets = Array.apply( + null, + Array(Math.ceil(_addresses.length / LIMIT)) + ).map((_e, i) => _addresses.slice(i * LIMIT, (i + 1) * LIMIT)); - const returnedFromSubgraph = await Promise.all( - addressSubsets.map((subset) => - subgraphRequest(SUBGRAPH_URL[network], makeQuery(blockNumber, subset)) - ) - ); + const returnedFromSubgraph = await Promise.all( + addressSubsets.map((subset) => + subgraphRequest(SUBGRAPH_URL[network], makeQuery(blockNumber, subset)) + ) + ); - const subgraphResult = returnedFromSubgraph.map((x) => x.votingWeights).flat(); - if (!subgraphResult) return; + const subgraphResult = returnedFromSubgraph + .map((x) => x.votingWeights) + .flat(); + if (!subgraphResult) return; - const score = {}; - subgraphResult.forEach((owner) => { - if (!score[getAddress(owner.address)]) { - score[getAddress(owner.address)] = parseFloat(owner.weight); - } - }); + const score = {}; + subgraphResult.forEach((owner) => { + if (!score[getAddress(owner.address)]) { + score[getAddress(owner.address)] = parseFloat(owner.weight); + } + }); - return score; + return score; } function makeQuery(snapshot, addressSet) { - const query = { - votingWeights: { - __args: { - where: { - address_in: addressSet, - block_lte: snapshot - }, - orderBy: 'block', - orderDirection: 'desc', - first: LIMIT - }, - address: true, - weight: true - } - }; - return query; + const query = { + votingWeights: { + __args: { + where: { + address_in: addressSet, + block_lte: snapshot + }, + orderBy: 'block', + orderDirection: 'desc', + first: LIMIT + }, + address: true, + weight: true + } + }; + return query; } diff --git a/src/strategies/wagdie-subgraph/examples.json b/src/strategies/wagdie-subgraph/examples.json index 56fbe445c..8ba202c75 100644 --- a/src/strategies/wagdie-subgraph/examples.json +++ b/src/strategies/wagdie-subgraph/examples.json @@ -16,6 +16,6 @@ "0x4F0EceDCd73dA0315134741d9D3830B08fE32e95", "0xa027b41dc6fe7abec1b6ac69335383604766623c" ], - "snapshot": 16470969 + "snapshot": 16470969 } ] diff --git a/src/strategies/wagdie-subgraph/index.ts b/src/strategies/wagdie-subgraph/index.ts index 5c6023e2d..90de39f67 100644 --- a/src/strategies/wagdie-subgraph/index.ts +++ b/src/strategies/wagdie-subgraph/index.ts @@ -74,17 +74,14 @@ export async function strategy( options.location.includes(charId) ) { // Staked character 1 bonus point - if (character.location?.id) - { - characterValue += 1 + if (character.location?.id) { + characterValue += 1; } // Seared character 4 bonus points - if (character.searedConcord?.id) - { - characterValue += 4 + if (character.searedConcord?.id) { + characterValue += 4; } - scores[userAddress] = - (scores[userAddress] ?? 0) + characterValue; + scores[userAddress] = (scores[userAddress] ?? 0) + characterValue; } } From bf0e6b8a272c37c1b32b52393786f2a3dab77111 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 29 Jan 2023 23:31:09 +0530 Subject: [PATCH 280/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.60 (#1028) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 68794bc55..c7a3943d2 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.59", + "@snapshot-labs/snapshot.js": "^0.4.60", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index ef4bbd037..0ac125608 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.59": - version "0.4.59" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.59.tgz#1bda092fd56f061bae0867daa0a9cb0680c7a5b5" - integrity sha512-6oXjzozrl7g7mP2zfd5YEXDg+9XElDYrfgENMsXEj4YNXZCa58TA7QbQwpGEE66tmvTveBg+DXQ528nUR//xOg== +"@snapshot-labs/snapshot.js@^0.4.60": + version "0.4.60" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.60.tgz#130fca5b67711a0f42a1d8fd74a3ce590382640e" + integrity sha512-mN2uWYJN1r0POBuRUDW2mC9fBMuARCCEL6ugbU8z1NBGKoCAMx7j4NkFk4pazt/BxoH50qM1fW1XvlCNJslvAQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 27786db1b8524faa9e177da922cdd7f2049894eb Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Tue, 31 Jan 2023 01:09:04 +0530 Subject: [PATCH 281/815] [erc721-with-metadata] Change default params (#1034) * [erc721-with-metadata] Change default params * Update examples.json --- src/strategies/erc721-with-metadata/examples.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/strategies/erc721-with-metadata/examples.json b/src/strategies/erc721-with-metadata/examples.json index df2bf4ecd..f983e7708 100644 --- a/src/strategies/erc721-with-metadata/examples.json +++ b/src/strategies/erc721-with-metadata/examples.json @@ -4,17 +4,17 @@ "strategy": { "name": "erc721-with-metadata", "params": { - "address": "0xedCbF9D4CC3BA9aAA896adADeac1b6DF6326f7D8", - "symbol": "KAP-NFT", + "address": "0x986010627A96200C287Cff73007b7b5797C32846", + "symbol": "NFT", "metadataSrc": "https://6242dbddb6734894c157cfc0.mockapi.io/api/votingWeights" } }, - "network": "4", + "network": "1", "addresses": [ - "0xa976C336B790CA8BA18c112aa9D8C4308De09632", - "0xb0b085dd0fe6c9632058f9ef088375c16f3aff12", - "0x7f16D5c969380E3420E17B4c3456A3844745A578" + "0x50dd57F50A17d57304e7A4F262Da30bEB31C2E87", + "0x1fbF1E602530fB2e849Ae46B34A29493BCd75EC9", + "0xD130470E8b4B73d74FB723d5cb8A9DfD83462a1f" ], - "snapshot": 10415558 + "snapshot": 16521706 } ] From ca2d2551109d16c2868e1ad5c2f78d6f080afe6e Mon Sep 17 00:00:00 2001 From: Carlos Febres Date: Tue, 31 Jan 2023 16:10:36 -0400 Subject: [PATCH 282/815] eco-voting-power strategy init (#1035) --- src/strategies/eco-voting-power/README.md | 11 ++ src/strategies/eco-voting-power/examples.json | 33 ++++ src/strategies/eco-voting-power/index.ts | 185 ++++++++++++++++++ src/strategies/eco-voting-power/schema.json | 22 +++ src/strategies/index.ts | 2 + 5 files changed, 253 insertions(+) create mode 100644 src/strategies/eco-voting-power/README.md create mode 100644 src/strategies/eco-voting-power/examples.json create mode 100644 src/strategies/eco-voting-power/index.ts create mode 100644 src/strategies/eco-voting-power/schema.json diff --git a/src/strategies/eco-voting-power/README.md b/src/strategies/eco-voting-power/README.md new file mode 100644 index 000000000..e3ace8df2 --- /dev/null +++ b/src/strategies/eco-voting-power/README.md @@ -0,0 +1,11 @@ +# eco-voting-power + +This is strategy returns the ECO voting power delegated to the `delegatee`. + +Here is an example of parameters: + +```json +{ + "delegatee": "0x6b175474e89094c44da98b954eedeac495271d0f" +} +``` diff --git a/src/strategies/eco-voting-power/examples.json b/src/strategies/eco-voting-power/examples.json new file mode 100644 index 000000000..188e63065 --- /dev/null +++ b/src/strategies/eco-voting-power/examples.json @@ -0,0 +1,33 @@ +[ + { + "name": "Example Eco Voting Power", + "strategy": { + "name": "eco-voting-power", + "params": { + "delegatee": "0x64923706f6ca6f3c364292834c5370e4f03e2368" + } + }, + "network": "5", + "addresses": [ + "0x40051de3036d76aee7b16cb2c21c86eb0dfa3f4c", + "0x35244c622e5034dc1bcf2ff3931cfa57192572ff", + "0x3ec87777b22d12ea95c55456324433a4c5a7bfe8", + "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", + "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e", + "0x1d5E65a087eBc3d03a294412E46CE5D6882969f4", + "0x1f254336E5c46639A851b9CfC165697150a6c327", + "0x2ec3F80BeDA63Ede96BA20375032CDD3aAfb3030", + "0x4AcBcA6BE2f8D2540bBF4CA77E45dA0A4a095Fa2", + "0x4F3D348a6D09837Ae7961B1E0cEe2cc118cec777", + "0x6D7f23A509E212Ba7773EC1b2505d1A134f54fbe", + "0x07a1f6fc89223c5ebD4e4ddaE89Ac97629856A0f", + "0x8d5F05270da470e015b67Ab5042BDbE2D2FEFB48", + "0x8d07D225a769b7Af3A923481E1FdF49180e6A265", + "0x8f60501dE5b9b01F9EAf1214dbE1924aA97F7fd0", + "0x9B8e8dD9151260c21CB6D7cc59067cd8DF306D58", + "0x17ea92D6FfbAA1c7F6B117c1E9D0c88ABdc8b84C", + "0x38C0039247A31F3939baE65e953612125cB88268" + ], + "snapshot": 8253435 + } +] diff --git a/src/strategies/eco-voting-power/index.ts b/src/strategies/eco-voting-power/index.ts new file mode 100644 index 000000000..af16c0c75 --- /dev/null +++ b/src/strategies/eco-voting-power/index.ts @@ -0,0 +1,185 @@ +import { WeiPerEther, Zero, One } from '@ethersproject/constants'; +import { formatEther } from '@ethersproject/units'; +import { BigNumber } from '@ethersproject/bignumber'; +import { StaticJsonRpcProvider } from '@ethersproject/providers'; + +import { getBlockNumber, subgraphRequest } from '../../utils'; +import { getAddress } from '@ethersproject/address'; + +export const author = 'carlosfebres'; +export const version = '1.0.0'; + +const ECO_SUBGRAPH_BY_CHAIN_ID = { + '1': 'https://api.thegraph.com/subgraphs/name/ecographs/the-eco-currency-subgraphs', + '5': 'https://api.thegraph.com/subgraphs/name/ecographs/staging-subgraphs' +}; + +const TOKEN_DELEGATEES_FIELDS = { + amount: true, + delegator: { + id: true + } +}; + +interface TokenDelegateesResult { + amount: string; + delegator: { + id: string; + }; +} + +interface QueryResult { + account: { + ecoTokenDelegatees: TokenDelegateesResult[]; + ecoCurrentTokenDelegatees: TokenDelegateesResult[]; + stakedEcoXTokenDelegatees: TokenDelegateesResult[]; + stakedEcoXCurrentTokenDelegatees: TokenDelegateesResult[]; + }; + inflationMultipliers: { + value: string; + }[]; +} + +function calculateVotingPower( + ecoVp: BigNumber, + stakedEcoXVp: BigNumber +): BigNumber { + return stakedEcoXVp.add(ecoVp.mul(10)); +} + +function createDelegationList( + items: TokenDelegateesResult[], + inflationMultiplier = One +): Record { + return Object.fromEntries( + items.map((item) => [ + item.delegator.id, + BigNumber.from(item.amount).div(inflationMultiplier) + ]) + ); +} + +export async function strategy( + space: string, + network: string, + provider: StaticJsonRpcProvider, + addresses: string[], + options, + snapshot: number | 'latest' +): Promise> { + const blockNumber = + snapshot !== 'latest' ? snapshot : await getBlockNumber(provider); + + const baseFilter = { + blockStarted_lte: blockNumber, + delegator_in: addresses.map((addr) => addr.toLowerCase()) + }; + + const query = { + account: { + __args: { id: options.delegatee }, + ecoTokenDelegatees: { + __aliasFor: 'tokenDelegatees', + __args: { + where: { + ...baseFilter, + token: 'eco', + blockEnded_gt: blockNumber + } + }, + ...TOKEN_DELEGATEES_FIELDS + }, + ecoCurrentTokenDelegatees: { + __aliasFor: 'tokenDelegatees', + __args: { + where: { + ...baseFilter, + token: 'eco', + blockEnded: null + } + }, + ...TOKEN_DELEGATEES_FIELDS + }, + stakedEcoXTokenDelegatees: { + __aliasFor: 'tokenDelegatees', + __args: { + where: { + ...baseFilter, + token: 'sEcox', + blockEnded_gt: blockNumber + } + }, + ...TOKEN_DELEGATEES_FIELDS + }, + stakedEcoXCurrentTokenDelegatees: { + __aliasFor: 'tokenDelegatees', + __args: { + where: { + ...baseFilter, + token: 'sEcox', + blockEnded: null + } + }, + ...TOKEN_DELEGATEES_FIELDS + } + }, + inflationMultipliers: { + __args: { + first: 1, + orderBy: 'blockNumber', + orderDirection: 'desc', + where: { blockNumber_lte: blockNumber } + }, + value: true + } + }; + + const subgraphUrl = ECO_SUBGRAPH_BY_CHAIN_ID[network]; + if (subgraphUrl == undefined) { + throw new Error(`Unsupported network with id: ${network}`); + } + + const { account: delegateesResult, inflationMultipliers }: QueryResult = + await subgraphRequest(subgraphUrl, query); + + const inflationMultiplier = inflationMultipliers.length + ? BigNumber.from(inflationMultipliers[0].value) + : WeiPerEther; + + const ecoHistoricalDelegations = createDelegationList( + delegateesResult.ecoTokenDelegatees, + inflationMultiplier + ); + const ecoCurrentDelegations = createDelegationList( + delegateesResult.ecoCurrentTokenDelegatees, + inflationMultiplier + ); + const stakedEcoXHistoricalDelegations = createDelegationList( + delegateesResult.stakedEcoXTokenDelegatees + ); + const stakedEcoXCurrentDelegations = createDelegationList( + delegateesResult.stakedEcoXCurrentTokenDelegatees + ); + + return Object.fromEntries( + addresses.map((address) => { + const ecoHistorical = ecoHistoricalDelegations[address] || Zero; + const ecoCurrent = ecoCurrentDelegations[address] || Zero; + const stakedEcoXHistorical = + stakedEcoXHistoricalDelegations[address] || Zero; + const stakedEcoXCurrent = stakedEcoXCurrentDelegations[address] || Zero; + + return [ + getAddress(address), + parseFloat( + formatEther( + calculateVotingPower( + ecoHistorical.add(ecoCurrent), + stakedEcoXHistorical.add(stakedEcoXCurrent) + ) + ) + ) + ]; + }) + ); +} diff --git a/src/strategies/eco-voting-power/schema.json b/src/strategies/eco-voting-power/schema.json new file mode 100644 index 000000000..44e250883 --- /dev/null +++ b/src/strategies/eco-voting-power/schema.json @@ -0,0 +1,22 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "delegatee": { + "type": "string", + "title": "Delegatee Address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } + }, + "required": ["delegatee"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index a9d8d78a3..a0b214860 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -1,6 +1,7 @@ import { readFileSync } from 'fs'; import path from 'path'; +import * as ecoVotingPower from './eco-voting-power'; import * as dpsNFTStrategy from './dps-nft-strategy'; import * as nounsPower from './nouns-rfp-power'; import * as erc20Votes from './erc20-votes'; @@ -420,6 +421,7 @@ import * as nexonArmyNFT from './nexon-army-nft'; import * as stakedotlinkVesting from './stakedotlink-vesting'; const strategies = { + 'eco-voting-power': ecoVotingPower, 'forta-shares': fortaShares, 'across-staked-acx': acrossStakedAcx, 'ethermon-erc721': ethermon721, From baa5b82bd03900d7ab55abc5626aa5f93e5bceb3 Mon Sep 17 00:00:00 2001 From: Velenir Date: Thu, 2 Feb 2023 18:37:55 +0100 Subject: [PATCH 283/815] ParaSwap sePSP2 strategy [psp-in-sepsp2-balance] (#1032) * outline strategy * fill in example * write the strategy * alt variant with fewer calls * cleanup * call at { blockTag } * cleanup * update Readme * add schema * simplify params --- src/strategies/index.ts | 4 +- .../psp-in-sepsp2-balance/README.md | 66 ++++++++ .../psp-in-sepsp2-balance/examples.json | 47 ++++++ src/strategies/psp-in-sepsp2-balance/index.ts | 147 ++++++++++++++++++ .../psp-in-sepsp2-balance/schema.json | 110 +++++++++++++ 5 files changed, 373 insertions(+), 1 deletion(-) create mode 100644 src/strategies/psp-in-sepsp2-balance/README.md create mode 100644 src/strategies/psp-in-sepsp2-balance/examples.json create mode 100644 src/strategies/psp-in-sepsp2-balance/index.ts create mode 100644 src/strategies/psp-in-sepsp2-balance/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index a0b214860..eec43bd9a 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -419,6 +419,7 @@ import * as babywealthyclub from './babywealthyclub'; import * as battleflyVGFLYAndStakedGFLY from './battlefly-vgfly-and-staked-gfly'; import * as nexonArmyNFT from './nexon-army-nft'; import * as stakedotlinkVesting from './stakedotlink-vesting'; +import * as pspInSePSP2Balance from './psp-in-sepsp2-balance'; const strategies = { 'eco-voting-power': ecoVotingPower, @@ -843,7 +844,8 @@ const strategies = { babywealthyclub, 'battlefly-vgfly-and-staked-gfly': battleflyVGFLYAndStakedGFLY, 'nexon-army-nft': nexonArmyNFT, - 'stakedotlink-vesting': stakedotlinkVesting + 'stakedotlink-vesting': stakedotlinkVesting, + 'psp-in-sepsp2-balance': pspInSePSP2Balance }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/psp-in-sepsp2-balance/README.md b/src/strategies/psp-in-sepsp2-balance/README.md new file mode 100644 index 000000000..68d1671ed --- /dev/null +++ b/src/strategies/psp-in-sepsp2-balance/README.md @@ -0,0 +1,66 @@ +# psp-in-sepsp2-balance + +This is a strategy to get PSP balances staked in sePSP2 contract and multiply that by `options.multiplier`. + +It works like this: +1. Get BPT balance an account holds +```js +const sePSP_balance = BPT_balance = SPSP.PSPBalance(address) +``` + +2. Get tokens of the Balancer Pool +```js +const [tokens] = await Vault.getPoolTokens(poolId) +``` + +3. Construct an exit pool request that could be used to unstake 1 BPT balance +```js +const exitPoolRequest = { + assets: tokens, // Balancer Pools underlying tokens + minAmountsOut: [0,0], // minimal amounts received + userData, // endoded [1, 1e18], // ExitKind.EXACT_BPT_IN_FOR_TOKENS_OUT = 1 + toInternalBalance: false, // transfer tokens to recipient, as opposed to depositing to internal balance +} + ``` + +4. Find how many tokens you would receive by unstaking 1 BPT balance +```js +const [amountsOut] = await BalancerHelpers.callStatic.queryExit( + poolId, + Zero_account, // sender + Zero_account, // recipient + exitPoolRequest + ) +// sender & recipient don't matter as we only getting an estimate +``` +`amountsOut` is a representation of BPT balance in the Balancer Pool's underlying tokens. In the same order as `assets` + +5. One of the `amountsOut` is PSP portion of 1 BPT. +```js +const PSP_In_1_BPT = amountsOut[index_from_assets] +``` + +6. Multiply PSP_balance by score multiplier. +```js +const Vote_power = PSP_In_1_BPT * BPT_balance * 2.5 +``` + +Here is an example of parameters: + +```json +{ + "address": "0xcafe001067cdef266afb7eb5a286dcfd277f3de5", + "symbol": "PSP", + "decimals": 18, + "sePSP2": { + "address": "0x593F39A4Ba26A9c8ed2128ac95D109E8e403C485", + "decimals": 18 + }, + "balancer": { + "poolId": "0xcb0e14e96f2cefa8550ad8e4aea344f211e5061d00020000000000000000011a", + "BalancerHelpers": "0x5aDDCCa35b7A0D07C74063c48700C8590E87864E", + "Vault": "0xBA12222222228d8Ba445958a75a0704d566BF2C8" + }, + "multiplier": 2.5 +} +``` diff --git a/src/strategies/psp-in-sepsp2-balance/examples.json b/src/strategies/psp-in-sepsp2-balance/examples.json new file mode 100644 index 000000000..9ccc11cfa --- /dev/null +++ b/src/strategies/psp-in-sepsp2-balance/examples.json @@ -0,0 +1,47 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "psp-in-sepsp2-balance", + "params": { + "address": "0xcafe001067cdef266afb7eb5a286dcfd277f3de5", + "symbol": "PSP", + "decimals": 18, + "sePSP2": { + "address": "0x593F39A4Ba26A9c8ed2128ac95D109E8e403C485", + "decimals": 18 + }, + "balancer": { + "poolId": "0xcb0e14e96f2cefa8550ad8e4aea344f211e5061d00020000000000000000011a", + "BalancerHelpers": "0x5aDDCCa35b7A0D07C74063c48700C8590E87864E", + "Vault": "0xBA12222222228d8Ba445958a75a0704d566BF2C8" + }, + "multiplier": 2.5 + } + }, + "network": "1", + "addresses": [ + "0x05182E579FDfCf69E4390c3411D8FeA1fb6467cf", + "0x0DDC793680FF4f5793849c8c6992be1695CbE72A", + "0x0edefa91e99da1eddd1372c1743a63b1595fc413", + "0xd37f7b32a541d9e423f759dff1dd63181651bd04", + "0xf9aa0da6e2fa01a17e2f69e878e45bb26c1b34b7", + "0xc570429a39a93fd267d1047b2363cfba07198ff7", + "0x4e8ffddb1403cf5306c6c7b31dc72ef5f44bc4f5", + "0x0ddc793680ff4f5793849c8c6992be1695cbe72a", + "0xd880507d359af862a5f8f318c8e934ab478ca818", + "0x510a7cd4ba40f7b6643f566a5d45ea55f5cd8d0e", + "0x1ff3c4bfa745b72f942c5cf2b769b3d8a6610a5e", + "0x5577933afc0522c5ee71115df61512f49da0543e", + "0x6eb8d6bccceb84832725dcf792468dd8ba088449", + "0xe768FF81990E7Ac73C18a2eCbf038815023599Dc", + "0xB9E11C28617D46866c1D7d95EaebAC3AC12CDAD3", + "0xB5714084eeF0f02eFDD145DFB3Fe2e3290591D7b", + "0xCC6B30531DE603787a4D0305FC7eD404374Cf771", + "0xcb492647CB51E243Fb2582C0300C4c7573acdEBf", + "0xB8f6f3cc7b162d7E5b9196140Fb1878cdA316ba0", + "0x584BaA4b71b0A3fA522658128f36a6A4AbeAC2ae" + ], + "snapshot": 16492220 + } +] \ No newline at end of file diff --git a/src/strategies/psp-in-sepsp2-balance/index.ts b/src/strategies/psp-in-sepsp2-balance/index.ts new file mode 100644 index 000000000..08dc87455 --- /dev/null +++ b/src/strategies/psp-in-sepsp2-balance/index.ts @@ -0,0 +1,147 @@ +import { BigNumberish, BigNumber } from '@ethersproject/bignumber'; +import { formatUnits, parseUnits } from '@ethersproject/units'; +import { Contract } from '@ethersproject/contracts'; +import { defaultAbiCoder } from '@ethersproject/abi'; +import { strategy as fetchERC20Balances } from '../erc20-balance-of'; +import { getAddress } from '@ethersproject/address'; + +export const author = 'paraswap'; +export const version = '0.1.0'; + +const BalancerVaultAbi = [ + 'function getPoolTokens(bytes32 poolId) external view returns (address[] tokens, uint256[] balances, uint256 lastChangeBlock)' +]; +interface PoolTokensFromVault { + tokens: string[]; + balances: BigNumber[]; + lastChangeBlock: BigNumber; +} + +const BalancerHelpersAbi = [ + 'function queryExit(bytes32 poolId, address sender, address recipient, tuple(address[] assets, uint256[] minAmountsOut, bytes userData, bool toInternalBalance) request) returns (uint256 bptIn, uint256[] amountsOut)' +]; + +interface QueryExitResult { + bptIn: BigNumber; + amountsOut: BigNumber[]; +} + +interface StrategyOptions { + address: string; + symbol: string; + decimals: number; + sePSP2: { address: string; decimals: number }; + balancer: { + poolId: string; + BalancerHelpers: string; + Vault: string; + }; + multiplier: number; +} + +const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; + +export async function strategy( + space: string, + network: string, + provider, + addresses: string[], + options: StrategyOptions, + snapshot: number +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const account2BPTBalance = await fetchERC20Balances( + space, + network, + provider, + addresses, + options.sePSP2, + snapshot + ); + + const balancerVault = new Contract( + options.balancer.Vault, + BalancerVaultAbi, + provider + ); + + const { tokens: poolTokens }: PoolTokensFromVault = + await balancerVault.getPoolTokens(options.balancer.poolId, { blockTag }); + + const tokenLowercase = options.address.toLowerCase(); + const tokenIndex = poolTokens.findIndex( + (token) => token.toLowerCase() === tokenLowercase + ); + + if (tokenIndex === -1) { + throw new Error( + `Token ${options.address} doesn't belong to Balancer Pool ${options.balancer.poolId}` + ); + } + + const balancerHelpers = new Contract( + options.balancer.BalancerHelpers, + BalancerHelpersAbi, + provider + ); + + const exitPoolRequest = constructExitPoolRequest( + poolTokens, + // how much will get for 1 BPT + parseUnits('1', options.sePSP2.decimals) + ); + + const queryExitResult: QueryExitResult = + await balancerHelpers.callStatic.queryExit( + options.balancer.poolId, + ZERO_ADDRESS, + ZERO_ADDRESS, + exitPoolRequest, + { blockTag } + ); + + const pspFor1BPT = parseFloat( + formatUnits(queryExitResult.amountsOut[tokenIndex], options.decimals) + ); + + const address2PSPinSePSP2 = Object.fromEntries( + Object.entries(account2BPTBalance).map(([address, bptBalance]) => { + const pspBalance = pspFor1BPT * bptBalance; + + const checksummedAddress = getAddress(address); + + return [checksummedAddress, pspBalance * options.multiplier]; + }) + ); + + return address2PSPinSePSP2; +} + +interface ExitPoolRequest { + assets: string[]; + minAmountsOut: BigNumberish[]; + userData: string; + toInternalBalance: boolean; +} + +// ExitKind enum for BalancerHerlpers.queryExit call +const EXACT_BPT_IN_FOR_TOKENS_OUT = 1; + +export function constructExitPoolRequest( + assets: string[], + bptAmountIn: BigNumberish +): ExitPoolRequest { + const abi = ['uint256', 'uint256']; + const data = [EXACT_BPT_IN_FOR_TOKENS_OUT, bptAmountIn]; + const userData = defaultAbiCoder.encode(abi, data); + + const minAmountsOut = assets.map(() => 0); + + return { + assets, + minAmountsOut, + userData, + toInternalBalance: false + }; +} diff --git a/src/strategies/psp-in-sepsp2-balance/schema.json b/src/strategies/psp-in-sepsp2-balance/schema.json new file mode 100644 index 000000000..cbe115d84 --- /dev/null +++ b/src/strategies/psp-in-sepsp2-balance/schema.json @@ -0,0 +1,110 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": [ + "PSP" + ] + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": [ + "18" + ] + }, + "address": { + "type": "string", + "title": "Address", + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42, + "examples": [ + "0xcafe001067cdef266afb7eb5a286dcfd277f3de5" + ] + }, + "sePSP2": { + "type": "object", + "title": "sePSP2", + "properties": { + "address": { + "type": "string", + "title": "Address", + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42, + "examples": [ + "0x593F39A4Ba26A9c8ed2128ac95D109E8e403C485" + ] + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": [ + "18" + ] + } + } + }, + "balancer": { + "type": "object", + "title": "Balancer", + "properties": { + "poolId": { + "type": "string", + "title": "Balancer_PoolId", + "examples": [ + "0xcb0e14e96f2cefa8550ad8e4aea344f211e5061d00020000000000000000011a" + ], + "pattern": "^0x[a-fA-F0-9]{64}$", + "minLength": 66, + "maxLength": 66 + }, + "BalancerHelpers": { + "type": "string", + "title": "BalancerHelpers_address", + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42, + "examples": [ + "0x5aDDCCa35b7A0D07C74063c48700C8590E87864E" + ] + }, + "Vault": { + "type": "string", + "title": "Vault_address", + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42, + "examples": [ + "0xBA12222222228d8Ba445958a75a0704d566BF2C8" + ] + } + } + }, + "multiplier": { + "type": "number", + "title": "Multiplier", + "examples": [ + "2.5" + ] + } + }, + "required": [ + "decimals", + "address", + "sePSP2", + "balancer", + "multiplier" + ], + "additionalProperties": false + } + } +} \ No newline at end of file From 7d706f7826a2a69d3d5c9e251cf2cd8c19a60715 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 3 Feb 2023 01:07:24 +0530 Subject: [PATCH 284/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.61 (#1040) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index c7a3943d2..66abc50f2 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.60", + "@snapshot-labs/snapshot.js": "^0.4.61", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 0ac125608..b835cf70f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.60": - version "0.4.60" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.60.tgz#130fca5b67711a0f42a1d8fd74a3ce590382640e" - integrity sha512-mN2uWYJN1r0POBuRUDW2mC9fBMuARCCEL6ugbU8z1NBGKoCAMx7j4NkFk4pazt/BxoH50qM1fW1XvlCNJslvAQ== +"@snapshot-labs/snapshot.js@^0.4.61": + version "0.4.61" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.61.tgz#a8849d34deed94443e0eba047e76a377ae0946a1" + integrity sha512-7EpZKcRmECbq8b46ghQa/MCSo99r2NxufZ5UJE1RImPRmFSwyekZUd7QP/KoqUacKtaJVbcYl3PXM5ZoYwhkNQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 35d29566e7c5f9a23c3f00a019865ee44cc9d9da Mon Sep 17 00:00:00 2001 From: ori-wagmi <97362935+ori-wagmi@users.noreply.github.com> Date: Fri, 3 Feb 2023 09:19:59 -0800 Subject: [PATCH 285/815] Fix test for API strategy. Make `decimals` parameter optional and add Readme. (#1037) * Remove unused params in examples.json and add Readme to API strategy * update readme * add decimals back to example.json * make decimals optional, update example.json to working IPFS endpoing * nit updates to readme --- src/strategies/api/README.md | 83 ++++++++++++++++++++++++++++++++ src/strategies/api/examples.json | 4 +- src/strategies/api/index.ts | 4 +- 3 files changed, 87 insertions(+), 4 deletions(-) create mode 100644 src/strategies/api/README.md diff --git a/src/strategies/api/README.md b/src/strategies/api/README.md new file mode 100644 index 000000000..d5f1154ad --- /dev/null +++ b/src/strategies/api/README.md @@ -0,0 +1,83 @@ +# API strategy + +Voting strategy using a REST API endpoint. Number of votes depends on the return of the API endpoint. + +## Cosntructing the API URL +This strategy will create an `api_url` based on the supplied parameters and the Proposal&Space settings. + +`api_url` is constructed as such: + +### For IPFS endpoints +IPFS endpoint is defined as a url starting with any of the following: + - https://gateway.pinata.cloud/ipfs/ + - https://ipfs.io/ipfs/ + - https://cloudflare-ipfs.com/ipfs/ + +1. `param.api`: The first part of the URL (e.g. https://gateway.pinata.cloud/ipfs/) + +2. `param.strategy`: The IPFS hash + +3. `param.additionalParameters` (optional): Any additional parameters you want to include + +The final URL is expected to look something like: `https://gateway.pinata.cloud/ipfs/QmbmhTivxYuLE5uhNEALoBmvP7Yg9acA2Lkw9V9PqaEmw6` + + +### For non-IPFS endpoints: + +1. `param.api`: The first part of the URL (e.g. https://www.myapi.com/) + +2. `param.strategy`: The resource name (e.g. get_vote_count) + +3. `network`: Set by the Snapshot space settings (e.g. Ethereum = 1) + +4. `snapshot`: Set by blockheight of the proposal (e.g. 11437846) + +5. `addresses`: A comma separated list of addresses to be queried + +The final URL is expected to look something like: `https://www.myapi.com/get_vote_count?network=1&snapshot=11437846&addresses=0xeD2bcC3104Da5F5f8fA988D6e9fAFd74Ae62f319,0x3c4B8C52Ed4c29eE402D9c91FfAe1Db2BAdd228D` + + +## `decimals` param (optional) +Users can optionally include a `decimals` property. This will be used by the strategy when processing the scores from the API response. `decimals` is used as the second argument of `formatUnits` (https://docs.ethers.org/v3/api-utils.html?highlight=formatunits#ether-strings-and-wei). Default value is 0. + +## Expected return of API +The API should return an object with the following structure: +``` +{ + "score": [ + { + "address": "0xeD2bcC3104Da5F5f8fA988D6e9fAFd74Ae62f319", + "score": "184000000000000000000" + }, + { + "address": "0x3c4B8C52Ed4c29eE402D9c91FfAe1Db2BAdd228D", + "score": "7469258545106344000000000" + }, + { + "address": "0xd649bACfF66f1C85618c5376ee4F38e43eE53b63", + "score": "2509787861801245" + }, + { + "address": "0x726022a9fe1322fA9590FB244b8164936bB00489", + "score": "2179896139461561200000" + }, + { + "address": "0xc6665eb39d2106fb1DBE54bf19190F82FD535c19", + "score": "0" + }, + { + "address": "0x6ef2376fa6e12dabb3a3ed0fb44e4ff29847af68", + "score": "100420" + } + ] +} +``` + +Note that for the example above, `element.score` is a string representation in wei. Your response can return any value as long as: + 1. The return can be stringified `.toString()` + 2. The stringified version of your response can be passed into the second argument of `formatUnits`: https://docs.ethers.org/v3/api-utils.html?highlight=formatunits#ether-strings-and-wei + +## Testing +You can test this strategy by updating the `examples.json` file and running `npm run test --strategy=api` + +To test local changes, change to this directory and run: `npm run build & npm run test --strategy=api` \ No newline at end of file diff --git a/src/strategies/api/examples.json b/src/strategies/api/examples.json index 31e2b0072..dd6fc0018 100644 --- a/src/strategies/api/examples.json +++ b/src/strategies/api/examples.json @@ -5,9 +5,7 @@ "name": "api", "params": { "api": "https://gateway.pinata.cloud/ipfs", - "symbol": "LIFE", - "decimals": 0, - "strategy": "QmQnW3TtpN8WS2YMXtWB1p7DFcVjetfZmMfJvXm5yAZ6QN" + "strategy": "QmbmhTivxYuLE5uhNEALoBmvP7Yg9acA2Lkw9V9PqaEmw6" } }, "network": "1", diff --git a/src/strategies/api/index.ts b/src/strategies/api/index.ts index 1c57c114d..7cbb37111 100644 --- a/src/strategies/api/index.ts +++ b/src/strategies/api/index.ts @@ -37,11 +37,13 @@ export async function strategy( 'Content-Type': 'application/json' } }); + const data = await response.json(); + return Object.fromEntries( data.score.map((value) => [ getAddress(value.address), - parseFloat(formatUnits(value.score.toString(), options.decimals)) + parseFloat(formatUnits(value.score.toString(), (options.hasOwnProperty("decimals") ? options.decimals : 0))) ]) ); } From de3dcab3372bf27898b849d4a0b795f0c61316b5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 3 Feb 2023 23:27:37 +0530 Subject: [PATCH 286/815] Automated lint (#1042) Co-authored-by: ChaituVR --- src/strategies/api/index.ts | 7 +++- .../psp-in-sepsp2-balance/examples.json | 2 +- .../psp-in-sepsp2-balance/schema.json | 42 +++++-------------- 3 files changed, 17 insertions(+), 34 deletions(-) diff --git a/src/strategies/api/index.ts b/src/strategies/api/index.ts index 7cbb37111..6da207a52 100644 --- a/src/strategies/api/index.ts +++ b/src/strategies/api/index.ts @@ -43,7 +43,12 @@ export async function strategy( return Object.fromEntries( data.score.map((value) => [ getAddress(value.address), - parseFloat(formatUnits(value.score.toString(), (options.hasOwnProperty("decimals") ? options.decimals : 0))) + parseFloat( + formatUnits( + value.score.toString(), + options.hasOwnProperty('decimals') ? options.decimals : 0 + ) + ) ]) ); } diff --git a/src/strategies/psp-in-sepsp2-balance/examples.json b/src/strategies/psp-in-sepsp2-balance/examples.json index 9ccc11cfa..f77f75174 100644 --- a/src/strategies/psp-in-sepsp2-balance/examples.json +++ b/src/strategies/psp-in-sepsp2-balance/examples.json @@ -44,4 +44,4 @@ ], "snapshot": 16492220 } -] \ No newline at end of file +] diff --git a/src/strategies/psp-in-sepsp2-balance/schema.json b/src/strategies/psp-in-sepsp2-balance/schema.json index cbe115d84..2bfd47c89 100644 --- a/src/strategies/psp-in-sepsp2-balance/schema.json +++ b/src/strategies/psp-in-sepsp2-balance/schema.json @@ -9,16 +9,12 @@ "symbol": { "type": "string", "title": "Symbol", - "examples": [ - "PSP" - ] + "examples": ["PSP"] }, "decimals": { "type": "number", "title": "Decimals", - "examples": [ - "18" - ] + "examples": ["18"] }, "address": { "type": "string", @@ -26,9 +22,7 @@ "pattern": "^0x[a-fA-F0-9]{40}$", "minLength": 42, "maxLength": 42, - "examples": [ - "0xcafe001067cdef266afb7eb5a286dcfd277f3de5" - ] + "examples": ["0xcafe001067cdef266afb7eb5a286dcfd277f3de5"] }, "sePSP2": { "type": "object", @@ -40,16 +34,12 @@ "pattern": "^0x[a-fA-F0-9]{40}$", "minLength": 42, "maxLength": 42, - "examples": [ - "0x593F39A4Ba26A9c8ed2128ac95D109E8e403C485" - ] + "examples": ["0x593F39A4Ba26A9c8ed2128ac95D109E8e403C485"] }, "decimals": { "type": "number", "title": "Decimals", - "examples": [ - "18" - ] + "examples": ["18"] } } }, @@ -73,9 +63,7 @@ "pattern": "^0x[a-fA-F0-9]{40}$", "minLength": 42, "maxLength": 42, - "examples": [ - "0x5aDDCCa35b7A0D07C74063c48700C8590E87864E" - ] + "examples": ["0x5aDDCCa35b7A0D07C74063c48700C8590E87864E"] }, "Vault": { "type": "string", @@ -83,28 +71,18 @@ "pattern": "^0x[a-fA-F0-9]{40}$", "minLength": 42, "maxLength": 42, - "examples": [ - "0xBA12222222228d8Ba445958a75a0704d566BF2C8" - ] + "examples": ["0xBA12222222228d8Ba445958a75a0704d566BF2C8"] } } }, "multiplier": { "type": "number", "title": "Multiplier", - "examples": [ - "2.5" - ] + "examples": ["2.5"] } }, - "required": [ - "decimals", - "address", - "sePSP2", - "balancer", - "multiplier" - ], + "required": ["decimals", "address", "sePSP2", "balancer", "multiplier"], "additionalProperties": false } } -} \ No newline at end of file +} From 4383e14945b067d14a8a55fdcb24454bdaa7c979 Mon Sep 17 00:00:00 2001 From: Appo <103305611+0xAppo@users.noreply.github.com> Date: Sat, 4 Feb 2023 12:11:57 -0500 Subject: [PATCH 287/815] Lodestar finance strategies [lodestar-staked-lp] (#1029) * adding Lodestar Finance strategies * Update examples.json * Lodestar Finance - Aelin Vesting * Lodestar Aelin Vesting * Lodestar Finance Strategies [lodestar-staked-lp] * throw error if more than 5 stake pool addresses are provided * fixing error reporting * changing where error is thrown --------- Co-authored-by: Lodestar Finance <111470016+LodestarFinance@users.noreply.github.com> Co-authored-by: Chaitanya --- src/strategies/index.ts | 2 + src/strategies/lodestar-staked-lp/README.md | 18 ++++ .../lodestar-staked-lp/examples.json | 24 +++++ src/strategies/lodestar-staked-lp/index.ts | 90 +++++++++++++++++++ 4 files changed, 134 insertions(+) create mode 100644 src/strategies/lodestar-staked-lp/README.md create mode 100644 src/strategies/lodestar-staked-lp/examples.json create mode 100644 src/strategies/lodestar-staked-lp/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index eec43bd9a..f0e93b167 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -413,6 +413,7 @@ import * as skaleDelegationWeighted from './skale-delegation-weighted'; import * as reliquary from './reliquary'; import * as acrossStakedAcx from './across-staked-acx'; import * as vstaPoolStaking from './vsta-pool-staking'; +import * as lodestarStakedLp from './lodestar-staked-lp'; import * as jpegdLockedJpegOf from './jpegd-locked-jpeg-of'; import * as litDaoGovernance from './lit-dao-governance'; import * as babywealthyclub from './babywealthyclub'; @@ -840,6 +841,7 @@ const strategies = { 'skale-delegation-weighted': skaleDelegationWeighted, reliquary, 'vsta-pool-staking': vstaPoolStaking, + 'lodestar-staked-lp': lodestarStakedLp, 'jpegd-locked-jpeg-of': jpegdLockedJpegOf, babywealthyclub, 'battlefly-vgfly-and-staked-gfly': battleflyVGFLYAndStakedGFLY, diff --git a/src/strategies/lodestar-staked-lp/README.md b/src/strategies/lodestar-staked-lp/README.md new file mode 100644 index 000000000..724a9c3f7 --- /dev/null +++ b/src/strategies/lodestar-staked-lp/README.md @@ -0,0 +1,18 @@ +# lodestar-staked-lp + +Used for fetching the staked LP token balance in a single staking pool and calculating +associated voting power. Voting power per staked LP token is calculated in terms of a "token weight", or the amount of the voting token that comprises 1 LP token (total amount of voting token in LP pool * 2 / total supply of LP tokens). The address' balance of LP tokens is multiplied by token weight to yield total voting power from staked LP tokens. + +Here is an example of parameters: + +```json +{ + "stakingPoolAddresses": [ + "0x4Ce0C8C8944205C0A134ef37A772ceEE327B4c11" + ], + "tokenAddress": "0xF19547f9ED24aA66b03c3a552D181Ae334FBb8DB", + "lpTokenAddress": "0xFB36f24872b9C57aa8264E1F9a235405C4D3fC36", + "symbol": "LODE", + "decimals": 18 +} +``` diff --git a/src/strategies/lodestar-staked-lp/examples.json b/src/strategies/lodestar-staked-lp/examples.json new file mode 100644 index 000000000..b01967d11 --- /dev/null +++ b/src/strategies/lodestar-staked-lp/examples.json @@ -0,0 +1,24 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "lodestar-staked-lp", + "params": { + "stakingPoolAddresses": [ + "0x4Ce0C8C8944205C0A134ef37A772ceEE327B4c11" + ], + "tokenAddress": "0xF19547f9ED24aA66b03c3a552D181Ae334FBb8DB", + "lpTokenAddress": "0xFB36f24872b9C57aa8264E1F9a235405C4D3fC36", + "symbol": "LODE", + "decimals": 18 + } + }, + "addresses": [ + "0xcada41bdb95227ee3f3c2f4a37a843d384fbb48d", + "0xdee375c0976e1e5b5a2cfdf1846eb055d6d107ed", + "0xa79456cc03fc4eca28ecd675988a6c78e421e12e" + ], + "network": 42161, + "snapshot": 44754575 + } +] \ No newline at end of file diff --git a/src/strategies/lodestar-staked-lp/index.ts b/src/strategies/lodestar-staked-lp/index.ts new file mode 100644 index 000000000..9825d5b40 --- /dev/null +++ b/src/strategies/lodestar-staked-lp/index.ts @@ -0,0 +1,90 @@ +/* eslint-disable prettier/prettier */ +import { formatUnits } from '@ethersproject/units'; +import { Multicaller, multicall } from '../../utils'; +import { getAddress } from '@ethersproject/address'; + +export const author = '0xAppo'; +export const version = '0.1.0'; + + +const abi = [ + 'function userInfo(address) view returns (uint256 amount, uint256 rewardDebt)', + 'function balanceOf(address account) external view returns (uint256)', + 'function decimals() external view returns (uint8)', + 'function token0() external view returns (address)', + 'function token1() external view returns (address)', + 'function totalSupply() external view returns (uint256)', + 'function getReserves() external view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const fetchContractData = await multicall( + network, + provider, + abi, + [ + [options.lpTokenAddress, 'token0', []], + [options.lpTokenAddress, 'token1', []], + [options.lpTokenAddress, 'getReserves', []], + [options.lpTokenAddress, 'totalSupply', []], + [options.lpTokenAddress, 'decimals', []], + [options.tokenAddress, 'decimals', []] + ], + { blockTag } + ); + + const token0Address = fetchContractData[0][0]; + const token1Address = fetchContractData[1][0]; + const lpTokenReserves = fetchContractData[2]; + const lpTokenTotalSupply = fetchContractData[3][0]; + const lpTokenDecimals = fetchContractData[4][0]; + const tokenDecimals = fetchContractData[5][0]; + + let tokenWeight; + + if (token0Address === options.tokenAddress) { + tokenWeight = + (parseFloat(formatUnits(lpTokenReserves._reserve0, tokenDecimals)) / + parseFloat(formatUnits(lpTokenTotalSupply, lpTokenDecimals))) * + 2; + } else if (token1Address === options.tokenAddress) { + tokenWeight = + (parseFloat(formatUnits(lpTokenReserves._reserve1, tokenDecimals)) / + parseFloat(formatUnits(lpTokenTotalSupply, lpTokenDecimals))) * + 2; + } else { + tokenWeight = 0; + } + + const multi = new Multicaller(network, provider, abi, { blockTag }); + + if (options.stakingPoolAddresses.length >= 10) { + throw new Error('Too many stake pool addresses provided.') + } + + options.stakingPoolAddresses.forEach(stakingPoolAddress => { + addresses.forEach((address) => + multi.call(address, stakingPoolAddress, 'userInfo', [address]) + ); + }) + + const result: Record = await multi.execute(); + + return Object.fromEntries( + Object.entries(result).map(([address, userInfo]) => [ + getAddress(address), + parseFloat(formatUnits(userInfo.amount, options.decimals)) * tokenWeight + ]) + ); +} + + From 0b6fb5c1a17e55dd43dbcd47102c6eb270dc905a Mon Sep 17 00:00:00 2001 From: Appo <103305611+0xAppo@users.noreply.github.com> Date: Sat, 4 Feb 2023 14:23:20 -0500 Subject: [PATCH 288/815] Lodestar finance strategies [lodestar-vesting] (#1030) * adding Lodestar Finance strategies * Update examples.json * Lodestar Finance - Aelin Vesting * Lodestar Aelin Vesting * Lodestar Finance Strategies [lodestar-staked-lp] * adding lodestar-vesting * adding check for number of addresses in options * Update src/strategies/lodestar-vesting/index.ts * fixing error reporting * Revert "fixing error reporting" This reverts commit 2da623944215b38eab51a8eee9a4f1cc21830696. * fixing error reporting * removing return from foreach loop --------- Co-authored-by: Lodestar Finance <111470016+LodestarFinance@users.noreply.github.com> Co-authored-by: Chaitanya --- src/strategies/index.ts | 2 + src/strategies/lodestar-vesting/README.md | 19 ++++++++ src/strategies/lodestar-vesting/examples.json | 30 ++++++++++++ src/strategies/lodestar-vesting/index.ts | 46 +++++++++++++++++++ 4 files changed, 97 insertions(+) create mode 100644 src/strategies/lodestar-vesting/README.md create mode 100644 src/strategies/lodestar-vesting/examples.json create mode 100644 src/strategies/lodestar-vesting/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index f0e93b167..2079d2c55 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -413,6 +413,7 @@ import * as skaleDelegationWeighted from './skale-delegation-weighted'; import * as reliquary from './reliquary'; import * as acrossStakedAcx from './across-staked-acx'; import * as vstaPoolStaking from './vsta-pool-staking'; +import * as lodestarVesting from './lodestar-vesting'; import * as lodestarStakedLp from './lodestar-staked-lp'; import * as jpegdLockedJpegOf from './jpegd-locked-jpeg-of'; import * as litDaoGovernance from './lit-dao-governance'; @@ -841,6 +842,7 @@ const strategies = { 'skale-delegation-weighted': skaleDelegationWeighted, reliquary, 'vsta-pool-staking': vstaPoolStaking, + 'lodestar-vesting': lodestarVesting, 'lodestar-staked-lp': lodestarStakedLp, 'jpegd-locked-jpeg-of': jpegdLockedJpegOf, babywealthyclub, diff --git a/src/strategies/lodestar-vesting/README.md b/src/strategies/lodestar-vesting/README.md new file mode 100644 index 000000000..0bfde7b7c --- /dev/null +++ b/src/strategies/lodestar-vesting/README.md @@ -0,0 +1,19 @@ +# lodestar-vesting + +Calculates voting power of locked & vesting ERC20 tokens. The indices of the beneficiary addresses and their vesting contract addresses MUST match in order to properly match beneficiaries with their associated vesting contracts. + +Here is an example of parameters: + +```json +{ + "address": "0xF19547f9ED24aA66b03c3a552D181Ae334FBb8DB", + "symbol": "LODE", + "decimals": 18, + "beneficiaryAddresses": [ + "0x41C2F1Af5a4a4C65b580c1397141684F96B68aAb" + ], + "contractAddresses": [ + "0x658fD8f0e4380c9823C6a18974096A2b2aC8842e" + ] +} +``` diff --git a/src/strategies/lodestar-vesting/examples.json b/src/strategies/lodestar-vesting/examples.json new file mode 100644 index 000000000..2953afe11 --- /dev/null +++ b/src/strategies/lodestar-vesting/examples.json @@ -0,0 +1,30 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "lodestar-vesting", + "params": { + "address": "0xF19547f9ED24aA66b03c3a552D181Ae334FBb8DB", + "symbol": "LODE", + "decimals": 18, + "beneficiaryAddresses": [ + "0x719Df6573bfA3bD240932cAD63839cfB85de3aB5", + "0xeAc36dF6A6212CC1D5c59b6F59547eeC083A1bDa", + "0x85EB5a2077E88559B8A63206Fbc9A9311f8e63a5" + ], + "contractAddresses": [ + "0x71C85F343715C406C58c1e8099F13890f2925c85", + "0x2DD5B039a7c54132B8733573a28Cd9d1a5Fa5328", + "0x05bc2c8310D18dB816264E95383b1C50FC32d297" + ] + } + }, + "network": "42161", + "addresses": [ + "0xeAc36dF6A6212CC1D5c59b6F59547eeC083A1bDa", + "0x719Df6573bfA3bD240932cAD63839cfB85de3aB5", + "0x85EB5a2077E88559B8A63206Fbc9A9311f8e63a5" + ], + "snapshot": 44776525 + } +] \ No newline at end of file diff --git a/src/strategies/lodestar-vesting/index.ts b/src/strategies/lodestar-vesting/index.ts new file mode 100644 index 000000000..5f8542dbc --- /dev/null +++ b/src/strategies/lodestar-vesting/index.ts @@ -0,0 +1,46 @@ +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; +import { getAddress } from '@ethersproject/address'; + +export const author = '0xAppo'; +export const version = '0.1.0'; + +const abi = [ + 'function balanceOf(address account) external view returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + if ( + options.beneficiaryAddresses.length >= 25 || + options.contractAddresses.length >= 25 + ) { + throw new Error('Too many beneficiary/contract addresses provided.'); + } + const multi = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => { + if (options.beneficiaryAddresses.includes(address)) { + const index = options.beneficiaryAddresses.indexOf(address); + const contractAddress = options.contractAddresses[index]; + multi.call(address, options.address, 'balanceOf', [contractAddress]); + } + }); + + const result: Record = await multi.execute(); + + return Object.fromEntries( + Object.entries(result).map(([address, balance]) => [ + getAddress(address), + parseFloat(formatUnits(balance, options.decimals)) + ]) + ); +} From a18d352d6ab6e89b31a95cce3bf4554083a1d529 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 5 Feb 2023 22:33:20 +0530 Subject: [PATCH 289/815] Automated lint (#1044) Co-authored-by: ChaituVR --- src/strategies/lodestar-staked-lp/examples.json | 6 ++---- src/strategies/lodestar-vesting/examples.json | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/strategies/lodestar-staked-lp/examples.json b/src/strategies/lodestar-staked-lp/examples.json index b01967d11..1f8e3c88e 100644 --- a/src/strategies/lodestar-staked-lp/examples.json +++ b/src/strategies/lodestar-staked-lp/examples.json @@ -4,9 +4,7 @@ "strategy": { "name": "lodestar-staked-lp", "params": { - "stakingPoolAddresses": [ - "0x4Ce0C8C8944205C0A134ef37A772ceEE327B4c11" - ], + "stakingPoolAddresses": ["0x4Ce0C8C8944205C0A134ef37A772ceEE327B4c11"], "tokenAddress": "0xF19547f9ED24aA66b03c3a552D181Ae334FBb8DB", "lpTokenAddress": "0xFB36f24872b9C57aa8264E1F9a235405C4D3fC36", "symbol": "LODE", @@ -21,4 +19,4 @@ "network": 42161, "snapshot": 44754575 } -] \ No newline at end of file +] diff --git a/src/strategies/lodestar-vesting/examples.json b/src/strategies/lodestar-vesting/examples.json index 2953afe11..3fe703851 100644 --- a/src/strategies/lodestar-vesting/examples.json +++ b/src/strategies/lodestar-vesting/examples.json @@ -27,4 +27,4 @@ ], "snapshot": 44776525 } -] \ No newline at end of file +] From 82d2a77d7f855a0a48eac84ede82b8401426e5a6 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Mon, 6 Feb 2023 02:01:05 +0530 Subject: [PATCH 290/815] Create validation.yml (#1047) --- .github/workflows/validation.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/workflows/validation.yml diff --git a/.github/workflows/validation.yml b/.github/workflows/validation.yml new file mode 100644 index 000000000..17c70aa5a --- /dev/null +++ b/.github/workflows/validation.yml @@ -0,0 +1,27 @@ +name: Test validation +on: + pull_request: + types: + - edited + - labeled + - synchronize + - ready_for_review + - review_requested + - reopened + +jobs: + test-validation: + if: contains(toJson(github.event.pull_request.labels), 'validation') + runs-on: ubuntu-latest + env: + PR_TITLE: ${{ github.event.pull_request.title }} + + steps: + - uses: actions/checkout@v2.3.4 + - name: yarn install and test validation + run: | + yarn install --frozen-lockfile + VALIDATION=$(echo $PR_TITLE | sed -e 's/.*\[\(.*\)\].*/\1/') + if [ -n "$VALIDATION" ]; then + yarn test:validation --validation=$STRATEGY + fi From 90816ab3f8570b7af59ea7449e8fda5ba3a7ef10 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Mon, 6 Feb 2023 02:15:06 +0530 Subject: [PATCH 291/815] [basic] Add title and description to validations and add few test cases (#1046) * Add title and description to validations and add few test cases * Update validation.yml * Remove unused test snapshot --- .github/workflows/validation.yml | 2 +- src/validations/basic/index.ts | 2 + src/validations/index.ts | 7 +- src/validations/passport-gated/index.ts | 4 +- src/validations/passport-weighted/index.ts | 3 + src/validations/validation.ts | 2 + test/__snapshots__/validation.test.ts.snap | 3 - test/validation.test.ts | 82 ++++++++++++++++++++-- 8 files changed, 93 insertions(+), 12 deletions(-) delete mode 100644 test/__snapshots__/validation.test.ts.snap diff --git a/.github/workflows/validation.yml b/.github/workflows/validation.yml index 17c70aa5a..eb38d8490 100644 --- a/.github/workflows/validation.yml +++ b/.github/workflows/validation.yml @@ -23,5 +23,5 @@ jobs: yarn install --frozen-lockfile VALIDATION=$(echo $PR_TITLE | sed -e 's/.*\[\(.*\)\].*/\1/') if [ -n "$VALIDATION" ]; then - yarn test:validation --validation=$STRATEGY + yarn test:validation --validation=$VALIDATION fi diff --git a/src/validations/basic/index.ts b/src/validations/basic/index.ts index 2e0886217..6c3ccb0df 100644 --- a/src/validations/basic/index.ts +++ b/src/validations/basic/index.ts @@ -5,6 +5,8 @@ export default class extends Validation { public id = 'basic'; public github = 'bonustrack'; public version = '0.2.0'; + public title = 'Basic'; + public description = 'Use any strategy to determine if a user can vote.'; async validate(): Promise { const minScore = this.params.minScore; diff --git a/src/validations/index.ts b/src/validations/index.ts index 31e93a17f..13fd2225d 100644 --- a/src/validations/index.ts +++ b/src/validations/index.ts @@ -47,7 +47,12 @@ Object.keys(validationClasses).forEach(function (validationName) { validation: validationClasses[validationName], examples, schema, - about + about, + id: new validationClasses[validationName]().id, + github: new validationClasses[validationName]().github, + version: new validationClasses[validationName]().version, + title: new validationClasses[validationName]().title, + description: new validationClasses[validationName]().description }; }); diff --git a/src/validations/passport-gated/index.ts b/src/validations/passport-gated/index.ts index 7febbdc08..7f0b91b8a 100644 --- a/src/validations/passport-gated/index.ts +++ b/src/validations/passport-gated/index.ts @@ -10,7 +10,9 @@ export default class extends Validation { public id = 'passport-gated'; public github = 'snapshot-labs'; public version = '0.1.0'; - + public title = 'Gitcoin Passport Gated'; + public description = + 'Protect your proposals from spam and vote manipulation by requiring users to have a Gitcoin Passport.'; async validate(): Promise { const requiredStamps = this.params.stamps; const passport: any = await getPassport(this.author); diff --git a/src/validations/passport-weighted/index.ts b/src/validations/passport-weighted/index.ts index 901a2067a..23a2e7421 100644 --- a/src/validations/passport-weighted/index.ts +++ b/src/validations/passport-weighted/index.ts @@ -10,6 +10,9 @@ export default class extends Validation { public id = 'passport-weighted'; public github = 'snapshot-labs'; public version = '0.1.0'; + public title = 'Gitcoin Passport Weighted'; + public description = + 'Protect your proposals from spam and vote manipulation by requiring users to have a Gitcoin Passport.'; async validate(): Promise { const passport: any = await getPassport(this.author); diff --git a/src/validations/validation.ts b/src/validations/validation.ts index 34c28bcc3..48913bcba 100644 --- a/src/validations/validation.ts +++ b/src/validations/validation.ts @@ -2,6 +2,8 @@ export default class Validation { public id = ''; public github = ''; public version = ''; + public title = ''; + public description = ''; public author: string; public space: string; diff --git a/test/__snapshots__/validation.test.ts.snap b/test/__snapshots__/validation.test.ts.snap deleted file mode 100644 index 1aed0f601..000000000 --- a/test/__snapshots__/validation.test.ts.snap +++ /dev/null @@ -1,3 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[` validation 1`] = `true`; diff --git a/test/validation.test.ts b/test/validation.test.ts index 0de09f2b3..0a2664d52 100644 --- a/test/validation.test.ts +++ b/test/validation.test.ts @@ -1,12 +1,29 @@ import snapshotjs from '@snapshot-labs/snapshot.js'; +import fetch from 'cross-fetch'; import snapshot from '../src'; -import examples from '../src/validations/passport-gated/examples.json'; -const [example] = examples; -const id = 'passport-gated'; +const validationArg = + process.env['npm_config_strategy'] || + ( + process.argv.find((arg) => arg.includes('--validation=')) || + '--validation=passport-gated' + ) + .split('--validation=') + .pop(); -describe('validation', () => { - it(`validate: ${id} "${example.name}"`, async () => { +const id = Object.keys(snapshot.validations).find( + (validation) => validationArg === validation +); +if (!id) throw 'Validation not found'; + +const examples = require(`../src/validations/${id}/examples.json`).map( + (example, index) => ({ index, example }) +); + +const [{ example }] = examples; + +describe('Validation', () => { + it(`validate: ${id}`, async () => { const validation = new snapshot.validations[id].validation( example.author, example.space, @@ -15,7 +32,7 @@ describe('validation', () => { example.params ); expect(await validation.validate()).toBe(true); - }, 10e3); + }, 30e3); // Check schema is valid with examples.json let schema; @@ -34,3 +51,56 @@ describe('validation', () => { } ); }); + +describe('All validations', () => { + it('All validations should have unique id and title', () => { + const ids = Object.keys(snapshot.validations).map( + (validation) => snapshot.validations[validation].id + ); + const titles = Object.keys(snapshot.validations).map( + (validation) => snapshot.validations[validation].title + ); + expect(new Set(ids).size).toBe(ids.length); + expect(new Set(titles).size).toBe(titles.length); + }); + + it('All validations should have examples.json', () => { + Object.keys(snapshot.validations).forEach((validation) => { + expect( + require(`../src/validations/${validation}/examples.json`) + ).toBeTruthy(); + }); + }); + + it('All validations should have a non-empty id, title, description, github and version', () => { + // Loop through all validations, and check that each has a non-empty id, title, description, github and version + Object.keys(snapshot.validations).forEach((validation) => { + const { id, title, description, github, version } = + snapshot.validations[validation]; + expect(id).toBeTruthy(); + expect(title).toBeTruthy(); + expect(description).toBeTruthy(); + expect(github).toBeTruthy(); + expect(version).toBeTruthy(); + + // Check that the version is in the correct format + expect(version).toMatch(/^\d+\.\d+\.\d+$/); + }); + }); +}); + +describe(`\nOthers:`, () => { + it('github in strategy should be a valid github username', async () => { + const github = snapshot.validations[id].github; + expect(typeof github).toBe('string'); + const githubUserData = await fetch( + `https://api.github.com/users/${github}` + ); + const githubUser = await githubUserData.json(); + expect(githubUser.message).not.toEqual('Not Found'); + }); + it('Version in strategy should be a valid string', async () => { + const version = snapshot.validations[id].version; + expect(typeof version).toBe('string'); + }); +}); From ca368dea0c4902ae0b6ced1c24b1f9a0be1ac4c0 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Mon, 6 Feb 2023 15:51:16 +0530 Subject: [PATCH 292/815] Remove scheam for psp-in-sepsp2-balance strategy (#1048) --- .../psp-in-sepsp2-balance/schema.json | 88 ------------------- 1 file changed, 88 deletions(-) delete mode 100644 src/strategies/psp-in-sepsp2-balance/schema.json diff --git a/src/strategies/psp-in-sepsp2-balance/schema.json b/src/strategies/psp-in-sepsp2-balance/schema.json deleted file mode 100644 index 2bfd47c89..000000000 --- a/src/strategies/psp-in-sepsp2-balance/schema.json +++ /dev/null @@ -1,88 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$ref": "#/definitions/Strategy", - "definitions": { - "Strategy": { - "title": "Strategy", - "type": "object", - "properties": { - "symbol": { - "type": "string", - "title": "Symbol", - "examples": ["PSP"] - }, - "decimals": { - "type": "number", - "title": "Decimals", - "examples": ["18"] - }, - "address": { - "type": "string", - "title": "Address", - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42, - "examples": ["0xcafe001067cdef266afb7eb5a286dcfd277f3de5"] - }, - "sePSP2": { - "type": "object", - "title": "sePSP2", - "properties": { - "address": { - "type": "string", - "title": "Address", - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42, - "examples": ["0x593F39A4Ba26A9c8ed2128ac95D109E8e403C485"] - }, - "decimals": { - "type": "number", - "title": "Decimals", - "examples": ["18"] - } - } - }, - "balancer": { - "type": "object", - "title": "Balancer", - "properties": { - "poolId": { - "type": "string", - "title": "Balancer_PoolId", - "examples": [ - "0xcb0e14e96f2cefa8550ad8e4aea344f211e5061d00020000000000000000011a" - ], - "pattern": "^0x[a-fA-F0-9]{64}$", - "minLength": 66, - "maxLength": 66 - }, - "BalancerHelpers": { - "type": "string", - "title": "BalancerHelpers_address", - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42, - "examples": ["0x5aDDCCa35b7A0D07C74063c48700C8590E87864E"] - }, - "Vault": { - "type": "string", - "title": "Vault_address", - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42, - "examples": ["0xBA12222222228d8Ba445958a75a0704d566BF2C8"] - } - } - }, - "multiplier": { - "type": "number", - "title": "Multiplier", - "examples": ["2.5"] - } - }, - "required": ["decimals", "address", "sePSP2", "balancer", "multiplier"], - "additionalProperties": false - } - } -} From fcb9854a6e1e2e17c735287e4fc5176fb1c3222d Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Mon, 6 Feb 2023 16:06:30 +0530 Subject: [PATCH 293/815] Update index.ts (#999) --- src/validations/basic/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/validations/basic/index.ts b/src/validations/basic/index.ts index 6c3ccb0df..38aa5909a 100644 --- a/src/validations/basic/index.ts +++ b/src/validations/basic/index.ts @@ -9,6 +9,7 @@ export default class extends Validation { public description = 'Use any strategy to determine if a user can vote.'; async validate(): Promise { + if(this.params.strategies?.length > 5) throw new Error(`Max number of strategies exceeded`); const minScore = this.params.minScore; if (minScore) { From 033893eb2bfb1cdbb604d39892d393b97dea6583 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Mon, 6 Feb 2023 16:13:56 +0530 Subject: [PATCH 294/815] Add a new param for static endpoints (#1045) --- src/strategies/api/README.md | 19 ++++++++++++++++--- src/strategies/api/index.ts | 12 ++++++++---- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/strategies/api/README.md b/src/strategies/api/README.md index d5f1154ad..f2e203cf3 100644 --- a/src/strategies/api/README.md +++ b/src/strategies/api/README.md @@ -21,6 +21,14 @@ IPFS endpoint is defined as a url starting with any of the following: The final URL is expected to look something like: `https://gateway.pinata.cloud/ipfs/QmbmhTivxYuLE5uhNEALoBmvP7Yg9acA2Lkw9V9PqaEmw6` +## For static endpoints +If your endpoint is not IPFS, you can use the `static` param so not all addresses are passed to the API. This is useful for APIs that have a limit on the number of addresses that can be passed in a single request. + +1. `param.api`: The first part of the URL (e.g. https://www.myapi.com/) + +2. `param.strategy`: The resource name (e.g. get_vote_count) + +3. `param.static`: Set to `true` ### For non-IPFS endpoints: @@ -36,9 +44,14 @@ The final URL is expected to look something like: `https://gateway.pinata.cloud/ The final URL is expected to look something like: `https://www.myapi.com/get_vote_count?network=1&snapshot=11437846&addresses=0xeD2bcC3104Da5F5f8fA988D6e9fAFd74Ae62f319,0x3c4B8C52Ed4c29eE402D9c91FfAe1Db2BAdd228D` - -## `decimals` param (optional) -Users can optionally include a `decimals` property. This will be used by the strategy when processing the scores from the API response. `decimals` is used as the second argument of `formatUnits` (https://docs.ethers.org/v3/api-utils.html?highlight=formatunits#ether-strings-and-wei). Default value is 0. +### List of params: +| Param | Description | Required | Default | +| --- | --- | --- | --- | +| `api` | The first part of the URL (e.g. https://www.myapi.com/) | Yes | | +| `strategy` (optional) | The resource name (e.g. get_vote_count) | Yes | '' | +| `static` (optional) | Set to `true` if you want to use the `static` endpoint | No | `false` | +| `additionalParameters` (optional) | Any additional parameters you want to include | No | | +| `decimals` (optional) | The number of decimals to use when processing the scores from the API response | No | `0` | ## Expected return of API The API should return an object with the following structure: diff --git a/src/strategies/api/index.ts b/src/strategies/api/index.ts index 6da207a52..f602d557d 100644 --- a/src/strategies/api/index.ts +++ b/src/strategies/api/index.ts @@ -21,14 +21,18 @@ export async function strategy( options, snapshot ) { - let api_url = options.api + '/' + options.strategy; - if (!isIPFS(api_url)) { + const api: string = options.api; + const strategy: string = options.strategy || ''; + const additionalParameters: string = options.additionalParameters || ''; + const staticFile: boolean = options.staticFile || false; + + let api_url = api + '/' + strategy + if (!isIPFS(api_url) && !staticFile) { api_url += '?network=' + network; api_url += '&snapshot=' + snapshot; api_url += '&addresses=' + addresses.join(','); } - if (options.additionalParameters) - api_url += '&' + options.additionalParameters; + if (additionalParameters) api_url += '&' + additionalParameters; const response = await fetch(api_url, { method: 'GET', From e520a86d8e2d20468a3ec5bc7700bd677651bf9d Mon Sep 17 00:00:00 2001 From: Carlos Febres Date: Tue, 7 Feb 2023 04:14:08 -0400 Subject: [PATCH 295/815] Eco Voting Power Strategy [eco-voting-power] (#1049) * eco-voting-power strategy init * [fix] allow addresses in any format (lower/upper case) --- src/strategies/eco-voting-power/examples.json | 5 +++-- src/strategies/eco-voting-power/index.ts | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/strategies/eco-voting-power/examples.json b/src/strategies/eco-voting-power/examples.json index 188e63065..a8003c8ea 100644 --- a/src/strategies/eco-voting-power/examples.json +++ b/src/strategies/eco-voting-power/examples.json @@ -4,12 +4,13 @@ "strategy": { "name": "eco-voting-power", "params": { - "delegatee": "0x64923706f6ca6f3c364292834c5370e4f03e2368" + "delegatee": "0x64923706f6ca6F3C364292834C5370e4f03e2368" } }, "network": "5", "addresses": [ - "0x40051de3036d76aee7b16cb2c21c86eb0dfa3f4c", + "0x18ab8b4fba1c770b279b97686f4265e882aa1e94", + "0x40051DE3036d76Aee7B16Cb2c21c86eB0dFa3f4c", "0x35244c622e5034dc1bcf2ff3931cfa57192572ff", "0x3ec87777b22d12ea95c55456324433a4c5a7bfe8", "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", diff --git a/src/strategies/eco-voting-power/index.ts b/src/strategies/eco-voting-power/index.ts index af16c0c75..f4d21daaf 100644 --- a/src/strategies/eco-voting-power/index.ts +++ b/src/strategies/eco-voting-power/index.ts @@ -67,17 +67,18 @@ export async function strategy( options, snapshot: number | 'latest' ): Promise> { + const _addresses = addresses.map((addr) => addr.toLowerCase()); const blockNumber = snapshot !== 'latest' ? snapshot : await getBlockNumber(provider); const baseFilter = { blockStarted_lte: blockNumber, - delegator_in: addresses.map((addr) => addr.toLowerCase()) + delegator_in: _addresses }; const query = { account: { - __args: { id: options.delegatee }, + __args: { id: options.delegatee.toLowerCase() }, ecoTokenDelegatees: { __aliasFor: 'tokenDelegatees', __args: { @@ -162,7 +163,7 @@ export async function strategy( ); return Object.fromEntries( - addresses.map((address) => { + _addresses.map((address) => { const ecoHistorical = ecoHistoricalDelegations[address] || Zero; const ecoCurrent = ecoCurrentDelegations[address] || Zero; const stakedEcoXHistorical = From 1a96a3ef15a1355f47d0886169d9e4c0bade8f30 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Tue, 7 Feb 2023 13:52:54 +0530 Subject: [PATCH 296/815] Update api strategy readme --- src/strategies/api/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/strategies/api/README.md b/src/strategies/api/README.md index f2e203cf3..23e312642 100644 --- a/src/strategies/api/README.md +++ b/src/strategies/api/README.md @@ -28,7 +28,7 @@ If your endpoint is not IPFS, you can use the `static` param so not all addresse 2. `param.strategy`: The resource name (e.g. get_vote_count) -3. `param.static`: Set to `true` +3. `param.staticFile`: Set to `true` ### For non-IPFS endpoints: @@ -49,7 +49,7 @@ The final URL is expected to look something like: `https://www.myapi.com/get_vot | --- | --- | --- | --- | | `api` | The first part of the URL (e.g. https://www.myapi.com/) | Yes | | | `strategy` (optional) | The resource name (e.g. get_vote_count) | Yes | '' | -| `static` (optional) | Set to `true` if you want to use the `static` endpoint | No | `false` | +| `staticFile` (optional) | Set to `true` if you want to use the `static` endpoint | No | `false` | | `additionalParameters` (optional) | Any additional parameters you want to include | No | | | `decimals` (optional) | The number of decimals to use when processing the scores from the API response | No | `0` | @@ -93,4 +93,4 @@ Note that for the example above, `element.score` is a string representation in w ## Testing You can test this strategy by updating the `examples.json` file and running `npm run test --strategy=api` -To test local changes, change to this directory and run: `npm run build & npm run test --strategy=api` \ No newline at end of file +To test local changes, change to this directory and run: `npm run build & npm run test --strategy=api` From 64047345596d008f3ca4f9f58c7c417e0b13712d Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Tue, 7 Feb 2023 15:52:43 +0530 Subject: [PATCH 297/815] If API ends with .json don't pass addresses query (#1043) * Fix api strategy If API return json file * Update index.ts * Update index.ts --- src/strategies/api/README.md | 4 +++- src/strategies/api/index.ts | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/strategies/api/README.md b/src/strategies/api/README.md index 23e312642..dfebc906b 100644 --- a/src/strategies/api/README.md +++ b/src/strategies/api/README.md @@ -22,7 +22,9 @@ IPFS endpoint is defined as a url starting with any of the following: The final URL is expected to look something like: `https://gateway.pinata.cloud/ipfs/QmbmhTivxYuLE5uhNEALoBmvP7Yg9acA2Lkw9V9PqaEmw6` ## For static endpoints -If your endpoint is not IPFS, you can use the `static` param so not all addresses are passed to the API. This is useful for APIs that have a limit on the number of addresses that can be passed in a single request. +If your endpoint is not IPFS, but API is returning static data: +You can use an API URL that ends with `.json` for example: `https://www.myapi.com/vote_count.json` +Or You can use the `staticFile` param so not all addresses are passed to the API. This is useful for APIs that have a limit on the number of addresses that can be passed in a single request. 1. `param.api`: The first part of the URL (e.g. https://www.myapi.com/) diff --git a/src/strategies/api/index.ts b/src/strategies/api/index.ts index f602d557d..168a91380 100644 --- a/src/strategies/api/index.ts +++ b/src/strategies/api/index.ts @@ -13,6 +13,10 @@ const isIPFS = (apiURL) => { ); }; +const isStaticAPI = (apiURL: string): boolean => { + return apiURL.endsWith('.json'); +}; + export async function strategy( space, network, @@ -27,7 +31,7 @@ export async function strategy( const staticFile: boolean = options.staticFile || false; let api_url = api + '/' + strategy - if (!isIPFS(api_url) && !staticFile) { + if (!isIPFS(api_url) && !isStaticAPI(api_url) && !staticFile) { api_url += '?network=' + network; api_url += '&snapshot=' + snapshot; api_url += '&addresses=' + addresses.join(','); From 3d6cb66ad4c5a82ca6f77633186e6089a09b62c7 Mon Sep 17 00:00:00 2001 From: Carlos Febres Date: Wed, 8 Feb 2023 00:13:15 -0400 Subject: [PATCH 298/815] Eco voting power [eco-voting-power] - Fix voting power calculation (#1050) * eco-voting-power strategy init * [fix] allow addresses in any format (lower/upper case) * [fix] allow delegatees with no data * fix voting power calculation --- src/strategies/eco-voting-power/index.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/strategies/eco-voting-power/index.ts b/src/strategies/eco-voting-power/index.ts index f4d21daaf..443e8ce9e 100644 --- a/src/strategies/eco-voting-power/index.ts +++ b/src/strategies/eco-voting-power/index.ts @@ -44,7 +44,7 @@ function calculateVotingPower( ecoVp: BigNumber, stakedEcoXVp: BigNumber ): BigNumber { - return stakedEcoXVp.add(ecoVp.mul(10)); + return stakedEcoXVp.add(ecoVp.div(10)); } function createDelegationList( @@ -140,26 +140,32 @@ export async function strategy( throw new Error(`Unsupported network with id: ${network}`); } - const { account: delegateesResult, inflationMultipliers }: QueryResult = + const { account: account, inflationMultipliers }: QueryResult = await subgraphRequest(subgraphUrl, query); + if (!account) { + return Object.fromEntries( + _addresses.map((address) => [getAddress(address), 0]) + ); + } + const inflationMultiplier = inflationMultipliers.length ? BigNumber.from(inflationMultipliers[0].value) : WeiPerEther; const ecoHistoricalDelegations = createDelegationList( - delegateesResult.ecoTokenDelegatees, + account.ecoTokenDelegatees, inflationMultiplier ); const ecoCurrentDelegations = createDelegationList( - delegateesResult.ecoCurrentTokenDelegatees, + account.ecoCurrentTokenDelegatees, inflationMultiplier ); const stakedEcoXHistoricalDelegations = createDelegationList( - delegateesResult.stakedEcoXTokenDelegatees + account.stakedEcoXTokenDelegatees ); const stakedEcoXCurrentDelegations = createDelegationList( - delegateesResult.stakedEcoXCurrentTokenDelegatees + account.stakedEcoXCurrentTokenDelegatees ); return Object.fromEntries( From ed728ee9b4777f722e79d957d22390f17eaf1795 Mon Sep 17 00:00:00 2001 From: Vigan Date: Fri, 10 Feb 2023 08:30:22 +0100 Subject: [PATCH 299/815] [pdn-balances-and-vests] New strategy specific for poseidon dao (#1051) * Added a new strategy specific for poseidon dao * changed the author and version as suggested --- src/strategies/index.ts | 4 +- .../pdn-balances-and-vests/README.md | 20 +++++ .../pdn-balances-and-vests/examples.json | 20 +++++ .../pdn-balances-and-vests/index.ts | 84 +++++++++++++++++++ .../pdn-balances-and-vests/schema.json | 33 ++++++++ 5 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 src/strategies/pdn-balances-and-vests/README.md create mode 100644 src/strategies/pdn-balances-and-vests/examples.json create mode 100644 src/strategies/pdn-balances-and-vests/index.ts create mode 100644 src/strategies/pdn-balances-and-vests/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 2079d2c55..3ae03a73b 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -422,6 +422,7 @@ import * as battleflyVGFLYAndStakedGFLY from './battlefly-vgfly-and-staked-gfly' import * as nexonArmyNFT from './nexon-army-nft'; import * as stakedotlinkVesting from './stakedotlink-vesting'; import * as pspInSePSP2Balance from './psp-in-sepsp2-balance'; +import * as pdnBalancesAndVests from './pdn-balances-and-vests'; const strategies = { 'eco-voting-power': ecoVotingPower, @@ -849,7 +850,8 @@ const strategies = { 'battlefly-vgfly-and-staked-gfly': battleflyVGFLYAndStakedGFLY, 'nexon-army-nft': nexonArmyNFT, 'stakedotlink-vesting': stakedotlinkVesting, - 'psp-in-sepsp2-balance': pspInSePSP2Balance + 'psp-in-sepsp2-balance': pspInSePSP2Balance, + 'pdn-balances-and-vests': pdnBalancesAndVests }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/pdn-balances-and-vests/README.md b/src/strategies/pdn-balances-and-vests/README.md new file mode 100644 index 000000000..4fff5bab2 --- /dev/null +++ b/src/strategies/pdn-balances-and-vests/README.md @@ -0,0 +1,20 @@ +# pdn-balances-and-vests + +## Calculating Vested Tokens with Balances + +To find out the total number of vested tokens with balances, follow these steps: + +1. Invoke the `balanceOf` function for each address to get its token balance. +2. Use the `getVestLength` function to determine the number of vests held by that address. +3. Invoke the `getVestMetaData` function to retrieve metadata for each vest, including the amount vested. +4. Add the amount vested for each vest to the total balance for the corresponding address. + +Here is an example of parameters: + +```json +{ + "address": "0xdd0d06EC5dB655f76641bdA81Fec3221C167787e", + "symbol": "PDN", + "decimals": 18 +} +``` diff --git a/src/strategies/pdn-balances-and-vests/examples.json b/src/strategies/pdn-balances-and-vests/examples.json new file mode 100644 index 000000000..7426c2312 --- /dev/null +++ b/src/strategies/pdn-balances-and-vests/examples.json @@ -0,0 +1,20 @@ +[ + { + "name": "PDN balances and vests", + "strategy": { + "name": "pdn-balances-and-vests", + "params": { + "address": "0xdd0d06EC5dB655f76641bdA81Fec3221C167787e", + "symbol": "PDN", + "decimals": 18 + } + }, + "network": "5", + "addresses": [ + "0xB6097b6932ad88D1159c10bA7D290ba05087507D", + "0x0a767592E4C4CbD5A65BAc08bd3c7112d68496A5", + "0x7db3c4099660a6f33bBfF63B3318CBf9b4D07743" + ], + "snapshot": 8458274 + } +] diff --git a/src/strategies/pdn-balances-and-vests/index.ts b/src/strategies/pdn-balances-and-vests/index.ts new file mode 100644 index 000000000..629141ef1 --- /dev/null +++ b/src/strategies/pdn-balances-and-vests/index.ts @@ -0,0 +1,84 @@ +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'viganzeqiri'; +export const version = '0.1.0'; + +const abi = [ + 'function balanceOf(address account) external view returns (uint256)', + 'function getVestLength(address _address) public view returns(uint)', + 'function getVestMetaData(uint _index, address _address) public view returns(uint, uint)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multi = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => + multi.call(address, options.address, 'balanceOf', [address]) + ); + const balances: Record = await multi.execute(); + + addresses.forEach((address) => + multi.call(address, options.address, 'getVestLength', [address]) + ); + const addressesWithVestLength: Record = + await multi.execute(); + + const formatedAddressVests = Object.entries(addressesWithVestLength).reduce< + Record + >((acc, [addresses, vestLength]) => { + acc[addresses] = Number(vestLength); + return acc; + }, {}); + + Object.entries(formatedAddressVests).forEach(([address, vestLength]) => { + if (vestLength > 0) { + const vestIndexes = Array.from(Array(vestLength).keys()); + + vestIndexes.forEach((vestIndex) => { + multi.call( + `${address}-${vestIndex}`, + options.address, + 'getVestMetaData', + [vestIndex, address] + ); + }); + } + }); + + const vestsMetadata: Record = await multi.execute(); + + const metadataWithAccumulatedVests = Object.entries(vestsMetadata).reduce( + (acc, [key, value]) => { + const [address] = key.split('-'); + const amountVestes = value[0] || 0; + + acc[address] = + (acc[address] || 0) + + parseFloat(formatUnits(amountVestes, options.decimals)); + + return acc; + }, + {} + ); + + return Object.fromEntries( + Object.entries(balances).map(([address, balance]) => { + const totalBalance = + (!!metadataWithAccumulatedVests[address] + ? metadataWithAccumulatedVests[address] + : 0) + parseFloat(formatUnits(balance, options.decimals)); + + return [address, totalBalance]; + }) + ); +} diff --git a/src/strategies/pdn-balances-and-vests/schema.json b/src/strategies/pdn-balances-and-vests/schema.json new file mode 100644 index 000000000..2113da8b8 --- /dev/null +++ b/src/strategies/pdn-balances-and-vests/schema.json @@ -0,0 +1,33 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. UNI"], + "maxLength": 16 + }, + "address": { + "type": "string", + "title": "Contract address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 18"] + } + }, + "required": ["address", "decimals"], + "additionalProperties": false + } + } +} From 9f1458558a1c8321d8148bdba11509488859c04d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 Feb 2023 19:29:59 +0530 Subject: [PATCH 300/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.62 (#1054) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 66abc50f2..ea8587748 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.61", + "@snapshot-labs/snapshot.js": "^0.4.62", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index b835cf70f..aebcaa8c7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.61": - version "0.4.61" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.61.tgz#a8849d34deed94443e0eba047e76a377ae0946a1" - integrity sha512-7EpZKcRmECbq8b46ghQa/MCSo99r2NxufZ5UJE1RImPRmFSwyekZUd7QP/KoqUacKtaJVbcYl3PXM5ZoYwhkNQ== +"@snapshot-labs/snapshot.js@^0.4.62": + version "0.4.62" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.62.tgz#47f3805a9aa413a999b223a1727f02a9fb3009af" + integrity sha512-LzKIjaUsBVT+h1WA5SJAajt2r2Y0Bsvc5Doh+m/c5k+Gns5qB8HdOisGFjCwVkZkLIm6ruvnf1Khvku72l3jCQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From c4b5d742edcf07dc9f9049305ff131226b9a5e37 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 13 Feb 2023 19:57:33 +0530 Subject: [PATCH 301/815] Automated lint (#1052) Co-authored-by: ChaituVR --- src/strategies/api/index.ts | 2 +- src/validations/basic/index.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/strategies/api/index.ts b/src/strategies/api/index.ts index 168a91380..d48e05d44 100644 --- a/src/strategies/api/index.ts +++ b/src/strategies/api/index.ts @@ -30,7 +30,7 @@ export async function strategy( const additionalParameters: string = options.additionalParameters || ''; const staticFile: boolean = options.staticFile || false; - let api_url = api + '/' + strategy + let api_url = api + '/' + strategy; if (!isIPFS(api_url) && !isStaticAPI(api_url) && !staticFile) { api_url += '?network=' + network; api_url += '&snapshot=' + snapshot; diff --git a/src/validations/basic/index.ts b/src/validations/basic/index.ts index 38aa5909a..ec218c4f3 100644 --- a/src/validations/basic/index.ts +++ b/src/validations/basic/index.ts @@ -9,7 +9,8 @@ export default class extends Validation { public description = 'Use any strategy to determine if a user can vote.'; async validate(): Promise { - if(this.params.strategies?.length > 5) throw new Error(`Max number of strategies exceeded`); + if (this.params.strategies?.length > 5) + throw new Error(`Max number of strategies exceeded`); const minScore = this.params.minScore; if (minScore) { From 6fad26236d0163f0b27a01d71c1438d9712dcd95 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 15 Feb 2023 01:55:28 +0530 Subject: [PATCH 302/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.63 (#1056) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index ea8587748..b19e1b3c8 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.62", + "@snapshot-labs/snapshot.js": "^0.4.63", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index aebcaa8c7..f5c1631c8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.62": - version "0.4.62" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.62.tgz#47f3805a9aa413a999b223a1727f02a9fb3009af" - integrity sha512-LzKIjaUsBVT+h1WA5SJAajt2r2Y0Bsvc5Doh+m/c5k+Gns5qB8HdOisGFjCwVkZkLIm6ruvnf1Khvku72l3jCQ== +"@snapshot-labs/snapshot.js@^0.4.63": + version "0.4.63" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.63.tgz#f7651f7c70112b779ac3ac4606a6853c46b39c3c" + integrity sha512-wSbfPRpkSj2YFbdTvxgerQsG8krmfM0s8VGwjzOvPY8ha8LIb+xJut9qzsrA3er/HkaTxgf2RTh+qWfRuGKj3g== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 277f24bf2b9c27f71cd7977e41fc8ade87f91c78 Mon Sep 17 00:00:00 2001 From: LpcAries <101619245+LpcAries@users.noreply.github.com> Date: Thu, 16 Feb 2023 17:19:43 +0800 Subject: [PATCH 303/815] [izumi-veizi] add strategy for calculating votes according to amount of veiZi (#1058) * add strategy for izumi * update izumi-veizi strategy --- src/strategies/index.ts | 2 + src/strategies/izumi-veizi/README.md | 13 +++++ src/strategies/izumi-veizi/examples.json | 26 +++++++++ src/strategies/izumi-veizi/index.ts | 68 ++++++++++++++++++++++++ src/strategies/izumi-veizi/schema.json | 33 ++++++++++++ 5 files changed, 142 insertions(+) create mode 100644 src/strategies/izumi-veizi/README.md create mode 100644 src/strategies/izumi-veizi/examples.json create mode 100644 src/strategies/izumi-veizi/index.ts create mode 100644 src/strategies/izumi-veizi/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 3ae03a73b..77ba02f02 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -423,8 +423,10 @@ import * as nexonArmyNFT from './nexon-army-nft'; import * as stakedotlinkVesting from './stakedotlink-vesting'; import * as pspInSePSP2Balance from './psp-in-sepsp2-balance'; import * as pdnBalancesAndVests from './pdn-balances-and-vests'; +import * as izumiVeiZi from './izumi-veizi' const strategies = { + 'izumi-veizi': izumiVeiZi, 'eco-voting-power': ecoVotingPower, 'forta-shares': fortaShares, 'across-staked-acx': acrossStakedAcx, diff --git a/src/strategies/izumi-veizi/README.md b/src/strategies/izumi-veizi/README.md new file mode 100644 index 000000000..cfc142002 --- /dev/null +++ b/src/strategies/izumi-veizi/README.md @@ -0,0 +1,13 @@ +# erc20-balance-of + +This is a strategy which used for counting veizi for izumi voting, it returns the balances of the voters for the veiZi including the amount of staked veNFT. + +Here is an example of parameters: + +```json +{ + "address": "0xB56A454d8DaC2AD4cB82337887717a2a427Fcd00", + "symbol": "veiZi", + "decimals": 18 +} +``` diff --git a/src/strategies/izumi-veizi/examples.json b/src/strategies/izumi-veizi/examples.json new file mode 100644 index 000000000..5ab285430 --- /dev/null +++ b/src/strategies/izumi-veizi/examples.json @@ -0,0 +1,26 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "izumi-veizi", + "params": { + "address": "0xB56A454d8DaC2AD4cB82337887717a2a427Fcd00", + "symbol": "veiZi", + "decimals": 18 + } + }, + "network": "1", + "addresses": [ + "0x6534069842F1aFCbb5b6e27eA2bAc2243f85FFF8", + "0x423F9B19Db22337D249c1d85eE045700846953B3", + "0x9558ab3bd4429B1D5658D9ea6C5E8F2b8B4B7431", + "0xB56A454d8DaC2AD4cB82337887717a2a427Fcd00", + "0x9997d7120862CEda99aB4a1c43698e0941F87b20", + "0x1d5E65a087eBc3d03a294412E46CE5D6882969f4", + "0x381F298A34D286CBe36b1C17097aE36350B66DC8", + "0x760484042a7856E62B627318796Ebb609C8131a1", + "0x72956796334bA8EB7c10a474e97F6F8773E40cFf" + ], + "snapshot": 16619300 + } +] diff --git a/src/strategies/izumi-veizi/index.ts b/src/strategies/izumi-veizi/index.ts new file mode 100644 index 000000000..055c44d4f --- /dev/null +++ b/src/strategies/izumi-veizi/index.ts @@ -0,0 +1,68 @@ +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'izumiFinance'; +export const version = '0.1.0'; + +const abi = [ + "function balanceOf(address owner) external view returns (uint256)", + "function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256)", + "function nftVeiZiAt(uint256 nftId, uint256 timestamp) external view returns (uint256)", + "function stakedNft(address) external view returns (uint256)", +] + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const block = await provider.getBlock(snapshot) + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const timeStamp = block.timestamp + let ans = {} as Record + + const nftBalance = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => nftBalance.call(address, options.address, 'balanceOf', [address])); + const balance: Record = await nftBalance.execute(); + + const nftIdCall = new Multicaller(network, provider, abi, { blockTag }); + Object.entries(balance).map(async ([address, balance]) => { + const num = Number(balance.toString()) + for (let i=0; i = await nftIdCall.execute() + + const pointCall = new Multicaller(network, provider, abi, { blockTag }) + Object.entries(ids).map(([path, id])=>{ + pointCall.call(path, options.address, 'nftVeiZiAt', [id, timeStamp]) + }) + const points: Record = await pointCall.execute() + + Object.entries(points).map(([path, point])=>{ + const owner = path.split("-")[0] + const tmp = Object.keys(ans).find((t)=>{return t===owner}) + const decimalPoint = Number(Math.floor(parseFloat(formatUnits(point, options.decimals)) * 100) / 100) + if (tmp !== undefined) { + ans[owner] = Number(ans[owner]) + decimalPoint + } + else { + Object.assign(ans, {[owner]:decimalPoint}) + } + }) + + return Object.fromEntries( + Object.entries(ans).map(([address, point]) => [ + address, + Math.floor(point / 10) * 10 + ]) + ); +} diff --git a/src/strategies/izumi-veizi/schema.json b/src/strategies/izumi-veizi/schema.json new file mode 100644 index 000000000..f2cf0991a --- /dev/null +++ b/src/strategies/izumi-veizi/schema.json @@ -0,0 +1,33 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. veiZi"], + "maxLength": 16 + }, + "address": { + "type": "string", + "title": "Contract address", + "examples": ["e.g. 0xB56A454d8DaC2AD4cB82337887717a2a427Fcd00"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 18"] + } + }, + "required": ["address", "decimals"], + "additionalProperties": false + } + } +} From cb8e8b5fc09e117e8e0b73fb8a952e27b2fa9196 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Fri, 17 Feb 2023 18:01:40 +0530 Subject: [PATCH 304/815] Add documentation for erc1155-balance-of strategy (#1061) --- src/strategies/erc1155-balance-of/README.md | 14 +++++++++++ .../erc1155-balance-of/examples.json | 2 +- src/strategies/erc1155-balance-of/index.ts | 25 +------------------ 3 files changed, 16 insertions(+), 25 deletions(-) create mode 100644 src/strategies/erc1155-balance-of/README.md diff --git a/src/strategies/erc1155-balance-of/README.md b/src/strategies/erc1155-balance-of/README.md new file mode 100644 index 000000000..967fc915d --- /dev/null +++ b/src/strategies/erc1155-balance-of/README.md @@ -0,0 +1,14 @@ +# erc1155-balances-of + +This strategy return the balances of the voters, for a specific token in a ERC1155 contract. + +> Note: If you want to get balance of all tokenIds in the contract, you can use the `erc1155-balance-of-all` strategy. If you have multiple tokenIds, you can use the `erc1155-balance-of-ids` or `erc1155-balance-of-ids-weighted` strategy. + +## Params + +| param | type | description | +| --- | --- | --- | +| `address` | `string` | The address of the ERC1155 contract | +| `tokenId` | `string` | The tokenId of the token to check | +| `decimals` | `number` | The number of decimals of the token | +| `symbol`(optional) | `string` | The symbol of the token | diff --git a/src/strategies/erc1155-balance-of/examples.json b/src/strategies/erc1155-balance-of/examples.json index b1832c297..f655f0c4e 100644 --- a/src/strategies/erc1155-balance-of/examples.json +++ b/src/strategies/erc1155-balance-of/examples.json @@ -14,7 +14,7 @@ "addresses": [ "0x0B7056e2D9064f2ec8647F1ae556BAcc06da6Db4", "0xcc5Ddc8CCD5B1E90Bc42F998ec864Ead0090A12B", - "0x0154d25120ed20a516fe43991702e7463c5a6f6e" + "0x0154d25120Ed20A516fE43991702e7463c5A6F6e" ], "snapshot": 11992257 } diff --git a/src/strategies/erc1155-balance-of/index.ts b/src/strategies/erc1155-balance-of/index.ts index ba412a3ce..32ce8bd92 100644 --- a/src/strategies/erc1155-balance-of/index.ts +++ b/src/strategies/erc1155-balance-of/index.ts @@ -5,30 +5,7 @@ export const author = 'dave4506'; export const version = '0.1.0'; const abi = [ - { - inputs: [ - { - internalType: 'address', - name: 'owner', - type: 'address' - }, - { - internalType: 'uint256', - name: 'id', - type: 'uint256' - } - ], - name: 'balanceOf', - outputs: [ - { - internalType: 'uint256', - name: '', - type: 'uint256' - } - ], - stateMutability: 'view', - type: 'function' - } + 'function balanceOf(address owner, uint256 id) view returns (uint256)' ]; export async function strategy( From 0a8f94fde71773d240100664e043133e32e5810c Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Sat, 18 Feb 2023 03:14:04 +0530 Subject: [PATCH 305/815] Ticket strategy documentation update (#1062) --- src/strategies/ticket/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/strategies/ticket/README.md diff --git a/src/strategies/ticket/README.md b/src/strategies/ticket/README.md new file mode 100644 index 000000000..6cf92526a --- /dev/null +++ b/src/strategies/ticket/README.md @@ -0,0 +1,10 @@ +# ticket + +Ticket strategy gives one voting power per one address, you can also pass a `value` parameter to give more voting power to the voter. + +## Params + +| param | type | description | default | +| --- | --- | --- | --- | +| `value` | `number` | The number of votes to give to the voter | 1 | +| `symbol` | `string` | The symbol of the token | optional | From 12e2bbd2bafea8388faace9dc1f79964a2dbb602 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Sat, 18 Feb 2023 18:30:40 +0530 Subject: [PATCH 306/815] Update passport-validation schema (#1063) --- src/validations/passport-gated/schema.json | 64 +++++++++++----------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/validations/passport-gated/schema.json b/src/validations/passport-gated/schema.json index b70b94b1e..44a3e35de 100644 --- a/src/validations/passport-gated/schema.json +++ b/src/validations/passport-gated/schema.json @@ -77,7 +77,7 @@ }, { "const": "FiveOrMoreGithubRepos", - "title": "Github repos > 4" + "title": "Github repos at least 5" }, { "const": "ForkedGithubRepoProvider", @@ -89,73 +89,73 @@ }, { "const": "TenOrMoreGithubFollowers", - "title": "Github followers > 9" + "title": "Github followers at least 10" }, { "const": "FiftyOrMoreGithubFollowers", - "title": "Github followers > 49" + "title": "Github followers at least 50" }, { "const": "GitcoinContributorStatistics#numGrantsContributeToGte#1", - "title": "Grants contributed > 1" + "title": "Grants contributed to at least 1" }, { "const": "GitcoinContributorStatistics#numGrantsContributeToGte#10", - "title": "Grants contributed > 10" + "title": "Grants contributed to at least 10" }, { "const": "GitcoinContributorStatistics#numGrantsContributeToGte#25", - "title": "Grants contributed > 25" + "title": "Grants contributed to at least 25" }, { "const": "GitcoinContributorStatistics#numGrantsContributeToGte#100", - "title": "Grants contributed > 100" + "title": "Grants contributed to at least 100" }, { "const": "GitcoinContributorStatistics#totalContributionAmountGte#10", - "title": "Grant contributions > $10" + "title": "Grant contributions at least $10" }, { "const": "GitcoinContributorStatistics#totalContributionAmountGte#100", - "title": "Grant contributions > $100" + "title": "Grant contributions at least $100" }, { "const": "GitcoinContributorStatistics#totalContributionAmountGte#1000", - "title": "Grant contributions > $1000" + "title": "Grant contributions at least $1000" }, { "const": "GitcoinGranteeStatistics#numOwnedGrants#1", - "title": "Grant owner > 1" + "title": "Grant owner of at least 1 Grant" }, { "const": "GitcoinGranteeStatistics#numGrantContributors#10", - "title": "Grant contributors > 10" + "title": "Grant contributors at least 10" }, { "const": "GitcoinGranteeStatistics#numGrantContributors#25", - "title": "Grant contributors > 25" + "title": "Grant contributors at least 25" }, { "const": "GitcoinGranteeStatistics#numGrantContributors#100", - "title": "Grant contributors > 100" + "title": "Grant contributors at least 100" }, { "const": "GitcoinGranteeStatistics#totalContributionAmount#100", - "title": "Grant contributions > $100" + "title": "Grant have received at least $100" }, { "const": "GitcoinGranteeStatistics#totalContributionAmount#1000", - "title": "Grant contributions > $1000" + "title": "Grant have received at least $1000" }, { "const": "GitcoinGranteeStatistics#totalContributionAmount#10000", - "title": "Grant contributions > $10000" + "title": "Grant have received at least $10000" }, { "const": "GitcoinGranteeStatistics#numGrantsInEcoAndCauseRound#1", - "title": "Grant owner Eco & Cause" + "title": "Grant owner at least 1 Eco & Cause" }, { "const": "Linkedin", @@ -175,59 +175,59 @@ }, { "const": "ethPossessionsGte#1", - "title": "ETH > 1" + "title": "ETH at least 1" }, { "const": "ethPossessionsGte#10", - "title": "ETH > 10" + "title": "ETH at least 10" }, { "const": "ethPossessionsGte#32", - "title": "ETH > 32" + "title": "ETH at least 32" }, { "const": "FirstEthTxnProvider", - "title": "First ETH > 30 days" + "title": "First ETH more than 30 days ago" }, { "const": "EthGTEOneTxnProvider", - "title": "ETH tx > 1" + "title": "ETH tx at least 1" }, { "const": "EthGasProvider", - "title": "ETH gas > 0.5" + "title": "ETH gas at least 0.5" }, { "const": "gtcPossessionsGte#10", - "title": "Gitcoin GTC > 10" + "title": "Gitcoin GTC at least 10" }, { "const": "gtcPossessionsGte#100", - "title": "Gitcoin GTC > 100" + "title": "Gitcoin GTC at least 100" }, { "const": "SelfStakingBronze", - "title": "GTC staked > 1" + "title": "GTC staked at least 1" }, { "const": "SelfStakingSilver", - "title": "GTC staked > 10" + "title": "GTC staked at least 10" }, { "const": "SelfStakingGold", - "title": "GTC staked > 100" + "title": "GTC staked at least 100" }, { "const": "CommunityStakingBronze", - "title": "Comm GTC staked > 1" + "title": "Comm GTC staked at least 1" }, { "const": "CommunityStakingSilver", - "title": "Comm GTC staked > 10" + "title": "Comm GTC staked at least 10" }, { "const": "CommunityStakingGold", - "title": "Comm GTC staked > 100" + "title": "Comm GTC staked at least 100" }, { "const": "NFT", From e7960f7be591dd1c8079d75440bef485cedfaa0a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 19 Feb 2023 23:45:15 +0530 Subject: [PATCH 307/815] Automated lint (#1064) Co-authored-by: ChaituVR --- src/strategies/index.ts | 2 +- src/strategies/izumi-veizi/index.ts | 110 +++++++++++++++------------- 2 files changed, 60 insertions(+), 52 deletions(-) diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 77ba02f02..2216117f7 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -423,7 +423,7 @@ import * as nexonArmyNFT from './nexon-army-nft'; import * as stakedotlinkVesting from './stakedotlink-vesting'; import * as pspInSePSP2Balance from './psp-in-sepsp2-balance'; import * as pdnBalancesAndVests from './pdn-balances-and-vests'; -import * as izumiVeiZi from './izumi-veizi' +import * as izumiVeiZi from './izumi-veizi'; const strategies = { 'izumi-veizi': izumiVeiZi, diff --git a/src/strategies/izumi-veizi/index.ts b/src/strategies/izumi-veizi/index.ts index 055c44d4f..a14e2d2aa 100644 --- a/src/strategies/izumi-veizi/index.ts +++ b/src/strategies/izumi-veizi/index.ts @@ -6,63 +6,71 @@ export const author = 'izumiFinance'; export const version = '0.1.0'; const abi = [ - "function balanceOf(address owner) external view returns (uint256)", - "function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256)", - "function nftVeiZiAt(uint256 nftId, uint256 timestamp) external view returns (uint256)", - "function stakedNft(address) external view returns (uint256)", -] + 'function balanceOf(address owner) external view returns (uint256)', + 'function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256)', + 'function nftVeiZiAt(uint256 nftId, uint256 timestamp) external view returns (uint256)', + 'function stakedNft(address) external view returns (uint256)' +]; export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot + space, + network, + provider, + addresses, + options, + snapshot ): Promise> { - const block = await provider.getBlock(snapshot) - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - const timeStamp = block.timestamp - let ans = {} as Record + const block = await provider.getBlock(snapshot); + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const timeStamp = block.timestamp; + const ans = {} as Record; - const nftBalance = new Multicaller(network, provider, abi, { blockTag }); - addresses.forEach((address) => nftBalance.call(address, options.address, 'balanceOf', [address])); - const balance: Record = await nftBalance.execute(); + const nftBalance = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => + nftBalance.call(address, options.address, 'balanceOf', [address]) + ); + const balance: Record = await nftBalance.execute(); - const nftIdCall = new Multicaller(network, provider, abi, { blockTag }); - Object.entries(balance).map(async ([address, balance]) => { - const num = Number(balance.toString()) - for (let i=0; i = await nftIdCall.execute() + const nftIdCall = new Multicaller(network, provider, abi, { blockTag }); + Object.entries(balance).map(async ([address, balance]) => { + const num = Number(balance.toString()); + for (let i = 0; i < num; i++) { + const path = address + '-' + i; + const stakedPath = address + '-' + 'staked'; + nftIdCall.call(path, options.address, 'tokenOfOwnerByIndex', [ + address, + i + ]); + nftIdCall.call(stakedPath, options.address, 'stakedNft', [address]); + } + }); + const ids: Record = await nftIdCall.execute(); - const pointCall = new Multicaller(network, provider, abi, { blockTag }) - Object.entries(ids).map(([path, id])=>{ - pointCall.call(path, options.address, 'nftVeiZiAt', [id, timeStamp]) - }) - const points: Record = await pointCall.execute() - - Object.entries(points).map(([path, point])=>{ - const owner = path.split("-")[0] - const tmp = Object.keys(ans).find((t)=>{return t===owner}) - const decimalPoint = Number(Math.floor(parseFloat(formatUnits(point, options.decimals)) * 100) / 100) - if (tmp !== undefined) { - ans[owner] = Number(ans[owner]) + decimalPoint - } - else { - Object.assign(ans, {[owner]:decimalPoint}) - } - }) + const pointCall = new Multicaller(network, provider, abi, { blockTag }); + Object.entries(ids).map(([path, id]) => { + pointCall.call(path, options.address, 'nftVeiZiAt', [id, timeStamp]); + }); + const points: Record = await pointCall.execute(); - return Object.fromEntries( - Object.entries(ans).map(([address, point]) => [ - address, - Math.floor(point / 10) * 10 - ]) + Object.entries(points).map(([path, point]) => { + const owner = path.split('-')[0]; + const tmp = Object.keys(ans).find((t) => { + return t === owner; + }); + const decimalPoint = Number( + Math.floor(parseFloat(formatUnits(point, options.decimals)) * 100) / 100 ); + if (tmp !== undefined) { + ans[owner] = Number(ans[owner]) + decimalPoint; + } else { + Object.assign(ans, { [owner]: decimalPoint }); + } + }); + + return Object.fromEntries( + Object.entries(ans).map(([address, point]) => [ + address, + Math.floor(point / 10) * 10 + ]) + ); } From 7d9232ce8c9a4326857f2a6f7337d92bbb3da7ec Mon Sep 17 00:00:00 2001 From: LpcAries <101619245+LpcAries@users.noreply.github.com> Date: Wed, 22 Feb 2023 19:09:05 +0800 Subject: [PATCH 308/815] adjust collecting strategy of veizi (#1065) --- src/strategies/izumi-veizi/examples.json | 9 +++++++-- src/strategies/izumi-veizi/index.ts | 11 +++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/strategies/izumi-veizi/examples.json b/src/strategies/izumi-veizi/examples.json index 5ab285430..1ff27bf1b 100644 --- a/src/strategies/izumi-veizi/examples.json +++ b/src/strategies/izumi-veizi/examples.json @@ -14,12 +14,17 @@ "0x6534069842F1aFCbb5b6e27eA2bAc2243f85FFF8", "0x423F9B19Db22337D249c1d85eE045700846953B3", "0x9558ab3bd4429B1D5658D9ea6C5E8F2b8B4B7431", - "0xB56A454d8DaC2AD4cB82337887717a2a427Fcd00", "0x9997d7120862CEda99aB4a1c43698e0941F87b20", "0x1d5E65a087eBc3d03a294412E46CE5D6882969f4", "0x381F298A34D286CBe36b1C17097aE36350B66DC8", "0x760484042a7856E62B627318796Ebb609C8131a1", - "0x72956796334bA8EB7c10a474e97F6F8773E40cFf" + "0x72956796334bA8EB7c10a474e97F6F8773E40cFf", + "0x5b54a9439c0b2B88E35DB66f93882479fEd4FDfb", + "0x5096905F6CFC0F7BBEE09D72Bd97DAE4a95Bc3d6", + "0xbCe0AF8E8e47C6f3E727cD95c4118f14a34A0DFE", + "0xDaB558F089dc6CBD96eae358bB12Cb4aD6043647", + "0x8E79c736De9c10c4b9909077560DcD2F78b0B969", + "0x7C28A20A66d687107dfA810566f237fb3810CBf4" ], "snapshot": 16619300 } diff --git a/src/strategies/izumi-veizi/index.ts b/src/strategies/izumi-veizi/index.ts index a14e2d2aa..e62f6e377 100644 --- a/src/strategies/izumi-veizi/index.ts +++ b/src/strategies/izumi-veizi/index.ts @@ -36,15 +36,22 @@ export async function strategy( const num = Number(balance.toString()); for (let i = 0; i < num; i++) { const path = address + '-' + i; - const stakedPath = address + '-' + 'staked'; nftIdCall.call(path, options.address, 'tokenOfOwnerByIndex', [ address, i ]); - nftIdCall.call(stakedPath, options.address, 'stakedNft', [address]); } }); + + const stakingCheck = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address)=>{ + const stakedPath = address + '-' + 'staked'; + stakingCheck.call(stakedPath, options.address, 'stakedNft', [address]); + }) + const ids: Record = await nftIdCall.execute(); + const stakedIds: Record = await stakingCheck.execute(); + Object.assign(ids, stakedIds); const pointCall = new Multicaller(network, provider, abi, { blockTag }); Object.entries(ids).map(([path, id]) => { From bec715b39ae37bce9f88bdfe4a6497ddb5c0f83a Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Fri, 24 Feb 2023 13:53:50 +0530 Subject: [PATCH 309/815] Fix basic validation strategy limit (#1069) --- src/validations/basic/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/validations/basic/index.ts b/src/validations/basic/index.ts index ec218c4f3..3dee0b85c 100644 --- a/src/validations/basic/index.ts +++ b/src/validations/basic/index.ts @@ -9,7 +9,7 @@ export default class extends Validation { public description = 'Use any strategy to determine if a user can vote.'; async validate(): Promise { - if (this.params.strategies?.length > 5) + if (this.params.strategies?.length > 8) throw new Error(`Max number of strategies exceeded`); const minScore = this.params.minScore; From 81a0724f9758209d00a12c5e658bf0cc6421b676 Mon Sep 17 00:00:00 2001 From: Coderdan Date: Mon, 27 Feb 2023 02:44:57 +0800 Subject: [PATCH 310/815] update subgraph url (#1071) --- src/strategies/aavegotchi-agip-17/index.ts | 2 +- src/strategies/aavegotchi-agip/index.ts | 2 +- src/strategies/aavegotchi-wagmi-guild/index.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/strategies/aavegotchi-agip-17/index.ts b/src/strategies/aavegotchi-agip-17/index.ts index 981cc2b24..cccb7bda5 100644 --- a/src/strategies/aavegotchi-agip-17/index.ts +++ b/src/strategies/aavegotchi-agip-17/index.ts @@ -4,7 +4,7 @@ export const author = 'candoizo'; export const version = '0.1.2'; const AAVEGOTCHI_SUBGRAPH_URL = { - 137: 'https://api.thegraph.com/subgraphs/name/aavegotchi/aavegotchi-core-matic' + 137: 'https://subgraph.satsuma-prod.com/tWYl5n5y04oz/aavegotchi/aavegotchi-core-matic/api' }; const maxResponsePerQuery = 1000; diff --git a/src/strategies/aavegotchi-agip/index.ts b/src/strategies/aavegotchi-agip/index.ts index 3317a3c9e..e3e1b84b3 100644 --- a/src/strategies/aavegotchi-agip/index.ts +++ b/src/strategies/aavegotchi-agip/index.ts @@ -4,7 +4,7 @@ export const author = 'candoizo'; export const version = '0.2.5'; const AAVEGOTCHI_SUBGRAPH_URL = { - 137: 'https://api.thegraph.com/subgraphs/name/aavegotchi/aavegotchi-core-matic' + 137: 'https://subgraph.satsuma-prod.com/tWYl5n5y04oz/aavegotchi/aavegotchi-core-matic/api' }; const prices = { diff --git a/src/strategies/aavegotchi-wagmi-guild/index.ts b/src/strategies/aavegotchi-wagmi-guild/index.ts index 41a732700..289a4d4a7 100644 --- a/src/strategies/aavegotchi-wagmi-guild/index.ts +++ b/src/strategies/aavegotchi-wagmi-guild/index.ts @@ -5,7 +5,7 @@ export const author = 'programmablewealth'; export const version = '0.1.0'; const AAVEGOTCHI_SUBGRAPH_URL = { - 137: 'https://api.thegraph.com/subgraphs/name/aavegotchi/aavegotchi-core-matic' + 137: 'https://subgraph.satsuma-prod.com/tWYl5n5y04oz/aavegotchi/aavegotchi-core-matic/api' }; const itemPriceParams = { From e0d7995be3286767671a447e524e62c5e90d393a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 27 Feb 2023 00:21:35 +0530 Subject: [PATCH 311/815] Automated lint (#1072) Co-authored-by: ChaituVR Co-authored-by: Chaitanya --- src/strategies/izumi-veizi/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/strategies/izumi-veizi/index.ts b/src/strategies/izumi-veizi/index.ts index e62f6e377..9146cd2ff 100644 --- a/src/strategies/izumi-veizi/index.ts +++ b/src/strategies/izumi-veizi/index.ts @@ -44,10 +44,10 @@ export async function strategy( }); const stakingCheck = new Multicaller(network, provider, abi, { blockTag }); - addresses.forEach((address)=>{ + addresses.forEach((address) => { const stakedPath = address + '-' + 'staked'; stakingCheck.call(stakedPath, options.address, 'stakedNft', [address]); - }) + }); const ids: Record = await nftIdCall.execute(); const stakedIds: Record = await stakingCheck.execute(); From c19e9441042cd2de257366459c357205a8d10c66 Mon Sep 17 00:00:00 2001 From: tempest-sol <96633876+tempest-sol@users.noreply.github.com> Date: Sun, 26 Feb 2023 13:25:06 -0600 Subject: [PATCH 312/815] [etherorcs-combo-balanceof] Add EtherOrcs holder strategy (#1070) * Add EtherOrcs holder strategy * Fix naming * Remove unused param * Fix build.. --- .../etherorcs-combo-balanceof/README.md | 1 + .../etherorcs-combo-balanceof/examples.json | 30 ++++++++++++ .../etherorcs-combo-balanceof/index.ts | 49 +++++++++++++++++++ src/strategies/index.ts | 2 + 4 files changed, 82 insertions(+) create mode 100644 src/strategies/etherorcs-combo-balanceof/README.md create mode 100644 src/strategies/etherorcs-combo-balanceof/examples.json create mode 100644 src/strategies/etherorcs-combo-balanceof/index.ts diff --git a/src/strategies/etherorcs-combo-balanceof/README.md b/src/strategies/etherorcs-combo-balanceof/README.md new file mode 100644 index 000000000..1c2a456f7 --- /dev/null +++ b/src/strategies/etherorcs-combo-balanceof/README.md @@ -0,0 +1 @@ +This is a simple strategy that takes no parameters and returns the count of Orcs owned from the graphql query at: https://open-api.etherorcs.com/api/graphql diff --git a/src/strategies/etherorcs-combo-balanceof/examples.json b/src/strategies/etherorcs-combo-balanceof/examples.json new file mode 100644 index 000000000..08720cec1 --- /dev/null +++ b/src/strategies/etherorcs-combo-balanceof/examples.json @@ -0,0 +1,30 @@ +[ + { + "name": "Ether Orcs Balance Of Example", + "strategy": { + "name": "etherorcs-combo-balanceof" + }, + "network": "1", + "addresses": [ + "0x90da518CfC3ceb176eD92eB83f933E8586880B8a", + "0x0d388658633418e8E51A7CF67c7059F863F053d9", + "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", + "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", + "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e", + "0x1d5E65a087eBc3d03a294412E46CE5D6882969f4", + "0x1f254336E5c46639A851b9CfC165697150a6c327", + "0x2ec3F80BeDA63Ede96BA20375032CDD3aAfb3030", + "0x4AcBcA6BE2f8D2540bBF4CA77E45dA0A4a095Fa2", + "0x4F3D348a6D09837Ae7961B1E0cEe2cc118cec777", + "0x6D7f23A509E212Ba7773EC1b2505d1A134f54fbe", + "0x07a1f6fc89223c5ebD4e4ddaE89Ac97629856A0f", + "0x8d5F05270da470e015b67Ab5042BDbE2D2FEFB48", + "0x8d07D225a769b7Af3A923481E1FdF49180e6A265", + "0x8f60501dE5b9b01F9EAf1214dbE1924aA97F7fd0", + "0x9B8e8dD9151260c21CB6D7cc59067cd8DF306D58", + "0x17ea92D6FfbAA1c7F6B117c1E9D0c88ABdc8b84C", + "0x38C0039247A31F3939baE65e953612125cB88268" + ], + "snapshot": 11437846 + } +] diff --git a/src/strategies/etherorcs-combo-balanceof/index.ts b/src/strategies/etherorcs-combo-balanceof/index.ts new file mode 100644 index 000000000..792d56dee --- /dev/null +++ b/src/strategies/etherorcs-combo-balanceof/index.ts @@ -0,0 +1,49 @@ +import fetch from 'cross-fetch'; + +export const author = 'tempest-sol'; +export const version = '0.1.1'; + +type OrcType = { + _id: number; + owner: string; +}; + +export async function strategy( + space, + network, + provider, + addresses, + _options, + _snapshot +): Promise> { + const count: Record = {}; + const res = await fetch('https://open-api.etherorcs.com/api/graphql', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + query: `query( + $orcsFilter: FilterFindManyorcsInput + ) { + orcs(filter: $orcsFilter) { + _id + owner + } + }`, + variables: { + orcsFilter: { + OR: addresses.map((address) => ({ owner: address.toLowerCase() })) + } + } + }) + }); + const response = await res.json(); + if (response && response.data) { + const orcs: OrcType[] = response.data.orcs; + addresses.forEach((address) => { + count[address] = orcs.filter( + (orc) => orc.owner.toLowerCase() === address.toLowerCase() + ).length; + }); + } + return count || {}; +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 2216117f7..53b3dfb1b 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -336,6 +336,7 @@ import * as citydaoSquareRoot from './citydao-square-root'; import * as recusalList from './recusal-list'; import * as rowdyRoos from './rowdy-roos'; import * as ethermon721 from './ethermon-erc721'; +import * as etherorcsComboBalanceOf from './etherorcs-combo-balanceof'; import * as hedgey from './hedgey'; import * as hedgeyMulti from './hedgey-multi'; import * as sybilProtection from './sybil-protection'; @@ -431,6 +432,7 @@ const strategies = { 'forta-shares': fortaShares, 'across-staked-acx': acrossStakedAcx, 'ethermon-erc721': ethermon721, + 'etherorcs-combo-balanceof': etherorcsComboBalanceOf, 'recusal-list': recusalList, 'landdao-token-tiers': landDaoTiers, 'giveth-balancer-balance': givethBalancerBalance, From 9831863ad0f70dfaa92e8aba10263218208ea174 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 27 Feb 2023 16:19:46 +0530 Subject: [PATCH 313/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.64 (#1073) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index b19e1b3c8..da8fca75c 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.63", + "@snapshot-labs/snapshot.js": "^0.4.64", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index f5c1631c8..6cadebbf2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.63": - version "0.4.63" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.63.tgz#f7651f7c70112b779ac3ac4606a6853c46b39c3c" - integrity sha512-wSbfPRpkSj2YFbdTvxgerQsG8krmfM0s8VGwjzOvPY8ha8LIb+xJut9qzsrA3er/HkaTxgf2RTh+qWfRuGKj3g== +"@snapshot-labs/snapshot.js@^0.4.64": + version "0.4.64" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.64.tgz#0c556682a49ac28cff61501f266e37fc5268c466" + integrity sha512-O22Xf2LihiB0w4wJzQ8/iy3oMSXKwlJNfT5iY4Y0j4KJADwOUrlw9DytzX8de+owJf6Y75v2CMGAx20yNYYuhw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 1dfff2124c9cd3e66753048e4aace8a4bec319f8 Mon Sep 17 00:00:00 2001 From: majkic99 <60391069+majkic99@users.noreply.github.com> Date: Mon, 27 Feb 2023 20:08:50 +0100 Subject: [PATCH 314/815] [lqty-proxy-stakers] create lqty proxy staking strategy (#1074) * create lqty proxy staking strategy * Update src/strategies/lqty-proxy-stakers/index.ts --------- Co-authored-by: Chaitanya --- src/strategies/index.ts | 4 +- src/strategies/lqty-proxy-stakers/README.md | 4 ++ .../lqty-proxy-stakers/examples.json | 19 +++++++ src/strategies/lqty-proxy-stakers/index.ts | 50 +++++++++++++++++++ 4 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 src/strategies/lqty-proxy-stakers/README.md create mode 100644 src/strategies/lqty-proxy-stakers/examples.json create mode 100644 src/strategies/lqty-proxy-stakers/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 53b3dfb1b..2f09be249 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -425,6 +425,7 @@ import * as stakedotlinkVesting from './stakedotlink-vesting'; import * as pspInSePSP2Balance from './psp-in-sepsp2-balance'; import * as pdnBalancesAndVests from './pdn-balances-and-vests'; import * as izumiVeiZi from './izumi-veizi'; +import * as lqtyProxyStakers from './lqty-proxy-stakers'; const strategies = { 'izumi-veizi': izumiVeiZi, @@ -855,7 +856,8 @@ const strategies = { 'nexon-army-nft': nexonArmyNFT, 'stakedotlink-vesting': stakedotlinkVesting, 'psp-in-sepsp2-balance': pspInSePSP2Balance, - 'pdn-balances-and-vests': pdnBalancesAndVests + 'pdn-balances-and-vests': pdnBalancesAndVests, + 'lqty-proxy-stakers': lqtyProxyStakers }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/lqty-proxy-stakers/README.md b/src/strategies/lqty-proxy-stakers/README.md new file mode 100644 index 000000000..97f94956b --- /dev/null +++ b/src/strategies/lqty-proxy-stakers/README.md @@ -0,0 +1,4 @@ +# lqty-proxy-stakers + +This is a strategy that returns how much LQTY a user is staking via his DSProxy + diff --git a/src/strategies/lqty-proxy-stakers/examples.json b/src/strategies/lqty-proxy-stakers/examples.json new file mode 100644 index 000000000..68164f524 --- /dev/null +++ b/src/strategies/lqty-proxy-stakers/examples.json @@ -0,0 +1,19 @@ +[ + { + "name": "Lqty proxy stakers", + "strategy": { + "name": "lqty-proxy-stakers", + "params": { + "proxyRegistryAddr" : "0x4678f0a6958e4D2Bc4F1BAF7Bc52E8F3564f3fE4", + "lqtyStakingAddr" : "0x4f9Fbb3f1E99B56e0Fe2892e623Ed36A76Fc605d" + } + }, + "network": "1", + "addresses": [ + "0x352c7DCcA6dD89A75efCBebc77BCF8Efb2128248", + "0x554Fe9292Cd2E2b9469E19e814842C060312FF00", + "0x39e99d18634E63Df7867287E3059F39b6C6f428d" + ], + "snapshot": 16718874 + } +] diff --git a/src/strategies/lqty-proxy-stakers/index.ts b/src/strategies/lqty-proxy-stakers/index.ts new file mode 100644 index 000000000..217f692df --- /dev/null +++ b/src/strategies/lqty-proxy-stakers/index.ts @@ -0,0 +1,50 @@ +import { BigNumberish } from '@ethersproject/bignumber'; +import { Multicaller } from '../../utils'; +import { formatUnits } from '@ethersproject/units'; + +export const author = 'majkic99'; +export const version = '0.1.0'; + +const abiStaking = ['function stakes(address) public view returns (uint256)']; +const abiProxyRegistry = [ + 'function proxies(address) public view returns (address)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const proxyMulti = new Multicaller(network, provider, abiProxyRegistry, { + blockTag + }); + addresses.forEach((address) => + proxyMulti.call(address, options.proxyRegistryAddr, 'proxies', [address]) + ); + const proxyAddresses: Record = + await proxyMulti.execute(); + + const stakersMulti = new Multicaller(network, provider, abiStaking, { + blockTag + }); + + addresses.forEach((address) => { + stakersMulti.call(address, options.lqtyStakingAddr, 'stakes', [ + proxyAddresses[address] + ]); + }); + + const result: Record = await stakersMulti.execute(); + + return Object.fromEntries( + Object.entries(result).map(([address, balance]) => [ + address, + parseFloat(formatUnits(balance, 18)) + ]) + ); +} From 16f010be916364939bfed029ca6df57e3d51d5bc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 28 Feb 2023 01:17:51 +0530 Subject: [PATCH 315/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.65 (#1075) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index da8fca75c..a01199d5b 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.64", + "@snapshot-labs/snapshot.js": "^0.4.65", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 6cadebbf2..d8d2562a7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.64": - version "0.4.64" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.64.tgz#0c556682a49ac28cff61501f266e37fc5268c466" - integrity sha512-O22Xf2LihiB0w4wJzQ8/iy3oMSXKwlJNfT5iY4Y0j4KJADwOUrlw9DytzX8de+owJf6Y75v2CMGAx20yNYYuhw== +"@snapshot-labs/snapshot.js@^0.4.65": + version "0.4.65" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.65.tgz#9d1279214352cc64821cbc0016b9e9b44e079f08" + integrity sha512-okWegbD6ilcjCR4akwHVY9AqUSJXsleLqoJzUlq2YDGcGRxYYTT9ZK/zRbPKPKHpaWCCpCQRgHjXhuVtKn354A== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From b67afb550d9c2ea1a44d0f0f2f2668a68f761fa2 Mon Sep 17 00:00:00 2001 From: Alan Sapede Date: Tue, 28 Feb 2023 07:42:22 +0100 Subject: [PATCH 316/815] [moonbeam-free-balance] Adds moonbeam free balance strategy (#1023) * Adds moonbeam free balance strategy * Replace blake2 wasm library by pure js * Reduces blake2 and clean index * Support for querying in batch * Use blakejs instead of raw implementation * Fixes addresses without value * switch to fully async/await --- package.json | 1 + src/strategies/index.ts | 2 + .../moonbeam-free-balance/README.md | 24 ++++ .../moonbeam-free-balance/examples.json | 16 +++ src/strategies/moonbeam-free-balance/index.ts | 113 ++++++++++++++++++ 5 files changed, 156 insertions(+) create mode 100644 src/strategies/moonbeam-free-balance/README.md create mode 100644 src/strategies/moonbeam-free-balance/examples.json create mode 100644 src/strategies/moonbeam-free-balance/index.ts diff --git a/package.json b/package.json index a01199d5b..ed215c445 100755 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", + "blakejs": "^1.2.1", "copyfiles": "^2.4.1", "cross-fetch": "^3.1.5", "eth-ens-namehash": "^2.0.8", diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 2f09be249..3186de066 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -421,6 +421,7 @@ import * as litDaoGovernance from './lit-dao-governance'; import * as babywealthyclub from './babywealthyclub'; import * as battleflyVGFLYAndStakedGFLY from './battlefly-vgfly-and-staked-gfly'; import * as nexonArmyNFT from './nexon-army-nft'; +import * as moonbeamFreeBalance from './moonbeam-free-balance'; import * as stakedotlinkVesting from './stakedotlink-vesting'; import * as pspInSePSP2Balance from './psp-in-sepsp2-balance'; import * as pdnBalancesAndVests from './pdn-balances-and-vests'; @@ -854,6 +855,7 @@ const strategies = { babywealthyclub, 'battlefly-vgfly-and-staked-gfly': battleflyVGFLYAndStakedGFLY, 'nexon-army-nft': nexonArmyNFT, + 'moonbeam-free-balance': moonbeamFreeBalance, 'stakedotlink-vesting': stakedotlinkVesting, 'psp-in-sepsp2-balance': pspInSePSP2Balance, 'pdn-balances-and-vests': pdnBalancesAndVests, diff --git a/src/strategies/moonbeam-free-balance/README.md b/src/strategies/moonbeam-free-balance/README.md new file mode 100644 index 000000000..bca71d053 --- /dev/null +++ b/src/strategies/moonbeam-free-balance/README.md @@ -0,0 +1,24 @@ +# Moonbeam Free Balance strategy + +This strategy return the free balances on Moonbeam network. The free balance includes the "locked" tokens, which can be used for voting, but not the "reserved" tokens. + +## Examples + +```JSON +[ + { + "name": "moonbeam-free-balance", + "strategy": { + "name": "moonbeam-free-balance", + "params": {} + }, + "network": "1284", + "addresses": [ + "0xf02ddb48eda520c915c0dabadc70ba12d1b49ad2", + "0x01bb6ce8b88f09a7d0bfb40eff7f2ad5e0df2e98", + "0xe751b9ea560a200161d1b70249495e3d22ec5b00" + ], + "snapshot": 14129872 + } +] +``` diff --git a/src/strategies/moonbeam-free-balance/examples.json b/src/strategies/moonbeam-free-balance/examples.json new file mode 100644 index 000000000..730ac5d70 --- /dev/null +++ b/src/strategies/moonbeam-free-balance/examples.json @@ -0,0 +1,16 @@ +[ + { + "name": "moonbeam-free-balance", + "strategy": { + "name": "moonbeam-free-balance", + "params": {} + }, + "network": "1284", + "addresses": [ + "0xf02ddb48eda520c915c0dabadc70ba12d1b49ad2", + "0x01bb6ce8b88f09a7d0bfb40eff7f2ad5e0df2e98", + "0xe751b9ea560a200161d1b70249495e3d22ec5b00" + ], + "snapshot": 2800000 + } +] diff --git a/src/strategies/moonbeam-free-balance/index.ts b/src/strategies/moonbeam-free-balance/index.ts new file mode 100644 index 000000000..06cfa1448 --- /dev/null +++ b/src/strategies/moonbeam-free-balance/index.ts @@ -0,0 +1,113 @@ +import { getAddress } from '@ethersproject/address'; +import { fetchJson } from '@ethersproject/web'; +import { JsonRpcProvider } from '@ethersproject/providers'; +import { blake2bHex } from 'blakejs'; + +export const author = 'crystalin'; +export const version = '0.1.0'; + +export function readLittleEndianBigInt(hex: string) { + return BigInt(`0x${hex.match(/../g)?.reverse().join('')}`); +} + +export async function strategy( + space: string, + network: string, + provider: JsonRpcProvider, + addresses: string[] +) { + // Pre-encoded key prefix for "system.account" storage + const accountPrefix = `0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9`; + + const batchSize = 100; + const batches = addresses.reduce((resultArray, item, index) => { + const chunkIndex = Math.floor(index / batchSize); + if (!resultArray[chunkIndex]) { + resultArray[chunkIndex] = []; // start a new chunk + } + resultArray[chunkIndex].push(item); + return resultArray; + }, [] as string[][]); + + // Stores all the retrieved balances + let balances: { [k: string]: number } = {}; + + for (let batchIndex = 0; batchIndex < batches.length; batchIndex++) { + const addressBatch = batches[batchIndex]; + + // Convert address to storage key. + const keys = await Promise.all( + addressBatch.map( + async (address) => + `${accountPrefix}${await blake2bHex( + Buffer.from(address.substring(2), 'hex'), + undefined, + 16 + )}${address.substring(2)}` + ) + ); + + // Build batch request for all the storage keys of the batch. + const reqs = keys.map((key, index) => ({ + method: 'state_getStorage', + params: [key], + id: batchIndex * batchSize + index + 1, + jsonrpc: '2.0' + })); + + // Query batch of storage items + const payloads: { id: number; result: string }[] = await fetchJson( + provider.connection, + JSON.stringify(reqs), + (payload: { + error?: { code?: number; data?: any; message?: string }; + result?: any; + }) => { + if (payload.error) { + const error: any = new Error(payload.error.message); + error.code = payload.error.code; + error.data = payload.error.data; + throw error; + } + return payload; + } + ); + + for (const payload of payloads) { + if (payload.result === null) { + break; + } + // Computes "system.account" key for given address + // Retrieves storage data for the "system.account" key + // account data structure (little endian): + // { + // nonce: 8 bits + // consumers: 8 bits + // providers: 8 bits + // sufficients: 8 bits + // data: { + // free: 32 bits + // reserved: 32 bits + // miscFrozen: 32 bits + // feeFrozen: 32 bits + // } + // } + // Converts the bigint into number. + // Result won't be precise, but should be lower than real value. + + const free = + payload.result.length >= 2 + 8 + 8 + 8 + 8 + 32 + ? Number( + readLittleEndianBigInt( + payload.result.substring( + 2 + 8 + 8 + 8 + 8, + 2 + 8 + 8 + 8 + 8 + 32 + ) + ) + ) + : 0; + balances[getAddress(addressBatch[(payload.id - 1) % batchSize])] = free; + } + } + return balances; +} From 0fff07aa993b987806d7a64b85e561389e332a6f Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Tue, 28 Feb 2023 12:51:14 +0530 Subject: [PATCH 317/815] Update yarn lock [moonbeam-free-balance] (#1076) * Adds moonbeam free balance strategy * Replace blake2 wasm library by pure js * Reduces blake2 and clean index * Support for querying in batch * Use blakejs instead of raw implementation * Fixes addresses without value * switch to fully async/await * Update yarn lock --------- Co-authored-by: Crystalin Co-authored-by: Alan Sapede --- yarn.lock | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/yarn.lock b/yarn.lock index d8d2562a7..a6d74a919 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1676,6 +1676,11 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== +blakejs@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.2.1.tgz#5057e4206eadb4a97f7c0b6e197a505042fc3814" + integrity sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ== + bn.js@^4.11.9: version "4.12.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" From 95fd8458971d3a5e44dfbd0c6285c96558825d7c Mon Sep 17 00:00:00 2001 From: Alan Sapede Date: Wed, 1 Mar 2023 08:29:49 +0100 Subject: [PATCH 318/815] [moonbeam-free-balance] Format moonbeam strategy to include decimals (#1077) * Format moonbeam strategy to include decimals * Adds example --- .../moonbeam-free-balance/examples.json | 6 +++-- src/strategies/moonbeam-free-balance/index.ts | 22 ++++++++++++------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/strategies/moonbeam-free-balance/examples.json b/src/strategies/moonbeam-free-balance/examples.json index 730ac5d70..22afee92e 100644 --- a/src/strategies/moonbeam-free-balance/examples.json +++ b/src/strategies/moonbeam-free-balance/examples.json @@ -3,7 +3,9 @@ "name": "moonbeam-free-balance", "strategy": { "name": "moonbeam-free-balance", - "params": {} + "params": { + "decimals": 18 + } }, "network": "1284", "addresses": [ @@ -11,6 +13,6 @@ "0x01bb6ce8b88f09a7d0bfb40eff7f2ad5e0df2e98", "0xe751b9ea560a200161d1b70249495e3d22ec5b00" ], - "snapshot": 2800000 + "snapshot": 3044139 } ] diff --git a/src/strategies/moonbeam-free-balance/index.ts b/src/strategies/moonbeam-free-balance/index.ts index 06cfa1448..49f6eedda 100644 --- a/src/strategies/moonbeam-free-balance/index.ts +++ b/src/strategies/moonbeam-free-balance/index.ts @@ -2,6 +2,7 @@ import { getAddress } from '@ethersproject/address'; import { fetchJson } from '@ethersproject/web'; import { JsonRpcProvider } from '@ethersproject/providers'; import { blake2bHex } from 'blakejs'; +import { formatFixed } from '@ethersproject/bignumber'; export const author = 'crystalin'; export const version = '0.1.0'; @@ -14,10 +15,12 @@ export async function strategy( space: string, network: string, provider: JsonRpcProvider, - addresses: string[] + addresses: string[], + options: { decimals } ) { // Pre-encoded key prefix for "system.account" storage const accountPrefix = `0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9`; + const { decimals } = options; const batchSize = 100; const batches = addresses.reduce((resultArray, item, index) => { @@ -72,7 +75,7 @@ export async function strategy( return payload; } ); - + for (const payload of payloads) { if (payload.result === null) { break; @@ -97,12 +100,15 @@ export async function strategy( const free = payload.result.length >= 2 + 8 + 8 + 8 + 8 + 32 - ? Number( - readLittleEndianBigInt( - payload.result.substring( - 2 + 8 + 8 + 8 + 8, - 2 + 8 + 8 + 8 + 8 + 32 - ) + ? parseFloat( + formatFixed( + readLittleEndianBigInt( + payload.result.substring( + 2 + 8 + 8 + 8 + 8, + 2 + 8 + 8 + 8 + 8 + 32 + ) + ), + decimals ) ) : 0; From 2dfa7c70dab1c46b572bf712a2b949b2aa9a1869 Mon Sep 17 00:00:00 2001 From: 0xButterfield <100517047+0xButterfield@users.noreply.github.com> Date: Thu, 2 Mar 2023 06:19:23 +0100 Subject: [PATCH 319/815] [delegation-with-overrides] feat: Add delegation-with-overrides (#1079) * feat: Add delegation-with-overrides * Apply suggestions from code review --------- Co-authored-by: Chaitanya --- .../delegation-with-overrides/README.md | 50 +++++++++++++ .../delegation-with-overrides/examples.json | 35 ++++++++++ .../delegation-with-overrides/index.ts | 70 +++++++++++++++++++ src/strategies/index.ts | 2 + 4 files changed, 157 insertions(+) create mode 100644 src/strategies/delegation-with-overrides/README.md create mode 100644 src/strategies/delegation-with-overrides/examples.json create mode 100644 src/strategies/delegation-with-overrides/index.ts diff --git a/src/strategies/delegation-with-overrides/README.md b/src/strategies/delegation-with-overrides/README.md new file mode 100644 index 000000000..ee3c8fc0f --- /dev/null +++ b/src/strategies/delegation-with-overrides/README.md @@ -0,0 +1,50 @@ +# delegation-with-overrides + +This strategy is based on the [delegation strategy](https://github.com/snapshot-labs/snapshot-strategies/tree/master/src/strategies/delegation), but with an optional `overrides` parameter: an address to address mapping, where the delegated voting power of each key will be forwarded to the corresponding value. + +For example: + +```json lines +{ + "overrides": { + // The delegated votes of: 0xAD9992f3631028CEF19e6D6C31e822C5bc2442CC + // will be forwarded to: 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 + "0xAD9992f3631028CEF19e6D6C31e822C5bc2442CC": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" + } +} +``` + +| 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) | +| overrides (optional) | Address mapping used to override delegated votes and forward to another address | + +Here is an example of parameters: + +```json +{ + "symbol": "veBAL (delegated)", + "strategies": [ + { + "symbol": "veBAL (delegated)", + "strategies": [ + { + "name": "erc20-balance-of", + "params": { + "symbol": "veBAL", + "address": "0xC128a9954e6c874eA3d62ce62B468bA073093F25", + "decimals": 18 + } + } + ], + "delegationSpace": "balancer.eth" + } + ], + "delegationSpace": "balancer.eth", + "overrides": { + "0xAD9992f3631028CEF19e6D6C31e822C5bc2442CC": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" + } +} + +``` diff --git a/src/strategies/delegation-with-overrides/examples.json b/src/strategies/delegation-with-overrides/examples.json new file mode 100644 index 000000000..53023be91 --- /dev/null +++ b/src/strategies/delegation-with-overrides/examples.json @@ -0,0 +1,35 @@ +[ + { + "name": "Example query", + "space": "balancer.eth", + "strategy": { + "name": "delegation-with-overrides", + "params": { + "symbol": "veBAL (delegated)", + "strategies": [ + { + "name": "erc20-balance-of", + "params": { + "symbol": "veBAL", + "address": "0xC128a9954e6c874eA3d62ce62B468bA073093F25", + "decimals": 18 + }, + "delegationSpace": "balancer.eth" + } + ], + "overrides": { + "0xAD9992f3631028CEF19e6D6C31e822C5bc2442CC": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" + }, + "delegationSpace": "balancer.eth" + } + }, + "network": "1", + "addresses": [ + "0xAD9992f3631028CEF19e6D6C31e822C5bc2442CC", + "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", + "0x512fce9B07Ce64590849115EE6B32fd40eC0f5F3", + "0xE58585B22cC2aC4270a2b92c2D2d8C5dB5A3330E" + ], + "snapshot": 16693494 + } +] diff --git a/src/strategies/delegation-with-overrides/index.ts b/src/strategies/delegation-with-overrides/index.ts new file mode 100644 index 000000000..36e915e02 --- /dev/null +++ b/src/strategies/delegation-with-overrides/index.ts @@ -0,0 +1,70 @@ +import { getDelegations } from '../../utils/delegation'; +import { getScoresDirect } from '../../utils'; +import { getAddress } from '@ethersproject/address'; + +export const author = '0xbutterfield'; +export const version = '0.1.0'; +export const dependOnOtherAddress = true; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const delegationSpace = options.delegationSpace || space; + const delegations = await getDelegations( + delegationSpace, + network, + addresses, + snapshot + ); + if (Object.keys(delegations).length === 0) return {}; + + const scores = ( + await getScoresDirect( + space, + options.strategies, + network, + provider, + Object.values(delegations).reduce((a: string[], b: string[]) => + a.concat(b) + ), + snapshot + ) + ).filter((score) => Object.keys(score).length !== 0); + + const overrides: { [delegatee: string]: string } = Object.fromEntries( + Object.entries(options.overrides ?? {}).map(([key, value]) => [ + getAddress(key), + getAddress(value as string) + ]) + ); + + return addresses + .map((address) => { + const addressScore = delegations[address] + ? delegations[address].reduce( + (a, b) => a + scores.reduce((x, y) => (y[b] ? x + y[b] : x), 0), + 0 + ) + : 0; + return [address, addressScore]; + }) + .reduce((acc, [address, addressScore]) => { + const delegatee = overrides[address]; + if (delegatee) { + return { + ...acc, + // Redirect the votes for address to delegatee + [address]: 0, + [delegatee]: (acc[delegatee] ?? 0) + addressScore + }; + } + // It is possible that address has already been set with an override, + // so add the score to that value (or zero) + return { ...acc, [address]: (acc[address] ?? 0) + addressScore }; + }, {}); +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 3186de066..902251d59 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -92,6 +92,7 @@ import * as stakedKeep from './staked-keep'; import * as stakedDaomaker from './staked-daomaker'; import * as typhoon from './typhoon'; import * as delegation from './delegation'; +import * as delegationWithOverrides from './delegation-with-overrides'; import * as withDelegation from './with-delegation'; import * as ticket from './ticket'; import * as work from './work'; @@ -545,6 +546,7 @@ const strategies = { 'balancer-unipool': balancerUnipool, typhoon, delegation, + 'delegation-with-overrides': delegationWithOverrides, 'with-delegation': withDelegation, ticket, work, From 31b3c29d3852c6fc94f68c6fa2984c4b5b6a1ce8 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Thu, 2 Mar 2023 23:57:39 +0530 Subject: [PATCH 320/815] [api-v2] api-v2 strategy without override option (#1080) --- src/strategies/api-v2/README.md | 50 ++++++++++++++++++++++ src/strategies/api-v2/examples.json | 23 ++++++++++ src/strategies/api-v2/index.ts | 66 +++++++++++++++++++++++++++++ src/strategies/index.ts | 2 + 4 files changed, 141 insertions(+) create mode 100644 src/strategies/api-v2/README.md create mode 100644 src/strategies/api-v2/examples.json create mode 100644 src/strategies/api-v2/index.ts diff --git a/src/strategies/api-v2/README.md b/src/strategies/api-v2/README.md new file mode 100644 index 000000000..baf43e591 --- /dev/null +++ b/src/strategies/api-v2/README.md @@ -0,0 +1,50 @@ +# API V2 strategy + +Voting strategy using a REST API endpoint. Number of votes depends on the return of the API endpoint. +(Unlike the `api` strategy, this strategy does not depend on voting power of other addresses) + +> Note: Better to use this strategy only if you are not using any override strategies (example: delegation strategy). + +## Parameters + +| Name | Type | Description | Default | +| --- | --- | --- | --- | +| `url` | `string` | URL of the API endpoint | `undefined` | +| `type` | `string` | Type of the API endpoint ( `api-get` or `api-post` or `ipfs` or `json` ) | `api-get` | +| `additionalParams` | `string` | Additional parameters for the API endpoint (optional) | `` | + +If you are passing a IPFS url use following format: + +```JSON +{ + "url": "ipfs://...", + "type": "ipfs" +} +``` + +If you are passing a JSON url use following format: + +```JSON +{ + "url": "https://...", + "type": "json" +} +``` + +If you are passing a API url use following format: (all voter addresses will be passed in the query string) + +```JSON +{ + "url": "https://...", + "type": "api-get" +} +``` + +If you are passing a API url with POST method use following format: + +```JSON +{ + "url": "https://...", + "type": "api-post" +} +``` diff --git a/src/strategies/api-v2/examples.json b/src/strategies/api-v2/examples.json new file mode 100644 index 000000000..e71fd883e --- /dev/null +++ b/src/strategies/api-v2/examples.json @@ -0,0 +1,23 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "api-v2", + "params": { + "url": "ipfs://QmbmhTivxYuLE5uhNEALoBmvP7Yg9acA2Lkw9V9PqaEmw6", + "type": "ipfs" + } + }, + "network": "1", + "addresses": [ + "0xeD2bcC3104Da5F5f8fA988D6e9fAFd74Ae62f319", + "0x3c4B8C52Ed4c29eE402D9c91FfAe1Db2BAdd228D", + "0xd649bACfF66f1C85618c5376ee4F38e43eE53b63", + "0x726022a9fe1322fA9590FB244b8164936bB00489", + "0xc6665eb39d2106fb1DBE54bf19190F82FD535c19", + "0x6ef2376fa6e12dabb3a3ed0fb44e4ff29847af68", + "0x89446aF03652c5257dB5C8E4E85495EB754196c5" + ], + "snapshot": 11437846 + } +] diff --git a/src/strategies/api-v2/index.ts b/src/strategies/api-v2/index.ts new file mode 100644 index 000000000..7f89f0b91 --- /dev/null +++ b/src/strategies/api-v2/index.ts @@ -0,0 +1,66 @@ +import { getAddress } from '@ethersproject/address'; +import fetch from 'cross-fetch'; +import { formatUnits } from '@ethersproject/units'; + +export const author = 'snapshot-labs'; +export const version = '0.1.0'; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + let url: string = options.url; + const additionalParameters: string = options.additionalParameters || ''; + const type: string = options.type || 'api-get'; + const method: string = type === 'api-post' ? 'POST' : 'GET'; + let body: string | null = null; + + if (!url) throw new Error('Invalid url'); + + if (type === 'ipfs') { + url = url.replace('ipfs://', 'https://gateway.pinata.cloud/ipfs/'); + } else if (type === 'api-get') { + url += '?network=' + network; + url += '&snapshot=' + snapshot; + url += '&addresses=' + addresses.join(','); + if (additionalParameters) url += '&' + additionalParameters; + } else if (type === 'api-post') { + const requestBody = { + options, + network, + snapshot, + addresses + }; + body = JSON.stringify(requestBody); + } + + const response = await fetch(url, { + method, + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + }, + body + }); + + const data = await response.json(); + + if (!data.score) throw new Error('Invalid response from API'); + + return Object.fromEntries( + addresses.map((address) => [ + getAddress(address), + parseFloat( + formatUnits( + data.score.find((s) => s.address === address)?.score?.toString() || + '0', + options.hasOwnProperty('decimals') ? options.decimals : 0 + ) + ) + ]) + ); +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 902251d59..4064b9186 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -137,6 +137,7 @@ import * as avnBalanceOfStaked from './avn-balance-of-staked'; import * as badgeth from './badgeth'; import * as api from './api'; import * as apiPost from './api-post'; +import * as apiV2 from './api-v2'; import * as xseen from './xseen'; import * as molochAll from './moloch-all'; import * as molochLoot from './moloch-loot'; @@ -588,6 +589,7 @@ const strategies = { 'avn-balance-of-staked': avnBalanceOfStaked, api, 'api-post': apiPost, + 'api-v2': apiV2, xseen, 'moloch-all': molochAll, 'moloch-loot': molochLoot, From 5cae78724daea320e28136f17cbfe5f30e3bf585 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Fri, 3 Mar 2023 00:40:09 +0530 Subject: [PATCH 321/815] Update readme (#1081) * Update readme * Update index.ts --- README.md | 5 +++-- src/strategies/etherorcs-combo-balanceof/index.ts | 4 +--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 4f688f905..6d2531d5a 100755 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Change values inside test/scores.ts and run ts-node test/scores.ts ``` -### Checklist for adding a new strategy +### Checklist for adding a new voting strategy or validation strategy Here is a simple checklist to look at when reviewing a PR for a new strategy: @@ -44,12 +44,13 @@ Here is a simple checklist to look at when reviewing a PR for a new strategy: - The strategy must be unique. - If the strategy does only a single call with an address as input, it's preferable to use the strategy "contract-call" instead of creating a new one. +- For validations better to use `basic` validation and use existing strategies #### Code - There should be a maximum of 5 requests, a request can use "fetch" a "subgraphRequest" or "multicall". - The strategy should not send a request for each voters, this doesn't scale. -- The strategy PR should not add any dependency in Snapshot.js. +- The strategy PR should not add any new dependency. - The score returned by the strategy should use the same casing for address than on the input, or should return checksum addresses. - Make sure voting power of one address does not depend on other addresses. diff --git a/src/strategies/etherorcs-combo-balanceof/index.ts b/src/strategies/etherorcs-combo-balanceof/index.ts index 792d56dee..b750b10fd 100644 --- a/src/strategies/etherorcs-combo-balanceof/index.ts +++ b/src/strategies/etherorcs-combo-balanceof/index.ts @@ -12,9 +12,7 @@ export async function strategy( space, network, provider, - addresses, - _options, - _snapshot + addresses ): Promise> { const count: Record = {}; const res = await fetch('https://open-api.etherorcs.com/api/graphql', { From 8f67ffe50f1a52cfe5ee36edd0aae2743aeb2c5c Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Fri, 3 Mar 2023 13:18:24 +0530 Subject: [PATCH 322/815] Fix duplications (#1083) --- .../delegation-with-overrides/index.ts | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/strategies/delegation-with-overrides/index.ts b/src/strategies/delegation-with-overrides/index.ts index 36e915e02..ed4666303 100644 --- a/src/strategies/delegation-with-overrides/index.ts +++ b/src/strategies/delegation-with-overrides/index.ts @@ -15,10 +15,22 @@ export async function strategy( snapshot ) { const delegationSpace = options.delegationSpace || space; + const overrides: { [delegatee: string]: string } = Object.fromEntries( + Object.entries(options.overrides ?? {}).map(([key, value]) => [ + getAddress(key), + getAddress(value as string) + ]) + ); + + // Remove duplicates + const allAddresses = addresses + .concat(Object.keys(overrides)) + .filter((v, i, a) => a.indexOf(v) === i); + const delegations = await getDelegations( delegationSpace, network, - addresses, + allAddresses, snapshot ); if (Object.keys(delegations).length === 0) return {}; @@ -36,14 +48,7 @@ export async function strategy( ) ).filter((score) => Object.keys(score).length !== 0); - const overrides: { [delegatee: string]: string } = Object.fromEntries( - Object.entries(options.overrides ?? {}).map(([key, value]) => [ - getAddress(key), - getAddress(value as string) - ]) - ); - - return addresses + return allAddresses .map((address) => { const addressScore = delegations[address] ? delegations[address].reduce( From 59647afdafd8976462547d9604f454704b812d32 Mon Sep 17 00:00:00 2001 From: Coderdan Date: Mon, 6 Mar 2023 00:15:32 +0800 Subject: [PATCH 323/815] Add new wearable IDs [aavegotchi-agip] (#1086) * update subgraph url * update strategy with new wearable ids --- src/strategies/aavegotchi-agip/examples.json | 8 +++-- src/strategies/aavegotchi-agip/index.ts | 32 ++++++++++++++++++-- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/strategies/aavegotchi-agip/examples.json b/src/strategies/aavegotchi-agip/examples.json index 5b8895b92..72a671a70 100644 --- a/src/strategies/aavegotchi-agip/examples.json +++ b/src/strategies/aavegotchi-agip/examples.json @@ -9,7 +9,11 @@ } }, "network": "137", - "addresses": ["0x027Ffd3c119567e85998f4E6B9c3d83D5702660c"], - "snapshot": 12089223 + "addresses": [ + "0x51195e21BDaE8722B29919db56d95Ef51FaecA6C", + "0xDd564df884Fd4e217c9ee6F65B4BA6e5641eAC63", + "0xBfe09443556773958bae1699b786d8E9680B5571" + ], + "snapshot": 39986904 } ] diff --git a/src/strategies/aavegotchi-agip/index.ts b/src/strategies/aavegotchi-agip/index.ts index e3e1b84b3..d3c278216 100644 --- a/src/strategies/aavegotchi-agip/index.ts +++ b/src/strategies/aavegotchi-agip/index.ts @@ -3,11 +3,15 @@ import { subgraphRequest } from '../../utils'; export const author = 'candoizo'; export const version = '0.2.5'; +interface Prices { + [id: string]: 0 | 5 | 10 | 20 | 50 | 100 | 300 | 2000 | 3000 | 10000; +} + const AAVEGOTCHI_SUBGRAPH_URL = { 137: 'https://subgraph.satsuma-prod.com/tWYl5n5y04oz/aavegotchi/aavegotchi-core-matic/api' }; -const prices = { +const prices: Prices = { '0': 0, '1': 5, '2': 5, @@ -323,7 +327,29 @@ const prices = { '312': 2000, '313': 10000, '314': 10000, - '315': 10000 + '315': 10000, + + //new + '350': 5, + '351': 5, + '352': 5, + '353': 5, + '354': 10, + '355': 100, + '356': 10, + '357': 100, + '358': 300, + '359': 300, + '360': 300, + '361': 300, + '362': 2000, + '363': 2000, + '364': 2000, + '365': 2000, + '366': 10000, + '367': 10000, + '368': 10000, + '369': 10000 }; const tokenAbi = [ @@ -443,7 +469,7 @@ export async function strategy( ownerItemValue = ownerItemInfo.reduce((total, { balance, itemId }) => { const amountOwned = Number(balance.toString()); const id = Number(itemId.toString()); - const pricetag = parseFloat(prices[id]); + const pricetag = prices[id]; let cost = pricetag * amountOwned; if (isNaN(cost)) cost = 0; return total + cost; From cfeda63990b5ff941d1aa71b280372d7ae3dde69 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 5 Mar 2023 23:07:40 +0530 Subject: [PATCH 324/815] Automated lint (#1085) Co-authored-by: ChaituVR Co-authored-by: Chaitanya --- src/strategies/lqty-proxy-stakers/examples.json | 4 ++-- src/strategies/moonbeam-free-balance/index.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/strategies/lqty-proxy-stakers/examples.json b/src/strategies/lqty-proxy-stakers/examples.json index 68164f524..971877d80 100644 --- a/src/strategies/lqty-proxy-stakers/examples.json +++ b/src/strategies/lqty-proxy-stakers/examples.json @@ -4,8 +4,8 @@ "strategy": { "name": "lqty-proxy-stakers", "params": { - "proxyRegistryAddr" : "0x4678f0a6958e4D2Bc4F1BAF7Bc52E8F3564f3fE4", - "lqtyStakingAddr" : "0x4f9Fbb3f1E99B56e0Fe2892e623Ed36A76Fc605d" + "proxyRegistryAddr": "0x4678f0a6958e4D2Bc4F1BAF7Bc52E8F3564f3fE4", + "lqtyStakingAddr": "0x4f9Fbb3f1E99B56e0Fe2892e623Ed36A76Fc605d" } }, "network": "1", diff --git a/src/strategies/moonbeam-free-balance/index.ts b/src/strategies/moonbeam-free-balance/index.ts index 49f6eedda..9225e01b5 100644 --- a/src/strategies/moonbeam-free-balance/index.ts +++ b/src/strategies/moonbeam-free-balance/index.ts @@ -33,7 +33,7 @@ export async function strategy( }, [] as string[][]); // Stores all the retrieved balances - let balances: { [k: string]: number } = {}; + const balances: { [k: string]: number } = {}; for (let batchIndex = 0; batchIndex < batches.length; batchIndex++) { const addressBatch = batches[batchIndex]; From b10c4c0fe82d440a09a9d43376e74278d8abb0d3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 5 Mar 2023 23:08:11 +0530 Subject: [PATCH 325/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.66 (#1084) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Chaitanya --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index ed215c445..b87217da3 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.65", + "@snapshot-labs/snapshot.js": "^0.4.66", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index a6d74a919..20d6b408d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.65": - version "0.4.65" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.65.tgz#9d1279214352cc64821cbc0016b9e9b44e079f08" - integrity sha512-okWegbD6ilcjCR4akwHVY9AqUSJXsleLqoJzUlq2YDGcGRxYYTT9ZK/zRbPKPKHpaWCCpCQRgHjXhuVtKn354A== +"@snapshot-labs/snapshot.js@^0.4.66": + version "0.4.66" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.66.tgz#5cddcd4dc6856c1735a2313789783ba661831931" + integrity sha512-UD3E2tJ1JBD7Ogw3QpidBp2yNnhNMWY5+ZH2AA5DWomd/sixEri0F+37O362voVxLP4JPM409kZE2heg8L3eQw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From f06a28cce116e867fe6482db961e4eee89532c2e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 5 Mar 2023 23:55:45 +0530 Subject: [PATCH 326/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.67 (#1087) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index b87217da3..98f404a21 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.66", + "@snapshot-labs/snapshot.js": "^0.4.67", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 20d6b408d..670bd1fcb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.66": - version "0.4.66" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.66.tgz#5cddcd4dc6856c1735a2313789783ba661831931" - integrity sha512-UD3E2tJ1JBD7Ogw3QpidBp2yNnhNMWY5+ZH2AA5DWomd/sixEri0F+37O362voVxLP4JPM409kZE2heg8L3eQw== +"@snapshot-labs/snapshot.js@^0.4.67": + version "0.4.67" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.67.tgz#86bf5066c51235e3455b6f38b7954ee086ef6296" + integrity sha512-9JEuMe3wVcUVaDq+03owIk0hFC1JijnFKPy1JTfW+7ow314YYQR76zTvJ4jkpivXuaBKWAh/EwyVPFaPdw+HhQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From c023dc65dbcfafb07d8386077322d35a9cfeefc3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 7 Mar 2023 17:44:27 +0530 Subject: [PATCH 327/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.68 (#1089) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 98f404a21..6aee78c33 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.67", + "@snapshot-labs/snapshot.js": "^0.4.68", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 670bd1fcb..db1d230a1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.67": - version "0.4.67" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.67.tgz#86bf5066c51235e3455b6f38b7954ee086ef6296" - integrity sha512-9JEuMe3wVcUVaDq+03owIk0hFC1JijnFKPy1JTfW+7ow314YYQR76zTvJ4jkpivXuaBKWAh/EwyVPFaPdw+HhQ== +"@snapshot-labs/snapshot.js@^0.4.68": + version "0.4.68" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.68.tgz#01b1da4a47d2a8f27a9d662e8768a457e46c8024" + integrity sha512-RVPo4iNnnt51nY7A0mVLSl3HGzsEmAQlH/ZtbI3TQtpCjI0pNG/VVvyvVG3/ue9/xgo5U6OzirD8DKcPT51fYQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 668fdcf0557613e4d902287292d86deb65612936 Mon Sep 17 00:00:00 2001 From: Mike Shultz Date: Tue, 7 Mar 2023 13:21:59 -0700 Subject: [PATCH 328/815] chore: update OGN strategy for new series staking (#1088) Co-authored-by: Chaitanya --- src/strategies/ogn/README.md | 2 +- src/strategies/ogn/examples.json | 4 ++-- src/strategies/ogn/index.ts | 11 +++++------ 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/strategies/ogn/README.md b/src/strategies/ogn/README.md index 31bdcafbc..caf9816e8 100644 --- a/src/strategies/ogn/README.md +++ b/src/strategies/ogn/README.md @@ -1,6 +1,6 @@ # ogn -A strategy for Origin Protocol governance. +A strategy for Origin Story governance. The score is based on the amount of OGN held in the wallet and the OGN staking contract. An average balance is calculated at the specified block number and 30 days prior to that. diff --git a/src/strategies/ogn/examples.json b/src/strategies/ogn/examples.json index aefdeb472..46975e0ef 100644 --- a/src/strategies/ogn/examples.json +++ b/src/strategies/ogn/examples.json @@ -5,7 +5,7 @@ "name": "ogn", "params": { "ognAddress": "0x8207c1ffc5b6804f6024322ccf34f29c3541ae26", - "stakingAddress": "0x501804B374EF06fa9C427476147ac09F1551B9A0", + "seriesAddress": "0xCcE8E784c777fb9435F89f4E45f8b7FC49f7669f", "symbol": "OGN", "decimals": 18 } @@ -31,6 +31,6 @@ "0x17ea92D6FfbAA1c7F6B117c1E9D0c88ABdc8b84C", "0x38C0039247A31F3939baE65e953612125cB88268" ], - "snapshot": 12842590 + "snapshot": 16767676 } ] diff --git a/src/strategies/ogn/index.ts b/src/strategies/ogn/index.ts index 34558a782..aa72a2cc3 100644 --- a/src/strategies/ogn/index.ts +++ b/src/strategies/ogn/index.ts @@ -3,12 +3,10 @@ import { getBlockNumber } from '../../utils'; import { multicall } from '../../utils'; export const author = 'franckc'; -export const version = '0.1.0'; +export const version = '0.2.0'; const abi = [ - 'function balanceOf(address account) external view returns (uint256)', - // Staking - 'function totalStaked(address account) external view returns (uint256)' + 'function balanceOf(address account) external view returns (uint256)' ]; // Number of blocks in 30 days, assuming 15 sec per block. @@ -35,8 +33,8 @@ export async function strategy( [address] ]); const stakingCalls = addresses.map((address: any) => [ - options.stakingAddress, - 'totalStaked', + options.seriesAddress, + 'balanceOf', [address] ]); @@ -47,6 +45,7 @@ export async function strategy( multicall(network, provider, abi, stakingCalls, { blockTag: blockTag1 }), multicall(network, provider, abi, stakingCalls, { blockTag: blockTag2 }) ]; + const responses = await Promise.all(multicalls); // Compute an average score. From d6a7be75ad0a165a2597833556af6b3e0c8ebf5c Mon Sep 17 00:00:00 2001 From: Carlos Febres Date: Wed, 8 Mar 2023 15:03:46 -0400 Subject: [PATCH 329/815] [eco-voting-power] Eco voting power - Use integers for Voting Power (#1078) * [eco-voting-power] use integers to avoid precision issues * [eco-voting-power] update examples.json --- src/strategies/eco-voting-power/examples.json | 6 +++--- src/strategies/eco-voting-power/index.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/strategies/eco-voting-power/examples.json b/src/strategies/eco-voting-power/examples.json index a8003c8ea..8742a5968 100644 --- a/src/strategies/eco-voting-power/examples.json +++ b/src/strategies/eco-voting-power/examples.json @@ -4,7 +4,7 @@ "strategy": { "name": "eco-voting-power", "params": { - "delegatee": "0x64923706f6ca6F3C364292834C5370e4f03e2368" + "delegatee": "0xbFB97a6e13E42518522379C94e0Ddd99F7b70b8b" } }, "network": "5", @@ -16,7 +16,7 @@ "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e", "0x1d5E65a087eBc3d03a294412E46CE5D6882969f4", - "0x1f254336E5c46639A851b9CfC165697150a6c327", + "0xE3DE066aC4CFa2C6169C6e8ccc2afe7b4E440C1D", "0x2ec3F80BeDA63Ede96BA20375032CDD3aAfb3030", "0x4AcBcA6BE2f8D2540bBF4CA77E45dA0A4a095Fa2", "0x4F3D348a6D09837Ae7961B1E0cEe2cc118cec777", @@ -29,6 +29,6 @@ "0x17ea92D6FfbAA1c7F6B117c1E9D0c88ABdc8b84C", "0x38C0039247A31F3939baE65e953612125cB88268" ], - "snapshot": 8253435 + "snapshot": 8620080 } ] diff --git a/src/strategies/eco-voting-power/index.ts b/src/strategies/eco-voting-power/index.ts index 443e8ce9e..2191d91c9 100644 --- a/src/strategies/eco-voting-power/index.ts +++ b/src/strategies/eco-voting-power/index.ts @@ -7,7 +7,7 @@ import { getBlockNumber, subgraphRequest } from '../../utils'; import { getAddress } from '@ethersproject/address'; export const author = 'carlosfebres'; -export const version = '1.0.0'; +export const version = '1.0.1'; const ECO_SUBGRAPH_BY_CHAIN_ID = { '1': 'https://api.thegraph.com/subgraphs/name/ecographs/the-eco-currency-subgraphs', @@ -178,7 +178,7 @@ export async function strategy( return [ getAddress(address), - parseFloat( + parseInt( formatEther( calculateVotingPower( ecoHistorical.add(ecoCurrent), From 124de3479108a2d9478db4341f30141f566ca36d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 10 Mar 2023 11:39:56 +0530 Subject: [PATCH 330/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.69 (#1092) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 6aee78c33..e79290c94 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.68", + "@snapshot-labs/snapshot.js": "^0.4.69", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index db1d230a1..a61f2e936 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.68": - version "0.4.68" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.68.tgz#01b1da4a47d2a8f27a9d662e8768a457e46c8024" - integrity sha512-RVPo4iNnnt51nY7A0mVLSl3HGzsEmAQlH/ZtbI3TQtpCjI0pNG/VVvyvVG3/ue9/xgo5U6OzirD8DKcPT51fYQ== +"@snapshot-labs/snapshot.js@^0.4.69": + version "0.4.69" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.69.tgz#20164f3a5195b6500d698ddc2081c2ca1dcaa566" + integrity sha512-mhKrPxW1afcZnYj+NV4XD7heL6Drpzu+IGPcefoLliaPv6Gv8FIhaXZM4d5FGwFvVJcqjh+DgLHOEjanodyUCA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From b1bb3ef66ed4d49a71ff7c531d91b835bab4b617 Mon Sep 17 00:00:00 2001 From: Sam <51686767+samuveth@users.noreply.github.com> Date: Fri, 10 Mar 2023 13:11:07 +0700 Subject: [PATCH 331/815] [ticket] feat: Add schema for Ticket strategy (#1091) * feat: Add schema for Ticket strategy * Update src/strategies/ticket/schema.json --------- Co-authored-by: Chaitanya --- src/strategies/ticket/schema.json | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/strategies/ticket/schema.json diff --git a/src/strategies/ticket/schema.json b/src/strategies/ticket/schema.json new file mode 100644 index 000000000..6cdcffbb8 --- /dev/null +++ b/src/strategies/ticket/schema.json @@ -0,0 +1,25 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. DOODLE"], + "maxLength": 16 + }, + "value": { + "type": "number", + "title": "Voting power", + "examples": ["e.g. 1"] + } + }, + "required": [], + "additionalProperties": false + } + } +} From 6ca20b8df3f3c8bcce81f39712c6ce1aef3d6b0a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 10 Mar 2023 12:01:58 +0530 Subject: [PATCH 332/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.70 (#1093) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index e79290c94..5e9787ab2 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.69", + "@snapshot-labs/snapshot.js": "^0.4.70", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index a61f2e936..b25d0c1e4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.69": - version "0.4.69" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.69.tgz#20164f3a5195b6500d698ddc2081c2ca1dcaa566" - integrity sha512-mhKrPxW1afcZnYj+NV4XD7heL6Drpzu+IGPcefoLliaPv6Gv8FIhaXZM4d5FGwFvVJcqjh+DgLHOEjanodyUCA== +"@snapshot-labs/snapshot.js@^0.4.70": + version "0.4.70" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.70.tgz#af64ff487913f479f15f59857ce33e537081d32b" + integrity sha512-9z18FqmMPxzUKgTh/7DAItABHqr2sFSUOWq22TCeLTu+4WTsZGh7f18Gjvnnw6xIixenfVZXchlC25TYVC/tVg== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 3b439dd64ffd5921907f5baeca9996d29c81a1fc Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Fri, 10 Mar 2023 12:15:21 +0530 Subject: [PATCH 333/815] [safe-vested] Fix safe-vested strategy calls limit (#1094) * [safe-vested] Reduce calls limit to 250 * rename option to limit --- src/strategies/safe-vested/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/strategies/safe-vested/index.ts b/src/strategies/safe-vested/index.ts index f7bb077d0..6398d6c07 100755 --- a/src/strategies/safe-vested/index.ts +++ b/src/strategies/safe-vested/index.ts @@ -53,7 +53,10 @@ export async function strategy( const allocationsList: [[AllocationDetails]] = await response.json(); const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - const multi = new Multicaller(network, provider, abi, { blockTag }); + const multi = new Multicaller(network, provider, abi, { + blockTag, + limit: 250 + }); // Get current vesting state from smart contract using the vestingId addresses.forEach((address) => { From de17484723ea07a3391e7075511a48e14e866800 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Sat, 11 Mar 2023 12:26:27 +0530 Subject: [PATCH 334/815] Migrate validations from snapshot.js (#1095) * Migrate validations from snapshot.js * update examples.json --- src/validations/aave/examples.json | 27 ++++++++++++ src/validations/aave/index.ts | 44 +++++++++++++++++++ src/validations/basic/examples.json | 2 +- src/validations/index.ts | 4 ++ src/validations/nouns/examples.json | 27 ++++++++++++ src/validations/nouns/index.ts | 44 +++++++++++++++++++ src/validations/passport-gated/examples.json | 2 +- .../passport-weighted/examples.json | 2 +- 8 files changed, 149 insertions(+), 3 deletions(-) create mode 100644 src/validations/aave/examples.json create mode 100644 src/validations/aave/index.ts create mode 100644 src/validations/nouns/examples.json create mode 100644 src/validations/nouns/index.ts diff --git a/src/validations/aave/examples.json b/src/validations/aave/examples.json new file mode 100644 index 000000000..61845e6d7 --- /dev/null +++ b/src/validations/aave/examples.json @@ -0,0 +1,27 @@ +[ + { + "name": "Example of a aave validation", + "author": "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", + "space": "fabien.eth", + "network": "1", + "snapshot": "latest", + "params": { + "minScore": 1, + "strategies": [ + { + "name": "ticket", + "params": {} + }, + { + "name": "aave-governance-power", + "params": { + "symbol": "AAVE+stkAAVE", + "decimals": 18, + "powerType": "vote", + "governanceStrategy": "0xb7e383ef9b1e9189fc0f71fb30af8aa14377429e" + } + } + ] + } + } +] diff --git a/src/validations/aave/index.ts b/src/validations/aave/index.ts new file mode 100644 index 000000000..88056197b --- /dev/null +++ b/src/validations/aave/index.ts @@ -0,0 +1,44 @@ +import { getProvider, getScoresDirect } from '../../utils'; +import Validation from '../validation'; + +export default class extends Validation { + public id = 'aave'; + public github = 'kartojal'; + public version = '0.1.0'; + public title = 'Aave'; + public description = + 'Use proposition power instead of voting power for aave-governance-power'; + + async validate(): Promise { + const minScore = this.params.minScore; + const strategies = [...this.params.strategies]; + + const aaveGovernanceStrategyIndex = strategies.findIndex( + ({ name }) => name === 'aave-governance-power' + ); + + // Use the proposition power instead of voting power + if (aaveGovernanceStrategyIndex >= 0) { + strategies[aaveGovernanceStrategyIndex].params.powerType = 'proposition'; + } + + if (minScore) { + const scores = await getScoresDirect( + this.space, + this.params.strategies, + this.network, + getProvider(this.network), + [this.author], + this.snapshot || 'latest' + ); + const totalScore: any = scores + .map((score: any) => + Object.values(score).reduce((a, b: any) => a + b, 0) + ) + .reduce((a, b: any) => a + b, 0); + if (totalScore < minScore) return false; + } + + return true; + } +} diff --git a/src/validations/basic/examples.json b/src/validations/basic/examples.json index 1dd454cc2..82b132d37 100644 --- a/src/validations/basic/examples.json +++ b/src/validations/basic/examples.json @@ -1,6 +1,6 @@ [ { - "name": "Example of a basic proposal validation", + "name": "Example of a basic validation", "author": "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", "space": "fabien.eth", "network": "1", diff --git a/src/validations/index.ts b/src/validations/index.ts index 13fd2225d..cf02d68c4 100644 --- a/src/validations/index.ts +++ b/src/validations/index.ts @@ -1,11 +1,15 @@ import { readFileSync } from 'fs'; import path from 'path'; import basic from './basic'; +import aave from './aave'; +import nouns from './nouns'; import passportGated from './passport-gated'; import passportWeighted from './passport-weighted'; const validationClasses = { basic, + aave, + nouns, 'passport-gated': passportGated, 'passport-weighted': passportWeighted }; diff --git a/src/validations/nouns/examples.json b/src/validations/nouns/examples.json new file mode 100644 index 000000000..1f581695a --- /dev/null +++ b/src/validations/nouns/examples.json @@ -0,0 +1,27 @@ +[ + { + "name": "Example of a nouns validation", + "author": "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", + "space": "fabien.eth", + "network": "1", + "snapshot": "latest", + "params": { + "minScore": 1, + "strategies": [ + { + "name": "ticket", + "params": {} + }, + { + "name": "nouns-rfp-power", + "params": { + "symbol": "NOUNS", + "decimals": 1, + "powerType": "vote", + "governanceStrategy": "0x50Acc1831E954fB5bB407d7A3CFe1e7769A41ab0" + } + } + ] + } + } +] diff --git a/src/validations/nouns/index.ts b/src/validations/nouns/index.ts new file mode 100644 index 000000000..28d77d72a --- /dev/null +++ b/src/validations/nouns/index.ts @@ -0,0 +1,44 @@ +import { getProvider, getScoresDirect } from '../../utils'; +import Validation from '../validation'; + +export default class extends Validation { + public id = 'nouns'; + public github = 'waterdrops'; + public version = '0.1.0'; + public title = 'Nouns'; + public description = + 'Use proposition power instead of voting power for nouns-rfp-power'; + + async validate(): Promise { + const minScore = this.params.minScore; + const strategies = [...this.params.strategies]; + + const nounsRFPStrategyIndex = strategies.findIndex( + ({ name }) => name === 'nouns-rfp-power' + ); + + // Use the proposition power instead of voting power + if (nounsRFPStrategyIndex >= 0) { + strategies[nounsRFPStrategyIndex].params.powerType = 'proposition'; + } + + if (minScore) { + const scores = await getScoresDirect( + this.space, + this.params.strategies, + this.network, + getProvider(this.network), + [this.author], + this.snapshot || 'latest' + ); + const totalScore: any = scores + .map((score: any) => + Object.values(score).reduce((a, b: any) => a + b, 0) + ) + .reduce((a, b: any) => a + b, 0); + if (totalScore < minScore) return false; + } + + return true; + } +} diff --git a/src/validations/passport-gated/examples.json b/src/validations/passport-gated/examples.json index cb8e122df..d10b35391 100644 --- a/src/validations/passport-gated/examples.json +++ b/src/validations/passport-gated/examples.json @@ -1,6 +1,6 @@ [ { - "name": "Example of a passport gated proposal validation", + "name": "Example of a passport gated validation", "author": "0x24F15402C6Bb870554489b2fd2049A85d75B982f", "space": "fabien.eth", "network": "1", diff --git a/src/validations/passport-weighted/examples.json b/src/validations/passport-weighted/examples.json index 28fbb99d1..8f8428b16 100644 --- a/src/validations/passport-weighted/examples.json +++ b/src/validations/passport-weighted/examples.json @@ -1,6 +1,6 @@ [ { - "name": "Example of a passport-weighted proposal validation", + "name": "Example of a passport-weighted validation", "author": "0x24F15402C6Bb870554489b2fd2049A85d75B982f", "space": "fabien.eth", "network": "1", From bdf6b24a1bf079924f09f6789e86fff3b8e7ee4e Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Sat, 11 Mar 2023 16:26:59 +0530 Subject: [PATCH 335/815] Remove aave and nouns validations (#1096) * Migrate validations from snapshot.js * update examples.json * Remove aave and nouns validations --- src/validations/aave/examples.json | 27 ------------------ src/validations/aave/index.ts | 44 ----------------------------- src/validations/index.ts | 4 --- src/validations/nouns/examples.json | 27 ------------------ src/validations/nouns/index.ts | 44 ----------------------------- 5 files changed, 146 deletions(-) delete mode 100644 src/validations/aave/examples.json delete mode 100644 src/validations/aave/index.ts delete mode 100644 src/validations/nouns/examples.json delete mode 100644 src/validations/nouns/index.ts diff --git a/src/validations/aave/examples.json b/src/validations/aave/examples.json deleted file mode 100644 index 61845e6d7..000000000 --- a/src/validations/aave/examples.json +++ /dev/null @@ -1,27 +0,0 @@ -[ - { - "name": "Example of a aave validation", - "author": "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", - "space": "fabien.eth", - "network": "1", - "snapshot": "latest", - "params": { - "minScore": 1, - "strategies": [ - { - "name": "ticket", - "params": {} - }, - { - "name": "aave-governance-power", - "params": { - "symbol": "AAVE+stkAAVE", - "decimals": 18, - "powerType": "vote", - "governanceStrategy": "0xb7e383ef9b1e9189fc0f71fb30af8aa14377429e" - } - } - ] - } - } -] diff --git a/src/validations/aave/index.ts b/src/validations/aave/index.ts deleted file mode 100644 index 88056197b..000000000 --- a/src/validations/aave/index.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { getProvider, getScoresDirect } from '../../utils'; -import Validation from '../validation'; - -export default class extends Validation { - public id = 'aave'; - public github = 'kartojal'; - public version = '0.1.0'; - public title = 'Aave'; - public description = - 'Use proposition power instead of voting power for aave-governance-power'; - - async validate(): Promise { - const minScore = this.params.minScore; - const strategies = [...this.params.strategies]; - - const aaveGovernanceStrategyIndex = strategies.findIndex( - ({ name }) => name === 'aave-governance-power' - ); - - // Use the proposition power instead of voting power - if (aaveGovernanceStrategyIndex >= 0) { - strategies[aaveGovernanceStrategyIndex].params.powerType = 'proposition'; - } - - if (minScore) { - const scores = await getScoresDirect( - this.space, - this.params.strategies, - this.network, - getProvider(this.network), - [this.author], - this.snapshot || 'latest' - ); - const totalScore: any = scores - .map((score: any) => - Object.values(score).reduce((a, b: any) => a + b, 0) - ) - .reduce((a, b: any) => a + b, 0); - if (totalScore < minScore) return false; - } - - return true; - } -} diff --git a/src/validations/index.ts b/src/validations/index.ts index cf02d68c4..13fd2225d 100644 --- a/src/validations/index.ts +++ b/src/validations/index.ts @@ -1,15 +1,11 @@ import { readFileSync } from 'fs'; import path from 'path'; import basic from './basic'; -import aave from './aave'; -import nouns from './nouns'; import passportGated from './passport-gated'; import passportWeighted from './passport-weighted'; const validationClasses = { basic, - aave, - nouns, 'passport-gated': passportGated, 'passport-weighted': passportWeighted }; diff --git a/src/validations/nouns/examples.json b/src/validations/nouns/examples.json deleted file mode 100644 index 1f581695a..000000000 --- a/src/validations/nouns/examples.json +++ /dev/null @@ -1,27 +0,0 @@ -[ - { - "name": "Example of a nouns validation", - "author": "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", - "space": "fabien.eth", - "network": "1", - "snapshot": "latest", - "params": { - "minScore": 1, - "strategies": [ - { - "name": "ticket", - "params": {} - }, - { - "name": "nouns-rfp-power", - "params": { - "symbol": "NOUNS", - "decimals": 1, - "powerType": "vote", - "governanceStrategy": "0x50Acc1831E954fB5bB407d7A3CFe1e7769A41ab0" - } - } - ] - } - } -] diff --git a/src/validations/nouns/index.ts b/src/validations/nouns/index.ts deleted file mode 100644 index 28d77d72a..000000000 --- a/src/validations/nouns/index.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { getProvider, getScoresDirect } from '../../utils'; -import Validation from '../validation'; - -export default class extends Validation { - public id = 'nouns'; - public github = 'waterdrops'; - public version = '0.1.0'; - public title = 'Nouns'; - public description = - 'Use proposition power instead of voting power for nouns-rfp-power'; - - async validate(): Promise { - const minScore = this.params.minScore; - const strategies = [...this.params.strategies]; - - const nounsRFPStrategyIndex = strategies.findIndex( - ({ name }) => name === 'nouns-rfp-power' - ); - - // Use the proposition power instead of voting power - if (nounsRFPStrategyIndex >= 0) { - strategies[nounsRFPStrategyIndex].params.powerType = 'proposition'; - } - - if (minScore) { - const scores = await getScoresDirect( - this.space, - this.params.strategies, - this.network, - getProvider(this.network), - [this.author], - this.snapshot || 'latest' - ); - const totalScore: any = scores - .map((score: any) => - Object.values(score).reduce((a, b: any) => a + b, 0) - ) - .reduce((a, b: any) => a + b, 0); - if (totalScore < minScore) return false; - } - - return true; - } -} From 0b7330ae70c5f1c80467a7356feb9dcd0fa8678c Mon Sep 17 00:00:00 2001 From: Leez <94301129+0xleez@users.noreply.github.com> Date: Tue, 14 Mar 2023 09:16:26 +0200 Subject: [PATCH 336/815] =?UTF-8?q?[jpegd-locked-jpeg-of]=20Update=20?= =?UTF-8?q?=E2=80=93=20ignore=20new=20collections=20(#1055)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * jpegd-boosts * rename * readme * switched from object to string abi * query subgraph at blockNumber * ignore new collections --------- Co-authored-by: Chaitanya --- src/strategies/index.ts | 2 +- .../jpegd-locked-jpeg-of/examples.json | 55 ++++++++++--------- src/strategies/jpegd-locked-jpeg-of/index.ts | 18 +++--- 3 files changed, 41 insertions(+), 34 deletions(-) diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 4064b9186..a976ba0d4 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -853,9 +853,9 @@ const strategies = { 'skale-delegation-weighted': skaleDelegationWeighted, reliquary, 'vsta-pool-staking': vstaPoolStaking, + 'jpegd-locked-jpeg-of': jpegdLockedJpegOf, 'lodestar-vesting': lodestarVesting, 'lodestar-staked-lp': lodestarStakedLp, - 'jpegd-locked-jpeg-of': jpegdLockedJpegOf, babywealthyclub, 'battlefly-vgfly-and-staked-gfly': battleflyVGFLYAndStakedGFLY, 'nexon-army-nft': nexonArmyNFT, diff --git a/src/strategies/jpegd-locked-jpeg-of/examples.json b/src/strategies/jpegd-locked-jpeg-of/examples.json index 59b010597..552c2195d 100644 --- a/src/strategies/jpegd-locked-jpeg-of/examples.json +++ b/src/strategies/jpegd-locked-jpeg-of/examples.json @@ -1,28 +1,31 @@ [ - { - "name": "Example query", - "strategy": { - "name": "jpegd-locked-jpeg-of", - "params": { - "collectionToProviderAddress": { - "CRYPTOPUNKS": "0xdf7806eaa13497efffdb1541d6b0fdd1a9566fd0", - "ETHERROCKS": "0x9921da2908cc59b13ddbcf45e64bfa91c78c4249", - "BAYC": "0x5b9cAA47A52e4BfbBce2f2A9f858c2A501B48C42", - "MAYC": "0xdEd112453BD8EA88CdaB214CFD92Ab06E232E9d7", - "DOODLES": "0xdd245B7823ee82D14419CE072Ef815868F0D1f1A", - "PUDGYPENGUINS": "0xd0bf9A40FebDfCA596fde589a343C6cDA37A7B90", - "AZUKI": "0xcaA0aa80637262fd3Ba6DD5b5598a2BAFAc27cE8", - "CLONEX": "0xb36B65400E13FF57dFDa29bBb7dC79eaA7ecA14C" + { + "name": "Example query", + "strategy": { + "name": "jpegd-locked-jpeg-of", + "params": { + "collectionToProviderAddress": { + "CRYPTOPUNKS": "0xdf7806eaa13497efffdb1541d6b0fdd1a9566fd0", + "ETHERROCKS": "0x9921da2908cc59b13ddbcf45e64bfa91c78c4249", + "BAYC": "0x5b9cAA47A52e4BfbBce2f2A9f858c2A501B48C42", + "MAYC": "0xdEd112453BD8EA88CdaB214CFD92Ab06E232E9d7", + "DOODLES": "0xdd245B7823ee82D14419CE072Ef815868F0D1f1A", + "PUDGYPENGUINS": "0xd0bf9A40FebDfCA596fde589a343C6cDA37A7B90", + "AZUKI": "0xcaA0aa80637262fd3Ba6DD5b5598a2BAFAc27cE8", + "CLONEX": "0xb36B65400E13FF57dFDa29bBb7dC79eaA7ecA14C", + "AUTOGLYPHS": "0xa74AbB04486f6926802cF6c3719c41b9ea10E49b", + "FIDENZAS": "0x1a6fA849D5bF62F9b7B83D125E77e15292c54b4f", + "RINGERS": "0x927318B867f0939Ab501dFd7b1B8d60E52ea5B59" + }, + "start": 15363080 + } }, - "start": 15363080 - } - }, - "network": "1", - "addresses": [ - "0x9c5083dd4838e120dbeac44c052179692aa5dac5", - "0xB0dAfc466871c29662E5cbf4227322C96A8Ccbe9", - "0x0017dfe08bcc0dc9a323ca5d4831e371534e9320" - ], - "snapshot": 16119881 - } -] + "network": "1", + "addresses": [ + "0x9c5083dd4838e120dbeac44c052179692aa5dac5", + "0xB0dAfc466871c29662E5cbf4227322C96A8Ccbe9", + "0x0017dfe08bcc0dc9a323ca5d4831e371534e9320" + ], + "snapshot": 16119881 + } +] \ No newline at end of file diff --git a/src/strategies/jpegd-locked-jpeg-of/index.ts b/src/strategies/jpegd-locked-jpeg-of/index.ts index ff34eeca7..921188f89 100644 --- a/src/strategies/jpegd-locked-jpeg-of/index.ts +++ b/src/strategies/jpegd-locked-jpeg-of/index.ts @@ -6,7 +6,7 @@ import { subgraphRequest } from '../../utils'; export const author = '0xleez'; export const version = '0.1.0'; -const UNISWAP_SUBGRAPH_URL = { +const SUBGRAPH_URL = { '1': 'https://api.thegraph.com/subgraphs/name/jpegd/jpegd-core-mainnet' }; @@ -44,18 +44,22 @@ export async function strategy( } }; - const result = await subgraphRequest(UNISWAP_SUBGRAPH_URL[network], params); + const result = await subgraphRequest(SUBGRAPH_URL[network], params); const jpegLocks = result.jpeglocks ?? []; const responses = await multicall( network, provider, abi, - jpegLocks.map((jpegLock: any) => [ - collectionToProviderAddress[jpegLock.collection.id], - jpegLock.type === 'LTV' ? 'ltvBoostPositions' : 'traitBoostPositions', - [jpegLock.nftIndex] - ]), + jpegLocks + .filter((jpegLock) => + Boolean(collectionToProviderAddress[jpegLock.collection.id]) + ) + .map((jpegLock: any) => [ + collectionToProviderAddress[jpegLock.collection.id], + jpegLock.type === 'LTV' ? 'ltvBoostPositions' : 'traitBoostPositions', + [jpegLock.nftIndex] + ]), { blockTag } ); From 486b7a7f2d7af361486c64c39735d7a79f85b0b3 Mon Sep 17 00:00:00 2001 From: Brandon Date: Tue, 14 Mar 2023 03:19:07 -0400 Subject: [PATCH 337/815] new strategy: Echelon voting strategy with eligibility criteria [echelon-wallet-prime-and-cached-key-gated] (#1090) * echelon erc1155 vote gating * trailing comma --- .../README.md | 36 +++++++ .../examples.json | 37 +++++++ .../index.ts | 99 +++++++++++++++++++ src/strategies/index.ts | 5 +- 4 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 src/strategies/echelon-wallet-prime-and-cached-key-gated/README.md create mode 100644 src/strategies/echelon-wallet-prime-and-cached-key-gated/examples.json create mode 100644 src/strategies/echelon-wallet-prime-and-cached-key-gated/index.ts diff --git a/src/strategies/echelon-wallet-prime-and-cached-key-gated/README.md b/src/strategies/echelon-wallet-prime-and-cached-key-gated/README.md new file mode 100644 index 000000000..6824fa491 --- /dev/null +++ b/src/strategies/echelon-wallet-prime-and-cached-key-gated/README.md @@ -0,0 +1,36 @@ +# echelon-wallet-prime-cached-key-gated + +This strategy looks at an ERC1155 caching (staking) contract and assigns a linearly decaying amount of voting power. The business context behind this is that each cached asset is eligible to claim a set amount of ERC20s over the same period; and thus can use those tokens to vote as well. + +For example, at block 0, the voting should have equivalent to 4000 units of voting power. A year later, they should have 0 units. + +As parameters, we pass in the base amount of voting power (e.g. 4000), starting block where there's no decay, and number of months until complete decay (e.g. 12). + +At a high level, the strategy grabs the UNIX timestamp in seconds for starting block, current block, and project timestamp of final block. It then queries the contract for the amount of cached ERC1155s. A simple slope formula is then applied to calculate the decay rate; which is then applied to determine the voting power per asset at current block. + +This strategy also makes use of the `erc20-balance-of` strategy. The erc20 balance is added to the equivalent value of the cached NFT. + +The weighted voting power is square rooted. + +In order to be eligible to vote, the address has to have a non-zero wallet erc1155 balance (using the `erc1155-all-balances-of` strategy) or be whitelisted. Additionally, the address cannot be blacklisted. + +Example of parameters: + +```json + "params": { + "symbol": "PRIME VOTE", + "address": "0xb23d80f5FefcDDaa212212F028021B41DEd428CF", + "decimals": 18, + "stakingAddress": "0x3399eff96D4b6Bae8a56F4852EB55736c9C2b041", + "baseValue": 4000, + "startingBlock": 15166749, + "monthsToDecay": 12, + "erc1155Address": "0x76BE3b62873462d2142405439777e971754E8E77", + "whitelist": [ + "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", + "0xFCfcC87E312f323768f9553255250A9357a04109" + ], + "blacklist": ["0xE6be99cbC7796F90baff870a2ffE838a540E27C9"] + } +``` + diff --git a/src/strategies/echelon-wallet-prime-and-cached-key-gated/examples.json b/src/strategies/echelon-wallet-prime-and-cached-key-gated/examples.json new file mode 100644 index 000000000..387c32c66 --- /dev/null +++ b/src/strategies/echelon-wallet-prime-and-cached-key-gated/examples.json @@ -0,0 +1,37 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "echelon-wallet-prime-and-cached-key-gated", + "params": { + "symbol": "PRIME VOTE", + "address": "0xb23d80f5FefcDDaa212212F028021B41DEd428CF", + "decimals": 18, + "stakingAddress": "0x3399eff96D4b6Bae8a56F4852EB55736c9C2b041", + "baseValue": 4000, + "startingBlock": 15166749, + "monthsToDecay": 12, + "erc1155Address": "0x76BE3b62873462d2142405439777e971754E8E77", + "whitelist": [ + "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", + "0xFCfcC87E312f323768f9553255250A9357a04109" + ], + "blacklist": ["0xE6be99cbC7796F90baff870a2ffE838a540E27C9"] + } + }, + "network": "1", + "addresses": [ + "0xE6be99cbC7796F90baff870a2ffE838a540E27C9", + "0xf98A4A42853cC611eED664627087d4ae19740ED8", + "0xbdc3C931387e2c6647b0D7237Ed30c702260fa80", + "0x5566eec3684F3ED896740590cc372758f25f056f", + "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", + "0xFCfcC87E312f323768f9553255250A9357a04109", + "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e", + "0x1d5E65a087eBc3d03a294412E46CE5D6882969f4", + "0x1f254336E5c46639A851b9CfC165697150a6c327", + "0x2ec3F80BeDA63Ede96BA20375032CDD3aAfb3030" + ], + "snapshot": 15540462 + } +] diff --git a/src/strategies/echelon-wallet-prime-and-cached-key-gated/index.ts b/src/strategies/echelon-wallet-prime-and-cached-key-gated/index.ts new file mode 100644 index 000000000..79c7068a7 --- /dev/null +++ b/src/strategies/echelon-wallet-prime-and-cached-key-gated/index.ts @@ -0,0 +1,99 @@ +import { Multicaller } from '../../utils'; +import { strategy as erc20BalanceOfStrategy } from '../erc20-balance-of'; +import { strategy as erc1155AllBalancesOf } from '../erc1155-all-balances-of'; + +export const author = 'brandonleung'; +export const version = '1.0.0'; + +const cachingAbi = [ + 'function cacheInfo(uint256, address) view returns (uint256 amount, int256 rewardDebt)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const stakingPool = new Multicaller(network, provider, cachingAbi, { + blockTag + }); + + const startingBlockTimestamp = ( + await provider.getBlock(options.startingBlock) + ).timestamp; + const endingBlockTimestamp = + startingBlockTimestamp + 2628288 * options.monthsToDecay; + const currentBlockTimestamp = (await provider.getBlock(snapshot)).timestamp; + + const decayRate = + (0 - options.baseValue) / (endingBlockTimestamp - startingBlockTimestamp); + + const votingPowerPerKey = + options.baseValue + + decayRate * (currentBlockTimestamp - startingBlockTimestamp); + + addresses.forEach((address) => { + stakingPool.call(address, options.stakingAddress, 'cacheInfo', [ + 0, + address + ]); + }); + const contractResponse = await stakingPool.execute(); + + const cachedKeyScore = Object.fromEntries( + addresses.map((address) => { + return [ + address, + contractResponse[address][0].toNumber() * votingPowerPerKey + ]; + }) + ); + + const walletScore = await erc20BalanceOfStrategy( + space, + network, + provider, + addresses, + options, + snapshot + ); + + const erc1155Options = { + address: options.erc1155Address + }; + const erc1155Balances = await erc1155AllBalancesOf( + space, + network, + provider, + addresses, + erc1155Options, + snapshot + ); + + const votingPower = Object.entries(walletScore).reduce( + (address, [key, value]) => ({ + ...address, + [key]: (address[key] || 0) + value + }), + { ...cachedKeyScore } + ); + + Object.keys(votingPower).forEach((key) => { + const whitelistedAddress = + options.whitelist.indexOf(key) !== -1 || + (key in erc1155Balances && erc1155Balances[key] > 0); + const blacklistedAddress = options.blacklist.indexOf(key) !== -1; + + votingPower[key] = + whitelistedAddress && !blacklistedAddress + ? Math.sqrt(votingPower[key]) + : 0; + }); + + return votingPower; +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index a976ba0d4..9c6e7645e 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -429,6 +429,7 @@ import * as pspInSePSP2Balance from './psp-in-sepsp2-balance'; import * as pdnBalancesAndVests from './pdn-balances-and-vests'; import * as izumiVeiZi from './izumi-veizi'; import * as lqtyProxyStakers from './lqty-proxy-stakers'; +import * as echelonWalletPrimeAndCachedKeyGated from './echelon-wallet-prime-and-cached-key-gated'; const strategies = { 'izumi-veizi': izumiVeiZi, @@ -863,7 +864,9 @@ const strategies = { 'stakedotlink-vesting': stakedotlinkVesting, 'psp-in-sepsp2-balance': pspInSePSP2Balance, 'pdn-balances-and-vests': pdnBalancesAndVests, - 'lqty-proxy-stakers': lqtyProxyStakers + 'lqty-proxy-stakers': lqtyProxyStakers, + 'echelon-wallet-prime-and-cached-key-gated': + echelonWalletPrimeAndCachedKeyGated }; Object.keys(strategies).forEach(function (strategyName) { From fce81f59782318c0285fc48fb661b01dc2bd1409 Mon Sep 17 00:00:00 2001 From: "system32.eth" <23362597+Raecaug@users.noreply.github.com> Date: Wed, 15 Mar 2023 13:22:17 -0400 Subject: [PATCH 338/815] Adding new strategy lrc-nft-search-mult[lrc-nft-search-mult] (#1098) * initial commit of lrc-nft-search-mult This is an extended functionality version of a previous Loopring NFT voting strategy. This allows for queried scores to be multiplied by a value to allow vote weighting in conjunction with multiple strategies. * Update index.ts Update to add lrc-nft-search-mult strategy * Update src/strategies/lrc-nft-search-mult/index.ts Update strategy version Co-authored-by: Chaitanya * Update examples.json Add additional addresses to satisfy test case conditions --------- Co-authored-by: Chaitanya --- src/strategies/index.ts | 2 + src/strategies/lrc-nft-search-mult/README.md | 29 ++++ .../lrc-nft-search-mult/examples.json | 22 +++ src/strategies/lrc-nft-search-mult/index.ts | 128 ++++++++++++++++++ 4 files changed, 181 insertions(+) create mode 100644 src/strategies/lrc-nft-search-mult/README.md create mode 100644 src/strategies/lrc-nft-search-mult/examples.json create mode 100644 src/strategies/lrc-nft-search-mult/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 9c6e7645e..df152e78d 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -365,6 +365,7 @@ import * as lrcL2SubgraphBalanceOf from './lrc-l2-subgraph-balance-of'; import * as lrcL2NftBalanceOf from './lrc-l2-nft-balance-of'; import * as lrcLPSubgraphBalanceOf from './lrc-lp-subgraph-balance-of'; import * as lrcNFTDAOSearch from './lrc-nft-dao-search'; +import * as lrcNFTmult from './lrc-nft-search-mult'; import * as erc3525VestingVoucher from './erc3525-vesting-voucher'; import * as rariFuse from './rari-fuse'; import * as selfswap from './selfswap'; @@ -802,6 +803,7 @@ const strategies = { 'lrc-l2-nft-balance-of': lrcL2NftBalanceOf, 'lrc-lp-subgraph-balance-of': lrcLPSubgraphBalanceOf, 'lrc-nft-dao-search': lrcNFTDAOSearch, + 'lrc-nft-search-mult': lrcNFTmult, 'rari-fuse': rariFuse, 'bancor-pool-token-underlying-balance': bancorPoolTokenUnderlyingBalance, selfswap, diff --git a/src/strategies/lrc-nft-search-mult/README.md b/src/strategies/lrc-nft-search-mult/README.md new file mode 100644 index 000000000..f98fdfffa --- /dev/null +++ b/src/strategies/lrc-nft-search-mult/README.md @@ -0,0 +1,29 @@ +# lrc-nft-search-mult + +This is a further improvement of karamorf's lrc-l2-nft-balance of Snapshot voting strategy by raecaug(system32). + +This strategy is an extension of lrc-nft-dao-search, allowing space owners to apply a multiplier to counted votes. +This can then be combined with additional voting strategies to allow for complex DAO setups with vote weighting of specific NFTs. +Providing a multiplier is necessary; if default behavior is desired, simply specify '1'. + +Strategy to read account balances for NFTs (72 or 1155) from LoopringV2 subgraph. Assumes we only want tokens minted by a specific account id. + +Here is an example of parameters: + +```json +{ + "graph": "https://api.thegraph.com/subgraphs/name/juanmardefago/loopring36", + "minter_account_id": "74447", + "tokens": ["token (Collection contract address) to include"], + "nft_ids": ["nftIDs, unique to every nft, even those under the same token contract"], + "blacklisted_account_ids": ["38482"], + "blacklisted_nft_ids": ["... nft id's to exclude ..."] + "multiplier": "3" // Setting this to '1' will result in normal vote counting behavior. +} +``` + +Use explorer.loopring.io to look up addresses and find account id's. + +Account id `38482` maps to `0x000000000000000000000000000000000000dead` and is used for burning tokens. + +to note: either the `minter_account_id` or the `tokens` parameter must be provided for this query to work. You do not need to specify both, just one of them. diff --git a/src/strategies/lrc-nft-search-mult/examples.json b/src/strategies/lrc-nft-search-mult/examples.json new file mode 100644 index 000000000..941898332 --- /dev/null +++ b/src/strategies/lrc-nft-search-mult/examples.json @@ -0,0 +1,22 @@ +[ + { + "name": "lrcNFTmult", + "strategy": { + "name": "lrc-nft-search-mult", + "params": { + "graph": "https://api.thegraph.com/subgraphs/name/juanmardefago/loopring36", + "minter_account_id": "157510", + "tokens": ["0xb6d91e38e4ac53c9f8952c6c6b1c7aee66c8b6f0"], + "nft_ids": [ + "0x1e31297dd163ca44a5fad74de4ffbebf1ba11d46e1b448b0e105449d827fb264" + ], + "blacklisted_account_ids": [""], + "blacklisted_nft_ids": [""], + "multiplier": "1" + } + }, + "network": "1", + "addresses": ["0xeE253D3fCC30787a1E58570E355010d0b9C33B60","0xddCCE06088517c56FA938bD99cD0820094010F8e","0x9Fd19B8ca6E49eD92142339F54026497cE913492"], + "snapshot": 15677787 + } +] diff --git a/src/strategies/lrc-nft-search-mult/index.ts b/src/strategies/lrc-nft-search-mult/index.ts new file mode 100644 index 000000000..fcc1cbcd4 --- /dev/null +++ b/src/strategies/lrc-nft-search-mult/index.ts @@ -0,0 +1,128 @@ +// Original code by Karamorf, upgraded by Raecaug(system32) +// Allows querys of Loopring L2 accounts & balances by specifying a nft minter, token contract address(and optionally specifying individual ids to white/blacklist) + +import { subgraphRequest } from '../../utils'; +export const author = 'raecaug'; +export const version = '0.1.0'; + +const LIMIT = 1000; + +function makeQuery( + snapshot, // This is an Ethereum block # or defaults to 'latest' + minter, // This is referred to as account # or account id on the Loopring L2 block explorer + tokens, // NFT collection contract addresses, also referred to as 'token address' + skip, // Used to skip response lines in requests + blacklisted_account_ids, // Ditto properties of 'minter' + blacklisted_nft_ids, // This is the nft id, which is unique for every nft ever minted, allows distinction between nfts in a collection at the chain level + nft_ids // Ditto properties of blacklisted version +) { + const query: any = { + // Query constructor, builds request with params from snapshot space settings + accountNFTSlots: { + __args: { + where: { + nft_: { + id_not_in: blacklisted_nft_ids, // Excluding blacklisted nft ids + nftID_in: nft_ids // Including uniquely specified nft ids + }, + account_not_in: blacklisted_account_ids // Excluding blacklisted account ids + }, + first: LIMIT, + skip: skip + }, + account: { address: true }, + balance: true + } + }; + + if (minter && minter !== '') { + //Check to ensure minter id is specified and not blank + query.accountNFTSlots.__args.where.nft_.minter = minter; + } + + if (tokens && tokens.length > 0) { + //Check to ensure at least 1 token to search for is specified + query.accountNFTSlots.__args.where.nft_.token_in = tokens; + } + + if (snapshot !== 'latest') { + // If the snapshot date is manually specified, overwrite the 'latest' block, strict inequality check operand used + query.accountNFTSlots.__args = { + ...query.accountNFTSlots.__args, + block: { + number: snapshot + } + }; + } + + return query; +} + +export async function strategy( // *****Logical execution begins here; args passed in by Snapshot settings***** + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + let blacklisted_account_ids = options.blacklisted_account_ids; + let blacklisted_nft_ids = options.blacklisted_nft_ids; + + let multiplier = options.multiplier; // Multiplier to be applied against returned NFT amounts + + let nft_ids = options.nft_ids; // Unique NFT ids, distinguishable from 1155 token contracts + + const balances = {}; // Initialization + let skip = 0; + let response_size = 0; + + if (!blacklisted_account_ids || blacklisted_account_ids.length === 0) { + // If no blacklisted accts specified, set to empty + blacklisted_account_ids = ['']; + } + + if (!blacklisted_nft_ids || blacklisted_nft_ids.length === 0) { + // If no unique nft_ids specified, set to empty + blacklisted_nft_ids = ['']; + } + + if (!nft_ids || nft_ids.length === 0) { + // If no unique nft_ids specified, set to empty + nft_ids = ['']; + } + + do { + // Transmit query and await results + const response = await subgraphRequest( + // Constructs response variable from subgraph query function + options.graph, // Parameter 1, options specified + makeQuery( + // Query constructor(defined above) called, results are the second parameter + snapshot, + options.minter_account_id, + options.tokens, + skip, + blacklisted_account_ids, + blacklisted_nft_ids, + nft_ids + ) + ); + + response.accountNFTSlots.forEach((slot) => { + // Checking against each accountNFTSlot element + if (!balances.hasOwnProperty(slot.account.address)) { + balances[slot.account.address] = 0; // If nothing returned, set this accounts balance to 0 + } + balances[slot.account.address] += (multiplier * parseInt(slot.balance)); // Otherwise, a bigint is returned; parse it, apply multiplier and store in balances array + }); + response_size = response.accountNFTSlots.length; // Value is set to 0 on loop entry, updated here, will break loop for anything other than 1000 + skip += response_size; + } while (response_size == LIMIT); + + const scores = Object.fromEntries( + addresses.map((address) => [address, balances[address.toLowerCase()]]) // Map returned addresses and balances as scores array + ); + + return scores; // Returns addresses and balances to Snapshot +} From 757430e20add7bcdcb12a4f7e9fd76ec40d7ad0c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 16 Mar 2023 23:47:56 +0530 Subject: [PATCH 339/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.72 (#1100) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 5e9787ab2..4d8a64d96 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.70", + "@snapshot-labs/snapshot.js": "^0.4.72", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index b25d0c1e4..db74f172a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.70": - version "0.4.70" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.70.tgz#af64ff487913f479f15f59857ce33e537081d32b" - integrity sha512-9z18FqmMPxzUKgTh/7DAItABHqr2sFSUOWq22TCeLTu+4WTsZGh7f18Gjvnnw6xIixenfVZXchlC25TYVC/tVg== +"@snapshot-labs/snapshot.js@^0.4.72": + version "0.4.72" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.72.tgz#a5a789d756ddc4fbc958204f72ec7e792c601d40" + integrity sha512-IOrTJV5T8oX3Qiav1IDmM9sXNizxBsPaG8rVGbxaMYwuVkw6zfWQgJ80ukWUzhROL3Tl5BTO0JQqxNcV8Zkidw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From c09fc51bb94a90936d1d6e4077f2d283eda3b230 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 18 Mar 2023 23:48:57 +0530 Subject: [PATCH 340/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.73 (#1102) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 4d8a64d96..32e83c20d 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.72", + "@snapshot-labs/snapshot.js": "^0.4.73", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index db74f172a..f0b20cf18 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.72": - version "0.4.72" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.72.tgz#a5a789d756ddc4fbc958204f72ec7e792c601d40" - integrity sha512-IOrTJV5T8oX3Qiav1IDmM9sXNizxBsPaG8rVGbxaMYwuVkw6zfWQgJ80ukWUzhROL3Tl5BTO0JQqxNcV8Zkidw== +"@snapshot-labs/snapshot.js@^0.4.73": + version "0.4.73" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.73.tgz#8e7973dd94f44c2fb7479b6b2ae0c48ec59b0ffa" + integrity sha512-xkuwM3sk5yTcA9vUxcHzkZj0ZbCBmIcY21MKeMFXWoo7TvfhX5lpw5BIbBsW6QC72JLZQ9bKxG7zvXRNtOTy6Q== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 695b4786c5b00810d115069981ccef56fb6a0e31 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 19 Mar 2023 22:50:31 +0530 Subject: [PATCH 341/815] Automated lint (#1103) Co-authored-by: ChaituVR --- .../jpegd-locked-jpeg-of/examples.json | 58 +++++++++---------- .../lrc-nft-search-mult/examples.json | 6 +- src/strategies/lrc-nft-search-mult/index.ts | 4 +- 3 files changed, 36 insertions(+), 32 deletions(-) diff --git a/src/strategies/jpegd-locked-jpeg-of/examples.json b/src/strategies/jpegd-locked-jpeg-of/examples.json index 552c2195d..548074751 100644 --- a/src/strategies/jpegd-locked-jpeg-of/examples.json +++ b/src/strategies/jpegd-locked-jpeg-of/examples.json @@ -1,31 +1,31 @@ [ - { - "name": "Example query", - "strategy": { - "name": "jpegd-locked-jpeg-of", - "params": { - "collectionToProviderAddress": { - "CRYPTOPUNKS": "0xdf7806eaa13497efffdb1541d6b0fdd1a9566fd0", - "ETHERROCKS": "0x9921da2908cc59b13ddbcf45e64bfa91c78c4249", - "BAYC": "0x5b9cAA47A52e4BfbBce2f2A9f858c2A501B48C42", - "MAYC": "0xdEd112453BD8EA88CdaB214CFD92Ab06E232E9d7", - "DOODLES": "0xdd245B7823ee82D14419CE072Ef815868F0D1f1A", - "PUDGYPENGUINS": "0xd0bf9A40FebDfCA596fde589a343C6cDA37A7B90", - "AZUKI": "0xcaA0aa80637262fd3Ba6DD5b5598a2BAFAc27cE8", - "CLONEX": "0xb36B65400E13FF57dFDa29bBb7dC79eaA7ecA14C", - "AUTOGLYPHS": "0xa74AbB04486f6926802cF6c3719c41b9ea10E49b", - "FIDENZAS": "0x1a6fA849D5bF62F9b7B83D125E77e15292c54b4f", - "RINGERS": "0x927318B867f0939Ab501dFd7b1B8d60E52ea5B59" - }, - "start": 15363080 - } + { + "name": "Example query", + "strategy": { + "name": "jpegd-locked-jpeg-of", + "params": { + "collectionToProviderAddress": { + "CRYPTOPUNKS": "0xdf7806eaa13497efffdb1541d6b0fdd1a9566fd0", + "ETHERROCKS": "0x9921da2908cc59b13ddbcf45e64bfa91c78c4249", + "BAYC": "0x5b9cAA47A52e4BfbBce2f2A9f858c2A501B48C42", + "MAYC": "0xdEd112453BD8EA88CdaB214CFD92Ab06E232E9d7", + "DOODLES": "0xdd245B7823ee82D14419CE072Ef815868F0D1f1A", + "PUDGYPENGUINS": "0xd0bf9A40FebDfCA596fde589a343C6cDA37A7B90", + "AZUKI": "0xcaA0aa80637262fd3Ba6DD5b5598a2BAFAc27cE8", + "CLONEX": "0xb36B65400E13FF57dFDa29bBb7dC79eaA7ecA14C", + "AUTOGLYPHS": "0xa74AbB04486f6926802cF6c3719c41b9ea10E49b", + "FIDENZAS": "0x1a6fA849D5bF62F9b7B83D125E77e15292c54b4f", + "RINGERS": "0x927318B867f0939Ab501dFd7b1B8d60E52ea5B59" }, - "network": "1", - "addresses": [ - "0x9c5083dd4838e120dbeac44c052179692aa5dac5", - "0xB0dAfc466871c29662E5cbf4227322C96A8Ccbe9", - "0x0017dfe08bcc0dc9a323ca5d4831e371534e9320" - ], - "snapshot": 16119881 - } -] \ No newline at end of file + "start": 15363080 + } + }, + "network": "1", + "addresses": [ + "0x9c5083dd4838e120dbeac44c052179692aa5dac5", + "0xB0dAfc466871c29662E5cbf4227322C96A8Ccbe9", + "0x0017dfe08bcc0dc9a323ca5d4831e371534e9320" + ], + "snapshot": 16119881 + } +] diff --git a/src/strategies/lrc-nft-search-mult/examples.json b/src/strategies/lrc-nft-search-mult/examples.json index 941898332..e0eaba892 100644 --- a/src/strategies/lrc-nft-search-mult/examples.json +++ b/src/strategies/lrc-nft-search-mult/examples.json @@ -16,7 +16,11 @@ } }, "network": "1", - "addresses": ["0xeE253D3fCC30787a1E58570E355010d0b9C33B60","0xddCCE06088517c56FA938bD99cD0820094010F8e","0x9Fd19B8ca6E49eD92142339F54026497cE913492"], + "addresses": [ + "0xeE253D3fCC30787a1E58570E355010d0b9C33B60", + "0xddCCE06088517c56FA938bD99cD0820094010F8e", + "0x9Fd19B8ca6E49eD92142339F54026497cE913492" + ], "snapshot": 15677787 } ] diff --git a/src/strategies/lrc-nft-search-mult/index.ts b/src/strategies/lrc-nft-search-mult/index.ts index fcc1cbcd4..89ba62305 100644 --- a/src/strategies/lrc-nft-search-mult/index.ts +++ b/src/strategies/lrc-nft-search-mult/index.ts @@ -69,7 +69,7 @@ export async function strategy( // *****Logical execution begins here; args pass let blacklisted_account_ids = options.blacklisted_account_ids; let blacklisted_nft_ids = options.blacklisted_nft_ids; - let multiplier = options.multiplier; // Multiplier to be applied against returned NFT amounts + const multiplier = options.multiplier; // Multiplier to be applied against returned NFT amounts let nft_ids = options.nft_ids; // Unique NFT ids, distinguishable from 1155 token contracts @@ -114,7 +114,7 @@ export async function strategy( // *****Logical execution begins here; args pass if (!balances.hasOwnProperty(slot.account.address)) { balances[slot.account.address] = 0; // If nothing returned, set this accounts balance to 0 } - balances[slot.account.address] += (multiplier * parseInt(slot.balance)); // Otherwise, a bigint is returned; parse it, apply multiplier and store in balances array + balances[slot.account.address] += multiplier * parseInt(slot.balance); // Otherwise, a bigint is returned; parse it, apply multiplier and store in balances array }); response_size = response.accountNFTSlots.length; // Value is set to 0 on loop entry, updated here, will break loop for anything other than 1000 skip += response_size; From 1d8089f08768fd4d3eb39a4be4a215fa7358a5d5 Mon Sep 17 00:00:00 2001 From: "ALex.Lin" Date: Wed, 22 Mar 2023 22:28:00 +0800 Subject: [PATCH 342/815] [math] feat: add minus operation (#1101) * feat: strategy.math support (sum $ minus) * chore: format readme * chore: remove math.sum * chore: smaller examples * Update index.ts --------- Co-authored-by: Chaitanya --- src/strategies/math/README.md | 1 + src/strategies/math/examples.json | 43 ++++++++++++++++++++++++++++--- src/strategies/math/index.ts | 13 +++++++++- src/strategies/math/options.ts | 9 ++++--- 4 files changed, 58 insertions(+), 8 deletions(-) diff --git a/src/strategies/math/README.md b/src/strategies/math/README.md index 4646c2495..cf0b8be8c 100644 --- a/src/strategies/math/README.md +++ b/src/strategies/math/README.md @@ -17,6 +17,7 @@ Currently supported operations are: | `a-if-lte-b` | 3 | (x, a, b) = x <= b ? a : x | | `a-if-gt-b` | 3 | (x, a, b) = x > b ? a : x | | `a-if-gte-b` | 3 | (x, a, b) = x >= b ? a : x | +| `minus` | 2 | x - a | ## Examples diff --git a/src/strategies/math/examples.json b/src/strategies/math/examples.json index 1564a81fd..95de058f7 100644 --- a/src/strategies/math/examples.json +++ b/src/strategies/math/examples.json @@ -1,4 +1,39 @@ [ + { + "name": "Example simple contract call plus / minus", + "strategy": { + "name": "math", + "params": { + "symbol": "MATH", + "operands": [ + { + "type": "strategy", + "strategy": { + "network": "1", + "name": "erc20-balance-of", + "params": { + "address": "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "symbol": "USDT", + "decimals": 6 + } + } + }, + { + "type": "constant", + "value": 6 + } + ], + "operation": "minus" + } + }, + "network": "1", + "addresses": [ + "0x5C52cC7c96bDE8594e5B77D5b76d042CB5FaE5f2", + "0x4D19C0a5357bC48be0017095d3C871D9aFC3F21d", + "0xf59869753f41Db720127Ceb8DbB8afAF89030De4" + ], + "snapshot": 16847746 + }, { "name": "Example nested query", "strategy": { @@ -28,7 +63,7 @@ }, "network": "1", "addresses": [ - "0xa478c2975ab1ea89e8196811f51a7b7ade33eb11", + "0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11", "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", "0xCba1A275e2D858EcffaF7a87F606f74B719a8A93", @@ -84,7 +119,7 @@ }, "network": "1", "addresses": [ - "0xa478c2975ab1ea89e8196811f51a7b7ade33eb11", + "0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11", "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", @@ -130,7 +165,7 @@ }, "network": "1", "addresses": [ - "0xa478c2975ab1ea89e8196811f51a7b7ade33eb11", + "0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11", "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", @@ -171,7 +206,7 @@ }, "network": "1", "addresses": [ - "0xa478c2975ab1ea89e8196811f51a7b7ade33eb11", + "0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11", "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", diff --git a/src/strategies/math/index.ts b/src/strategies/math/index.ts index 73384e18c..ab418cd20 100644 --- a/src/strategies/math/index.ts +++ b/src/strategies/math/index.ts @@ -13,7 +13,7 @@ import { } from './options'; export const author = 'xJonathanLEI'; -export const version = '0.2.1'; +export const version = '0.2.2'; export async function strategy( space, @@ -140,6 +140,17 @@ function resolveOperation( ) ); } + case Operation.MINUS: { + const arr = Object.entries(resolvedOperands[0]).map( + ([address, score]: [string, number]) => [ + address, + score > resolvedOperands[1][address] + ? score - resolvedOperands[1][address] + : 0 + ] + ); + return Object.fromEntries(arr); + } } } diff --git a/src/strategies/math/options.ts b/src/strategies/math/options.ts index c8982c548..82ba85ed3 100644 --- a/src/strategies/math/options.ts +++ b/src/strategies/math/options.ts @@ -29,7 +29,8 @@ export enum Operation { AIfLteB = 'a-if-lte-b', AIfGtB = 'a-if-gt-b', AIfGteB = 'a-if-gte-b', - Multiply = 'multiply' + Multiply = 'multiply', + MINUS = 'minus' } interface LegacyFields { @@ -62,7 +63,8 @@ const operandCountByOperation: Record = { [Operation.AIfLtB]: 3, [Operation.AIfLteB]: 3, [Operation.AIfGtB]: 3, - [Operation.AIfGteB]: 3 + [Operation.AIfGteB]: 3, + [Operation.MINUS]: 2 }; export function validateOptions(rawOptions: OptionalOptions): Options { @@ -81,7 +83,8 @@ export function validateOptions(rawOptions: OptionalOptions): Options { rawOptions.operation !== Operation.AIfLteB && rawOptions.operation !== Operation.AIfGtB && rawOptions.operation !== Operation.AIfGteB && - rawOptions.operation !== Operation.Multiply + rawOptions.operation !== Operation.Multiply && + rawOptions.operation !== Operation.MINUS ) { throw new Error('Invalid `operation`'); } From f5ccbba92b7dfe4d6312dfc49130a25f47c93a33 Mon Sep 17 00:00:00 2001 From: Chuddy Date: Fri, 24 Mar 2023 10:39:48 -0700 Subject: [PATCH 343/815] add aura vault deposit token underlying asset balance [aura-vault-balance-of-single-asset] (#1110) * Add Aura Vault Deposit Token Underlying Asset Balance * Update src/strategies/aura-vault-balance-of-single-asset/README.md --------- Co-authored-by: Chaitanya --- .../README.md | 30 +++++++++ .../examples.json | 21 ++++++ .../index.ts | 64 +++++++++++++++++++ src/strategies/index.ts | 2 + 4 files changed, 117 insertions(+) create mode 100644 src/strategies/aura-vault-balance-of-single-asset/README.md create mode 100644 src/strategies/aura-vault-balance-of-single-asset/examples.json create mode 100644 src/strategies/aura-vault-balance-of-single-asset/index.ts diff --git a/src/strategies/aura-vault-balance-of-single-asset/README.md b/src/strategies/aura-vault-balance-of-single-asset/README.md new file mode 100644 index 000000000..7b1cfe56b --- /dev/null +++ b/src/strategies/aura-vault-balance-of-single-asset/README.md @@ -0,0 +1,30 @@ +# aura-vault-balance-of-single-asset + +This strategy returns the balance of an underlying asset in a BPT LP pair staked on Aura + +For example: +- aura50WETH-50AURA-vault total supply: 137,880 (staked BPT) +- 50WETH-50AURA total supply: 145,710 (unstaked BPT) +- token of interest (either WETH or AURA): AURA +- Alice aura50WETH-50AURA-vault balance: 50,000 +- 50WETH-50AURA total Aura balance: 1,878,388 + +_Note: aura50WETH-50AURA-vault and 50WETH-50AURA minted 1:1_ + +Alice AURA balance: 1,878,388 AURA * 50,000 / 145,710 = 644,563 AURA + +## Params + +- `auraVaultDeposit` - (**Required**, `string`) Address of aura vault deposit token (ex: aura50WETH-50AURA-vault address) +- `tokenIndex` - (**Required**, `string`) Index of token in 50/50 pair on Balancer Vault +- `decimals` - (**Required**, `string`) Decimals of underlying asset + +Here is an example of parameters: + +```json +{ + "auraLocker": "0x712cc5bed99aa06fc4d5fb50aea3750fa5161d0f", + "auraVoterProxy": "1", + "votingEscrow": "18" +} +``` diff --git a/src/strategies/aura-vault-balance-of-single-asset/examples.json b/src/strategies/aura-vault-balance-of-single-asset/examples.json new file mode 100644 index 000000000..bcb14ae85 --- /dev/null +++ b/src/strategies/aura-vault-balance-of-single-asset/examples.json @@ -0,0 +1,21 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "aura-vault-balance-of-single-asset", + "params": { + "auraVaultDeposit": "0x712cc5bed99aa06fc4d5fb50aea3750fa5161d0f", + "tokenIndex": "1", + "decimals": "18" + } + }, + "network": "1", + "addresses": [ + "0x905c1cA2ac32eE0799E4Aa31927f1166A93F3b17", + "0x4F76fF660dc5e37b098De28E6ec32978E4b5bEb6", + "0xDA6b2a5e0c56542984d84A710F90EefD94CA1991", + "0xa669070D106E96CC2390523E9745B425a1b3a0E0" + ], + "snapshot": 16897224 + } +] diff --git a/src/strategies/aura-vault-balance-of-single-asset/index.ts b/src/strategies/aura-vault-balance-of-single-asset/index.ts new file mode 100644 index 000000000..954f93812 --- /dev/null +++ b/src/strategies/aura-vault-balance-of-single-asset/index.ts @@ -0,0 +1,64 @@ +import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'chuddster'; +export const version = '0.1.0'; + +const BALANCER_VAULT = "0xBA12222222228d8Ba445958a75a0704d566BF2C8" + +const abi = [ + 'function asset() external view returns (address)', + 'function getPoolId() external view returns (bytes32)', + 'function totalSupply() external view returns (uint256)', + 'function balanceOf(address account) external view returns (uint256)', + 'function getPoolTokens(bytes32 poolId) external view returns (address[] tokens, uint256[] balances, uint256 lastChangeBlock)' +]; + +interface Params { + auraVaultDeposit: string; + tokenIndex: string; + decimals: string; +} + +export async function strategy( + space, + network, + provider, + addresses, + options: Params, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multi = new Multicaller(network, provider, abi, { blockTag }); + + multi.call('bptAsset', options.auraVaultDeposit, 'asset', []); + + const bptAssetResult: Record = await multi.execute(); + + multi.call('poolId', bptAssetResult.bptAsset, 'getPoolId', []) + + const poolIdResult: Record = await multi.execute(); + + multi.call('underlyingBalance', BALANCER_VAULT, 'getPoolTokens', [poolIdResult.poolId]) + + const underlyingBalanceResult = await multi.execute(); + const underlyingBalance = underlyingBalanceResult.underlyingBalance.balances[parseInt(options.tokenIndex)] + + multi.call('bptTotalSupply', bptAssetResult.bptAsset, 'totalSupply', []) + + const bptTotalSupply: Record = await multi.execute(); + + addresses.forEach((address) => + multi.call(address, options.auraVaultDeposit, 'balanceOf', [address]) + ); + const result: Record = await multi.execute(); + + return Object.fromEntries( + Object.entries(result).map(([address, balance]) => [ + address, + parseFloat(formatUnits(balance.mul(underlyingBalance).div(bptTotalSupply.bptTotalSupply), parseInt(options.decimals))) + ]) + ); +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index df152e78d..4b70dcde8 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -352,6 +352,7 @@ import * as arrakisFinance from './arrakis-finance'; import * as auraFinance from './aura-vlaura-vebal'; import * as auraFinanceWithOverrides from './aura-vlaura-vebal-with-overrides'; import * as auraBalanceOfVlauraVebal from './aura-balance-of-vlaura-vebal'; +import * as auraBalanceOfSingleAsset from './aura-vault-balance-of-single-asset'; import * as rocketpoolNodeOperator from './rocketpool-node-operator'; import * as earthfundChildDaoStakingBalance from './earthfund-child-dao-staking-balance'; import * as unipilotVaultPilotBalance from './unipilot-vault-pilot-balance'; @@ -789,6 +790,7 @@ const strategies = { 'aura-vlaura-vebal': auraFinance, 'aura-vlaura-vebal-with-overrides': auraFinanceWithOverrides, 'aura-balance-of-vlaura-vebal': auraBalanceOfVlauraVebal, + 'aura-vault-balance-of-single-asset': auraBalanceOfSingleAsset, 'rocketpool-node-operator': rocketpoolNodeOperator, 'earthfund-child-dao-staking-balance': earthfundChildDaoStakingBalance, 'sd-boost-twavp': sdBoostTWAVP, From 713a7579e9f313ff7585a2272864f7e92f7186c6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 25 Mar 2023 23:16:25 +0530 Subject: [PATCH 344/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.74 (#1108) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 32e83c20d..35dad0ff8 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.73", + "@snapshot-labs/snapshot.js": "^0.4.74", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index f0b20cf18..4bf0185b4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.73": - version "0.4.73" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.73.tgz#8e7973dd94f44c2fb7479b6b2ae0c48ec59b0ffa" - integrity sha512-xkuwM3sk5yTcA9vUxcHzkZj0ZbCBmIcY21MKeMFXWoo7TvfhX5lpw5BIbBsW6QC72JLZQ9bKxG7zvXRNtOTy6Q== +"@snapshot-labs/snapshot.js@^0.4.74": + version "0.4.74" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.74.tgz#edce76c5003409a64fc071e0b379a326b66eddda" + integrity sha512-OfOkkJG2D/vI4oaC+PkOl+qxDnP7wLAD6RVQap8slNXvwkXBJWQFdPBJRXFo6ulrmq4n4w72aFFlutDht02vTA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 5a16e6f2dc9423ae24c29cd0b90bda7863c22eea Mon Sep 17 00:00:00 2001 From: Sam <51686767+samuveth@users.noreply.github.com> Date: Sun, 26 Mar 2023 02:04:34 +0700 Subject: [PATCH 345/815] Add schema to for basic validation (#1111) Co-authored-by: Chaitanya --- src/validations/basic/schema.json | 44 +++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/validations/basic/schema.json diff --git a/src/validations/basic/schema.json b/src/validations/basic/schema.json new file mode 100644 index 000000000..12006feee --- /dev/null +++ b/src/validations/basic/schema.json @@ -0,0 +1,44 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Validation", + "definitions": { + "Validation": { + "title": "Basic validation", + "type": "object", + "properties": { + "minScore": { + "title": "Minimum score", + "type": "number", + "minimum": 1 + }, + "strategies": { + "$id": "strategies", + "title": "Strategies", + "type": "array", + "items": { + "title": "Strategy", + "type": "object", + "default": { + "name": "erc20-balance-of", + "network": "1", + "params": {} + }, + "properties": { + "name": { + "type": "string" + }, + "network": { + "type": "string" + }, + "params": { + "type": "object" + } + } + } + } + }, + "required": ["minScore"], + "additionalProperties": false + } + } +} From 320db4f05e141a12d6655681ebcc779345da81e2 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Sun, 26 Mar 2023 01:09:52 +0530 Subject: [PATCH 346/815] Revert "Add schema to for basic validation (#1111)" (#1112) This reverts commit 5a16e6f2dc9423ae24c29cd0b90bda7863c22eea. --- src/validations/basic/schema.json | 44 ------------------------------- 1 file changed, 44 deletions(-) delete mode 100644 src/validations/basic/schema.json diff --git a/src/validations/basic/schema.json b/src/validations/basic/schema.json deleted file mode 100644 index 12006feee..000000000 --- a/src/validations/basic/schema.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$ref": "#/definitions/Validation", - "definitions": { - "Validation": { - "title": "Basic validation", - "type": "object", - "properties": { - "minScore": { - "title": "Minimum score", - "type": "number", - "minimum": 1 - }, - "strategies": { - "$id": "strategies", - "title": "Strategies", - "type": "array", - "items": { - "title": "Strategy", - "type": "object", - "default": { - "name": "erc20-balance-of", - "network": "1", - "params": {} - }, - "properties": { - "name": { - "type": "string" - }, - "network": { - "type": "string" - }, - "params": { - "type": "object" - } - } - } - } - }, - "required": ["minScore"], - "additionalProperties": false - } - } -} From e1497e54d831104d54f0c460f0345c05fa45e88f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 00:16:27 +0530 Subject: [PATCH 347/815] Automated lint (#1114) Co-authored-by: ChaituVR --- .../index.ts | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/strategies/aura-vault-balance-of-single-asset/index.ts b/src/strategies/aura-vault-balance-of-single-asset/index.ts index 954f93812..19001ea0e 100644 --- a/src/strategies/aura-vault-balance-of-single-asset/index.ts +++ b/src/strategies/aura-vault-balance-of-single-asset/index.ts @@ -5,7 +5,7 @@ import { Multicaller } from '../../utils'; export const author = 'chuddster'; export const version = '0.1.0'; -const BALANCER_VAULT = "0xBA12222222228d8Ba445958a75a0704d566BF2C8" +const BALANCER_VAULT = '0xBA12222222228d8Ba445958a75a0704d566BF2C8'; const abi = [ 'function asset() external view returns (address)', @@ -37,18 +37,23 @@ export async function strategy( const bptAssetResult: Record = await multi.execute(); - multi.call('poolId', bptAssetResult.bptAsset, 'getPoolId', []) + multi.call('poolId', bptAssetResult.bptAsset, 'getPoolId', []); - const poolIdResult: Record = await multi.execute(); + const poolIdResult: Record = await multi.execute(); - multi.call('underlyingBalance', BALANCER_VAULT, 'getPoolTokens', [poolIdResult.poolId]) + multi.call('underlyingBalance', BALANCER_VAULT, 'getPoolTokens', [ + poolIdResult.poolId + ]); - const underlyingBalanceResult = await multi.execute(); - const underlyingBalance = underlyingBalanceResult.underlyingBalance.balances[parseInt(options.tokenIndex)] + const underlyingBalanceResult = await multi.execute(); + const underlyingBalance = + underlyingBalanceResult.underlyingBalance.balances[ + parseInt(options.tokenIndex) + ]; - multi.call('bptTotalSupply', bptAssetResult.bptAsset, 'totalSupply', []) + multi.call('bptTotalSupply', bptAssetResult.bptAsset, 'totalSupply', []); - const bptTotalSupply: Record = await multi.execute(); + const bptTotalSupply: Record = await multi.execute(); addresses.forEach((address) => multi.call(address, options.auraVaultDeposit, 'balanceOf', [address]) @@ -58,7 +63,12 @@ export async function strategy( return Object.fromEntries( Object.entries(result).map(([address, balance]) => [ address, - parseFloat(formatUnits(balance.mul(underlyingBalance).div(bptTotalSupply.bptTotalSupply), parseInt(options.decimals))) + parseFloat( + formatUnits( + balance.mul(underlyingBalance).div(bptTotalSupply.bptTotalSupply), + parseInt(options.decimals) + ) + ) ]) ); } From 10648ed7f8c8950a315b16eff1393ab0b3e0f577 Mon Sep 17 00:00:00 2001 From: Leez <94301129+0xleez@users.noreply.github.com> Date: Mon, 27 Mar 2023 22:27:26 +0300 Subject: [PATCH 348/815] [jpegd-locked-jpeg-of] Update - get contract addresses from subgraph instead of params (#1115) * jpegd-boosts * rename * readme * switched from object to string abi * query subgraph at blockNumber * ignore new collections * get nftValueProvider address from subgraph instead of params * Update index.ts --------- Co-authored-by: Chaitanya --- .../jpegd-locked-jpeg-of/examples.json | 43 ++++++------------- src/strategies/jpegd-locked-jpeg-of/index.ts | 20 +++------ 2 files changed, 21 insertions(+), 42 deletions(-) diff --git a/src/strategies/jpegd-locked-jpeg-of/examples.json b/src/strategies/jpegd-locked-jpeg-of/examples.json index 548074751..a631f29ef 100644 --- a/src/strategies/jpegd-locked-jpeg-of/examples.json +++ b/src/strategies/jpegd-locked-jpeg-of/examples.json @@ -1,31 +1,16 @@ [ - { - "name": "Example query", - "strategy": { - "name": "jpegd-locked-jpeg-of", - "params": { - "collectionToProviderAddress": { - "CRYPTOPUNKS": "0xdf7806eaa13497efffdb1541d6b0fdd1a9566fd0", - "ETHERROCKS": "0x9921da2908cc59b13ddbcf45e64bfa91c78c4249", - "BAYC": "0x5b9cAA47A52e4BfbBce2f2A9f858c2A501B48C42", - "MAYC": "0xdEd112453BD8EA88CdaB214CFD92Ab06E232E9d7", - "DOODLES": "0xdd245B7823ee82D14419CE072Ef815868F0D1f1A", - "PUDGYPENGUINS": "0xd0bf9A40FebDfCA596fde589a343C6cDA37A7B90", - "AZUKI": "0xcaA0aa80637262fd3Ba6DD5b5598a2BAFAc27cE8", - "CLONEX": "0xb36B65400E13FF57dFDa29bBb7dC79eaA7ecA14C", - "AUTOGLYPHS": "0xa74AbB04486f6926802cF6c3719c41b9ea10E49b", - "FIDENZAS": "0x1a6fA849D5bF62F9b7B83D125E77e15292c54b4f", - "RINGERS": "0x927318B867f0939Ab501dFd7b1B8d60E52ea5B59" + { + "name": "Example query", + "strategy": { + "name": "jpegd-locked-jpeg-of", + "params": {} }, - "start": 15363080 - } - }, - "network": "1", - "addresses": [ - "0x9c5083dd4838e120dbeac44c052179692aa5dac5", - "0xB0dAfc466871c29662E5cbf4227322C96A8Ccbe9", - "0x0017dfe08bcc0dc9a323ca5d4831e371534e9320" - ], - "snapshot": 16119881 - } -] + "network": "1", + "addresses": [ + "0x9c5083dd4838e120dbeac44c052179692aa5dac5", + "0xB0dAfc466871c29662E5cbf4227322C96A8Ccbe9", + "0x0017dfe08bcc0dc9a323ca5d4831e371534e9320" + ], + "snapshot": 16119881 + } +] \ No newline at end of file diff --git a/src/strategies/jpegd-locked-jpeg-of/index.ts b/src/strategies/jpegd-locked-jpeg-of/index.ts index 921188f89..8a9bdad01 100644 --- a/src/strategies/jpegd-locked-jpeg-of/index.ts +++ b/src/strategies/jpegd-locked-jpeg-of/index.ts @@ -4,7 +4,7 @@ import { multicall } from '../../utils'; import { subgraphRequest } from '../../utils'; export const author = '0xleez'; -export const version = '0.1.0'; +export const version = '0.1.1'; const SUBGRAPH_URL = { '1': 'https://api.thegraph.com/subgraphs/name/jpegd/jpegd-core-mainnet' @@ -25,8 +25,6 @@ export async function strategy( ) { const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - const { collectionToProviderAddress } = options; - const params = { jpeglocks: { __args: { @@ -36,7 +34,7 @@ export async function strategy( block: blockTag != 'latest' ? { number: blockTag } : null }, owner: { id: true }, - collection: { id: true }, + collection: { id: true, nftValueProviderAddress: true }, type: true, nftIndex: true, amount: true, @@ -51,15 +49,11 @@ export async function strategy( network, provider, abi, - jpegLocks - .filter((jpegLock) => - Boolean(collectionToProviderAddress[jpegLock.collection.id]) - ) - .map((jpegLock: any) => [ - collectionToProviderAddress[jpegLock.collection.id], - jpegLock.type === 'LTV' ? 'ltvBoostPositions' : 'traitBoostPositions', - [jpegLock.nftIndex] - ]), + jpegLocks.map((jpegLock: any) => [ + getAddress(jpegLock.collection.nftValueProviderAddress), + jpegLock.type === 'LTV' ? 'ltvBoostPositions' : 'traitBoostPositions', + [jpegLock.nftIndex] + ]), { blockTag } ); From be15fd38d23abba90c933cd19aa9ba8096ee1350 Mon Sep 17 00:00:00 2001 From: Isaac Martin Date: Tue, 28 Mar 2023 03:45:23 -0400 Subject: [PATCH 349/815] add erc115 weighted by token id [erc1155-weighted-by-id] (#1106) * weighted * change spelling * remove unneeed file * update examples --- .../erc1155-weighted-by-id/README.md | 11 +++++ .../erc1155-weighted-by-id/examples.json | 40 ++++++++++++++++ .../erc1155-weighted-by-id/index.ts | 48 +++++++++++++++++++ src/strategies/index.ts | 3 ++ 4 files changed, 102 insertions(+) create mode 100644 src/strategies/erc1155-weighted-by-id/README.md create mode 100644 src/strategies/erc1155-weighted-by-id/examples.json create mode 100644 src/strategies/erc1155-weighted-by-id/index.ts diff --git a/src/strategies/erc1155-weighted-by-id/README.md b/src/strategies/erc1155-weighted-by-id/README.md new file mode 100644 index 000000000..f3006fb15 --- /dev/null +++ b/src/strategies/erc1155-weighted-by-id/README.md @@ -0,0 +1,11 @@ +# erc1155-weighted-by-id + +This strategy takes in an array of ERC1155 token ids and the weight attached to each token ID. It returns the highest value a wallet holds, and does not calculate a sum. + +## Params + +| Param | Description | Required | +| --------------------------------------------------------------------------------- | ----------------------------------------------------------- | -------- | +| ids | Array of ERC1155 Token IDs | Yes | +| weight | Array of Weights that map to the TokenID of the same index. | +| The balance of an owners token is multiplied by the weight to calculate the score | Yes | diff --git a/src/strategies/erc1155-weighted-by-id/examples.json b/src/strategies/erc1155-weighted-by-id/examples.json new file mode 100644 index 000000000..c71d5e1cf --- /dev/null +++ b/src/strategies/erc1155-weighted-by-id/examples.json @@ -0,0 +1,40 @@ +[ + { + "name": "ERC1155 Weighted by id", + "strategy": { + "name": "erc1155-weighted-by-id", + "params": { + "symbol": "COINAGE", + "address": "0x4776defcf622c60c6419cccc9ee9e9042fadf3f7", + "ids": ["1", "3"], + "weight": [25, 1] + } + }, + "network": "1", + "addresses": [ + "0x2274091DAad5B7bF734f426B9aA8513955075b9E", + "0x65A922561638015E394A20356C31E9A6217513B8", + "0x1A9deC77516BA05316938D7Fb32F51D646f8d91f" + ], + "snapshot": 16648731 + }, + { + "name": "Example query", + "strategy": { + "name": "erc1155-weighted-by-id", + "params": { + "symbol": "COINAGE", + "address": "0x4776defcf622c60c6419cccc9ee9e9042fadf3f7", + "ids": ["2", "1"], + "weight": [50, 10] + } + }, + "network": "1", + "addresses": [ + "0x2274091DAad5B7bF734f426B9aA8513955075b9E", + "0x65A922561638015E394A20356C31E9A6217513B8", + "0x1A9deC77516BA05316938D7Fb32F51D646f8d91f" + ], + "snapshot": 16648731 + } +] diff --git a/src/strategies/erc1155-weighted-by-id/index.ts b/src/strategies/erc1155-weighted-by-id/index.ts new file mode 100644 index 000000000..2342662c7 --- /dev/null +++ b/src/strategies/erc1155-weighted-by-id/index.ts @@ -0,0 +1,48 @@ +import { multicall } from '../../utils'; + +export const author = 'isaac-martin'; +export const version = '1.0.0'; + +const abi = [ + 'function balanceOfBatch(address[], uint256[]) external view returns (uint256[])' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const response = await multicall( + network, + provider, + abi, + addresses.map((address: any) => [ + options.address, + 'balanceOfBatch', + [Array(options.ids.length).fill(address), options.ids] + ]), + { blockTag } + ); + + const getWeightCount = (balance: number, currentIndex: number): number => { + // will either return 0 or 1 depending if the user holds one of these tokens + const count = Math.min(balance, 1); + return count * options.weight[currentIndex]; + }; + + return Object.fromEntries( + response.map((values, i) => [ + addresses[i], + values[0].reduce( + (prev, curr, currentIndex) => + Math.max(prev, getWeightCount(curr.toNumber(), currentIndex)), + 0 + ) + ]) + ); +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 4b70dcde8..c1a381330 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -295,6 +295,7 @@ import * as givethGnosisBalanceV2 from './giveth-gnosis-balance-v2'; import * as givethBalancerBalance from './giveth-balancer-balance'; import * as erc1155BalanceOfIds from './erc1155-balance-of-ids'; import * as erc1155BalanceOfIdsWeighted from './erc1155-balance-of-ids-weighted'; +import * as erc1155weighted from './erc1155-weighted-by-id'; import * as stakersAndHolders from './stakers-and-holders'; import * as banksyDao from './banksy-dao'; import * as spacey2025 from './spacey2025'; @@ -433,6 +434,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'; + const strategies = { 'izumi-veizi': izumiVeiZi, 'eco-voting-power': ecoVotingPower, @@ -736,6 +738,7 @@ const strategies = { 'staked-uniswap-modifiable': stakedUniswapModifiable, 'erc1155-balance-of-ids': erc1155BalanceOfIds, 'erc1155-balance-of-ids-weighted': erc1155BalanceOfIdsWeighted, + 'erc1155-weighted-by-id': erc1155weighted, 'stakers-and-holders': stakersAndHolders, 'banksy-dao': banksyDao, spacey2025: spacey2025, From 0d8225d0f518b068312ff3dbada49b0623ce21f1 Mon Sep 17 00:00:00 2001 From: Leez <94301129+0xleez@users.noreply.github.com> Date: Tue, 28 Mar 2023 10:46:22 +0300 Subject: [PATCH 350/815] update readme (#1116) --- src/strategies/jpegd-locked-jpeg-of/README.md | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/src/strategies/jpegd-locked-jpeg-of/README.md b/src/strategies/jpegd-locked-jpeg-of/README.md index 6769b1e49..92436e6f7 100644 --- a/src/strategies/jpegd-locked-jpeg-of/README.md +++ b/src/strategies/jpegd-locked-jpeg-of/README.md @@ -1,24 +1,3 @@ # jpegd-locked-jpeg-of This strategy returns voters' aggregated locked JPEG token balance for Trait and LTV Boosts on the JPEG'd platform - -## Params - -- `collectionToProviderAddress` - (**Required**, `object`) Collection name (uppercase) to NftValueProvider address - -Here is an example of parameters: - -```json -{ - "collectionToProviderAddress": { - "CRYPTOPUNKS": "0xdf7806eaa13497efffdb1541d6b0fdd1a9566fd0", - "ETHERROCKS": "0x9921da2908cc59b13ddbcf45e64bfa91c78c4249", - "BAYC": "0x5b9cAA47A52e4BfbBce2f2A9f858c2A501B48C42", - "MAYC": "0xdEd112453BD8EA88CdaB214CFD92Ab06E232E9d7", - "DOODLES": "0xdd245B7823ee82D14419CE072Ef815868F0D1f1A", - "PUDGYPENGUINS": "0xd0bf9A40FebDfCA596fde589a343C6cDA37A7B90", - "AZUKI": "0xcaA0aa80637262fd3Ba6DD5b5598a2BAFAc27cE8", - "CLONEX": "0xb36B65400E13FF57dFDa29bBb7dC79eaA7ecA14C" - } -} -``` From 4da838e50c273eb905daee82ffc36e177fe7cae7 Mon Sep 17 00:00:00 2001 From: gzeon Date: Wed, 29 Mar 2023 02:28:19 +0800 Subject: [PATCH 351/815] [arbitrum] feat: Arbitrum DAO Percentage of Votable Supply (#1118) * feat: Arbitrum DAO Percentage of Votable Supply * docs: remove unused option --- src/validations/arbitrum/README.md | 19 +++++++++ src/validations/arbitrum/examples.json | 27 +++++++++++++ src/validations/arbitrum/index.ts | 56 ++++++++++++++++++++++++++ src/validations/index.ts | 4 +- 4 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 src/validations/arbitrum/README.md create mode 100644 src/validations/arbitrum/examples.json create mode 100644 src/validations/arbitrum/index.ts diff --git a/src/validations/arbitrum/README.md b/src/validations/arbitrum/README.md new file mode 100644 index 000000000..21afa8f33 --- /dev/null +++ b/src/validations/arbitrum/README.md @@ -0,0 +1,19 @@ +# Arbitrum DAO Percentage of Votable Supply + +- [Overview](#overview) +- [Options](#options) + +## Overview + +This validation module check the number of basis points (bps, i.e. 0.01%) of vote a delegate control, which is used to enforce the 0.01% snapshot proposer requirement specified in [The Constitution of the Arbitrum DAO](https://docs.arbitrum.foundation/dao-constitution). + +Arbitrum use an EXCLUDE_ADDRESS (0x00000000000000000000000000000000000A4B86) to mark non-votable tokens, tokens delegated to the EXCLUDE_ADDRESS will be excluded from votable supply. + +You should use this validation module with erc20-votes strategy configured with the same token address and decimals. + +## Options + +- **minBps:** The minimum basis points required to pass validation, e.g. 1 +- **address:** The address of the ERC-20 token contract, e.g. "0x912CE59144191C1204E64559FE8253a0e49E6548" +- **decimals:** The decimal of the token, e.g. 18 +- **excludeaddr** The special delegation address for non-votable token, e.g. "0x00000000000000000000000000000000000A4B86" diff --git a/src/validations/arbitrum/examples.json b/src/validations/arbitrum/examples.json new file mode 100644 index 000000000..107d4e284 --- /dev/null +++ b/src/validations/arbitrum/examples.json @@ -0,0 +1,27 @@ +[ + { + "name": "Example of Arbitrum DAO Validation", + "author": "0x0eb5b03c0303f2f47cd81d7be4275af8ed347576", + "space": "arbitrumfoundation.eth", + "network": "42161", + "snapshot": "latest", + "params": { + "minBps": 1, + "address": "0x912CE59144191C1204E64559FE8253a0e49E6548", + "decimals": 18, + "excludeaddr": "0x00000000000000000000000000000000000A4B86", + "strategies": [ + { + "name": "erc20-votes", + "params": { + "symbol": "ARB", + "address": "0x912CE59144191C1204E64559FE8253a0e49E6548", + "decimals": 18 + }, + "network": "42161" + } + ] + } + } +] + diff --git a/src/validations/arbitrum/index.ts b/src/validations/arbitrum/index.ts new file mode 100644 index 000000000..6c8d51e53 --- /dev/null +++ b/src/validations/arbitrum/index.ts @@ -0,0 +1,56 @@ +import Validation from '../validation'; +import { getProvider, getScoresDirect } from '../../utils'; +import { multicall } from '../../utils'; +import { formatUnits } from '@ethersproject/units'; + +const abi = [ + 'function getVotes(address account) view returns (uint256)', + 'function totalSupply() view returns (uint256)' +]; + +export default class extends Validation { + public id = 'arbitrum'; + public github = 'gzeoneth'; + public version = '0.1.0'; + public title = 'Arbitrum DAO Percentage of Votable Supply'; + public description = 'Use with erc20-votes to validate by percentage of votable supply.'; + + async validate(): Promise { + if (this.params.strategies?.length > 8) + throw new Error(`Max number of strategies exceeded`); + const minBps = this.params.minBps; + const decimals = this.params.decimals; + const excludeaddr = this.params.excludeaddr ?? '0x00000000000000000000000000000000000A4B86'; + + if (minBps) { + const scores = await getScoresDirect( + this.space, + this.params.strategies, + this.network, + getProvider(this.network), + [this.author], + this.snapshot || 'latest' + ); + const totalScore: any = scores + .map((score: any) => + Object.values(score).reduce((a, b: any) => a + b, 0) + ) + .reduce((a, b: any) => a + b, 0); + const [[totalSupply], [excludedSupply]] = await multicall( + this.network, + getProvider(this.network), + abi, + [ + [this.params.address, 'totalSupply', []], + [this.params.address, 'getVotes', [excludeaddr]] + ], + { blockTag: this.snapshot || 'latest' } + ); + const votableSupply = parseFloat(formatUnits(totalSupply.sub(excludedSupply).toString(), decimals)) + const bpsOfVotable = totalScore * 10000 / votableSupply + if (bpsOfVotable < minBps) return false; + } + + return true; + } +} diff --git a/src/validations/index.ts b/src/validations/index.ts index 13fd2225d..199e4af89 100644 --- a/src/validations/index.ts +++ b/src/validations/index.ts @@ -3,11 +3,13 @@ import path from 'path'; import basic from './basic'; import passportGated from './passport-gated'; import passportWeighted from './passport-weighted'; +import arbitrum from './arbitrum'; const validationClasses = { basic, 'passport-gated': passportGated, - 'passport-weighted': passportWeighted + 'passport-weighted': passportWeighted, + 'arbitrum': arbitrum }; const validations = {}; From d0f12262b154756f9d248b2f22d4cd6a11da6666 Mon Sep 17 00:00:00 2001 From: rsquare Date: Fri, 31 Mar 2023 18:36:36 +0200 Subject: [PATCH 352/815] Otterspace - new networks [otterspace-badges] (#1117) * Adding mainnet & opti-goerli. Pickign highest badge weight * Update src/strategies/otterspace-badges/index.ts Co-authored-by: Chaitanya * fix: schema change in badge owner --------- Co-authored-by: Chaitanya --- .../otterspace-badges/examples.json | 20 ++++++------- src/strategies/otterspace-badges/index.ts | 30 ++++++++++++++----- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/strategies/otterspace-badges/examples.json b/src/strategies/otterspace-badges/examples.json index 4d73e27f2..e92a36fb1 100644 --- a/src/strategies/otterspace-badges/examples.json +++ b/src/strategies/otterspace-badges/examples.json @@ -24,10 +24,10 @@ }, "network": "5", "addresses": [ - "0xbb9ecfd5685502977b5b7c1ac0cdff8c136a4da8", - "0x33d0bbd05cf3c7e040d33bc1f338585a087e5dd9", + "0xbB9ECfD5685502977B5b7C1AC0cdff8C136A4Da8", + "0x33d0BBd05cf3C7E040d33bc1F338585A087e5Dd9", "0x0F1c502d4EF5b1940a7A77062e51353D8B366547", - "0xeade2ceedea3b8d0d1d10537f507b9d262870748" + "0xEAde2cEeDeA3b8d0D1d10537f507b9d262870748" ], "snapshot": 7509588 }, @@ -43,10 +43,10 @@ }, "network": "5", "addresses": [ - "0xbb9ecfd5685502977b5b7c1ac0cdff8c136a4da8", - "0x33d0bbd05cf3c7e040d33bc1f338585a087e5dd9", + "0xbB9ECfD5685502977B5b7C1AC0cdff8C136A4Da8", + "0x33d0BBd05cf3C7E040d33bc1F338585A087e5Dd9", "0x0F1c502d4EF5b1940a7A77062e51353D8B366547", - "0xeade2ceedea3b8d0d1d10537f507b9d262870748" + "0xEAde2cEeDeA3b8d0D1d10537f507b9d262870748" ], "snapshot": 7509588 }, @@ -71,8 +71,8 @@ }, "network": "10", "addresses": [ - "0x76d84163bc0bbf58d6d3f2332f8a9c5b339df983", - "0x73677662f66088236ddfc95da42e405cf3f4ce13", + "0x76D84163bc0BbF58d6d3F2332f8A9c5B339dF983", + "0x73677662f66088236dDFc95DA42e405Cf3F4ce13", "0x0F1c502d4EF5b1940a7A77062e51353D8B366547" ], "snapshot": 21528802 @@ -89,8 +89,8 @@ }, "network": "10", "addresses": [ - "0x76d84163bc0bbf58d6d3f2332f8a9c5b339df983", - "0x73677662f66088236ddfc95da42e405cf3f4ce13", + "0x76D84163bc0BbF58d6d3F2332f8A9c5B339dF983", + "0x73677662f66088236dDFc95DA42e405Cf3F4ce13", "0x0F1c502d4EF5b1940a7A77062e51353D8B366547" ], "snapshot": 21528802 diff --git a/src/strategies/otterspace-badges/index.ts b/src/strategies/otterspace-badges/index.ts index 731a97b41..20bd5ec3a 100644 --- a/src/strategies/otterspace-badges/index.ts +++ b/src/strategies/otterspace-badges/index.ts @@ -2,11 +2,14 @@ import { error } from 'console'; import { subgraphRequest } from '../../utils'; export const author = 'otterspace-xyz'; -export const version = '1.0.0'; +export const version = '1.0.1'; const OTTERSPACE_SUBGRAPH_API_URLS_BY_CHAIN_ID = { + '1': 'https://api.thegraph.com/subgraphs/name/otterspace-xyz/badges-mainnet', '5': 'https://api.thegraph.com/subgraphs/name/otterspace-xyz/badges-goerli', - '10': 'https://api.thegraph.com/subgraphs/name/otterspace-xyz/badges-optimism' + '10': 'https://api.thegraph.com/subgraphs/name/otterspace-xyz/badges-optimism-alpha', + '420': + 'https://api.thegraph.com/subgraphs/name/otterspace-xyz/badges-optimism-goerli' }; function fetchBadgesForRaft( @@ -36,7 +39,9 @@ function fetchBadgesForRaft( }, block: blockTag != 'latest' ? { number: blockTag } : null }, - owner: true, + owner: { + id: true + }, spec: { id: true } @@ -51,6 +56,7 @@ function getBadgeWeight(specs: any[], badgeSpecID: string): number { if (specs && specs.length > 0) { const specConfig = specs.find((spec: any) => spec.id === badgeSpecID); + badgeWeight = specConfig && isBadgeActive(specConfig.status, specConfig.metadata?.expiresAt || null) @@ -73,11 +79,19 @@ function applyBadgeWeights(badges: [], options: any) { const badgeWeights = {}; badges.forEach((badge: any) => { - const badgeAddress = badge.owner.toLowerCase(); - - if (badgeWeights[badgeAddress]) return; - - badgeWeights[badgeAddress] = getBadgeWeight(options.specs, badge.spec.id); + const badgeAddress = badge.owner.id.toLowerCase(); + + const badgeWeight = getBadgeWeight(options.specs, badge.spec.id); + + // picks the highest weight when multiple badges are held by the same address + if ( + !badgeWeights[badgeAddress] || + badgeWeight > badgeWeights[badgeAddress] + ) { + badgeWeights[badgeAddress] = badgeWeight; + } else { + return; + } }); return badgeWeights; From 38c6a12aafb5a69659c5296931f19d4d4fa2e587 Mon Sep 17 00:00:00 2001 From: JD <103535732+JDoy99@users.noreply.github.com> Date: Sat, 1 Apr 2023 05:07:59 +0100 Subject: [PATCH 353/815] [rdnt-capital-voting] added total dlp strategy (#1109) * [rdnt-capital-dlp] added total dlp check strategy * Create README.md * Added rdnt-capital-locked-dlp strategy * Reverted strategy back to lockedBalances as uint * Updated strategy which returns rdnt amount in locked dLP * added BSC functionality * RDNT in LP strat * Updated name * Update examples.json * Update src/strategies/rdnt-capital-voting/README.md Co-authored-by: Chaitanya * Update README.md --------- Co-authored-by: TomBrandy <103236817+TomBrandy@users.noreply.github.com> Co-authored-by: Chaitanya --- src/strategies/index.ts | 4 +- src/strategies/rdnt-capital-voting/README.md | 11 ++ .../rdnt-capital-voting/examples.json | 40 +++++ src/strategies/rdnt-capital-voting/index.ts | 139 ++++++++++++++++++ 4 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 src/strategies/rdnt-capital-voting/README.md create mode 100644 src/strategies/rdnt-capital-voting/examples.json create mode 100644 src/strategies/rdnt-capital-voting/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index c1a381330..83495a9fe 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -433,6 +433,7 @@ import * as pdnBalancesAndVests from './pdn-balances-and-vests'; 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'; const strategies = { @@ -873,7 +874,8 @@ const strategies = { 'pdn-balances-and-vests': pdnBalancesAndVests, 'lqty-proxy-stakers': lqtyProxyStakers, 'echelon-wallet-prime-and-cached-key-gated': - echelonWalletPrimeAndCachedKeyGated + echelonWalletPrimeAndCachedKeyGated, + 'rdnt-capital-voting': rdntCapitalVoting }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/rdnt-capital-voting/README.md b/src/strategies/rdnt-capital-voting/README.md new file mode 100644 index 000000000..24620446f --- /dev/null +++ b/src/strategies/rdnt-capital-voting/README.md @@ -0,0 +1,11 @@ +This strategy returns the total dLP of a user + +Here is an example of parameters: + +{ + "rdnt": "0x3082cc23568ea640225c2467653db90e9250aaa0", + "lpToken": "0x32DF62DC3AED2CD6224193052CE665DC18165841", + "lockingContract": "0x76ba3eC5f5adBf1C58c91e86502232317EeA72dE", + "balancerPoolId": "0x32df62dc3aed2cd6224193052ce665dc181658410002000000000000000003bd", + "balancerVault": "0xBA12222222228d8Ba445958a75a0704d566BF2C8" + } diff --git a/src/strategies/rdnt-capital-voting/examples.json b/src/strategies/rdnt-capital-voting/examples.json new file mode 100644 index 000000000..cffa2db05 --- /dev/null +++ b/src/strategies/rdnt-capital-voting/examples.json @@ -0,0 +1,40 @@ +[ + { + "name": "RDNT in dLP - Arbitrum", + "strategy": { + "name": "rdnt-capital-voting", + "params": { + "rdnt": "0x3082cc23568ea640225c2467653db90e9250aaa0", + "lpToken": "0x32DF62DC3AED2CD6224193052CE665DC18165841", + "lockingContract": "0x76ba3eC5f5adBf1C58c91e86502232317EeA72dE", + "balancerPoolId": "0x32df62dc3aed2cd6224193052ce665dc181658410002000000000000000003bd", + "balancerVault": "0xBA12222222228d8Ba445958a75a0704d566BF2C8" + } + }, + "network": "42161", + "addresses": [ + "0x2eAA7327e9B5Ff46bc2B7452acE9e44A1528eb84", + "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", + "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e" + ], + "snapshot": 75307012 + }, + { + "name": "RDNT in dLP - BSC", + "strategy": { + "name": "rdnt-capital-voting", + "params": { + "rdnt": "0xf7DE7E8A6bd59ED41a4b5fe50278b3B7f31384dF", + "lpToken": "0x346575fc7f07e6994d76199e41d13dc1575322e1", + "lockingContract": "0x4FD9F7C5ca0829A656561486baDA018505dfcB5E" + } + }, + "network": "56", + "addresses": [ + "0x2b4516253e984b30804356cB5be476ccfB45fa49", + "0x31d64d45dE2c5b0742635da913FCD587BBCd4C5A", + "0x2eAA7327e9B5Ff46bc2B7452acE9e44A1528eb84" + ], + "snapshot": 26920121 + } +] diff --git a/src/strategies/rdnt-capital-voting/index.ts b/src/strategies/rdnt-capital-voting/index.ts new file mode 100644 index 000000000..72ad21a47 --- /dev/null +++ b/src/strategies/rdnt-capital-voting/index.ts @@ -0,0 +1,139 @@ +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller, multicall, call } from '../../utils'; + +export const author = 'JDoy99'; +export const version = '0.1.0'; + +const erc20Abi = [ + 'function balanceOf(address owner) external returns (uint256)' +]; +const lpTokenAbi = [ + 'function getReserves() view returns (uint112, uint112, uint32)', + 'function token0() view returns (address)', + 'function totalSupply() view returns (uint256)' +]; +const mfdAbi = [ + 'function lockedBalances(address) view returns (uint256, uint256, uint256, uint256, tuple(uint256,uint256,uint256,uint256)[])' +]; +const balancerVaultAbi = [ + 'function getPoolTokenInfo(bytes32,address) view returns (uint256)' +]; + +const toJsNum = (bn: BigNumberish) => { + return parseFloat(formatUnits(bn)); +}; + +const rdntPerBalancerLpToken = async (network, provider, options, blockTag) => { + const rdntInVault = await call(provider, balancerVaultAbi, [ + options.balancerVault, + 'getPoolTokenInfo', + [options.balancerPoolId, options.rdnt], + { blockTag } + ]); + const rdntInLp = toJsNum(rdntInVault); + + const [totalSupplyBn] = await multicall( + network, + provider, + lpTokenAbi, + [[options.lpToken, 'totalSupply']], + { blockTag } + ); + + const totalSupply = toJsNum(totalSupplyBn[0]); + return rdntInLp / totalSupply; +}; + +const rdntPerUniLpToken = async (network, provider, options, blockTag) => { + const [totalSupplyBn, token0s, reserves] = await multicall( + network, + provider, + lpTokenAbi, + [ + [options.lpToken, 'totalSupply'], + [options.lpToken, 'token0'], + [options.lpToken, 'getReserves'] + ], + { blockTag } + ); + + const totalSupply = toJsNum(totalSupplyBn[0]); + const [reserve0, reserve1] = reserves; + const [token0] = token0s; + + let rdntInLp; + if (token0.toLowerCase() === options.rdnt.toLowerCase()) { + rdntInLp = toJsNum(reserve0); + } else { + rdntInLp = toJsNum(reserve1); + } + + return rdntInLp / totalSupply; +}; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + // Get RDNT per LP token (LP provider dependent) + let rdntPerLp; + if (network === '42161') { + rdntPerLp = await rdntPerBalancerLpToken( + network, + provider, + options, + blockTag + ); + } else if (network === '56') { + rdntPerLp = await rdntPerUniLpToken(network, provider, options, blockTag); + } + + // console.log(`RDNT per LP token: ${rdntPerLp}`); + + // Get non-locked LP balances + const lpBalanceMulticall = new Multicaller(network, provider, erc20Abi, { + blockTag + }); + addresses.forEach((address) => + lpBalanceMulticall.call(address, options.lpToken, 'balanceOf', [address]) + ); + const lpBalances: Record = + await lpBalanceMulticall.execute(); + + // Get locked LP balances + const mfdMulticall = new Multicaller(network, provider, mfdAbi, { + blockTag + }); + addresses.forEach((address) => { + mfdMulticall.call(address, options.lockingContract, 'lockedBalances', [ + address + ]); + }); + const lockedBalances = await mfdMulticall.execute(); + + // Combined locked & unlocked LP balances for all users + // TODO: better way of handling this accumulation w/ new typed result obj + Object.keys(lockedBalances).forEach(function (key) { + if (lpBalances.hasOwnProperty(key)) { + lpBalances[key] = + toJsNum(lpBalances[key]) + toJsNum(lockedBalances[key][2]); + } else { + lpBalances[key] = toJsNum(lockedBalances[key][2]); + } + }); + + // User's total LP balance * RDNT per LP token => total RDNT in their LP positions + return Object.fromEntries( + Object.entries(lpBalances).map(([address, balance]) => [ + address, + balance * rdntPerLp + ]) + ); +} From b74977aab743ccba82382890a947a452adc344d6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 2 Apr 2023 23:18:26 +0530 Subject: [PATCH 354/815] Automated lint (#1119) Co-authored-by: ChaituVR --- src/strategies/index.ts | 1 - .../jpegd-locked-jpeg-of/examples.json | 30 +++++++++---------- src/validations/arbitrum/examples.json | 1 - src/validations/arbitrum/index.ts | 12 +++++--- src/validations/index.ts | 2 +- 5 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 83495a9fe..8942c8f8f 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -435,7 +435,6 @@ 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'; - const strategies = { 'izumi-veizi': izumiVeiZi, 'eco-voting-power': ecoVotingPower, diff --git a/src/strategies/jpegd-locked-jpeg-of/examples.json b/src/strategies/jpegd-locked-jpeg-of/examples.json index a631f29ef..c1517e148 100644 --- a/src/strategies/jpegd-locked-jpeg-of/examples.json +++ b/src/strategies/jpegd-locked-jpeg-of/examples.json @@ -1,16 +1,16 @@ [ - { - "name": "Example query", - "strategy": { - "name": "jpegd-locked-jpeg-of", - "params": {} - }, - "network": "1", - "addresses": [ - "0x9c5083dd4838e120dbeac44c052179692aa5dac5", - "0xB0dAfc466871c29662E5cbf4227322C96A8Ccbe9", - "0x0017dfe08bcc0dc9a323ca5d4831e371534e9320" - ], - "snapshot": 16119881 - } -] \ No newline at end of file + { + "name": "Example query", + "strategy": { + "name": "jpegd-locked-jpeg-of", + "params": {} + }, + "network": "1", + "addresses": [ + "0x9c5083dd4838e120dbeac44c052179692aa5dac5", + "0xB0dAfc466871c29662E5cbf4227322C96A8Ccbe9", + "0x0017dfe08bcc0dc9a323ca5d4831e371534e9320" + ], + "snapshot": 16119881 + } +] diff --git a/src/validations/arbitrum/examples.json b/src/validations/arbitrum/examples.json index 107d4e284..6c7c603aa 100644 --- a/src/validations/arbitrum/examples.json +++ b/src/validations/arbitrum/examples.json @@ -24,4 +24,3 @@ } } ] - diff --git a/src/validations/arbitrum/index.ts b/src/validations/arbitrum/index.ts index 6c8d51e53..e00c4bf9d 100644 --- a/src/validations/arbitrum/index.ts +++ b/src/validations/arbitrum/index.ts @@ -13,14 +13,16 @@ export default class extends Validation { public github = 'gzeoneth'; public version = '0.1.0'; public title = 'Arbitrum DAO Percentage of Votable Supply'; - public description = 'Use with erc20-votes to validate by percentage of votable supply.'; + public description = + 'Use with erc20-votes to validate by percentage of votable supply.'; async validate(): Promise { if (this.params.strategies?.length > 8) throw new Error(`Max number of strategies exceeded`); const minBps = this.params.minBps; const decimals = this.params.decimals; - const excludeaddr = this.params.excludeaddr ?? '0x00000000000000000000000000000000000A4B86'; + const excludeaddr = + this.params.excludeaddr ?? '0x00000000000000000000000000000000000A4B86'; if (minBps) { const scores = await getScoresDirect( @@ -46,8 +48,10 @@ export default class extends Validation { ], { blockTag: this.snapshot || 'latest' } ); - const votableSupply = parseFloat(formatUnits(totalSupply.sub(excludedSupply).toString(), decimals)) - const bpsOfVotable = totalScore * 10000 / votableSupply + const votableSupply = parseFloat( + formatUnits(totalSupply.sub(excludedSupply).toString(), decimals) + ); + const bpsOfVotable = (totalScore * 10000) / votableSupply; if (bpsOfVotable < minBps) return false; } diff --git a/src/validations/index.ts b/src/validations/index.ts index 199e4af89..7ea926042 100644 --- a/src/validations/index.ts +++ b/src/validations/index.ts @@ -9,7 +9,7 @@ const validationClasses = { basic, 'passport-gated': passportGated, 'passport-weighted': passportWeighted, - 'arbitrum': arbitrum + arbitrum: arbitrum }; const validations = {}; From 90fcf5ba5b3c2102c2e7ba09a64424588c16eade Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 3 Apr 2023 14:34:26 +0530 Subject: [PATCH 355/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.75 (#1120) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 35dad0ff8..36829951e 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.74", + "@snapshot-labs/snapshot.js": "^0.4.75", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 4bf0185b4..69fe876ad 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.74": - version "0.4.74" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.74.tgz#edce76c5003409a64fc071e0b379a326b66eddda" - integrity sha512-OfOkkJG2D/vI4oaC+PkOl+qxDnP7wLAD6RVQap8slNXvwkXBJWQFdPBJRXFo6ulrmq4n4w72aFFlutDht02vTA== +"@snapshot-labs/snapshot.js@^0.4.75": + version "0.4.75" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.75.tgz#523f0c20add731ab75e88157c9a1168da3be305f" + integrity sha512-clPkpRzlOuRbvPdYUeW6cwAA+3tEGWFgs5VZTBy/pBONSi1VcN1ElaBWRacdFrGPbx2HXPRas71IeBWEBCqYtQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 42ac653e1ff5c237b841789988104e7d706bbe60 Mon Sep 17 00:00:00 2001 From: vpoklopic <78506565+vpoklopic@users.noreply.github.com> Date: Fri, 14 Apr 2023 14:28:15 +0200 Subject: [PATCH 356/815] [thales] Update Thales strategy to include Arbitrum stakers (#1127) * Thales strategy * Change Thales strategy to pull data from OP mainnet * Update src/strategies/thales/index.ts Co-authored-by: Chaitanya * Update subgraph link for Thales strategy * Update src/strategies/thales/index.ts Co-authored-by: Chaitanya * Update Thales strategy to include Arbitrum stakers --------- Co-authored-by: Chaitanya --- src/strategies/thales/examples.json | 4 +- src/strategies/thales/index.ts | 72 ++++++++++++++++++++++------- 2 files changed, 58 insertions(+), 18 deletions(-) diff --git a/src/strategies/thales/examples.json b/src/strategies/thales/examples.json index 5bdc68da5..5e0375bac 100644 --- a/src/strategies/thales/examples.json +++ b/src/strategies/thales/examples.json @@ -5,7 +5,9 @@ "name": "thales", "params": { "symbol": "THALES", - "decimals": 18 + "decimals": 18, + "blockOptimism": 88627878, + "blockArbitrum": 78979794 } }, "network": "10", diff --git a/src/strategies/thales/index.ts b/src/strategies/thales/index.ts index 9c6846e1e..cbb2bcc15 100644 --- a/src/strategies/thales/index.ts +++ b/src/strategies/thales/index.ts @@ -3,20 +3,17 @@ import { formatUnits } from '@ethersproject/units'; import { subgraphRequest } from '../../utils'; export const author = 'vpoklopic'; -export const version = '1.0.2'; +export const version = '1.0.3'; -const THALES_SUBGRAPH_URL = - 'https://api.thegraph.com/subgraphs/name/thales-markets/thales-token'; +const THALES_SUBGRAPH_URL = { + optimism: + 'https://api.thegraph.com/subgraphs/name/thales-markets/thales-token', + arbitrum: + 'https://api.thegraph.com/subgraphs/name/thales-markets/thales-token-arbitrum' +}; -export async function strategy( - _space, - _network, - _provider, - addresses, - options, - snapshot -) { - const params = { +function returnGraphParams(addresses: string[]) { + return { stakers: { __args: { first: 1000, @@ -32,21 +29,62 @@ export async function strategy( totalStakedAmount: true } }; +} - if (snapshot !== 'latest') { +export async function strategy( + _space, + _network, + _provider, + addresses, + options +) { + const optimismGraphParams = returnGraphParams(addresses); + if (options.blockOptimism !== undefined) { + // @ts-ignore + optimismGraphParams.stakers.__args.block = { + number: options.blockOptimism + }; + } + + const arbitrumGraphParams = returnGraphParams(addresses); + if (options.blockArbitrum !== undefined) { // @ts-ignore - params.stakers.__args.block = { number: snapshot }; + arbitrumGraphParams.stakers.__args.block = { + number: options.blockArbitrum + }; } const score = {}; - const result = await subgraphRequest(THALES_SUBGRAPH_URL, params); - if (result && result.stakers) { - result.stakers.forEach((staker) => { + + const [optimismStakers, arbitrumStakers] = await Promise.all([ + subgraphRequest(THALES_SUBGRAPH_URL.optimism, optimismGraphParams), + subgraphRequest(THALES_SUBGRAPH_URL.arbitrum, arbitrumGraphParams) + ]); + + // We are starting by mapping all Optimism stakers + if (optimismStakers && optimismStakers.stakers) { + optimismStakers.stakers.forEach((staker) => { score[getAddress(staker.id)] = parseFloat( formatUnits(staker.totalStakedAmount, options.decimals) ); }); } + // If the Optimism staker is also staker on Arbitrum, add an amount + // Otherwise, just set Arbitrum staked amount as a score + if (arbitrumStakers && arbitrumStakers.stakers) { + arbitrumStakers.stakers.forEach((staker) => { + const key = getAddress(staker.id); + const stakedAmount = parseFloat( + formatUnits(staker.totalStakedAmount, options.decimals) + ); + if (!!score[key]) { + score[key] += stakedAmount; + } else { + score[key] = stakedAmount; + } + }); + } + return score || {}; } From 15164f68e25121c56c380e9cdd010d00e9a98ac7 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 14 Apr 2023 14:50:15 +0200 Subject: [PATCH 357/815] [degenzoo-erc721-animals-weighted] Strategy on Animal Weight (#1125) * [DegenZoo] Strategy on Animal Weight * Update src/strategies/degenzoo-erc721-animals-weighted/index.ts Co-authored-by: Chaitanya * Update src/strategies/degenzoo-erc721-animals-weighted/README.md Co-authored-by: Chaitanya * Updated documentation --------- Co-authored-by: Chaitanya --- .../README.md | 36 ++++++++ .../examples.json | 19 ++++ .../degenzoo-erc721-animals-weighted/index.ts | 90 +++++++++++++++++++ src/strategies/index.ts | 4 +- 4 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 src/strategies/degenzoo-erc721-animals-weighted/README.md create mode 100644 src/strategies/degenzoo-erc721-animals-weighted/examples.json create mode 100644 src/strategies/degenzoo-erc721-animals-weighted/index.ts diff --git a/src/strategies/degenzoo-erc721-animals-weighted/README.md b/src/strategies/degenzoo-erc721-animals-weighted/README.md new file mode 100644 index 000000000..9efe27f52 --- /dev/null +++ b/src/strategies/degenzoo-erc721-animals-weighted/README.md @@ -0,0 +1,36 @@ +# degenzoo-erc721-animals-weighted + +This strategy allows you to determine the voting power by reading the metadata attribute of holding NFT. +`tokenURI(tokenID)` returns the individual metadata URI in ERC721. + +Each animal has it's own "Staked Tokens" attribute. + +The voting power is the sum of all Staked tokens of each Zoo owner. + + +Example: + +```tokenURI(36) +[ + { + "0x91646c2c2fF05C4e9822740b0aD9d8B3DA51382b-36": "data:application/json;base64,eyJuYW1lIjogIkRlZ2VuWm9vICM2NDAxIiwgImRlc2NyaXB0aW9uIjogIkRlZ2Vuem9vICM2NDAxIGlzIHN0aWxsIGFuIGVnZy4uLiB3aHkgbm90IGhhdGNoIGl0PyIsICJpbWFnZSI6ICJpcGZzOi8vYmFmeWJlaWNqaXltb3VneHVqczJmenN4anVrbTdlNjU0eXRlcjRhb2hkcDc0ZWJvbXhjZDN5dnJzcWEvZWdnLnBuZyIsImF0dHJpYnV0ZXMiOiBbeyJ0cmFpdF90eXBlIjogIkxldmVsIiwgInZhbHVlIjogIjAifSwgeyJ0cmFpdF90eXBlIjogIlJhcml0eSIsICJ2YWx1ZSI6ICIwIn1dfQ==", + } +] +``` + +This data are encoded onchain and decoding them is providing the metadata attribute of each animal. The 'Staked Tokens' value is used to calculate the weight of each user + +``` example metadata of an animal +[ + { trait_type: 'Rank', value: '42' }, + { trait_type: 'Rarity', value: 'Endangered' }, + { trait_type: 'Shininess', value: 'false' }, + { trait_type: 'Variant', value: '2' }, + { trait_type: 'Multiplier', value: '12012' }, + { trait_type: 'Staked Tokens', value: '12012' }, + { trait_type: 'Level', value: '1' }, + { trait_type: 'Evolve Time', value: '1987200' }, + { trait_type: 'Hatch Timestamp', value: '1680706434' } + ] + +``` \ No newline at end of file diff --git a/src/strategies/degenzoo-erc721-animals-weighted/examples.json b/src/strategies/degenzoo-erc721-animals-weighted/examples.json new file mode 100644 index 000000000..fcfef5d64 --- /dev/null +++ b/src/strategies/degenzoo-erc721-animals-weighted/examples.json @@ -0,0 +1,19 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "degenzoo-erc721-animals-weighted", + "params": { + "address": "0x6defa7058d517f2dada60d79b7e26ab8a1219aca", + "symbol": "NFT" + } + }, + "network": "56", + "addresses": [ + "0x91646c2c2fF05C4e9822740b0aD9d8B3DA51382b", + "0xb9cc4a34BaA26D27363eE224CD652a6eBc59b49b", + "0x7219Fc75f990d0147F51960c8E4Dc868c6f3670C" + ], + "snapshot": 27121184 + } +] diff --git a/src/strategies/degenzoo-erc721-animals-weighted/index.ts b/src/strategies/degenzoo-erc721-animals-weighted/index.ts new file mode 100644 index 000000000..3626fe06f --- /dev/null +++ b/src/strategies/degenzoo-erc721-animals-weighted/index.ts @@ -0,0 +1,90 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import { Multicaller } from '../../utils'; + +export const author = 'aorfevre'; +export const version = '0.1.0'; + +const abi = [ + 'function balanceOf(address account) external view returns (uint256)', + 'function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256)', + 'function tokenURI(uint256 tokenId) external view returns (string)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + // Fetch the balanceOf the addresses i.e. how many vouchers do they hold? + const balanceOfMulti = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => + balanceOfMulti.call(address, options.address, 'balanceOf', [address]) + ); + const ownedCounts: Record = await balanceOfMulti.execute(); + + // Fetch the voucher token IDs held for each address + const tokenIdsMulti = new Multicaller(network, provider, abi, { blockTag }); + addresses.map((address) => { + let ownedCount = ownedCounts[address]; + while (ownedCount.gt(0)) { + const index = ownedCount.sub(1); + tokenIdsMulti.call( + `${address}-${index.toString()}`, + options.address, + 'tokenOfOwnerByIndex', + [address, index.toNumber()] + ); + ownedCount = index; + } + }); + const ownerTokenIds: Record = await tokenIdsMulti.execute(); + + // Fetch the voucher data for each voucher held by an address among the address + const tokenURIMulti = new Multicaller(network, provider, abi, { blockTag }); + Object.entries(ownerTokenIds).map(([addressWithIndex, tokenId]) => { + tokenURIMulti.call(`${addressWithIndex}`, options.address, `tokenURI`, [ + tokenId + ]); + }); + const ownerTokenURIs: Record = await tokenURIMulti.execute(); + + // Go through the list of results and sum up claimable values + const claimableVotingPower: Record = {}; + Object.entries(ownerTokenURIs).map(([addressWithIndex, tokenURI]) => { + const address = addressWithIndex.split('-')[0]; + + if (tokenURI.split(',')[0] == 'data:application/json;base64') { + const decoded = JSON.parse( + atob(tokenURI.slice('data:application/json;base64'.length + 1)) + ); + if (decoded.attributes) { + for (const i in decoded.attributes) { + if ( + decoded.attributes[i] && + decoded.attributes[i].trait_type === 'Staked Tokens' + ) { + if (!claimableVotingPower[address]) { + claimableVotingPower[address] = 0; + } + claimableVotingPower[address] += Number( + decoded.attributes[i].value + ); + } + } + } + } + }); + + // Return the computed values + return Object.fromEntries( + Object.entries(claimableVotingPower).map(([address, votingPower]) => [ + address, + votingPower + ]) + ); +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 8942c8f8f..d9ac4d0e8 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -434,6 +434,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 degenzooErc721AnimalsWeighted from './degenzoo-erc721-animals-weighted'; const strategies = { 'izumi-veizi': izumiVeiZi, @@ -874,7 +875,8 @@ const strategies = { 'lqty-proxy-stakers': lqtyProxyStakers, 'echelon-wallet-prime-and-cached-key-gated': echelonWalletPrimeAndCachedKeyGated, - 'rdnt-capital-voting': rdntCapitalVoting + 'rdnt-capital-voting': rdntCapitalVoting, + 'degenzoo-erc721-animals-weighted': degenzooErc721AnimalsWeighted }; Object.keys(strategies).forEach(function (strategyName) { From 5eb36c8fda1618169ecdc17019ea2c9c50bebcad Mon Sep 17 00:00:00 2001 From: HaynarCool Date: Fri, 14 Apr 2023 20:52:43 +0800 Subject: [PATCH 358/815] [galxe-loyalty-points] add galxe-loyalty-points strategy (#1104) * add galxe-loyalty-points strategy * Update src/strategies/galxe-loyalty-points/examples.json * fix example data * add README * use space url instead of space id * update to prd version * feat: support snapshot --------- Co-authored-by: Chaitanya --- src/strategies/galxe-loyalty-points/README.md | 26 +++++++++ .../galxe-loyalty-points/examples.json | 23 ++++++++ src/strategies/galxe-loyalty-points/index.ts | 56 +++++++++++++++++++ src/strategies/index.ts | 2 + 4 files changed, 107 insertions(+) create mode 100644 src/strategies/galxe-loyalty-points/README.md create mode 100644 src/strategies/galxe-loyalty-points/examples.json create mode 100644 src/strategies/galxe-loyalty-points/index.ts diff --git a/src/strategies/galxe-loyalty-points/README.md b/src/strategies/galxe-loyalty-points/README.md new file mode 100644 index 000000000..b191b562f --- /dev/null +++ b/src/strategies/galxe-loyalty-points/README.md @@ -0,0 +1,26 @@ +# Grant Voting Power with Galxe's Loyalty Points + +With Galxe’s Loyalty Point System, there are a number of strategies you could utilize to reward your community. Our “galxe-loyalty-points” strategy on [Snapshot.org](http://Snapshot.org) is especially designed to accommodate projects that don’t issue ERC-20 tokens or NFTs. By using Galxe Loyalty Points, you can easily reward your contributors with voting power on your proposals. + +Galxe leverages the [Snapshot](https://snapshot.org/#/) platform for Loyalty Points voting, which offers a simple and secure way to vote on-chain. If you’re not familiar with Snapshot, check out their documentation on the [home-snapshot](https://docs.snapshot.org/) to get started. You can seamlessly integrate Galxe Loyalty Points to let your most loyal community members to vote on gated Snapshot proposals. + +For testing purposes, we’ve provided a [playground here](https://snapshot.org/#/playground/galxe-loyalty-points) for you to try things out! + +Here’s how to set it up: + +1. Access your Snapshot Space admin and select the “galxe-loyalty-points” strategy. +2. Since your Galxe Loyalty Points are not tied to any specific chain or snapshot yet, pick whichever chain and snapshot you’d like for testing. +3. Set up the strategy parameters accordingly. + ``` + { + "symbol": "PTS", // Voting power unit shows in proposal + "space_url": "https://galxe.com/SummerSpace/campaigns" // Galxe space url + } + ``` +4. Input some addresses to test the voting power of each address, and you’re good to go! + +At Galxe, we believe in the power of community, decentralized decision-making, and blockchain technology to drive innovation. With Galxe Loyalty Point System and voting strategy, we’re working to make decentralized decision making more accessible and user-friendly for everyone. + +### About Galxe + +Galxe is the leading platform for building web3 community. With over 30 million users, Galxe has propelled the growth of Optimism, Polygon, Arbitrum, and more than 1800 partners with reward-based loyalty programs. Start your campaign today at [galxe.com](http://galxe.com/)! diff --git a/src/strategies/galxe-loyalty-points/examples.json b/src/strategies/galxe-loyalty-points/examples.json new file mode 100644 index 000000000..448f43e81 --- /dev/null +++ b/src/strategies/galxe-loyalty-points/examples.json @@ -0,0 +1,23 @@ +[ + { + "name": "Galxe users loyalty points", + "strategy": { + "name": "galxe-loyalty-points", + "params": { + "symbol": "PTS", + "space_url": "https://galxe.com/SummerSpace/campaigns" + } + }, + "network": "137", + "addresses": [ + "0x09092D6eCF228F3ba3C639c8dD2540fe7E675255", + "0x69D0341d380a1229f4751a0A721345dBc716586C", + "0xe5fF2C80759db9408dC9fD22b155b851Cd5aAA94", + "0xBaE38Bf54f2aA0e6159f3d9B656300f61DBd2ED3", + "0x5924EB6A482CeA85e23403E448257FbE5c58A9ed", + "0xD02BAE47fD93325fd0cc3d660B73D8f93C4D7B5E", + "0xfDAc618DDB79f77eb2Ea5c52b7c50f8f728DAFce" + ], + "snapshot": 1 + } +] diff --git a/src/strategies/galxe-loyalty-points/index.ts b/src/strategies/galxe-loyalty-points/index.ts new file mode 100644 index 000000000..196384dfa --- /dev/null +++ b/src/strategies/galxe-loyalty-points/index.ts @@ -0,0 +1,56 @@ +import fetch from 'cross-fetch'; +import { error } from 'console'; + +export const author = 'HaynarCool'; +export const version = '0.1.0'; + +const graphqlUrl = 'https://graphigo.prd.galaxy.eco/query'; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const url = new URL(options.space_url); + const parts = url.pathname.split('/'); + if (parts.length < 2) { + throw error('invalid galxe space url'); + } + const graphqlParams = { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + operationName: 'galxeLoyaltyPoints', + query: `query galxeLoyaltyPoints($alias: String! $addresses: [String!]! $snapshotId: String!) { + space(alias: $alias) { + addressesLoyaltyPoints(addresses: $addresses, snapshotId: $snapshotId) { + address + space + points + } + } + }`, + variables: { + alias: parts[1], + addresses: addresses, + snapshotId: typeof snapshot === 'number' ? snapshot : '' + } + }) + }; + const graphqlData = await fetch(graphqlUrl, graphqlParams) + .then((r) => r.json()) + .catch((e) => { + console.error('query galxe user loyalty points failed'); + throw e; + }); + const scores = {}; + graphqlData.data.space.addressesLoyaltyPoints.forEach((item) => { + scores[item.address] = item.points; + }); + return scores; +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index d9ac4d0e8..e1106d0d8 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -251,6 +251,7 @@ import * as digitalaxLPStakers from './digitalax-lp-stakers'; import * as digitalaxMonaStakersMatic from './digitalax-mona-stakers-matic'; import * as digitalaxLPStakersMatic from './digitalax-lp-stakers-matic'; import * as galaxyNftWithScore from './galaxy-nft-with-score'; +import * as galxeLoyaltyPoints from './galxe-loyalty-points'; import * as gatenetTotalStaked from './gatenet-total-staked'; import * as vesper from './vesper'; import * as thales from './thales'; @@ -695,6 +696,7 @@ const strategies = { 'digitalax-lp-stakers-matic': digitalaxLPStakersMatic, 'colony-reputation': colonyReputation, 'galaxy-nft-with-score': galaxyNftWithScore, + 'galxe-loyalty-points': galxeLoyaltyPoints, 'gatenet-total-staked': gatenetTotalStaked, vesper, thales, From 0836e486dc7afb85066f2ce88840e77ab8ec8ba2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 17 Apr 2023 13:49:57 +0530 Subject: [PATCH 359/815] Automated lint (#1131) Co-authored-by: ChaituVR --- src/strategies/degenzoo-erc721-animals-weighted/examples.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategies/degenzoo-erc721-animals-weighted/examples.json b/src/strategies/degenzoo-erc721-animals-weighted/examples.json index fcfef5d64..94feba35b 100644 --- a/src/strategies/degenzoo-erc721-animals-weighted/examples.json +++ b/src/strategies/degenzoo-erc721-animals-weighted/examples.json @@ -14,6 +14,6 @@ "0xb9cc4a34BaA26D27363eE224CD652a6eBc59b49b", "0x7219Fc75f990d0147F51960c8E4Dc868c6f3670C" ], - "snapshot": 27121184 + "snapshot": 27121184 } ] From d581c8e7d0d21273fcd293baf98aa17cbad09395 Mon Sep 17 00:00:00 2001 From: Taha Abbasi Date: Mon, 17 Apr 2023 02:31:15 -0600 Subject: [PATCH 360/815] Staked Defi Balance Strategy Added for All Ferrum Network Staking Contracts [staked-defi-balance] (#1129) * Added staked-defi-balance strategy that works will all Ferrum Network Staking contracts * Added functionalty for Ferrum Staking contract based voting * Added README with instructions for using the new strategy * Updated readme with release notes and usage examples for staked-defi-balance strategy * Update src/strategies/staked-defi-balance/index.ts Removing name and token declaration from strategy as they are provided in example.json per ChaituVR's suggestion. Co-authored-by: Chaitanya --------- Co-authored-by: Chaitanya --- src/strategies/index.ts | 2 + src/strategies/staked-defi-balance/README.md | 66 +++++++++++++++++++ .../staked-defi-balance/examples.json | 48 ++++++++++++++ src/strategies/staked-defi-balance/index.ts | 51 ++++++++++++++ .../staked-defi-balance/schema.json | 64 ++++++++++++++++++ 5 files changed, 231 insertions(+) create mode 100644 src/strategies/staked-defi-balance/README.md create mode 100644 src/strategies/staked-defi-balance/examples.json create mode 100644 src/strategies/staked-defi-balance/index.ts create mode 100644 src/strategies/staked-defi-balance/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index e1106d0d8..d37b8deec 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -435,6 +435,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 stakedDefiBalance from './staked-defi-balance'; import * as degenzooErc721AnimalsWeighted from './degenzoo-erc721-animals-weighted'; const strategies = { @@ -878,6 +879,7 @@ const strategies = { 'echelon-wallet-prime-and-cached-key-gated': echelonWalletPrimeAndCachedKeyGated, 'rdnt-capital-voting': rdntCapitalVoting, + 'staked-defi-balance': stakedDefiBalance, 'degenzoo-erc721-animals-weighted': degenzooErc721AnimalsWeighted }; diff --git a/src/strategies/staked-defi-balance/README.md b/src/strategies/staked-defi-balance/README.md new file mode 100644 index 000000000..eea910cde --- /dev/null +++ b/src/strategies/staked-defi-balance/README.md @@ -0,0 +1,66 @@ +# staked-defi-balance + +This custom strategy returns the score of addresses based on their staked token balance in a specific Ferrum Network DeFi staking pool contract. + +Here is an example of parameters: + +```json +{ + "tokenContractAddress": "0xe685d3CC0be48BD59082eDe30C3b64CbFc0326e2", + "symbol": "cFRM", + "decimals": 18, + "minStakedBalance": "100000000000000000000000", + "stakingPoolContractAddress": "0xb4927895cbee88e651e0582893051b3b0f8d7db8", + "methodABI": [ + { + "inputs": [ + { + "internalType": "address", + "name": "id", + "type": "address" + }, + { + "internalType": "address", + "name": "staker", + "type": "address" + } + ], + "name": "stakeOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } + ] + } +``` + +Release Notes +------------- + +### New Strategy: Staked Defi Balance + +In this update, we have added a new strategy called `Staked Defi Balance` to the snapshot-strategies repository. This custom strategy allows users to calculate the scores of addresses based on their staked token balance in a specific staking pool contract. + +#### Changes + +1. New Strategy File: A new file named `index.ts` has been added to the `src/strategies/staked-defi-balance` directory. This file contains the implementation of the `Staked Defi Balance` strategy, including multicall functionality to fetch staking balances and score calculation logic. + +2. Examples File: A new `examples.json` file has been added to the `src/strategies/staked-defi-balance` directory. This file demonstrates how to use the new strategy with the correct parameters, such as `tokenContractAddress`, `symbol`, `decimals`, `minStakedBalance`, `stakingPoolContractAddress`, and `methodABI`. + +3. Schema File: A new `schema.json` file has been added to the `src/strategies/staked-defi-balance` directory. This file defines the JSON schema for the strategy parameters, ensuring that they follow the correct structure and data types. The schema enforces the required parameters and validates their format. + +#### Impact + +This update expands the capabilities of the snapshot-strategies repository by providing a new strategy for users to calculate scores based on staked token balances. This strategy can be helpful for governance proposals and voting mechanisms that involve staked tokens in a specific staking pool contract. + +#### Usage + +To use this strategy, include it in your Snapshot configuration and provide the necessary parameters as shown in the `examples.json` file. Make sure the parameters follow the structure defined in the `schema.json` file for proper validation. + +Please make sure to update your Snapshot configuration to include the new strategy and follow the release notes for any future updates or changes. \ No newline at end of file diff --git a/src/strategies/staked-defi-balance/examples.json b/src/strategies/staked-defi-balance/examples.json new file mode 100644 index 000000000..25105a4dc --- /dev/null +++ b/src/strategies/staked-defi-balance/examples.json @@ -0,0 +1,48 @@ +[ + { + "name": "Staked Defi Balance", + "strategy": { + "name": "staked-defi-balance", + "params": { + "tokenContractAddress": "0xe685d3CC0be48BD59082eDe30C3b64CbFc0326e2", + "symbol": "cFRM", + "decimals": 18, + "minStakedBalance": "100000000000000000000000", + "stakingPoolContractAddress": "0xb4927895cbee88e651e0582893051b3b0f8d7db8", + "methodABI": [ + { + "inputs": [ + { + "internalType": "address", + "name": "id", + "type": "address" + }, + { + "internalType": "address", + "name": "staker", + "type": "address" + } + ], + "name": "stakeOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } + ] + } + }, + "network": "42161", + "addresses": [ + "0x4c4180bf5ec78af9025bdd935ed69e29c2f6cbae", + "0x5785530b6f0ea72b0dba474d55b43e1af1182cad", + "0x2ed211293b1db5e7d177e2711bea83700e45b150" + ], + "snapshot": 74259791 + } +] \ No newline at end of file diff --git a/src/strategies/staked-defi-balance/index.ts b/src/strategies/staked-defi-balance/index.ts new file mode 100644 index 000000000..696aee587 --- /dev/null +++ b/src/strategies/staked-defi-balance/index.ts @@ -0,0 +1,51 @@ +// src/strategies/staked-defi-balance/index.ts + +import { formatUnits } from '@ethersproject/units'; +import { getAddress } from '@ethersproject/address'; +import { multicall } from '../../utils'; + +export const author = 'taha-abbasi'; +export const version = '0.1.0'; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const stakingPoolContractAddress = options.stakingPoolContractAddress; + const abi = options.methodABI; + + const stakingCalls = addresses.map(address => { + return [ + stakingPoolContractAddress, + 'stakeOf', + [options.tokenContractAddress, address] + ]; + }); + + const stakes = await multicall(network, provider, abi, stakingCalls, { blockTag }); + + const stakesMapped = {}; + for (let i = 0; i < addresses.length; i++) { + stakesMapped[getAddress(addresses[i])] = stakes[i][0]; + } + + const addressScores = Object.fromEntries( + addresses.map((address) => { + const normalizedAddress = getAddress(address); + const stakedBalance = stakesMapped[normalizedAddress]; + const formattedStakedBalance = parseFloat(formatUnits(stakedBalance, options.decimals)); + return [ + normalizedAddress, + stakedBalance.gte(options.minStakedBalance) ? formattedStakedBalance : 0 + ]; + }) + ); + + return addressScores; +} + diff --git a/src/strategies/staked-defi-balance/schema.json b/src/strategies/staked-defi-balance/schema.json new file mode 100644 index 000000000..230d66296 --- /dev/null +++ b/src/strategies/staked-defi-balance/schema.json @@ -0,0 +1,64 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Staked Defi Balance", + "type": "object", + "properties": { + "tokenContractAddress": { + "type": "string", + "pattern": "^0x[a-fA-F0-9]{40}$" + }, + "symbol": { + "type": "string" + }, + "decimals": { + "type": "integer", + "minimum": 0 + }, + "minStakedBalance": { + "type": "string", + "pattern": "^[0-9]+$" + }, + "stakingPoolContractAddress": { + "type": "string", + "pattern": "^0x[a-fA-F0-9]{40}$" + }, + "methodABI": { + "type": "array", + "items": { + "type": "object", + "properties": { + "inputs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "internalType": { "type": "string" }, + "name": { "type": "string" }, + "type": { "type": "string" } + }, + "required": ["internalType", "name", "type"] + } + }, + "name": { "type": "string" }, + "outputs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "internalType": { "type": "string" }, + "name": { "type": "string" }, + "type": { "type": "string" } + }, + "required": ["internalType", "name", "type"] + } + }, + "stateMutability": { "type": "string" }, + "type": { "type": "string" } + }, + "required": ["inputs", "name", "outputs", "stateMutability", "type"] + } + } + }, + "required": ["tokenContractAddress", "decimals", "minStakedBalance", "stakingPoolContractAddress", "methodABI"] + } + \ No newline at end of file From 2b785bc78fc195a7b8e6f93ca1fc0b0006cd41ae Mon Sep 17 00:00:00 2001 From: unRealGamer <114133451+unRealGamer28@users.noreply.github.com> Date: Mon, 17 Apr 2023 02:51:58 -0600 Subject: [PATCH 361/815] [cap-voting-power] Added cap-voting-power strategy (#1123) * Added cap-voting-power strategy * Added a limit to options.vestingAddresses length Limit is set in code with maxVestingAddressCount set to 500 --- src/strategies/cap-voting-power/README.md | 62 ++++ src/strategies/cap-voting-power/examples.json | 66 +++++ src/strategies/cap-voting-power/index.ts | 278 ++++++++++++++++++ src/strategies/index.ts | 2 + 4 files changed, 408 insertions(+) create mode 100644 src/strategies/cap-voting-power/README.md create mode 100644 src/strategies/cap-voting-power/examples.json create mode 100644 src/strategies/cap-voting-power/index.ts diff --git a/src/strategies/cap-voting-power/README.md b/src/strategies/cap-voting-power/README.md new file mode 100644 index 000000000..05236ce6a --- /dev/null +++ b/src/strategies/cap-voting-power/README.md @@ -0,0 +1,62 @@ +# cap-voting-power + +This strategy is used to calculate the off-chain voting power for addresses with tokens vested in a contract. It also includes a clamping mechanism to limit the voting power of the vesting contracts based on the total voting power of the voting escrow contract. All parameters are required. + +Some things to note if you plan on using this strategy: + +1. All vestingAddresses objects MUST have address, lockedTokens, cliffMonths, vestingMonths, startDateTimestamp and initialReleasePercentage. +2. The Vesting Contract's voting power is clamped to a percentage (clampPercentage) of the total voting power. This value must be between 0 and 1. +3. Total voting power is calculated based on the Voting Escrow Contract's voting power. Therefore, you must specify the voting escrow contract address (votingEscrowContractAddress) and the number of decimals in your token (decimals) as parameters. +4. For optimal performance and memory management, the strategy imposes a limit of 500 vesting addresses in the parameters. Adhere to this limit when setting up the strategy. + +Here is an example of parameters: + +```json +{ + "votingEscrowContractAddress": "0x3362A77AC77fF5098618F8C7CFB4eA27E738229f", + "decimals": 18, + "vestingAddresses": [ + { + "address": "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", + "lockedTokens": 1000, + "cliffMonths": 12, + "vestingMonths": 24, + "startDateTimestamp": 1602033545, + "initialReleasePercentage": 0.25 + }, + { + "address": "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", + "lockedTokens": 2000, + "cliffMonths": 12, + "vestingMonths": 24, + "startDateTimestamp": 1602033545, + "initialReleasePercentage": 0.25 + }, + { + "address": "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e", + "lockedTokens": 5000, + "cliffMonths": 12, + "vestingMonths": 24, + "startDateTimestamp": 1602033545, + "initialReleasePercentage": 0.25 + }, + { + "address": "0xC83df6FD76484938C10843fa37c7Cbba327c8eDC", + "lockedTokens": 10000, + "cliffMonths": 12, + "vestingMonths": 24, + "startDateTimestamp": 1602033545, + "initialReleasePercentage": 0.25 + }, + { + "address": "0x8E83aD3ecC12E2e2Df1021CDe01e53C9465D5883", + "lockedTokens": 20000, + "cliffMonths": 12, + "vestingMonths": 24, + "startDateTimestamp": 1602033545, + "initialReleasePercentage": 0.25 + } + ], + "clampPercentage": 0.4 +} +``` \ No newline at end of file diff --git a/src/strategies/cap-voting-power/examples.json b/src/strategies/cap-voting-power/examples.json new file mode 100644 index 000000000..f44cd72d2 --- /dev/null +++ b/src/strategies/cap-voting-power/examples.json @@ -0,0 +1,66 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "cap-voting-power", + "params": { + "votingEscrowContractAddress": "0x3362A77AC77fF5098618F8C7CFB4eA27E738229f", + "decimals": 18, + "vestingAddresses": [ + { + "address": "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", + "lockedTokens": 1000, + "cliffMonths": 12, + "vestingMonths": 24, + "startDateTimestamp": 1602033545, + "initialReleasePercentage": 0.25 + }, + { + "address": "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", + "lockedTokens": 2000, + "cliffMonths": 12, + "vestingMonths": 24, + "startDateTimestamp": 1602033545, + "initialReleasePercentage": 0.25 + }, + { + "address": "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e", + "lockedTokens": 5000, + "cliffMonths": 12, + "vestingMonths": 24, + "startDateTimestamp": 1602033545, + "initialReleasePercentage": 0.25 + }, + { + "address": "0xC83df6FD76484938C10843fa37c7Cbba327c8eDC", + "lockedTokens": 10000, + "cliffMonths": 12, + "vestingMonths": 24, + "startDateTimestamp": 1602033545, + "initialReleasePercentage": 0.25 + }, + { + "address": "0x8E83aD3ecC12E2e2Df1021CDe01e53C9465D5883", + "lockedTokens": 20000, + "cliffMonths": 12, + "vestingMonths": 24, + "startDateTimestamp": 1602033545, + "initialReleasePercentage": 0.25 + } + ], + "clampPercentage": 0.4 + } + }, + "network": "80001", + "addresses": [ + "0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11", + "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", + "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", + "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", + "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e", + "0xC83df6FD76484938C10843fa37c7Cbba327c8eDC", + "0x8E83aD3ecC12E2e2Df1021CDe01e53C9465D5883" + ], + "snapshot": 33129875 + } +] diff --git a/src/strategies/cap-voting-power/index.ts b/src/strategies/cap-voting-power/index.ts new file mode 100644 index 000000000..058313513 --- /dev/null +++ b/src/strategies/cap-voting-power/index.ts @@ -0,0 +1,278 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Contract } from '@ethersproject/contracts'; + +export const author = 'unRealGamer28'; +export const version = '0.1.0'; + +const abi = ['function totalSupply(uint256 t) external view returns (uint256)']; + +const maxLockupDuration = 4 * 365 * 24 * 60 * 60; // Maximum lockup duration is 4 years in seconds based on Curve VE contract +const maxVestingDuration = 4 * 365 * 24 * 60 * 60; // Maximum vesting duration is 4 years in seconds +const maxVestingAddressCount = 500; // Maximum number of vesting addresses + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + // Assertions/checks to validate options + if (!options.vestingAddresses || options.vestingAddresses.length === 0) { + throw new Error( + 'Invalid options provided! Please make sure vestingAddresses is provided.' + ); + } + if (options.vestingAddresses.length > maxVestingAddressCount) { + throw new Error( + `Too many vesting addresses provided! The maximum allowed is ${maxVestingAddressCount}.` + ); + } + options.vestingAddresses.forEach((vestingAddress) => { + if ( + !('address' in vestingAddress) || + !('lockedTokens' in vestingAddress) || + !('cliffMonths' in vestingAddress) || + !('vestingMonths' in vestingAddress) || + !('startDateTimestamp' in vestingAddress) || + !('initialReleasePercentage' in vestingAddress) + ) { + throw new Error( + 'Invalid options provided! Please make sure each vesting address object has all required properties.' + ); + } + }); + if (options.clampPercentage < 0 || options.clampPercentage > 1) { + throw new Error( + 'Invalid clamp percentage! Please provide a number between 0 and 1.' + ); + } + if (!options.votingEscrowContractAddress || !options.decimals) { + throw new Error( + 'Invalid options provided! Please make sure votingEscrowContractAddress and decimals are provided.' + ); + } + + // Find current timestamp + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + let block; + try { + block = await provider.getBlock(blockTag); + } catch (error) { + throw new Error('Failed to get block information'); + } + const now = block.timestamp; + + // Calculate voting power for each vesting address and create vestingAddressesArray + const vestingVotingPower = {}; + const vestingAddressesArray: string[] = []; + options.vestingAddresses.forEach((vestingAddress) => { + const { + address, + lockedTokens, + cliffMonths, + vestingMonths, + startDateTimestamp, + initialReleasePercentage + } = vestingAddress; + + // Calculate the cliffEndDateTimestamp by adding the cliff duration (in seconds) to the startDateTimestamp. + const cliffEndDateTimestamp = + startDateTimestamp + ((cliffMonths * 365) / 12) * (24 * 60 * 60); + // Calculate the endDateTimestamp by adding the total vesting duration (in seconds) to the startDateTimestamp. + const endDateTimestamp = + startDateTimestamp + + (((cliffMonths + vestingMonths) * 365) / 12) * (24 * 60 * 60); + const votingPower = votingPowerCalc( + lockedTokens, + now, + startDateTimestamp, + cliffEndDateTimestamp, + endDateTimestamp, + initialReleasePercentage + ); + + // Add the final voting power of any duplicate addresses + vestingVotingPower[address] = + vestingVotingPower[address] === undefined + ? votingPower + : vestingVotingPower[address] + votingPower; + + vestingAddressesArray.push(address); + }); + + // Calculate total voting power for vesting addresses + let vestingTotalVotingPower = 0; + Object.values(vestingVotingPower).forEach((value) => { + if (typeof value === 'number') vestingTotalVotingPower += value; + }); + + // Get voting escrow's total voting power + const votingEscrowContract = new Contract( + options.votingEscrowContractAddress, + abi, + provider + ); + const votingEscrowTotalVotingPower: BigNumber = + await votingEscrowContract.totalSupply(now); + const escrowTotalVotingPower = parseFloat( + formatUnits(votingEscrowTotalVotingPower, options.decimals) + ); + + // Clamp the vesting voting power for each address if the total vesting voting power is greater than the clamped total vesting voting power based on the clamp percentage + const vestingClampedTotalVotingPower = calculateClampedVotingPower( + escrowTotalVotingPower, + options.clampPercentage + ); + if (vestingTotalVotingPower > vestingClampedTotalVotingPower) { + const clampRatio = vestingClampedTotalVotingPower / vestingTotalVotingPower; + + // Calculate the new clamped voting power for each vesting address + Object.keys(vestingVotingPower).forEach((address) => { + vestingVotingPower[address] = vestingVotingPower[address] * clampRatio; + }); + } + + // Return the final voting power for addresses that are in the vestingAddressesArray + const result = {}; + addresses.forEach((address: string) => { + if (vestingAddressesArray.includes(address)) { + result[address] = vestingVotingPower[address]; + } + }); + return result; +} + +/** + * Calculate the voting power based on the given parameters. + * + * @function + * @param {number} lockedToken - The number of tokens locked in the vesting contract. + * @param {number} currentDateTS - The current date timestamp (in seconds). + * @param {number} startDateTS - The start date timestamp of the vesting period (in seconds). + * @param {number} cliffEndDateTS - The end date timestamp of the cliff period (in seconds). + * @param {number} endDateTS - The end date timestamp of the vesting period (in seconds). + * @param {number} initialReleasePercentage - The initial percentage of tokens released at the end of the cliff. + * @returns {number} The calculated voting power based on the input parameters. + */ +function votingPowerCalc( + lockedToken, + currentDateTS, + startDateTS, + cliffEndDateTS, + endDateTS, + initialReleasePercentage +): number { + // Store function parameters as constants + const lockedTokenAmount = lockedToken; + let currentTimestamp = currentDateTS; + const startTimestamp = startDateTS; + const cliffEndTimestamp = cliffEndDateTS; + const endTimestamp = endDateTS; + + // Calculate initial release amount based on initial release percentage + const initialReleaseAmount = lockedTokenAmount * initialReleasePercentage; + // Calculate adjusted locked token amount + const adjustedLockedTokenAmount = lockedTokenAmount - initialReleaseAmount; + + // Assertions/checks to limit function parameters + if (startTimestamp > currentTimestamp) currentTimestamp = startTimestamp; + if (endTimestamp < currentTimestamp) return 0; // If endTimestamp is in the past, return 0 voting power + if (startTimestamp > endTimestamp) + throw new Error('Vesting start date cannot begin after the end date.'); + if (startTimestamp > cliffEndTimestamp) + throw new Error( + 'Vesting start date cannot begin after the cliff end date.' + ); + if (endTimestamp < cliffEndTimestamp) + throw new Error('Vesting end date cannot end before the cliff end date.'); + if (lockedTokenAmount <= 0) + throw new Error('Token amount must be greater than 0.'); + + // Calculate cliffDuration and vestingDuration, and asset it matches to totalDuration + const totalDuration = endTimestamp - startTimestamp; + const cliffDuration = cliffEndTimestamp - startTimestamp; + const vestingDuration = endTimestamp - cliffEndTimestamp; + if (cliffDuration + vestingDuration != totalDuration) + throw new Error( + "Cliff duration and vesting duration don't match up to total duration." + ); + + // Calculate remaining cliff duration and vesting duration + let remainingCliffDuration; + if (currentTimestamp >= cliffEndTimestamp) remainingCliffDuration = 0; + else remainingCliffDuration = cliffEndTimestamp - currentTimestamp; + + let remainingVestingDuration; + if (currentTimestamp >= cliffEndTimestamp) + remainingVestingDuration = endTimestamp - currentTimestamp; + else remainingVestingDuration = vestingDuration; + + // Clamp remaining cliff duration and vesting duration to maxLockupDuration and maxVestingDuration respectively + const clampedRemainingCliffDuration = Math.min( + remainingCliffDuration, + maxLockupDuration + ); + const clampedRemainingVestingDuration = Math.min( + remainingVestingDuration, + maxVestingDuration + ); + + // Calculate decayed voting power for the cliffDuration (25% portion) + const decayCliffVPInitialRelease = + (initialReleaseAmount / maxLockupDuration) * clampedRemainingCliffDuration; + + // Calculate decayed voting power for the cliffDuration (75% portion) + const decayCliffVPAdjustedLockedToken = + (adjustedLockedTokenAmount / maxLockupDuration) * + clampedRemainingCliffDuration; + + // Calculate the average decayed voting power for the vestingDuration (75% portion) + const tokensVestedPerSecond = adjustedLockedTokenAmount / vestingDuration; + const remainingTokenAmount = remainingVestingDuration * tokensVestedPerSecond; + + const decayVestingVPAdjustedLockedToken = + (remainingTokenAmount / maxVestingDuration) * + clampedRemainingVestingDuration * + 0.5; // Average the decayed voting power + + // Combine all decayed voting power + const currentVotingPower = + decayCliffVPInitialRelease + + decayCliffVPAdjustedLockedToken + + decayVestingVPAdjustedLockedToken; + + // Cap currentVotingPower to maximumVotingPower (lockedTokenAmount) + if (currentVotingPower >= lockedTokenAmount) { + return lockedTokenAmount; + } + + // Finally, return the currentVotingPower + return currentVotingPower; +} + +/** + * Calculate the clamped voting power of the vesting contract. + * + * @param {number} escrowVotingPower - The total voting power of the escrow contract. + * @param {number} vestingClampPercentage - The desired percentage of total voting power for the vesting contract. + * @return {number} The clamped voting power for the vesting contract. + */ +function calculateClampedVotingPower( + escrowVotingPower, + vestingClampPercentage +) { + // Calculate the percentage of voting power allocated to the escrow contract, + // which is the remaining percentage after allocating the vestingClampPercentage to the vesting contract + const escrowClampPercentage = 1 - vestingClampPercentage; + + // Calculate the combined total voting power of the escrow and vesting contracts, + // considering the escrowVotingPower and the escrowClampPercentage + const totalVotingPower = escrowVotingPower / escrowClampPercentage; + + // Return the clamped voting power for the vesting contract, + // which is the product of the total voting power and the vestingClampPercentage + return totalVotingPower * vestingClampPercentage; +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index d37b8deec..c7da09bd8 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -437,8 +437,10 @@ import * as echelonWalletPrimeAndCachedKeyGated from './echelon-wallet-prime-and import * as rdntCapitalVoting from './rdnt-capital-voting'; import * as stakedDefiBalance from './staked-defi-balance'; import * as degenzooErc721AnimalsWeighted from './degenzoo-erc721-animals-weighted'; +import * as capVotingPower from './cap-voting-power'; const strategies = { + 'cap-voting-power': capVotingPower, 'izumi-veizi': izumiVeiZi, 'eco-voting-power': ecoVotingPower, 'forta-shares': fortaShares, From ab33141072c7af435b6f8259675a06861990bb2b Mon Sep 17 00:00:00 2001 From: Sam <51686767+samuveth@users.noreply.github.com> Date: Wed, 19 Apr 2023 14:30:18 +0700 Subject: [PATCH 362/815] [basic] Add schema to for basic validation (#1113) * Add schema to for basic validation * Update schema.json * Update schema.json * Update schema.json * Update schema.json * Update src/validations/basic/schema.json --------- Co-authored-by: Chaitanya --- src/validations/basic/schema.json | 51 +++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 src/validations/basic/schema.json diff --git a/src/validations/basic/schema.json b/src/validations/basic/schema.json new file mode 100644 index 000000000..81c0cf80b --- /dev/null +++ b/src/validations/basic/schema.json @@ -0,0 +1,51 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Validation", + "definitions": { + "Validation": { + "title": "Basic validation", + "type": "object", + "properties": { + "minScore": { + "title": "Minimum score", + "type": "number", + "minimum": 1 + }, + "useVotingStrategies": { + "description": "Use voting strategies", + "type": "boolean", + "default": false + }, + "strategies": { + "title": "Strategies", + "type": "array", + "items": { + "title": "Strategy", + "type": "object", + "default": { + "name": "ticket", + "network": "1", + "params": { + "symbol": "DAI" + } + }, + "properties": { + "name": { + "type": "string" + }, + "network": { + "type": "string" + }, + "params": { + "type": "object" + } + }, + "required": ["name", "params"] + } + } + }, + "required": ["minScore"], + "additionalProperties": false + } + } +} From 48893fd78cf863f2f1fcf6e33960acdb64295321 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 19 Apr 2023 13:02:51 +0530 Subject: [PATCH 363/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.76 (#1132) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 36829951e..b8ce9b40c 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.75", + "@snapshot-labs/snapshot.js": "^0.4.76", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 69fe876ad..c8cad877f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.75": - version "0.4.75" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.75.tgz#523f0c20add731ab75e88157c9a1168da3be305f" - integrity sha512-clPkpRzlOuRbvPdYUeW6cwAA+3tEGWFgs5VZTBy/pBONSi1VcN1ElaBWRacdFrGPbx2HXPRas71IeBWEBCqYtQ== +"@snapshot-labs/snapshot.js@^0.4.76": + version "0.4.76" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.76.tgz#1e673a4a9194a9b4bf45a235ebc5cf7e527f2579" + integrity sha512-fDGxA+d4wckNrmGnL77yqrLBUwCj1w9OIpLFYOENoo3nvcLdcQ+Kfz75iVE0nYkzByn6XgIqO9R1td0BrOrfXw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 1006ab620bed334dd49e8ec720df5f822d2de916 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Wed, 19 Apr 2023 16:48:35 +0530 Subject: [PATCH 364/815] Remove useVotingStrategies in basic validation --- src/validations/basic/schema.json | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/validations/basic/schema.json b/src/validations/basic/schema.json index 81c0cf80b..9a2822c19 100644 --- a/src/validations/basic/schema.json +++ b/src/validations/basic/schema.json @@ -11,11 +11,6 @@ "type": "number", "minimum": 1 }, - "useVotingStrategies": { - "description": "Use voting strategies", - "type": "boolean", - "default": false - }, "strategies": { "title": "Strategies", "type": "array", From e777ecd5d04b9ccd9f3a660b49d6bcc3d37fc87f Mon Sep 17 00:00:00 2001 From: Zuza Zuber <39556343+zzuziak@users.noreply.github.com> Date: Wed, 19 Apr 2023 18:35:45 +0200 Subject: [PATCH 365/815] require strategies to use snapshot (#1105) Co-authored-by: Chaitanya --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6d2531d5a..54fbccf3c 100755 --- a/README.md +++ b/README.md @@ -48,11 +48,12 @@ Here is a simple checklist to look at when reviewing a PR for a new strategy: #### Code +- Strategies should always use a `snapshot` to calculate user's voting power. As a result the voting power should not change throughout the proposal duration. - There should be a maximum of 5 requests, a request can use "fetch" a "subgraphRequest" or "multicall". - The strategy should not send a request for each voters, this doesn't scale. - The strategy PR should not add any new dependency. -- The score returned by the strategy should use the same casing for address than on the input, or should return checksum addresses. -- Make sure voting power of one address does not depend on other addresses. +- The score returned by the strategy should use the same casing for address as on the input, or should return checksum addresses. +- Make sure that voting power of one address does not depend on other addresses. #### Example From 563de1eca4d24d689d19cd121d905467ba803240 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 20 Apr 2023 00:55:19 +0530 Subject: [PATCH 366/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.77 (#1134) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index b8ce9b40c..63f238e6d 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.76", + "@snapshot-labs/snapshot.js": "^0.4.77", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index c8cad877f..0216b0521 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.76": - version "0.4.76" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.76.tgz#1e673a4a9194a9b4bf45a235ebc5cf7e527f2579" - integrity sha512-fDGxA+d4wckNrmGnL77yqrLBUwCj1w9OIpLFYOENoo3nvcLdcQ+Kfz75iVE0nYkzByn6XgIqO9R1td0BrOrfXw== +"@snapshot-labs/snapshot.js@^0.4.77": + version "0.4.77" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.77.tgz#a0042d63a4f262f6e0f425914c8ac1f23bd504c0" + integrity sha512-HJdPEWF0xtRhU3Q1u2IuaQww2PzRGzb1khdfBiwwaTyWkEaP/ytLta2EezLH8btLAn2HD3I8rQIw1+TqA9hccg== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From a55e6ddb4894515595c848e5a12d21f82d8c29cb Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Thu, 20 Apr 2023 18:45:36 +0530 Subject: [PATCH 367/815] New param for proposal validations only and voting validations only (#1137) --- src/validations/arbitrum/index.ts | 1 + src/validations/index.ts | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/validations/arbitrum/index.ts b/src/validations/arbitrum/index.ts index e00c4bf9d..009b51a2f 100644 --- a/src/validations/arbitrum/index.ts +++ b/src/validations/arbitrum/index.ts @@ -15,6 +15,7 @@ export default class extends Validation { public title = 'Arbitrum DAO Percentage of Votable Supply'; public description = 'Use with erc20-votes to validate by percentage of votable supply.'; + public proposalValidationOnly = true; async validate(): Promise { if (this.params.strategies?.length > 8) diff --git a/src/validations/index.ts b/src/validations/index.ts index 7ea926042..ee47e2564 100644 --- a/src/validations/index.ts +++ b/src/validations/index.ts @@ -45,16 +45,22 @@ Object.keys(validationClasses).forEach(function (validationName) { } catch (error) { about = ''; } + + const validationClass = validationClasses[validationName]; + const validationInstance = new validationClass(); + validations[validationName] = { - validation: validationClasses[validationName], + validation: validationClass, examples, schema, about, - id: new validationClasses[validationName]().id, - github: new validationClasses[validationName]().github, - version: new validationClasses[validationName]().version, - title: new validationClasses[validationName]().title, - description: new validationClasses[validationName]().description + id: validationInstance.id, + github: validationInstance.github, + version: validationInstance.version, + title: validationInstance.title, + description: validationInstance.description, + proposalValidationOnly: validationInstance.proposalValidationOnly, + votingValidationOnly: validationInstance.votingValidationOnly }; }); From 97c0cd2a5107d97602fa51353a266c00fe1c6af2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 20 Apr 2023 18:48:11 +0530 Subject: [PATCH 368/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.78 (#1136) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 63f238e6d..a3934aee5 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.77", + "@snapshot-labs/snapshot.js": "^0.4.78", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 0216b0521..25dfa41df 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.77": - version "0.4.77" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.77.tgz#a0042d63a4f262f6e0f425914c8ac1f23bd504c0" - integrity sha512-HJdPEWF0xtRhU3Q1u2IuaQww2PzRGzb1khdfBiwwaTyWkEaP/ytLta2EezLH8btLAn2HD3I8rQIw1+TqA9hccg== +"@snapshot-labs/snapshot.js@^0.4.78": + version "0.4.78" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.78.tgz#1caf0e5af8c0e17f4de71c1d9bfe91a4e3e626a7" + integrity sha512-6gl0leNtJuoqFExBpXJook9V3V1vuh9gekZuJbcPrmelEIkOy3vf8aVeh0NutT1xsI2NWk6MWMZ27k2MSudtZg== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 1806829fe014574bc1ffbe1f449b55e92e515cee Mon Sep 17 00:00:00 2001 From: "Ratan (Rai) Sur" Date: Thu, 20 Apr 2023 14:36:21 -0400 Subject: [PATCH 369/815] Multinetwork Support for Math [math] (#1135) * multinetwork math * default to math global network --- src/strategies/math/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategies/math/index.ts b/src/strategies/math/index.ts index ab418cd20..5a302628f 100644 --- a/src/strategies/math/index.ts +++ b/src/strategies/math/index.ts @@ -170,7 +170,7 @@ async function resolveOperand( strategyOperand.strategy.name ].strategy( space, - network, + strategyOperand.strategy.network ?? network, provider, addresses, strategyOperand.strategy.params, From fa615c4129c2080f312173ad156c17da78374605 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 24 Apr 2023 10:04:09 +0530 Subject: [PATCH 370/815] Automated lint (#1138) Co-authored-by: ChaituVR --- .../staked-defi-balance/examples.json | 94 ++++++------- src/strategies/staked-defi-balance/index.ts | 81 +++++------ .../staked-defi-balance/schema.json | 127 +++++++++--------- 3 files changed, 155 insertions(+), 147 deletions(-) diff --git a/src/strategies/staked-defi-balance/examples.json b/src/strategies/staked-defi-balance/examples.json index 25105a4dc..1c14df23a 100644 --- a/src/strategies/staked-defi-balance/examples.json +++ b/src/strategies/staked-defi-balance/examples.json @@ -1,48 +1,48 @@ [ - { - "name": "Staked Defi Balance", - "strategy": { - "name": "staked-defi-balance", - "params": { - "tokenContractAddress": "0xe685d3CC0be48BD59082eDe30C3b64CbFc0326e2", - "symbol": "cFRM", - "decimals": 18, - "minStakedBalance": "100000000000000000000000", - "stakingPoolContractAddress": "0xb4927895cbee88e651e0582893051b3b0f8d7db8", - "methodABI": [ - { - "inputs": [ - { - "internalType": "address", - "name": "id", - "type": "address" - }, - { - "internalType": "address", - "name": "staker", - "type": "address" - } - ], - "name": "stakeOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } - ] - } - }, - "network": "42161", - "addresses": [ - "0x4c4180bf5ec78af9025bdd935ed69e29c2f6cbae", - "0x5785530b6f0ea72b0dba474d55b43e1af1182cad", - "0x2ed211293b1db5e7d177e2711bea83700e45b150" - ], - "snapshot": 74259791 - } -] \ No newline at end of file + { + "name": "Staked Defi Balance", + "strategy": { + "name": "staked-defi-balance", + "params": { + "tokenContractAddress": "0xe685d3CC0be48BD59082eDe30C3b64CbFc0326e2", + "symbol": "cFRM", + "decimals": 18, + "minStakedBalance": "100000000000000000000000", + "stakingPoolContractAddress": "0xb4927895cbee88e651e0582893051b3b0f8d7db8", + "methodABI": [ + { + "inputs": [ + { + "internalType": "address", + "name": "id", + "type": "address" + }, + { + "internalType": "address", + "name": "staker", + "type": "address" + } + ], + "name": "stakeOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } + ] + } + }, + "network": "42161", + "addresses": [ + "0x4c4180bf5ec78af9025bdd935ed69e29c2f6cbae", + "0x5785530b6f0ea72b0dba474d55b43e1af1182cad", + "0x2ed211293b1db5e7d177e2711bea83700e45b150" + ], + "snapshot": 74259791 + } +] diff --git a/src/strategies/staked-defi-balance/index.ts b/src/strategies/staked-defi-balance/index.ts index 696aee587..249c3eda9 100644 --- a/src/strategies/staked-defi-balance/index.ts +++ b/src/strategies/staked-defi-balance/index.ts @@ -8,44 +8,47 @@ export const author = 'taha-abbasi'; export const version = '0.1.0'; export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot + space, + network, + provider, + addresses, + options, + snapshot ): Promise> { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - const stakingPoolContractAddress = options.stakingPoolContractAddress; - const abi = options.methodABI; - - const stakingCalls = addresses.map(address => { - return [ - stakingPoolContractAddress, - 'stakeOf', - [options.tokenContractAddress, address] - ]; - }); - - const stakes = await multicall(network, provider, abi, stakingCalls, { blockTag }); - - const stakesMapped = {}; - for (let i = 0; i < addresses.length; i++) { - stakesMapped[getAddress(addresses[i])] = stakes[i][0]; - } - - const addressScores = Object.fromEntries( - addresses.map((address) => { - const normalizedAddress = getAddress(address); - const stakedBalance = stakesMapped[normalizedAddress]; - const formattedStakedBalance = parseFloat(formatUnits(stakedBalance, options.decimals)); - return [ - normalizedAddress, - stakedBalance.gte(options.minStakedBalance) ? formattedStakedBalance : 0 - ]; - }) - ); - - return addressScores; + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const stakingPoolContractAddress = options.stakingPoolContractAddress; + const abi = options.methodABI; + + const stakingCalls = addresses.map((address) => { + return [ + stakingPoolContractAddress, + 'stakeOf', + [options.tokenContractAddress, address] + ]; + }); + + const stakes = await multicall(network, provider, abi, stakingCalls, { + blockTag + }); + + const stakesMapped = {}; + for (let i = 0; i < addresses.length; i++) { + stakesMapped[getAddress(addresses[i])] = stakes[i][0]; + } + + const addressScores = Object.fromEntries( + addresses.map((address) => { + const normalizedAddress = getAddress(address); + const stakedBalance = stakesMapped[normalizedAddress]; + const formattedStakedBalance = parseFloat( + formatUnits(stakedBalance, options.decimals) + ); + return [ + normalizedAddress, + stakedBalance.gte(options.minStakedBalance) ? formattedStakedBalance : 0 + ]; + }) + ); + + return addressScores; } - diff --git a/src/strategies/staked-defi-balance/schema.json b/src/strategies/staked-defi-balance/schema.json index 230d66296..3bf132731 100644 --- a/src/strategies/staked-defi-balance/schema.json +++ b/src/strategies/staked-defi-balance/schema.json @@ -1,64 +1,69 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "Staked Defi Balance", - "type": "object", - "properties": { - "tokenContractAddress": { - "type": "string", - "pattern": "^0x[a-fA-F0-9]{40}$" - }, - "symbol": { - "type": "string" - }, - "decimals": { - "type": "integer", - "minimum": 0 - }, - "minStakedBalance": { - "type": "string", - "pattern": "^[0-9]+$" - }, - "stakingPoolContractAddress": { - "type": "string", - "pattern": "^0x[a-fA-F0-9]{40}$" - }, - "methodABI": { - "type": "array", - "items": { - "type": "object", - "properties": { - "inputs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "internalType": { "type": "string" }, - "name": { "type": "string" }, - "type": { "type": "string" } - }, - "required": ["internalType", "name", "type"] - } - }, - "name": { "type": "string" }, - "outputs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "internalType": { "type": "string" }, - "name": { "type": "string" }, - "type": { "type": "string" } - }, - "required": ["internalType", "name", "type"] - } - }, - "stateMutability": { "type": "string" }, - "type": { "type": "string" } + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Staked Defi Balance", + "type": "object", + "properties": { + "tokenContractAddress": { + "type": "string", + "pattern": "^0x[a-fA-F0-9]{40}$" + }, + "symbol": { + "type": "string" + }, + "decimals": { + "type": "integer", + "minimum": 0 + }, + "minStakedBalance": { + "type": "string", + "pattern": "^[0-9]+$" + }, + "stakingPoolContractAddress": { + "type": "string", + "pattern": "^0x[a-fA-F0-9]{40}$" + }, + "methodABI": { + "type": "array", + "items": { + "type": "object", + "properties": { + "inputs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "internalType": { "type": "string" }, + "name": { "type": "string" }, + "type": { "type": "string" } + }, + "required": ["internalType", "name", "type"] + } + }, + "name": { "type": "string" }, + "outputs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "internalType": { "type": "string" }, + "name": { "type": "string" }, + "type": { "type": "string" } + }, + "required": ["internalType", "name", "type"] + } }, - "required": ["inputs", "name", "outputs", "stateMutability", "type"] - } + "stateMutability": { "type": "string" }, + "type": { "type": "string" } + }, + "required": ["inputs", "name", "outputs", "stateMutability", "type"] } - }, - "required": ["tokenContractAddress", "decimals", "minStakedBalance", "stakingPoolContractAddress", "methodABI"] - } - \ No newline at end of file + } + }, + "required": [ + "tokenContractAddress", + "decimals", + "minStakedBalance", + "stakingPoolContractAddress", + "methodABI" + ] +} From d146081b86799c4bf6135aa3093a36a79aef3ca3 Mon Sep 17 00:00:00 2001 From: fextr <34183870+fextr@users.noreply.github.com> Date: Tue, 25 Apr 2023 15:38:34 +0400 Subject: [PATCH 371/815] [zunami-pool-gauge-aggregated-balance-of] Add zunami snapshot-strategy (#1139) * init zunami-pool-gauge-aggregated-balance-of * [zunami-pool-gauge-aggregated-balance-of] blackListAddress from strategy params --- src/strategies/index.ts | 4 +- .../README.md | 3 + .../examples.json | 34 ++++++++++ .../index.ts | 63 +++++++++++++++++++ .../schema.json | 50 +++++++++++++++ 5 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 src/strategies/zunami-pool-gauge-aggregated-balance-of/README.md create mode 100644 src/strategies/zunami-pool-gauge-aggregated-balance-of/examples.json create mode 100644 src/strategies/zunami-pool-gauge-aggregated-balance-of/index.ts create mode 100644 src/strategies/zunami-pool-gauge-aggregated-balance-of/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index c7da09bd8..8f0f03001 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -438,6 +438,7 @@ import * as rdntCapitalVoting from './rdnt-capital-voting'; import * as stakedDefiBalance from './staked-defi-balance'; import * as degenzooErc721AnimalsWeighted from './degenzoo-erc721-animals-weighted'; import * as capVotingPower from './cap-voting-power'; +import * as zunamiPoolGaugeAggregatedBalanceOf from './zunami-pool-gauge-aggregated-balance-of'; const strategies = { 'cap-voting-power': capVotingPower, @@ -882,7 +883,8 @@ const strategies = { echelonWalletPrimeAndCachedKeyGated, 'rdnt-capital-voting': rdntCapitalVoting, 'staked-defi-balance': stakedDefiBalance, - 'degenzoo-erc721-animals-weighted': degenzooErc721AnimalsWeighted + 'degenzoo-erc721-animals-weighted': degenzooErc721AnimalsWeighted, + 'zunami-pool-gauge-aggregated-balance-of': zunamiPoolGaugeAggregatedBalanceOf }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/zunami-pool-gauge-aggregated-balance-of/README.md b/src/strategies/zunami-pool-gauge-aggregated-balance-of/README.md new file mode 100644 index 000000000..950a5f6cf --- /dev/null +++ b/src/strategies/zunami-pool-gauge-aggregated-balance-of/README.md @@ -0,0 +1,3 @@ +# zunami-pool-gauge-aggregated-balance-of + +Collect aggregated balance from curve pool/gauges diff --git a/src/strategies/zunami-pool-gauge-aggregated-balance-of/examples.json b/src/strategies/zunami-pool-gauge-aggregated-balance-of/examples.json new file mode 100644 index 000000000..98c1d21de --- /dev/null +++ b/src/strategies/zunami-pool-gauge-aggregated-balance-of/examples.json @@ -0,0 +1,34 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "zunami-pool-gauge-aggregated-balance-of", + "params": { + "address": "0x0AD930970b60d24bd30F612D287f188A7626B147", + "decimals": 18, + "lpPriceDecimals": 18, + "curvePoolAddress": "0x68934F60758243eafAf4D2cFeD27BF8010bede3a", + "blackListAddresses": [ + "0xBdCA4F610e7101Cc172E2135ba025737B99AbD30", + "0xbc61f6973cE564eFFB16Cd79B5BC3916eaD592E2", + "0x989AEb4d175e16225E39E87d0D97A3360524AD80" + ] + } + }, + "network": "1", + "addresses": [ + "0xF9605D8c4c987d7Cb32D0d11FbCb8EeeB1B22D5d", + "0x1c012C98676eAFB6C1D4886a543c4fFf50a43FE0", + "0x5180db0237291A6449DdA9ed33aD90a38787621c", + "0x924402163f01cCA1b161A3188d3f32601843Ae4A", + "0xa6dC407C39bd07F6D6C3780C2F5a53e690387F4a", + "0x287CDD0A59d69E9F101E90BDBCC892607DF08CF9", + "0x2d34816C3c83554CE97144c623C381b303Aba732", + + "0xBdCA4F610e7101Cc172E2135ba025737B99AbD30", + "0xbc61f6973cE564eFFB16Cd79B5BC3916eaD592E2", + "0x989AEb4d175e16225E39E87d0D97A3360524AD80" + ], + "snapshot": 17116797 + } +] diff --git a/src/strategies/zunami-pool-gauge-aggregated-balance-of/index.ts b/src/strategies/zunami-pool-gauge-aggregated-balance-of/index.ts new file mode 100644 index 000000000..258d3526e --- /dev/null +++ b/src/strategies/zunami-pool-gauge-aggregated-balance-of/index.ts @@ -0,0 +1,63 @@ +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { call, Multicaller } from '../../utils'; + +export const author = 'fextr'; +export const version = '1.0.0'; + +const zunamiSnapshotHelperAbi = [ + 'function aggregatedBalanceOf(address _account) external view returns (uint256)' +]; + +const curveAbi = ['function get_virtual_price() view returns (uint256)']; + +interface StrategyOptions { + address: string; + decimals: number; + lpPriceDecimals: number; + curvePoolAddress: string; + blackListAddresses: string[]; +} + +export async function strategy( + space, + network, + provider, + addresses: string[], + options: StrategyOptions, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const lpPrice = parseFloat( + formatUnits( + await call( + provider, + curveAbi, + [options.curvePoolAddress, 'get_virtual_price'], + { blockTag } + ), + options.lpPriceDecimals + ) + ); + + const multi = new Multicaller(network, provider, zunamiSnapshotHelperAbi, { + blockTag + }); + const blackListAddressesArr = Array.from(options.blackListAddresses).map( + (address) => address.toLowerCase() + ); + addresses + .filter((address) => !blackListAddressesArr.includes(address.toLowerCase())) + .forEach((address) => + multi.call(address, options.address, 'aggregatedBalanceOf', [address]) + ); + const result: Record = await multi.execute(); + + return Object.fromEntries( + Object.entries(result).map(([address, balance]) => [ + address, + parseFloat(formatUnits(balance, options.decimals)) * lpPrice + ]) + ); +} diff --git a/src/strategies/zunami-pool-gauge-aggregated-balance-of/schema.json b/src/strategies/zunami-pool-gauge-aggregated-balance-of/schema.json new file mode 100644 index 000000000..9c73b2745 --- /dev/null +++ b/src/strategies/zunami-pool-gauge-aggregated-balance-of/schema.json @@ -0,0 +1,50 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "zunami-pool-gauge-aggregated-balance-of", + "type": "object", + "properties": { + "address": { + "type": "string", + "title": "Snapshot helper address", + "examples": ["e.g. 0x0AD930970b60d24bd30F612D287f188A7626B147"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 18"], + "minimum": 1 + }, + "curvePoolAddress": { + "type": "string", + "title": "Curve pool address", + "examples": ["e.g. 0x68934F60758243eafAf4D2cFeD27BF8010bede3a"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "lpPriceDecimals": { + "type": "number", + "title": "Curve lp price decimals", + "examples": ["e.g. 18"], + "minimum": 1 + }, + "blackListAddresses": { + "type": "array", + "title": "Black listed addresses", + "examples": [ + "0xBdCA4F610e7101Cc172E2135ba025737B99AbD30", + "0xbc61f6973cE564eFFB16Cd79B5BC3916eaD592E2" + ] + } + }, + "required": ["address", "decimals", "curvePoolAddress", "lpPriceDecimals", "blackListAddresses"], + "additionalProperties": false + } + } +} From 88cc797a6b05c8bc88aac17c8d877932489d0c87 Mon Sep 17 00:00:00 2001 From: Pablo Date: Tue, 25 Apr 2023 21:52:13 +0200 Subject: [PATCH 372/815] Colleteral Held in a ERC721 QiDao Vault (#1140) --- .../erc721-collateral-held/README.md | 12 +++ .../erc721-collateral-held/examples.json | 20 +++++ .../erc721-collateral-held/index.ts | 74 +++++++++++++++++++ .../erc721-collateral-held/schema.json | 28 +++++++ src/strategies/index.ts | 4 +- 5 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 src/strategies/erc721-collateral-held/README.md create mode 100644 src/strategies/erc721-collateral-held/examples.json create mode 100644 src/strategies/erc721-collateral-held/index.ts create mode 100644 src/strategies/erc721-collateral-held/schema.json diff --git a/src/strategies/erc721-collateral-held/README.md b/src/strategies/erc721-collateral-held/README.md new file mode 100644 index 000000000..7325368f8 --- /dev/null +++ b/src/strategies/erc721-collateral-held/README.md @@ -0,0 +1,12 @@ +# erc721-collateralHeld + +This strategy returns the total collateral held by voters in ERC721 vaults. It takes into account the ERC721 tokens owned by each voter and then calculates the sum of the collateral held in the associated vaults. + +Here is an example of parameters: + +```json +{ + "address": "0xc76a3cbefe490ae4450b2fcc2c38666aa99f7aa0", + "symbol": "WEAMVT" +} +``` diff --git a/src/strategies/erc721-collateral-held/examples.json b/src/strategies/erc721-collateral-held/examples.json new file mode 100644 index 000000000..5c0c21f4f --- /dev/null +++ b/src/strategies/erc721-collateral-held/examples.json @@ -0,0 +1,20 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "erc721-collateral-held", + "params": { + "address": "0x950eceee9e7d7366a24fc9d2ed4c0c37d17a0fa9", + "symbol": "AAMVT" + } + }, + "network": "42161", + "addresses": [ + "0x20798fd64a342d1ee640348e42c14181fdc842d8", + "0x985a29e88e75394dbdae41a269409f701ccf6a43", + "0x825c657e9e72c04b7dc1e92b947f2fa33d1127fb", + "0x14ccd6fb7c6d5693969f38c8ef5c08d77d260ce4" + ], + "snapshot": 84179668 + } +] diff --git a/src/strategies/erc721-collateral-held/index.ts b/src/strategies/erc721-collateral-held/index.ts new file mode 100644 index 000000000..ba97fbd20 --- /dev/null +++ b/src/strategies/erc721-collateral-held/index.ts @@ -0,0 +1,74 @@ +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; +import { getAddress } from '@ethersproject/address'; + +export const author = 'publu'; +export const version = '0.0.1'; + +const abi = [ + 'function balanceOf(address account) external view returns (uint256)', + 'function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256)', + 'function vaultCollateral(uint256 vaultId) external view returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multi1 = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => + multi1.call(address, options.address, 'balanceOf', [address]) + ); + const result: Record = await multi1.execute(); + + // get the vault number owned by each user. + const multi2 = new Multicaller(network, provider, abi, { blockTag }); + const tokenIds: Record = Object.fromEntries(addresses.map((address) => [address, []])); + for (const address of addresses) { + const balance = result[address]; + for (let i = 0; i < balance; i++) { + multi2.call(`${address}_${i}`, options.address, 'tokenOfOwnerByIndex', [address, i]); + } + } + const tokenIdsResult = await multi2.execute(); + + for (const key in tokenIdsResult) { + const [address,] = key.split('_'); + tokenIds[address].push(tokenIdsResult[key]); + } + + // get the vaultCollateral by the tokenIds and store that as the amount held by the address + const multi3 = new Multicaller(network, provider, abi, { blockTag }); + for (const address in tokenIds) { + for (const tokenId of tokenIds[address]) { + multi3.call(address, options.address, 'vaultCollateral', [tokenId]); + } + } + const collaterals: Record = await multi3.execute(); + + const resultWithDefault = {}; + for (const address of addresses) { + const balance = collaterals[address] || 0; + resultWithDefault[address] = parseFloat(formatUnits(balance, options.decimals)); + } + + // Convert addresses to checksum format before returning + const resultWithChecksum = {}; + for (const address in resultWithDefault) { + resultWithChecksum[getAddress(address)] = resultWithDefault[address]; + } + + // Check that at least one object with an address is returned + if (Object.keys(resultWithChecksum).length === 0) { + resultWithChecksum[getAddress(addresses[0])] = 0; + } + + return resultWithChecksum; +} diff --git a/src/strategies/erc721-collateral-held/schema.json b/src/strategies/erc721-collateral-held/schema.json new file mode 100644 index 000000000..0017eeaa4 --- /dev/null +++ b/src/strategies/erc721-collateral-held/schema.json @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. UNI"], + "maxLength": 16 + }, + "address": { + "type": "string", + "title": "Contract address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } + }, + "required": ["address"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 8f0f03001..19216ab69 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -439,6 +439,7 @@ import * as stakedDefiBalance from './staked-defi-balance'; import * as degenzooErc721AnimalsWeighted from './degenzoo-erc721-animals-weighted'; import * as capVotingPower from './cap-voting-power'; import * as zunamiPoolGaugeAggregatedBalanceOf from './zunami-pool-gauge-aggregated-balance-of'; +import * as erc721CollateralHeld from './erc721-collateral-held'; const strategies = { 'cap-voting-power': capVotingPower, @@ -884,7 +885,8 @@ const strategies = { 'rdnt-capital-voting': rdntCapitalVoting, 'staked-defi-balance': stakedDefiBalance, 'degenzoo-erc721-animals-weighted': degenzooErc721AnimalsWeighted, - 'zunami-pool-gauge-aggregated-balance-of': zunamiPoolGaugeAggregatedBalanceOf + 'zunami-pool-gauge-aggregated-balance-of': zunamiPoolGaugeAggregatedBalanceOf, + 'erc721-collateral-held': erc721CollateralHeld, }; Object.keys(strategies).forEach(function (strategyName) { From 7e36c348f73ebb736de4faf3debaf30b2e4785b7 Mon Sep 17 00:00:00 2001 From: Sam <51686767+samuveth@users.noreply.github.com> Date: Wed, 26 Apr 2023 18:01:42 +0700 Subject: [PATCH 373/815] Add items to zunami strategy (#1141) --- .../schema.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/strategies/zunami-pool-gauge-aggregated-balance-of/schema.json b/src/strategies/zunami-pool-gauge-aggregated-balance-of/schema.json index 9c73b2745..59426c1fa 100644 --- a/src/strategies/zunami-pool-gauge-aggregated-balance-of/schema.json +++ b/src/strategies/zunami-pool-gauge-aggregated-balance-of/schema.json @@ -40,10 +40,22 @@ "examples": [ "0xBdCA4F610e7101Cc172E2135ba025737B99AbD30", "0xbc61f6973cE564eFFB16Cd79B5BC3916eaD592E2" - ] + ], + "items": { + "type": "string", + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } } }, - "required": ["address", "decimals", "curvePoolAddress", "lpPriceDecimals", "blackListAddresses"], + "required": [ + "address", + "decimals", + "curvePoolAddress", + "lpPriceDecimals", + "blackListAddresses" + ], "additionalProperties": false } } From 7f69277e3578b408fa443985bef2a446ae9b3d55 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 26 Apr 2023 19:08:39 +0530 Subject: [PATCH 374/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.79 (#1142) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index a3934aee5..2d7d783fa 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.78", + "@snapshot-labs/snapshot.js": "^0.4.79", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 25dfa41df..bb2ab9095 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.78": - version "0.4.78" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.78.tgz#1caf0e5af8c0e17f4de71c1d9bfe91a4e3e626a7" - integrity sha512-6gl0leNtJuoqFExBpXJook9V3V1vuh9gekZuJbcPrmelEIkOy3vf8aVeh0NutT1xsI2NWk6MWMZ27k2MSudtZg== +"@snapshot-labs/snapshot.js@^0.4.79": + version "0.4.79" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.79.tgz#ebc5208f12d98ed448c4c2a820756e53e2455187" + integrity sha512-hJB6nUOosLaUJBZhZIj+YLNL1/zlv17b+savPm+VE4wRj7TGQZyU7TDKxeQFnSwRNk6dgC7dZoc+Xun0yIdp8A== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From e1823c98fda8a0dcc9c5b4269901d68b8d764881 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 27 Apr 2023 01:01:41 +0530 Subject: [PATCH 375/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.80 (#1144) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 2d7d783fa..1d57a0b03 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.79", + "@snapshot-labs/snapshot.js": "^0.4.80", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index bb2ab9095..c1f094a65 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.79": - version "0.4.79" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.79.tgz#ebc5208f12d98ed448c4c2a820756e53e2455187" - integrity sha512-hJB6nUOosLaUJBZhZIj+YLNL1/zlv17b+savPm+VE4wRj7TGQZyU7TDKxeQFnSwRNk6dgC7dZoc+Xun0yIdp8A== +"@snapshot-labs/snapshot.js@^0.4.80": + version "0.4.80" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.80.tgz#537005d7d9107d29a957265c779bc04f0ce86b19" + integrity sha512-C32pE2ocVDlzO545afFri1hgBz0RsK70QDLlukz806F/qa9WPOQtaUBF/iB8TAU8QfmqnZM38mJiR8sY0Dadzw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 0a6c4e083415d30c0f5238a33c6dfbc6fe0eeada Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 27 Apr 2023 19:26:50 +0530 Subject: [PATCH 376/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.81 (#1145) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 1d57a0b03..a6001a560 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.80", + "@snapshot-labs/snapshot.js": "^0.4.81", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index c1f094a65..e85890fe9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.80": - version "0.4.80" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.80.tgz#537005d7d9107d29a957265c779bc04f0ce86b19" - integrity sha512-C32pE2ocVDlzO545afFri1hgBz0RsK70QDLlukz806F/qa9WPOQtaUBF/iB8TAU8QfmqnZM38mJiR8sY0Dadzw== +"@snapshot-labs/snapshot.js@^0.4.81": + version "0.4.81" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.81.tgz#e3312133bed0bb7daa6c84d0a02fa45f8feb9b87" + integrity sha512-sFeHlHPY25h5kt+98Ltt7nMjm7hGx/oiQU2TT1eYWLXIOOHo2BzXwBokhA5+cLSpSAPTjg0emOypkoTbqO5M5g== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 78909b9181a17aca559c2d98e8816a6326ac8a91 Mon Sep 17 00:00:00 2001 From: Archethect Date: Sat, 29 Apr 2023 20:05:43 +0200 Subject: [PATCH 377/815] [battlefly-vgfly-and-staked-gfly]Feature/battlefly dao voting upgrade for founders voting (#1146) * Add support for staked V1 and V2 voting * Fix math bug * Fix to use gFLY backing instead of Magic backing * Fix version number + description --- .../battlefly-vgfly-and-staked-gfly/README.md | 4 + .../examples.json | 8 +- .../battlefly-vgfly-and-staked-gfly/index.ts | 91 ++++++++++++++++++- 3 files changed, 96 insertions(+), 7 deletions(-) diff --git a/src/strategies/battlefly-vgfly-and-staked-gfly/README.md b/src/strategies/battlefly-vgfly-and-staked-gfly/README.md index 3c6f5026a..9e6ac679e 100644 --- a/src/strategies/battlefly-vgfly-and-staked-gfly/README.md +++ b/src/strategies/battlefly-vgfly-and-staked-gfly/README.md @@ -5,6 +5,7 @@ This strategy calculates the voting power for addresses with one or more of the * An amount of unvested tokens * An amount of staked tokens * An amount of staked LP tokens +* An amount of staked founder tokens As input a graphUrl is required which will return those amounts for each queried address. Additionally, the gFLY, magic vgFLY and LP token addresses are required for some on-chain calls that are not possible with Subgraph. @@ -15,6 +16,9 @@ Additionally, the gFLY, magic vgFLY and LP token addresses are required for some "gFLYAddress": "0x872bAD41CFc8BA731f811fEa8B2d0b9fd6369585", "magicAddress": "0x539bdE0d7Dbd336b79148AA742883198BBF60342", "lpAddress": "0x088F2Bd3667F385427d9289C28725D43d4b74AB4", + "v1FoundersVault": "0x2F67932136D84De27D99Ed89a423b907A1b10930", + "v2FoundersVault": "0x6c9CC5a6d5484CB8eAB1438632BBf667A5E25eD9", + "foundersToken": "0xc43104775BD9f6076808B5F8dF6CbdBeac96d7dE", "vgFLYAddress": "0x86d643b7f4a2a6772A4B1bFBee5EcE46A1DE3dfD", "symbol": "gFLY", "decimals": 18 diff --git a/src/strategies/battlefly-vgfly-and-staked-gfly/examples.json b/src/strategies/battlefly-vgfly-and-staked-gfly/examples.json index 7ecc45ad2..40c0cf4c8 100644 --- a/src/strategies/battlefly-vgfly-and-staked-gfly/examples.json +++ b/src/strategies/battlefly-vgfly-and-staked-gfly/examples.json @@ -1,6 +1,6 @@ [ { - "name": "Battlefly vgFLY holders and gFLY stakers", + "name": "Battlefly vgFLY holders, gFLY stakers and founder token stakers", "strategy": { "name": "battlefly-vgfly-and-staked-gfly", "params": { @@ -8,6 +8,9 @@ "gFLYAddress": "0x872bAD41CFc8BA731f811fEa8B2d0b9fd6369585", "magicAddress": "0x539bdE0d7Dbd336b79148AA742883198BBF60342", "lpAddress": "0x088F2Bd3667F385427d9289C28725D43d4b74AB4", + "v1FoundersVault": "0x2F67932136D84De27D99Ed89a423b907A1b10930", + "v2FoundersVault": "0x6c9CC5a6d5484CB8eAB1438632BBf667A5E25eD9", + "foundersToken": "0xc43104775BD9f6076808B5F8dF6CbdBeac96d7dE", "vgFLYAddress": "0x86d643b7f4a2a6772A4B1bFBee5EcE46A1DE3dfD", "symbol": "gFLY", "decimals": 18 @@ -17,7 +20,8 @@ "addresses": [ "0x0eB468F89E5bcFA4c933c8982D8d19554e101cfe", "0x78063Ed58Edea4Ae4981946D6b4Cc63d8928CCBC", - "0x4026b3Da349C2952255Ca9db4F055ea57F4e037C" + "0x4026b3Da349C2952255Ca9db4F055ea57F4e037C", + "0x06C244a9BaFBC96E609A8DF32A07178552C7295a" ], "snapshot": 47081042 } diff --git a/src/strategies/battlefly-vgfly-and-staked-gfly/index.ts b/src/strategies/battlefly-vgfly-and-staked-gfly/index.ts index 478dccc72..17a706f68 100644 --- a/src/strategies/battlefly-vgfly-and-staked-gfly/index.ts +++ b/src/strategies/battlefly-vgfly-and-staked-gfly/index.ts @@ -4,7 +4,7 @@ import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; import { formatUnits } from '@ethersproject/units'; export const author = 'Archethect'; -export const version = '0.0.1'; +export const version = '0.0.2'; const abi = [ 'function balanceOf(address account) external view returns (uint256)', @@ -20,9 +20,14 @@ const calcVotingPower = ( stakedAsString: string, stakedLPAsString: string, vestingAsString: string, + founderStakes: { type: string }[], claimableOf: BigNumberish, decimals: number, - tokenWeight: number + tokenWeight: number, + v1VaultGFlyStaked: BigNumber, + v2VaultGFlyStaked: BigNumber, + totalV1FoundersStaked: BigNumber, + totalV2FoundersStaked: BigNumber ) => { const staked = parseFloat( formatUnits(BigNumber.from(stakedAsString), decimals) @@ -33,7 +38,30 @@ const calcVotingPower = ( const vesting = parseFloat( formatUnits(BigNumber.from(vestingAsString).sub(claimableOf), decimals) ); - return staked + vesting + stakedLP * tokenWeight; + + let v1 = 0; + let v2 = 0; + + founderStakes.map((element) => { + if (element.type === 'v1') { + v1 += 1; + } else if (element.type === 'v2') { + v2 += 1; + } + }); + + const founders = parseFloat( + formatUnits( + BigNumber.from(v1) + .mul(v1VaultGFlyStaked.div(totalV1FoundersStaked)) + .add( + BigNumber.from(v2).mul(v2VaultGFlyStaked.div(totalV2FoundersStaked)) + ), + decimals + ) + ); + + return staked + vesting + stakedLP * tokenWeight + founders; }; export async function strategy( @@ -60,6 +88,12 @@ export async function strategy( }, first: 1000 }, + founderStakes: { + __args: { + first: 1000 + }, + type: true + }, id: true, staked: true, stakedLP: true, @@ -67,15 +101,42 @@ export async function strategy( } }; + // Setup subgraph query to fetch amount of gFLY staked by V1 and V2 vaults + const paramsV1AndV2 = { + _meta: { + block: { + number: true + } + }, + accounts: { + __args: { + where: { + id_in: [ + options.v1FoundersVault.toLowerCase(), + options.v2FoundersVault.toLowerCase() + ] + } + }, + id: true, + staked: true + } + }; + if (snapshot !== 'latest') { // @ts-ignore params.accounts.__args.block = { number: snapshot }; + // @ts-ignore + paramsV1AndV2.accounts.__args.block = params.accounts.__args.block; } const result = await subgraphRequest(DF_SUBGRAPH_URL, { ...params }); + const resultV1andV2 = await subgraphRequest(DF_SUBGRAPH_URL, { + ...paramsV1AndV2 + }); + // Take the same block number than from subgraph for consistency const blockTag = typeof snapshot === 'number' ? snapshot : result._meta.block.number; @@ -91,7 +152,9 @@ export async function strategy( [options.lpAddress, 'token1', []], [options.lpAddress, 'getReserves', []], [options.lpAddress, 'totalSupply', []], - [options.lpAddress, 'decimals', []] + [options.lpAddress, 'decimals', []], + [options.foundersToken, 'balanceOf', [options.v1FoundersVault]], + [options.foundersToken, 'balanceOf', [options.v2FoundersVault]] ], { blockTag } ); @@ -103,6 +166,8 @@ export async function strategy( const lpTokenReserves = fetchContractData[2]; const lpTokenTotalSupply = fetchContractData[3][0]; const lpTokenDecimals = fetchContractData[4][0]; + const totalV1FoundersStaked = fetchContractData[5][0]; + const totalV2FoundersStaked = fetchContractData[6][0]; // calculate single lp token weight @@ -128,6 +193,17 @@ export async function strategy( ); const claimableOfResult: Record = await multi.execute(); + let v1VaultGFlyStaked; + let v2VaultGFlyStaked; + + resultV1andV2.accounts.map((element) => { + if (element.id === options.v1FoundersVault.toLowerCase()) { + v1VaultGFlyStaked = BigNumber.from(element.staked); + } else if (element.id === options.v2FoundersVault.toLowerCase()) { + v2VaultGFlyStaked = BigNumber.from(element.staked); + } + }); + return Object.fromEntries( result.accounts.map((a) => [ getAddress(a.id), @@ -135,9 +211,14 @@ export async function strategy( a.staked, a.stakedLP, a.vesting, + a.founderStakes, claimableOfResult[getAddress(a.id)], options.decimals, - tokenWeight + tokenWeight, + v1VaultGFlyStaked, + v2VaultGFlyStaked, + BigNumber.from(totalV1FoundersStaked), + BigNumber.from(totalV2FoundersStaked) ) ]) ); From 3163e06456466e3aca0759008083797b5ae2f19f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 29 Apr 2023 23:47:24 +0530 Subject: [PATCH 378/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.82 (#1147) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index a6001a560..5d91b6516 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.81", + "@snapshot-labs/snapshot.js": "^0.4.82", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index e85890fe9..2d9461212 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.81": - version "0.4.81" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.81.tgz#e3312133bed0bb7daa6c84d0a02fa45f8feb9b87" - integrity sha512-sFeHlHPY25h5kt+98Ltt7nMjm7hGx/oiQU2TT1eYWLXIOOHo2BzXwBokhA5+cLSpSAPTjg0emOypkoTbqO5M5g== +"@snapshot-labs/snapshot.js@^0.4.82": + version "0.4.82" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.82.tgz#5e37e7075fbacba9e4bed0fcc67461bf9f9d5751" + integrity sha512-JQPemFSPST+z4TPkpUTpzGzXJPJemp/xuDd2VY8btw7/SWtBZ+LupuLfzrNQzssELr0I5GkJJwUX5yyphnWuDg== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From a8555ec5aa1f7b332f4134b065ffba9de7196c89 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 30 Apr 2023 21:38:26 +0530 Subject: [PATCH 379/815] Automated lint (#1148) Co-authored-by: ChaituVR --- src/strategies/erc721-collateral-held/index.ts | 15 +++++++++++---- src/strategies/index.ts | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/strategies/erc721-collateral-held/index.ts b/src/strategies/erc721-collateral-held/index.ts index ba97fbd20..126bde093 100644 --- a/src/strategies/erc721-collateral-held/index.ts +++ b/src/strategies/erc721-collateral-held/index.ts @@ -30,17 +30,22 @@ export async function strategy( // get the vault number owned by each user. const multi2 = new Multicaller(network, provider, abi, { blockTag }); - const tokenIds: Record = Object.fromEntries(addresses.map((address) => [address, []])); + const tokenIds: Record = Object.fromEntries( + addresses.map((address) => [address, []]) + ); for (const address of addresses) { const balance = result[address]; for (let i = 0; i < balance; i++) { - multi2.call(`${address}_${i}`, options.address, 'tokenOfOwnerByIndex', [address, i]); + multi2.call(`${address}_${i}`, options.address, 'tokenOfOwnerByIndex', [ + address, + i + ]); } } const tokenIdsResult = await multi2.execute(); for (const key in tokenIdsResult) { - const [address,] = key.split('_'); + const [address] = key.split('_'); tokenIds[address].push(tokenIdsResult[key]); } @@ -56,7 +61,9 @@ export async function strategy( const resultWithDefault = {}; for (const address of addresses) { const balance = collaterals[address] || 0; - resultWithDefault[address] = parseFloat(formatUnits(balance, options.decimals)); + resultWithDefault[address] = parseFloat( + formatUnits(balance, options.decimals) + ); } // Convert addresses to checksum format before returning diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 19216ab69..72d9bdaf5 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -886,7 +886,7 @@ const strategies = { 'staked-defi-balance': stakedDefiBalance, 'degenzoo-erc721-animals-weighted': degenzooErc721AnimalsWeighted, 'zunami-pool-gauge-aggregated-balance-of': zunamiPoolGaugeAggregatedBalanceOf, - 'erc721-collateral-held': erc721CollateralHeld, + 'erc721-collateral-held': erc721CollateralHeld }; Object.keys(strategies).forEach(function (strategyName) { From 5b03e5968112ae70d10237d0cc566b95a501a788 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Sat, 6 May 2023 01:02:35 +0530 Subject: [PATCH 380/815] Update readme to test validation --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 54fbccf3c..bfa0377f4 100755 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ yarn yarn build ``` -### Test strategy with predefined tests +### Test strategy with predefined tests (params from examples.json file) > Note: If you're writing a new strategy, make sure to add it to strategies/index.ts before testing* @@ -28,6 +28,12 @@ yarn test --strategy=eth-balance yarn test --strategy=eth-balance --more=200 ``` +### Test validation with predefined tests (params from examples.json file) + +``` +yarn test:validation --validation=basic +``` + ### Test strategy with different parameters Change values inside test/scores.ts and run From 47e849fc89ad6b3f0e3341ece77024d6b4f856f3 Mon Sep 17 00:00:00 2001 From: Andrei Badea <105772011+andreibadea20@users.noreply.github.com> Date: Fri, 5 May 2023 22:45:57 +0300 Subject: [PATCH 381/815] change dps-nft-strategy (#1150) Co-authored-by: Chaitanya --- src/strategies/dps-nft-strategy/examples.json | 13 ++-- src/strategies/dps-nft-strategy/index.ts | 71 +++++++++++-------- src/strategies/dps-nft-strategy/schema.json | 17 +++++ 3 files changed, 65 insertions(+), 36 deletions(-) create mode 100644 src/strategies/dps-nft-strategy/schema.json diff --git a/src/strategies/dps-nft-strategy/examples.json b/src/strategies/dps-nft-strategy/examples.json index eda6fbc77..db52241d9 100644 --- a/src/strategies/dps-nft-strategy/examples.json +++ b/src/strategies/dps-nft-strategy/examples.json @@ -7,13 +7,14 @@ "symbol": "DPS" } }, - "network": "1285", + "network": "1284", "addresses": [ - "0xa387c8fa7be086d01d063e3426dc3ab5c7c10462", - "0x0e32ebbfe09f59481ea8fc07a6a44501b3158e83", - "0xc0e0e7122c163a8c70c9858e8674c51fb7117e88", - "0x5114e0a7a2fc85685bc114477d7c3035d47daf8b" + "0x926cE67776A621f64cCe3bFDd8d7DCC627b5134E", + "0x5114E0A7A2fC85685bc114477d7C3035d47daf8B", + "0x73b0d4b2507f867C3ECf567128A2265B084D918c", + "0x8c6fDBca2070590D7f2cE5b2c1ED1C305D968E5D", + "0x899831D937937d011305E73EE782cce0455DF15a" ], - "snapshot": 2137412 + "snapshot": 3489028 } ] diff --git a/src/strategies/dps-nft-strategy/index.ts b/src/strategies/dps-nft-strategy/index.ts index 6f2001d5b..290e88aa6 100644 --- a/src/strategies/dps-nft-strategy/index.ts +++ b/src/strategies/dps-nft-strategy/index.ts @@ -2,68 +2,79 @@ import { getAddress } from '@ethersproject/address'; import { subgraphRequest } from '../../utils'; export const author = 'andreibadea20'; -export const version = '0.2.0'; +export const version = '0.3.0'; -const DPS_SUBGRAPH_URL = { - '1285': - 'https://api.thegraph.com/subgraphs/name/andreibadea20/dps-subgraph-moonriver' +const DPS_SUBGRAPH_URL_MOONBEAM = { + '1284': + 'https://api.thegraph.com/subgraphs/name/andreibadea20/dps-holders-moonbeam' }; const PAGE_SIZE = 1000; -const params = { - users: { +const params_moonbeam = { + holders: { __args: { - block: { number: 793940 }, + block: { number: 2847359 }, first: PAGE_SIZE, skip: 0 }, id: true, - numberOfTokens: true, - listOfNFTsLocked: { + listOfDPSOwned: true, + listOfDPSLocked: { tokenId: true }, - listOfNFTsReturned: { + listOfDPSReturned: { tokenId: true } } }; export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot + space: any, + network: string | number, + provider: any, + addresses: any, + options: any, + snapshot: string ) { if (snapshot !== 'latest') { // @ts-ignore - params.users.__args.block = { number: snapshot }; + params_moonbeam.holders.__args.block = { number: snapshot }; } const score = {}; let page = 0; while (page !== -1) { - params.users.__args.skip = page * PAGE_SIZE; - const result = await subgraphRequest(DPS_SUBGRAPH_URL[network], params); + params_moonbeam.holders.__args.skip = page * PAGE_SIZE; - if (result && result.users) { - result.users.forEach((u) => { - const userAddress = getAddress(u.id); + const result = await subgraphRequest( + DPS_SUBGRAPH_URL_MOONBEAM[network], + params_moonbeam + ); - let userScore = parseInt(u.numberOfTokens); + if (result && result.holders) { + result.holders.forEach( + (holder: { + id: string; + listOfDPSOwned: string; + listOfDPSLocked: string | any[]; + listOfDPSReturned: string | any[]; + }) => { + const userAddress = getAddress(holder.id); - const lockedNFTs = u.listOfNFTsLocked.length; - const claimedNFTs = u.listOfNFTsReturned.length; + let userScore = holder.listOfDPSOwned.length; - userScore = userScore + lockedNFTs - claimedNFTs; + const lockedNFTs = holder.listOfDPSLocked.length; + const claimedNFTs = holder.listOfDPSReturned.length; - if (!score[userAddress]) score[userAddress] = 0; - score[userAddress] = userScore; - }); - page = result.users.length < PAGE_SIZE ? -1 : page + 1; + userScore = userScore + lockedNFTs - claimedNFTs; + + if (!score[userAddress]) score[userAddress] = 0; + score[userAddress] = userScore; + } + ); + page = result.holders.length < PAGE_SIZE ? -1 : page + 1; } else { page = -1; } diff --git a/src/strategies/dps-nft-strategy/schema.json b/src/strategies/dps-nft-strategy/schema.json new file mode 100644 index 000000000..09d5ee244 --- /dev/null +++ b/src/strategies/dps-nft-strategy/schema.json @@ -0,0 +1,17 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "title": "DPS" + } + }, + "required": [], + "additionalProperties": false + } + } +} From 5862f3bbdd23333a5109d4de2c1133b53da890a9 Mon Sep 17 00:00:00 2001 From: QYuQianchen <10935300+QYuQianchen@users.noreply.github.com> Date: Wed, 10 May 2023 16:22:39 +0300 Subject: [PATCH 382/815] [hopr-stake-and-balance-qv] Add new strategy (#1154) * Add strategies for staking program and wx/x/-/hopr tokens. Work despite network (1 or 100) * add strategy that calculate staked token and hopr tokens on multiple chains in a QV fashion * remove comments * add readme for hopr-stake-and-balance-qv --- .../hopr-stake-and-balance-qv/README.md | 31 ++ .../hopr-stake-and-balance-qv/examples.json | 48 +++ .../hopr-stake-and-balance-qv/index.ts | 396 ++++++++++++++++++ src/strategies/index.ts | 2 + 4 files changed, 477 insertions(+) create mode 100644 src/strategies/hopr-stake-and-balance-qv/README.md create mode 100644 src/strategies/hopr-stake-and-balance-qv/examples.json create mode 100644 src/strategies/hopr-stake-and-balance-qv/index.ts diff --git a/src/strategies/hopr-stake-and-balance-qv/README.md b/src/strategies/hopr-stake-and-balance-qv/README.md new file mode 100644 index 000000000..8d50dd516 --- /dev/null +++ b/src/strategies/hopr-stake-and-balance-qv/README.md @@ -0,0 +1,31 @@ +# HOPR Stake and Balance QV + +This `hopr-stake-and-balance-qv` strategy calculates voting power with: +`(B1 + B2 + B3 + S1 + S2)^0.5` + +where: +- B1: balance of HOPR token on mainnet +- B2: balance of HOPR token on Gnosis chain (xHOPR) +- B3: balance of wrapped HOPR token on Gnosis chain (wxHOPR) +- S1: amount of xHOPR token staked into the latest staking season +- S2: amount of wxHOPR token unclaimed from the latest staking season + +## Parameters +- "tokenAddress": Contract address of HOPR token on mainnet. Value should be `"0xf5581dfefd8fb0e4aec526be659cfab1f8c781da"` +- "symbol": Token Symbol. Value should be `"HOPR"`. +- "season": Number of the on-going season. E.g. `7`. +- "fallbackGnosisBlock": Fallback block number on Gnosis chain, in case Gnosis block number cannot be translated from Ethereum mainnet due to subgraph issues. E.g. `27852687`, +- "subgraphStudioProdQueryApiKey": Production decetralized subgraph studio query API key. If no key can be provided, use `null`. +- "subgraphStudioDevAccountId": Development subgraph studio account ID. Note that this ID should not be exposed normally. If unknown, use `null`. +- "subgraphHostedAccountName": Legacy hosted subgraph account name. Vallue is `"hoprnet"`. +- "useStake": If the staking program should be consided. If `false`, `S1 + S2 === 0`. Value should be set to `true`. +- "useHoprOnGnosis": If tokens on Gnosis chain should be consided. If `false`, `B2 + B3 === 0`. Value should be set to `true`. +- "useHoprOnMainnet": If tokens on Ethereum mainnet should be consided. If `false`, `B1 === 0`. Value should be set to `true`. +- "subgraphStudioProdAllSeasonQueryId": Production stake all season subgraph ID .Value is `"DrkbaCvNGVcNH1RghepLRy6NSHFi8Dmwp4T2LN3LqcjY"`. +- "subgraphStudioDevAllSeasonVersion": Latest development version of the stake all season subgraph. E.g. `"v0.0.9"` +- "subgraphStudioDevAllSeasonSubgraphName": Name of the staking subgraph in Graph Studio. Value should be `"hopr-stake-all-seasons"`. +- "subgraphHostedAllSeasonSubgraphName": Name of the staking subgraph in Graph Hosted service. Value should be `"hopr-stake-all-seasons"`. +- "subgraphStudioProdHoprOnGnosisQueryId": Latest development version of the HOPR token balances on Gnosis subgraph. Value should be `"njToE7kpetd3P9sJdYQPSq6yQjBs7w9DahQpBj6WAoD"`. +- "subgraphStudioDevHoprOnGnosisSubgraphName": Name of the HOPR token balances on Gnosis subgraph in Graph Studio. Value should be "hopr-on-gnosis"` +- "subgraphStudioDevHoprOnGnosisVersion": Latest development version of the HOPR token balances on Gnosis subgraph. E.g. "v0.0.2"` +- "subgraphHostedHoprOnGnosisSubgraphName": Name of the the HOPR token balances on Gnosis in Graph Hosted service. Value should be `"hopr-on-xdai"` diff --git a/src/strategies/hopr-stake-and-balance-qv/examples.json b/src/strategies/hopr-stake-and-balance-qv/examples.json new file mode 100644 index 000000000..d56e72a4e --- /dev/null +++ b/src/strategies/hopr-stake-and-balance-qv/examples.json @@ -0,0 +1,48 @@ +[ + { + "name": "Calculate score based on HOPR stake season x and token balances across chains", + "strategy": { + "name": "hopr-stake-and-balance-qv", + "params": { + "tokenAddress": "0xf5581dfefd8fb0e4aec526be659cfab1f8c781da", + "symbol": "HOPR", + "season": 7, + "fallbackGnosisBlock": 27852687, + "subgraphStudioProdQueryApiKey": null, + "subgraphStudioDevAccountId": null, + "subgraphHostedAccountName": "hoprnet", + "useStake": true, + "useHoprOnGnosis": true, + "useHoprOnMainnet": true, + "subgraphStudioProdAllSeasonQueryId": "DrkbaCvNGVcNH1RghepLRy6NSHFi8Dmwp4T2LN3LqcjY", + "subgraphStudioDevAllSeasonVersion": "v0.0.9", + "subgraphStudioDevAllSeasonSubgraphName": "hopr-stake-all-seasons", + "subgraphHostedAllSeasonSubgraphName": "hopr-stake-all-seasons", + "subgraphStudioProdHoprOnGnosisQueryId": "njToE7kpetd3P9sJdYQPSq6yQjBs7w9DahQpBj6WAoD", + "subgraphStudioDevHoprOnGnosisSubgraphName": "hopr-on-gnosis", + "subgraphStudioDevHoprOnGnosisVersion": "v0.0.2", + "subgraphHostedHoprOnGnosisSubgraphName": "hopr-on-xdai" + } + }, + "network": "1", + "addresses": [ + "0x04BBB7eA18EA570aE47d4489991645E4E49bBf37", + "0x2aF80738aC01e7883d11c912dFe8322C129ae5C5", + "0x0bb43EFc1a613658177D8f67CcF9CFFD8B25b906", + "0x53e85186ebF5A7d4BD06324F7b9D8B3623EF0307", + "0x2DCDB99930E279f1e9Ad11F491163051432542A0", + "0x4326990033eCd87A5444383Cf8c715E696301910", + "0xEd6a59A7C1D5a88b7cb5eb877A7A6078A7e801C7", + "0xeFC05B0D0C8bE8D4Cb3a220ef582E9f7E6FBCd00", + "0xC7B169b108c5e75991C520AEA97140534291C81D", + "0x04Be52434EB64aDdF373137310551ac42013677c", + "0xBE8C93a8C18AF63aAB449994AFAc13E71240ccC4", + "0xf813773eBDD4759c1B780d745081f046A5B776fB", + "0x7F26C34Ed10bF66602009231bBFF24f2f84e9270", + "0x4abd7276C53279b3aBFFF2B5D8A47c0AFc84833B", + "0x3e1A12a6019ee26418F22B656926fE38F5e58C5f", + "0x7A27A4D91231aCB3282b410Cc784517B417FA0DA" + ], + "snapshot": 17220270 + } +] diff --git a/src/strategies/hopr-stake-and-balance-qv/index.ts b/src/strategies/hopr-stake-and-balance-qv/index.ts new file mode 100644 index 000000000..d5e46b602 --- /dev/null +++ b/src/strategies/hopr-stake-and-balance-qv/index.ts @@ -0,0 +1,396 @@ +import { formatUnits, parseUnits } from '@ethersproject/units'; +import { BigNumber } from '@ethersproject/bignumber'; +import { multicall, subgraphRequest } from '../../utils'; + +/** + * @dev Calculate score based on Quadratic Voting system.Token balance comes from + * - Mainnet HOPR token balance, read from multicall + * - Gnosis chain, HOPR token balance, read from subgraph (xHOPR balance and wxHOPR balance) and multicall (mainnet HOPR balance) + * - Gnosis chain. HOPR token staked into the most recent stake season, read from subgraph. + */ +export const author = 'QYuQianchen'; +export const version = '0.1.0'; + +const XDAI_BLOCK_HOSTED_SUBGRAPH_URL = + 'https://api.thegraph.com/subgraphs/name/1hive/xdai-blocks'; +const QUERY_LIMIT = 1000; // 1000 addresses per query in Subgraph +const tokenAbi = ['function balanceOf(address) view returns (uint256)']; // get mainnet HOPR token balance +// const DEFAULT_HOPR_STAKING_ALL_SEASONS_PROD_SUBGRAPH_ID = 'DrkbaCvNGVcNH1RghepLRy6NSHFi8Dmwp4T2LN3LqcjY'; +// const DEFAULT_HOPR_ON_GNOSIS_PROD_SUBGRAPH_ID = 'njToE7kpetd3P9sJdYQPSq6yQjBs7w9DahQpBj6WAoD'; +const DEFAULT_HOPR_HOSTED_ACCOUNT_NAME = 'hoprnet'; +const DEFAULT_HOPR_STAKING_ALL_SEASONS_HOSTED_SUBGRAPH_NAME = + 'hopr-stake-all-seasons'; +const DEFAULT_HOPR_BALANCE_ON_GNOSIS_HOSTED_SUBGRAPH_NAME = 'hopr-on-xdai'; + +function getStudioProdSubgraphUrl( + apiKey: string | null | undefined, + subgraphId: string +): string | null { + return !apiKey + ? null + : `https://gateway.thegraph.com/api/${apiKey}/subgraphs/id/${subgraphId}`; +} +function getStudioDevSubgraphUrl( + accountStudioId: string | null | undefined, + subgraphName: string, + version: string +): string | null { + return !accountStudioId + ? null + : `https://api.studio.thegraph.com/query/${accountStudioId}/${subgraphName}/${version}`; +} +function getHostedSubgraphUrl( + accountName: string, + subgraphName: string +): string { + return `https://api.thegraph.com/subgraphs/name/${accountName}/${subgraphName}`; +} + +/** + * Try to query subgraphs from three differnt endpoints (hosted service, studio for development, studio in production), if applicable + * @param hostedSubgraphUrl hosted subgrpah url + * @param stuidoDevSubgraphUrl development url foro studio subgraph + * @param studioProdSubgraphUrl production url foro studio subgraph + * @param builtQuery query object + * @returns null or an object of summed token balance per address + */ +async function subgraphRequestsToVariousServices( + hostedSubgraphUrl: string, + stuidoDevSubgraphUrl: string | null, + studioProdSubgraphUrl: string | null, + builtQuery: any +): Promise { + try { + // first try with hosted service + return subgraphRequest(hostedSubgraphUrl, builtQuery); + } catch (error) { + // console.log('Failed to get data from hostedSubgraphUrl'); + } + + // then try with studio dev service + if (stuidoDevSubgraphUrl) { + try { + return subgraphRequest(stuidoDevSubgraphUrl, builtQuery); + } catch (error) { + // console.log('Failed to get data from stuidoDevSubgraphUrl'); + } + } + + // then try with studio prod service + if (studioProdSubgraphUrl) { + try { + return subgraphRequest(studioProdSubgraphUrl, builtQuery); + } catch (error) { + // console.log('Failed to get data from studioProdSubgraphUrl'); + } + } + return null; +} + +/** + * Get block number from Gnosis chain at a given timestamp. + * The timestamp of the returned block should be no-bigger than the desired timestamp + * @param timestamp number of timestamp + * @param fallbackBlockNumber fallback block number on Gnosis chain, in case no result gets returned. + * @returns a number + */ +async function getGnosisBlockNumber( + timestamp: number, + fallbackBlockNumber: number +): Promise { + const query = { + blocks: { + __args: { + first: 1, + orderBy: 'number', + orderDirection: 'desc', + where: { + timestamp_lte: timestamp + } + }, + number: true, + timestamp: true + } + }; + + // query from subgraph + const data = await subgraphRequestsToVariousServices( + XDAI_BLOCK_HOSTED_SUBGRAPH_URL, + null, + null, + query + ); + return !data ? fallbackBlockNumber : Number(data.blocks[0].number); +} + +async function stakingSubgraphQuery( + hostedSubgraphUrl: string, + stuidoDevSubgraphUrl: string | null, + studioProdSubgraphUrl: string | null, + seasonNumber: string, + addresses: string[], + blockNumber: number, + snapshot: number | string +): Promise<{ [propName: string]: BigNumber }> { + const query = { + stakingParticipations: { + __args: { + first: QUERY_LIMIT, + where: { + account_: { + id_in: addresses.map((adr) => adr.toLowerCase()) + }, + stakingSeason_: { + seasonNumber + } + } + }, + account: { + id: true + }, + actualLockedTokenAmount: true, + airdropLockedTokenAmount: true, + unclaimedRewards: true, + virtualLockedTokenAmount: true + } + }; + + if (snapshot !== 'latest') { + // @ts-ignore + query.stakingParticipations.__args.block = { number: blockNumber }; + } + + // query from subgraph + const data = await subgraphRequestsToVariousServices( + hostedSubgraphUrl, + stuidoDevSubgraphUrl, + studioProdSubgraphUrl, + query + ); + + // map result (data.accounts) to addresses + const entries = !data + ? addresses.map((addr) => [addr, BigNumber.from('0')]) + : data.stakingParticipations.map((d) => [ + d.account.id, + BigNumber.from(d.actualLockedTokenAmount) + .add(BigNumber.from(d.airdropLockedTokenAmount)) + .add(BigNumber.from(d.virtualLockedTokenAmount)) + .add(BigNumber.from(d.unclaimedRewards)) + ]); + return Object.fromEntries(entries); +} + +async function hoprTotalOnGnosisSubgraphQuery( + hostedSubgraphUrl: string, + stuidoDevSubgraphUrl: string | null, + studioProdSubgraphUrl: string | null, + addresses: string[], + blockNumber: number, + snapshot: number | string +): Promise<{ [propName: string]: BigNumber }> { + const query = { + accounts: { + __args: { + first: QUERY_LIMIT, + where: { + id_in: addresses.map((adr) => adr.toLowerCase()) + } + }, + id: true, + totalBalance: true + } + }; + + if (snapshot !== 'latest') { + // @ts-ignore + query.accounts.__args.block = { number: blockNumber }; + } + + // query from subgraph + const data = await subgraphRequestsToVariousServices( + hostedSubgraphUrl, + stuidoDevSubgraphUrl, + studioProdSubgraphUrl, + query + ); + + // map result (data.accounts) to addresses + const entries = !data + ? addresses.map((addr) => [addr, BigNumber.from('0')]) + : data.accounts.map((d) => [ + d.id, + parseUnits(d.totalBalance.toString(), 18) + ]); + return Object.fromEntries(entries); +} + +/** + * Calculate the final score + * @param shouldIncludeMainnetValue if the mainnet token balance should be taken into account + * @param subgraphScore Sum of score from two subgraphs + * @param mainnetTokenResults Multicall returned result, this should contain token balances in an array + * @param index index of the current address + * @returns squared root of the sum of subgraph scores and token amounts if the sum is above 1, if not, returns 0. + */ +function calculateScore( + shouldIncludeMainnetValue: boolean, + subgraphScore: BigNumber, + mainnetTokenResults: BigNumber[], + index: number +) { + const summedAmount = shouldIncludeMainnetValue + ? subgraphScore.add(BigNumber.from(mainnetTokenResults[index].toString())) + : subgraphScore; + const summedAmountInEth = parseFloat(formatUnits(summedAmount, 18)); + if (summedAmountInEth > 1) { + return Math.sqrt(summedAmountInEth); + } else { + return 0; + } +} + +export async function strategy( + _space, + network, + provider, + addresses, + options, + snapshot +) { + // Network must be Ethereum Mainnet + if (network !== '1') { + throw new Error('Wrong network! Please use mainnet.'); + } + + // Get the block on mainnet and find the corresponding time on Gnosis chain) + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + // get token balance (if applicable) and block + const [resHoprOnMainnet, block] = await Promise.all([ + options.useHoprOnMainnet + ? multicall( + network, + provider, + tokenAbi, + addresses.map((address: any) => [ + options.tokenAddress, + 'balanceOf', + [address] + ]), + { blockTag } + ) + : [], + provider.getBlock(blockTag) + ]); + + // get the block number for subgraph query + const subgraphBlock = await getGnosisBlockNumber( + block.timestamp, + options.fallbackGnosisBlock + ); + // console.log( + // `Block on mainnet: ${block.number} and on Gnosis ${subgraphBlock}` + // ); + + // trim addresses to sub of "QUERY_LIMIT" addresses. + const addressSubsets = Array.apply( + null, + Array(Math.ceil(addresses.length / QUERY_LIMIT)) + ).map((_e, i) => addresses.slice(i * QUERY_LIMIT, (i + 1) * QUERY_LIMIT)); + + let returnedFromSubgraphStake; + if (options.useStake) { + // construct URLs for stake season + const hostedAllSeasonSubgraphUrl: string = getHostedSubgraphUrl( + options.subgraphHostedAccountName ?? DEFAULT_HOPR_HOSTED_ACCOUNT_NAME, + options.subgraphHostedAllSeasonSubgraphName ?? + DEFAULT_HOPR_STAKING_ALL_SEASONS_HOSTED_SUBGRAPH_NAME + ); + const stuidoDevAllSeasonSubgraphUrl = getStudioDevSubgraphUrl( + options.subgraphStudioDevAccountId, + options.subgraphStudioDevAllSeasonSubgraphName, + options.subgraphStudioDevAllSeasonVersion + ); + const studioProdAllSeasonSubgraphUrl = getStudioProdSubgraphUrl( + options.subgraphStudioProdQueryApiKey, + options.subgraphStudioProdAllSeasonQueryId + ); + // get subgraph result for stake season + returnedFromSubgraphStake = await Promise.all( + addressSubsets.map((subset) => + stakingSubgraphQuery( + hostedAllSeasonSubgraphUrl, + stuidoDevAllSeasonSubgraphUrl, + studioProdAllSeasonSubgraphUrl, + options.season.toString(), + subset, + subgraphBlock, + snapshot + ) + ) + ); + } + + let returnedFromSubgraphOnGnosis; + if (options.useHoprOnGnosis) { + // construct URLs for HOPR on Gnosis + const hostedHoprOnGnosisSubgraphUrl: string = getHostedSubgraphUrl( + options.subgraphHostedAccountName ?? DEFAULT_HOPR_HOSTED_ACCOUNT_NAME, + options.subgraphHostedTokenOnGnosisSubgraphName ?? + DEFAULT_HOPR_BALANCE_ON_GNOSIS_HOSTED_SUBGRAPH_NAME + ); + const stuidoDevHoprOnGnosisSubgraphUrl = getStudioDevSubgraphUrl( + options.subgraphStudioDevAccountId, + options.subgraphStudioDevHoprOnGnosisSubgraphName, + options.subgraphStudioDevHoprOnGnosisVersion + ); + const studioProdHoprOnGnosisSubgraphUrl = getStudioProdSubgraphUrl( + options.subgraphStudioProdQueryApiKey, + options.subgraphStudioProdHoprOnGnosisQueryId + ); + // get subgraph result for hopr on gnosis + returnedFromSubgraphOnGnosis = await Promise.all( + addressSubsets.map((subset) => + hoprTotalOnGnosisSubgraphQuery( + hostedHoprOnGnosisSubgraphUrl, + stuidoDevHoprOnGnosisSubgraphUrl, + studioProdHoprOnGnosisSubgraphUrl, + subset, + subgraphBlock, + snapshot + ) + ) + ); + } + + // get and parse balance from subgraph + const subgraphStakeBalanceStake = Object.assign( + {}, + ...returnedFromSubgraphStake + ); + const subgraphStakeBalanceOnGnosis = Object.assign( + {}, + ...returnedFromSubgraphOnGnosis + ); + + const subgraphScore: BigNumber[] = addresses.map((address) => + ( + subgraphStakeBalanceStake[address.toLowerCase()] ?? BigNumber.from('0') + ).add( + subgraphStakeBalanceOnGnosis[address.toLowerCase()] ?? BigNumber.from('0') + ) + ); + + // return sqrt(subgraph score + hopr on mainet score) + return Object.fromEntries( + addresses.map((adr, i) => [ + adr, + calculateScore( + options.useHoprOnMainnet, + subgraphScore[i], + resHoprOnMainnet, + i + ) + ]) + ); +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 72d9bdaf5..7ae4bc977 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -222,6 +222,7 @@ import * as hoprStaking from './hopr-staking'; import * as hoprStakingS2 from './hopr-staking-s2'; import * as hoprStakingBySeason from './hopr-staking-by-season'; import * as hoprBridgedBalance from './hopr-bridged-balance'; +import * as hoprStakeAndBalanceQV from './hopr-stake-and-balance-qv'; import * as lootCharacterGuilds from './loot-character-guilds'; import * as swapr from './swapr'; import * as cyberkongz from './cyberkongz'; @@ -670,6 +671,7 @@ const strategies = { 'hopr-staking': hoprStaking, 'hopr-staking-s2': hoprStakingS2, 'hopr-staking-by-season': hoprStakingBySeason, + 'hopr-stake-and-balance-qv': hoprStakeAndBalanceQV, 'hopr-bridged-balance': hoprBridgedBalance, 'occ-stake-of': occStakeOf, swapr, From 67635234080a0e6b3bd252e2beb0e1b54094ca11 Mon Sep 17 00:00:00 2001 From: Andrei Badea <105772011+andreibadea20@users.noreply.github.com> Date: Wed, 10 May 2023 23:18:50 +0300 Subject: [PATCH 383/815] [dps-nft-strategy] add new strategy on nova (#1152) * change dps-nft-strategy * add nova strategy for dps-nfts * remove dps-nft-strategy-nova * delete strategy from index * clear the code * change params in strategy * Update index.ts --------- Co-authored-by: Chaitanya --- src/strategies/dps-nft-strategy/README.md | 4 ++-- src/strategies/dps-nft-strategy/examples.json | 12 ++++++------ src/strategies/dps-nft-strategy/index.ts | 12 ++++++------ test/strategy.test.ts | 1 + 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/strategies/dps-nft-strategy/README.md b/src/strategies/dps-nft-strategy/README.md index 17b577067..8a44292fd 100644 --- a/src/strategies/dps-nft-strategy/README.md +++ b/src/strategies/dps-nft-strategy/README.md @@ -1,6 +1,6 @@ # dps-nft-strategy -This is a strategy similar with ERC721, which it calculates the voting power as the balances of the voters for a specific ERC721 token, but this takes into account locked NFTs +This is a strategy similar with ERC721, which it calculates the voting power as the balances * 3 of the voters for a specific ERC721 token, but this takes into account locked NFTs and claimed NFTs. It is a strategy using for a game, where users can lock their NFTs in order to achive different things. Here is an example for calculating voting power: @@ -11,5 +11,5 @@ Bob locked NFTs: 7 Bob claimed NFTs: 3 -=> Bob voting power: 40 + 7 - 3 = 44 +=> Bob voting power: (40 + 7 - 3) * 3 = 44 * 3 diff --git a/src/strategies/dps-nft-strategy/examples.json b/src/strategies/dps-nft-strategy/examples.json index db52241d9..0425e8545 100644 --- a/src/strategies/dps-nft-strategy/examples.json +++ b/src/strategies/dps-nft-strategy/examples.json @@ -9,12 +9,12 @@ }, "network": "1284", "addresses": [ - "0x926cE67776A621f64cCe3bFDd8d7DCC627b5134E", - "0x5114E0A7A2fC85685bc114477d7C3035d47daf8B", - "0x73b0d4b2507f867C3ECf567128A2265B084D918c", - "0x8c6fDBca2070590D7f2cE5b2c1ED1C305D968E5D", - "0x899831D937937d011305E73EE782cce0455DF15a" + "0x926ce67776a621f64cce3bfdd8d7dcc627b5134e", + "0x5114e0a7a2fc85685bc114477d7c3035d47daf8b", + "0x73b0d4b2507f867c3ecf567128a2265b084d918c", + "0x8c6fdbca2070590d7f2ce5b2c1ed1c305d968e5d", + "0x899831d937937d011305e73ee782cce0455df15a" ], - "snapshot": 3489028 + "snapshot": 3516443 } ] diff --git a/src/strategies/dps-nft-strategy/index.ts b/src/strategies/dps-nft-strategy/index.ts index 290e88aa6..6eda761e4 100644 --- a/src/strategies/dps-nft-strategy/index.ts +++ b/src/strategies/dps-nft-strategy/index.ts @@ -2,7 +2,7 @@ import { getAddress } from '@ethersproject/address'; import { subgraphRequest } from '../../utils'; export const author = 'andreibadea20'; -export const version = '0.3.0'; +export const version = '0.3.1'; const DPS_SUBGRAPH_URL_MOONBEAM = { '1284': @@ -11,7 +11,7 @@ const DPS_SUBGRAPH_URL_MOONBEAM = { const PAGE_SIZE = 1000; -const params_moonbeam = { +const params = { holders: { __args: { block: { number: 2847359 }, @@ -39,18 +39,18 @@ export async function strategy( ) { if (snapshot !== 'latest') { // @ts-ignore - params_moonbeam.holders.__args.block = { number: snapshot }; + params.holders.__args.block = { number: snapshot }; } const score = {}; let page = 0; while (page !== -1) { - params_moonbeam.holders.__args.skip = page * PAGE_SIZE; + params.holders.__args.skip = page * PAGE_SIZE; const result = await subgraphRequest( DPS_SUBGRAPH_URL_MOONBEAM[network], - params_moonbeam + params ); if (result && result.holders) { @@ -71,7 +71,7 @@ export async function strategy( userScore = userScore + lockedNFTs - claimedNFTs; if (!score[userAddress]) score[userAddress] = 0; - score[userAddress] = userScore; + score[userAddress] = 3 * userScore; } ); page = result.holders.length < PAGE_SIZE ? -1 : page + 1; diff --git a/test/strategy.test.ts b/test/strategy.test.ts index d16342365..618f69598 100644 --- a/test/strategy.test.ts +++ b/test/strategy.test.ts @@ -61,6 +61,7 @@ describe.each(examples)( it('Must use a snapshot block number in the past', async () => { expect(typeof example.snapshot).toBe('number'); + const provider = snapshot.utils.getProvider(example.network); const blockNumber = await snapshot.utils.getBlockNumber(provider); expect(example.snapshot).toBeLessThanOrEqual(blockNumber); From 3e808f4232c4db2651d930260f075c4b8571c9a5 Mon Sep 17 00:00:00 2001 From: Taha Abbasi Date: Wed, 10 May 2023 16:38:06 -0600 Subject: [PATCH 384/815] [staked-defi-balance] support for multiple contracts, including traditional staking & open staking across different networks (#1149) * Updated schema and strategy to look at various staking contracts on the same network * Updated structure for multichain v1 * added support for multichain and multipel contracts * Preparing staked-defi-balance 1.0.0 for release * updated schema to allow latest in the snapshot params * Preparing release staked-defi-balance 1.1.0 * fixing Schema title * Updated schema to validate EVM addresses * Added multi-staked-defi-balance strategy and updated staked-defi-balance strategy to work with multi-staked-defi-balance per reviewers request * Removed unnecessary logs and updated README.md * Removing multi-staked-defi-balance and submitting the udpated staked-defi-balance strategy * Limited params to 5 calls per strategy * Throwing an error on multicall failure * remove try catch --------- Co-authored-by: ChaituVR --- .../ABI/openStakingABI.json | 26 +++++ .../ABI/standardStakingABI.json | 21 ++++ src/strategies/staked-defi-balance/README.md | 102 ++++++++-------- .../staked-defi-balance/examples.json | 72 +++++------- src/strategies/staked-defi-balance/index.ts | 99 +++++++++++----- .../staked-defi-balance/schema.json | 110 ++++++++---------- src/strategies/staked-defi-balance/types.ts | 17 +++ 7 files changed, 260 insertions(+), 187 deletions(-) create mode 100644 src/strategies/staked-defi-balance/ABI/openStakingABI.json create mode 100644 src/strategies/staked-defi-balance/ABI/standardStakingABI.json create mode 100644 src/strategies/staked-defi-balance/types.ts diff --git a/src/strategies/staked-defi-balance/ABI/openStakingABI.json b/src/strategies/staked-defi-balance/ABI/openStakingABI.json new file mode 100644 index 000000000..727483127 --- /dev/null +++ b/src/strategies/staked-defi-balance/ABI/openStakingABI.json @@ -0,0 +1,26 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "id", + "type": "address" + }, + { + "internalType": "address", + "name": "staker", + "type": "address" + } + ], + "name": "stakeOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/src/strategies/staked-defi-balance/ABI/standardStakingABI.json b/src/strategies/staked-defi-balance/ABI/standardStakingABI.json new file mode 100644 index 000000000..9c568fdcd --- /dev/null +++ b/src/strategies/staked-defi-balance/ABI/standardStakingABI.json @@ -0,0 +1,21 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "stakeOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/src/strategies/staked-defi-balance/README.md b/src/strategies/staked-defi-balance/README.md index eea910cde..1ed47834f 100644 --- a/src/strategies/staked-defi-balance/README.md +++ b/src/strategies/staked-defi-balance/README.md @@ -1,66 +1,70 @@ -# staked-defi-balance +staked-defi-balance +=================== This custom strategy returns the score of addresses based on their staked token balance in a specific Ferrum Network DeFi staking pool contract. Here is an example of parameters: ```json + { - "tokenContractAddress": "0xe685d3CC0be48BD59082eDe30C3b64CbFc0326e2", - "symbol": "cFRM", - "decimals": 18, - "minStakedBalance": "100000000000000000000000", - "stakingPoolContractAddress": "0xb4927895cbee88e651e0582893051b3b0f8d7db8", - "methodABI": [ - { - "inputs": [ - { - "internalType": "address", - "name": "id", - "type": "address" - }, - { - "internalType": "address", - "name": "staker", - "type": "address" - } - ], - "name": "stakeOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } - ] - } + "tokenContractAddress": "0xe685d3CC0be48BD59082eDe30C3b64CbFc0326e2", + "symbol": "cFRM", + "decimals": 18, + "minStakedBalance": "100000000000000000000000", + "stakingPoolContractAddress": "0xb4927895cbee88e651e0582893051b3b0f8d7db8", + "stakingType": "open" +} ``` -Release Notes -------------- - -### New Strategy: Staked Defi Balance - -In this update, we have added a new strategy called `Staked Defi Balance` to the snapshot-strategies repository. This custom strategy allows users to calculate the scores of addresses based on their staked token balance in a specific staking pool contract. - -#### Changes +Parameters +---------- -1. New Strategy File: A new file named `index.ts` has been added to the `src/strategies/staked-defi-balance` directory. This file contains the implementation of the `Staked Defi Balance` strategy, including multicall functionality to fetch staking balances and score calculation logic. +- `tokenContractAddress`: The address of the token contract for the staked token. +- `symbol`: The symbol of the staked token. +- `decimals`: The number of decimals for the staked token. +- `minStakedBalance`: The minimum staked balance required for a user to be included in the score calculation. The value should be in wei. +- `stakingPoolContractAddress`: The address of the staking pool contract. +- `stakingType`: The type of staking pool contract. Supported values are "open" and "standard". -2. Examples File: A new `examples.json` file has been added to the `src/strategies/staked-defi-balance` directory. This file demonstrates how to use the new strategy with the correct parameters, such as `tokenContractAddress`, `symbol`, `decimals`, `minStakedBalance`, `stakingPoolContractAddress`, and `methodABI`. +Examples +-------- -3. Schema File: A new `schema.json` file has been added to the `src/strategies/staked-defi-balance` directory. This file defines the JSON schema for the strategy parameters, ensuring that they follow the correct structure and data types. The schema enforces the required parameters and validates their format. +To use this strategy in your Snapshot configuration, you can refer to the following example: -#### Impact +```json -This update expands the capabilities of the snapshot-strategies repository by providing a new strategy for users to calculate scores based on staked token balances. This strategy can be helpful for governance proposals and voting mechanisms that involve staked tokens in a specific staking pool contract. +{ + "name": "Staked Defi Balance", + "strategy": { + "name": "staked-defi-balance", + "params": [ + { + "tokenContractAddress": "0xaf329a957653675613D0D98f49fc93326AeB36Fc", + "symbol": "cFRM", + "decimals": 18, + "minStakedBalance": "1000000000000000000", + "stakingPoolContractAddress": "0x35e15ff9ebb37d8c7a413fd85bad515396dc8008", + "stakingType": "open" + } + ] + }, + "network": "56", + "addresses": [ + "0x4c4180bf5ec78af9025bdd935ed69e29c2f6cbae", + "0x5785530b6f0ea72b0dba474d55b43e1af1182cad", + "0x468b83D6c8941115E9c61385aff8b71ADD5B8cE8", + "0xdd4ebebe197ca16dc2042414e3b243ab265b0d9a", + "0x697e8e42a50d9a759a238baab25919b177defb89", + "0x6479f7157f06e6610174b1029388B8D4193c00A0" + ], + "snapshot": 27877333 +} +``` -#### Usage +Compatibility +------------- -To use this strategy, include it in your Snapshot configuration and provide the necessary parameters as shown in the `examples.json` file. Make sure the parameters follow the structure defined in the `schema.json` file for proper validation. +This strategy is compatible with the multi-staked-defi-balance strategy v1.0.0, and it's recommended to use them together for a better user experience. -Please make sure to update your Snapshot configuration to include the new strategy and follow the release notes for any future updates or changes. \ No newline at end of file +For more information on how to use this strategy, you can refer to the [multi-staked-defi-balance README](../multi-staked-defi-balance/README.md). \ No newline at end of file diff --git a/src/strategies/staked-defi-balance/examples.json b/src/strategies/staked-defi-balance/examples.json index 1c14df23a..fe77789ce 100644 --- a/src/strategies/staked-defi-balance/examples.json +++ b/src/strategies/staked-defi-balance/examples.json @@ -1,48 +1,28 @@ [ - { - "name": "Staked Defi Balance", - "strategy": { - "name": "staked-defi-balance", - "params": { - "tokenContractAddress": "0xe685d3CC0be48BD59082eDe30C3b64CbFc0326e2", - "symbol": "cFRM", - "decimals": 18, - "minStakedBalance": "100000000000000000000000", - "stakingPoolContractAddress": "0xb4927895cbee88e651e0582893051b3b0f8d7db8", - "methodABI": [ - { - "inputs": [ - { - "internalType": "address", - "name": "id", - "type": "address" - }, - { - "internalType": "address", - "name": "staker", - "type": "address" - } - ], - "name": "stakeOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } - ] - } - }, - "network": "42161", - "addresses": [ - "0x4c4180bf5ec78af9025bdd935ed69e29c2f6cbae", - "0x5785530b6f0ea72b0dba474d55b43e1af1182cad", - "0x2ed211293b1db5e7d177e2711bea83700e45b150" - ], - "snapshot": 74259791 - } + { + "name": "Staked Defi Balance", + "strategy": { + "name": "staked-defi-balance", + "params": [ + { + "tokenContractAddress": "0xaf329a957653675613D0D98f49fc93326AeB36Fc", + "symbol": "cFRM", + "decimals": 18, + "minStakedBalance": "1000000000000000000", + "stakingPoolContractAddress": "0x35e15ff9ebb37d8c7a413fd85bad515396dc8008", + "stakingType": "open" + } + ] + }, + "network": "56", + "addresses": [ + "0x4c4180bf5ec78af9025bdd935ed69e29c2f6cbae", + "0x5785530b6f0ea72b0dba474d55b43e1af1182cad", + "0x468b83D6c8941115E9c61385aff8b71ADD5B8cE8", + "0xdd4ebebe197ca16dc2042414e3b243ab265b0d9a", + "0x697e8e42a50d9a759a238baab25919b177defb89", + "0x6479f7157f06e6610174b1029388B8D4193c00A0" + ], + "snapshot": 27877333 + } ] diff --git a/src/strategies/staked-defi-balance/index.ts b/src/strategies/staked-defi-balance/index.ts index 249c3eda9..0d2bf6e18 100644 --- a/src/strategies/staked-defi-balance/index.ts +++ b/src/strategies/staked-defi-balance/index.ts @@ -2,10 +2,13 @@ import { formatUnits } from '@ethersproject/units'; import { getAddress } from '@ethersproject/address'; -import { multicall } from '../../utils'; +import { multicall, getProvider } from '../../utils'; +import openStakingAbi from './ABI/openStakingABI.json'; +import standardStakingAbi from './ABI/standardStakingABI.json'; +import { ABI } from './types'; export const author = 'taha-abbasi'; -export const version = '0.1.0'; +export const version = '1.2.6'; export async function strategy( space, @@ -15,40 +18,80 @@ export async function strategy( options, snapshot ): Promise> { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - const stakingPoolContractAddress = options.stakingPoolContractAddress; - const abi = options.methodABI; - - const stakingCalls = addresses.map((address) => { - return [ - stakingPoolContractAddress, - 'stakeOf', - [options.tokenContractAddress, address] - ]; - }); + const maxContractsPerStrategy = 5; + if (options.length > maxContractsPerStrategy) { + throw new Error( + 'Maximum of 5 contracts allowed per strategy, see details: https://github.com/snapshot-labs/snapshot-strategies#code' + ); + } + const addressScores = {}; - const stakes = await multicall(network, provider, abi, stakingCalls, { - blockTag - }); + for (const params of options) { + const paramNetwork = network.toString(); + const paramSnapshot = typeof snapshot === 'number' ? snapshot : 'latest'; - const stakesMapped = {}; - for (let i = 0; i < addresses.length; i++) { - stakesMapped[getAddress(addresses[i])] = stakes[i][0]; - } + const stakingPoolContractAddress = params.stakingPoolContractAddress; + let abi: ABI; + switch (params.stakingType) { + case 'open': + abi = openStakingAbi[0] as ABI; + break; + case 'standard': + abi = standardStakingAbi[0] as ABI; + break; + default: + throw new Error(`Invalid stakingType: ${params.stakingType}`); + } + + const stakingCalls = addresses.map((address) => { + const inputs = abi.inputs.map((input) => { + if (input.name === 'id') { + return params.tokenContractAddress; + } else if (input.name === 'staker' || input.name === 'account') { + return address; + } + }); + return [stakingPoolContractAddress, abi.name, inputs]; + }); + + const stakes = await multicall( + paramNetwork, + getProvider(paramNetwork), + [abi], + stakingCalls, + { blockTag: paramSnapshot } + ); - const addressScores = Object.fromEntries( - addresses.map((address) => { + const stakesMapped = {}; + for (let i = 0; i < addresses.length; i++) { + stakesMapped[getAddress(addresses[i])] = stakes[i][0]; + } + + addresses.forEach((address) => { const normalizedAddress = getAddress(address); const stakedBalance = stakesMapped[normalizedAddress]; const formattedStakedBalance = parseFloat( - formatUnits(stakedBalance, options.decimals) + formatUnits(stakedBalance, params.decimals) ); - return [ - normalizedAddress, - stakedBalance.gte(options.minStakedBalance) ? formattedStakedBalance : 0 - ]; - }) + + // Initialize address score if it doesn't exist + if (!addressScores[normalizedAddress]) { + addressScores[normalizedAddress] = 0; + } + + addressScores[normalizedAddress] += formattedStakedBalance; + }); + } + + // Filter out addresses that have a total staked balance less than the minStakedBalance + const minStakedBalance = parseFloat( + formatUnits(options[0].minStakedBalance, options[0].decimals) ); + Object.keys(addressScores).forEach((address) => { + if (addressScores[address] < minStakedBalance) { + delete addressScores[address]; + } + }); return addressScores; } diff --git a/src/strategies/staked-defi-balance/schema.json b/src/strategies/staked-defi-balance/schema.json index 3bf132731..69561f9b1 100644 --- a/src/strategies/staked-defi-balance/schema.json +++ b/src/strategies/staked-defi-balance/schema.json @@ -1,69 +1,51 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "title": "Staked Defi Balance", - "type": "object", - "properties": { - "tokenContractAddress": { - "type": "string", - "pattern": "^0x[a-fA-F0-9]{40}$" - }, - "symbol": { - "type": "string" - }, - "decimals": { - "type": "integer", - "minimum": 0 - }, - "minStakedBalance": { - "type": "string", - "pattern": "^[0-9]+$" - }, - "stakingPoolContractAddress": { - "type": "string", - "pattern": "^0x[a-fA-F0-9]{40}$" - }, - "methodABI": { - "type": "array", - "items": { - "type": "object", - "properties": { - "inputs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "internalType": { "type": "string" }, - "name": { "type": "string" }, - "type": { "type": "string" } - }, - "required": ["internalType", "name", "type"] - } - }, - "name": { "type": "string" }, - "outputs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "internalType": { "type": "string" }, - "name": { "type": "string" }, - "type": { "type": "string" } - }, - "required": ["internalType", "name", "type"] - } + "type": "array", + "items": { + "type": "object", + "properties": { + "tokenContractAddress": { + "type": "string", + "pattern": "^0x[a-fA-F0-9]{40}$" + }, + "symbol": { + "type": "string" + }, + "decimals": { + "type": "integer" + }, + "minStakedBalance": { + "type": "string" + }, + "stakingPoolContractAddress": { + "type": "string", + "pattern": "^0x[a-fA-F0-9]{40}$" + }, + "stakingType": { + "oneOf": [ + { + "type": "string", + "enum": [ + "standard" + ] }, - "stateMutability": { "type": "string" }, - "type": { "type": "string" } - }, - "required": ["inputs", "name", "outputs", "stateMutability", "type"] + { + "type": "string", + "enum": [ + "open" + ] + } + ] } - } - }, - "required": [ - "tokenContractAddress", - "decimals", - "minStakedBalance", - "stakingPoolContractAddress", - "methodABI" - ] -} + }, + "required": [ + "tokenContractAddress", + "symbol", + "decimals", + "minStakedBalance", + "stakingPoolContractAddress", + "stakingType" + ] + } +} \ No newline at end of file diff --git a/src/strategies/staked-defi-balance/types.ts b/src/strategies/staked-defi-balance/types.ts new file mode 100644 index 000000000..5fee9af20 --- /dev/null +++ b/src/strategies/staked-defi-balance/types.ts @@ -0,0 +1,17 @@ +// src/strategies/staked-defi-balance/types.ts + +export interface ABI { + inputs: { + internalType: string; + name: 'id' | 'staker' | 'account'; + type: string; + }[]; + name: string; + outputs: { + internalType: string; + name: string; + type: string; + }[]; + stateMutability: string; + type: string; + } \ No newline at end of file From f760c2454d184c7535929b0c2c191cb5bfd87e48 Mon Sep 17 00:00:00 2001 From: Taha Abbasi Date: Thu, 11 May 2023 10:50:42 -0600 Subject: [PATCH 385/815] [staked-defi-balance] Fixed params structure to make it less confusing (#1157) * Updated schema and strategy to look at various staking contracts on the same network * Updated structure for multichain v1 * added support for multichain and multipel contracts * Preparing staked-defi-balance 1.0.0 for release * updated schema to allow latest in the snapshot params * Preparing release staked-defi-balance 1.1.0 * fixing Schema title * Updated schema to validate EVM addresses * Added multi-staked-defi-balance strategy and updated staked-defi-balance strategy to work with multi-staked-defi-balance per reviewers request * Removed unnecessary logs and updated README.md * Removing multi-staked-defi-balance and submitting the udpated staked-defi-balance strategy * Limited params to 5 calls per strategy * Throwing an error on multicall failure * remove try catch * Updated structure to make it less confusing to use minStakedBalance with multiple contracts * Examples ready for 1.3.0 * updating README.md for 1.3.0 * Update README.md for 1.3.0 --------- Co-authored-by: ChaituVR --- src/strategies/staked-defi-balance/README.md | 66 ++++---------- .../staked-defi-balance/examples.json | 22 ++--- src/strategies/staked-defi-balance/index.ts | 17 ++-- .../staked-defi-balance/schema.json | 90 ++++++++++--------- 4 files changed, 85 insertions(+), 110 deletions(-) diff --git a/src/strategies/staked-defi-balance/README.md b/src/strategies/staked-defi-balance/README.md index 1ed47834f..f4df5edcf 100644 --- a/src/strategies/staked-defi-balance/README.md +++ b/src/strategies/staked-defi-balance/README.md @@ -1,70 +1,40 @@ staked-defi-balance =================== -This custom strategy returns the score of addresses based on their staked token balance in a specific Ferrum Network DeFi staking pool contract. +This custom strategy returns the score of addresses based on their staked token balance in a specific staking pool contract. It works with staking contracts built and deployed by Ferrum Network. You can use this strategy to track the cumulative balance of staking contracts deployed on multiple EVM chains by adding it to your space multiple times with the network and contract configuration. Here is an example of parameters: ```json { - "tokenContractAddress": "0xe685d3CC0be48BD59082eDe30C3b64CbFc0326e2", - "symbol": "cFRM", - "decimals": 18, - "minStakedBalance": "100000000000000000000000", - "stakingPoolContractAddress": "0xb4927895cbee88e651e0582893051b3b0f8d7db8", - "stakingType": "open" + "minStakedBalance": "1", + "contracts": [ + { + "tokenContractAddress": "0xaf329a957653675613D0D98f49fc93326AeB36Fc", + "symbol": "cFRM", + "decimals": 18, + "stakingPoolContractAddress": "0x35e15ff9ebb37d8c7a413fd85bad515396dc8008", + "stakingType": "open" + } + ] } ``` Parameters ---------- -- `tokenContractAddress`: The address of the token contract for the staked token. -- `symbol`: The symbol of the staked token. -- `decimals`: The number of decimals for the staked token. - `minStakedBalance`: The minimum staked balance required for a user to be included in the score calculation. The value should be in wei. -- `stakingPoolContractAddress`: The address of the staking pool contract. -- `stakingType`: The type of staking pool contract. Supported values are "open" and "standard". +- `contracts`: An array of contract configurations where each configuration contains: + - `tokenContractAddress`: The address of the token contract for the staked token. + - `symbol`: The symbol of the staked token. + - `decimals`: The number of decimals for the staked token. + - `stakingPoolContractAddress`: The address of the staking pool contract. + - `stakingType`: The type of staking pool contract. Supported values are "open" and "standard". Examples -------- To use this strategy in your Snapshot configuration, you can refer to the following example: -```json - -{ - "name": "Staked Defi Balance", - "strategy": { - "name": "staked-defi-balance", - "params": [ - { - "tokenContractAddress": "0xaf329a957653675613D0D98f49fc93326AeB36Fc", - "symbol": "cFRM", - "decimals": 18, - "minStakedBalance": "1000000000000000000", - "stakingPoolContractAddress": "0x35e15ff9ebb37d8c7a413fd85bad515396dc8008", - "stakingType": "open" - } - ] - }, - "network": "56", - "addresses": [ - "0x4c4180bf5ec78af9025bdd935ed69e29c2f6cbae", - "0x5785530b6f0ea72b0dba474d55b43e1af1182cad", - "0x468b83D6c8941115E9c61385aff8b71ADD5B8cE8", - "0xdd4ebebe197ca16dc2042414e3b243ab265b0d9a", - "0x697e8e42a50d9a759a238baab25919b177defb89", - "0x6479f7157f06e6610174b1029388B8D4193c00A0" - ], - "snapshot": 27877333 -} -``` - -Compatibility -------------- - -This strategy is compatible with the multi-staked-defi-balance strategy v1.0.0, and it's recommended to use them together for a better user experience. - -For more information on how to use this strategy, you can refer to the [multi-staked-defi-balance README](../multi-staked-defi-balance/README.md). \ No newline at end of file +image diff --git a/src/strategies/staked-defi-balance/examples.json b/src/strategies/staked-defi-balance/examples.json index fe77789ce..0d2e1be5d 100644 --- a/src/strategies/staked-defi-balance/examples.json +++ b/src/strategies/staked-defi-balance/examples.json @@ -3,16 +3,18 @@ "name": "Staked Defi Balance", "strategy": { "name": "staked-defi-balance", - "params": [ - { - "tokenContractAddress": "0xaf329a957653675613D0D98f49fc93326AeB36Fc", - "symbol": "cFRM", - "decimals": 18, - "minStakedBalance": "1000000000000000000", - "stakingPoolContractAddress": "0x35e15ff9ebb37d8c7a413fd85bad515396dc8008", - "stakingType": "open" - } - ] + "params": { + "minStakedBalance": "300000", + "contracts": [ + { + "tokenContractAddress": "0xaf329a957653675613D0D98f49fc93326AeB36Fc", + "symbol": "cFRM", + "decimals": 18, + "stakingPoolContractAddress": "0x35e15ff9ebb37d8c7a413fd85bad515396dc8008", + "stakingType": "open" + } + ] + } }, "network": "56", "addresses": [ diff --git a/src/strategies/staked-defi-balance/index.ts b/src/strategies/staked-defi-balance/index.ts index 0d2bf6e18..f27779f19 100644 --- a/src/strategies/staked-defi-balance/index.ts +++ b/src/strategies/staked-defi-balance/index.ts @@ -8,7 +8,7 @@ import standardStakingAbi from './ABI/standardStakingABI.json'; import { ABI } from './types'; export const author = 'taha-abbasi'; -export const version = '1.2.6'; +export const version = '1.3.0'; export async function strategy( space, @@ -19,14 +19,12 @@ export async function strategy( snapshot ): Promise> { const maxContractsPerStrategy = 5; - if (options.length > maxContractsPerStrategy) { - throw new Error( - 'Maximum of 5 contracts allowed per strategy, see details: https://github.com/snapshot-labs/snapshot-strategies#code' - ); + if (options.contracts.length > maxContractsPerStrategy) { + throw new Error('Maximum of 5 contracts allowed per strategy, see details: https://github.com/snapshot-labs/snapshot-strategies#code'); } const addressScores = {}; - for (const params of options) { + for (const params of options.contracts) { const paramNetwork = network.toString(); const paramSnapshot = typeof snapshot === 'number' ? snapshot : 'latest'; @@ -74,7 +72,6 @@ export async function strategy( formatUnits(stakedBalance, params.decimals) ); - // Initialize address score if it doesn't exist if (!addressScores[normalizedAddress]) { addressScores[normalizedAddress] = 0; } @@ -83,10 +80,8 @@ export async function strategy( }); } - // Filter out addresses that have a total staked balance less than the minStakedBalance - const minStakedBalance = parseFloat( - formatUnits(options[0].minStakedBalance, options[0].decimals) - ); + const minStakedBalance = parseFloat(options.minStakedBalance); + Object.keys(addressScores).forEach((address) => { if (addressScores[address] < minStakedBalance) { delete addressScores[address]; diff --git a/src/strategies/staked-defi-balance/schema.json b/src/strategies/staked-defi-balance/schema.json index 69561f9b1..eee75ed04 100644 --- a/src/strategies/staked-defi-balance/schema.json +++ b/src/strategies/staked-defi-balance/schema.json @@ -1,51 +1,59 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "title": "Staked Defi Balance", - "type": "array", - "items": { - "type": "object", - "properties": { - "tokenContractAddress": { - "type": "string", - "pattern": "^0x[a-fA-F0-9]{40}$" - }, - "symbol": { - "type": "string" - }, - "decimals": { - "type": "integer" - }, - "minStakedBalance": { - "type": "string" - }, - "stakingPoolContractAddress": { - "type": "string", - "pattern": "^0x[a-fA-F0-9]{40}$" - }, - "stakingType": { - "oneOf": [ - { + "type": "object", + "properties": { + "minStakedBalance": { + "type": "string" + }, + "contracts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tokenContractAddress": { "type": "string", - "enum": [ - "standard" - ] + "pattern": "^0x[a-fA-F0-9]{40}$" + }, + "symbol": { + "type": "string" }, - { + "decimals": { + "type": "integer" + }, + "stakingPoolContractAddress": { "type": "string", - "enum": [ - "open" + "pattern": "^0x[a-fA-F0-9]{40}$" + }, + "stakingType": { + "oneOf": [ + { + "type": "string", + "enum": [ + "standard" + ] + }, + { + "type": "string", + "enum": [ + "open" + ] + } ] } + }, + "required": [ + "tokenContractAddress", + "symbol", + "decimals", + "stakingPoolContractAddress", + "stakingType" ] } - }, - "required": [ - "tokenContractAddress", - "symbol", - "decimals", - "minStakedBalance", - "stakingPoolContractAddress", - "stakingType" - ] - } -} \ No newline at end of file + } + }, + "required": [ + "minStakedBalance", + "contracts" + ] +} From 11e1ef83671575a52fc0c0582c9971237f14f72d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 15 May 2023 02:48:33 +0530 Subject: [PATCH 386/815] Automated lint (#1159) Co-authored-by: ChaituVR --- .../ABI/openStakingABI.json | 50 ++++++++--------- .../ABI/standardStakingABI.json | 40 ++++++------- .../staked-defi-balance/examples.json | 56 +++++++++---------- src/strategies/staked-defi-balance/index.ts | 4 +- .../staked-defi-balance/schema.json | 13 +---- src/strategies/staked-defi-balance/types.ts | 24 ++++---- 6 files changed, 91 insertions(+), 96 deletions(-) diff --git a/src/strategies/staked-defi-balance/ABI/openStakingABI.json b/src/strategies/staked-defi-balance/ABI/openStakingABI.json index 727483127..9c5d284d9 100644 --- a/src/strategies/staked-defi-balance/ABI/openStakingABI.json +++ b/src/strategies/staked-defi-balance/ABI/openStakingABI.json @@ -1,26 +1,26 @@ [ - { - "inputs": [ - { - "internalType": "address", - "name": "id", - "type": "address" - }, - { - "internalType": "address", - "name": "staker", - "type": "address" - } - ], - "name": "stakeOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] \ No newline at end of file + { + "inputs": [ + { + "internalType": "address", + "name": "id", + "type": "address" + }, + { + "internalType": "address", + "name": "staker", + "type": "address" + } + ], + "name": "stakeOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/src/strategies/staked-defi-balance/ABI/standardStakingABI.json b/src/strategies/staked-defi-balance/ABI/standardStakingABI.json index 9c568fdcd..48265808b 100644 --- a/src/strategies/staked-defi-balance/ABI/standardStakingABI.json +++ b/src/strategies/staked-defi-balance/ABI/standardStakingABI.json @@ -1,21 +1,21 @@ [ - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "stakeOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] \ No newline at end of file + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "stakeOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/src/strategies/staked-defi-balance/examples.json b/src/strategies/staked-defi-balance/examples.json index 0d2e1be5d..912c3de1c 100644 --- a/src/strategies/staked-defi-balance/examples.json +++ b/src/strategies/staked-defi-balance/examples.json @@ -1,30 +1,30 @@ [ - { - "name": "Staked Defi Balance", - "strategy": { - "name": "staked-defi-balance", - "params": { - "minStakedBalance": "300000", - "contracts": [ - { - "tokenContractAddress": "0xaf329a957653675613D0D98f49fc93326AeB36Fc", - "symbol": "cFRM", - "decimals": 18, - "stakingPoolContractAddress": "0x35e15ff9ebb37d8c7a413fd85bad515396dc8008", - "stakingType": "open" - } - ] - } - }, - "network": "56", - "addresses": [ - "0x4c4180bf5ec78af9025bdd935ed69e29c2f6cbae", - "0x5785530b6f0ea72b0dba474d55b43e1af1182cad", - "0x468b83D6c8941115E9c61385aff8b71ADD5B8cE8", - "0xdd4ebebe197ca16dc2042414e3b243ab265b0d9a", - "0x697e8e42a50d9a759a238baab25919b177defb89", - "0x6479f7157f06e6610174b1029388B8D4193c00A0" - ], - "snapshot": 27877333 - } + { + "name": "Staked Defi Balance", + "strategy": { + "name": "staked-defi-balance", + "params": { + "minStakedBalance": "300000", + "contracts": [ + { + "tokenContractAddress": "0xaf329a957653675613D0D98f49fc93326AeB36Fc", + "symbol": "cFRM", + "decimals": 18, + "stakingPoolContractAddress": "0x35e15ff9ebb37d8c7a413fd85bad515396dc8008", + "stakingType": "open" + } + ] + } + }, + "network": "56", + "addresses": [ + "0x4c4180bf5ec78af9025bdd935ed69e29c2f6cbae", + "0x5785530b6f0ea72b0dba474d55b43e1af1182cad", + "0x468b83D6c8941115E9c61385aff8b71ADD5B8cE8", + "0xdd4ebebe197ca16dc2042414e3b243ab265b0d9a", + "0x697e8e42a50d9a759a238baab25919b177defb89", + "0x6479f7157f06e6610174b1029388B8D4193c00A0" + ], + "snapshot": 27877333 + } ] diff --git a/src/strategies/staked-defi-balance/index.ts b/src/strategies/staked-defi-balance/index.ts index f27779f19..a4ac9eb14 100644 --- a/src/strategies/staked-defi-balance/index.ts +++ b/src/strategies/staked-defi-balance/index.ts @@ -20,7 +20,9 @@ export async function strategy( ): Promise> { const maxContractsPerStrategy = 5; if (options.contracts.length > maxContractsPerStrategy) { - throw new Error('Maximum of 5 contracts allowed per strategy, see details: https://github.com/snapshot-labs/snapshot-strategies#code'); + throw new Error( + 'Maximum of 5 contracts allowed per strategy, see details: https://github.com/snapshot-labs/snapshot-strategies#code' + ); } const addressScores = {}; diff --git a/src/strategies/staked-defi-balance/schema.json b/src/strategies/staked-defi-balance/schema.json index eee75ed04..7e4fb094d 100644 --- a/src/strategies/staked-defi-balance/schema.json +++ b/src/strategies/staked-defi-balance/schema.json @@ -29,15 +29,11 @@ "oneOf": [ { "type": "string", - "enum": [ - "standard" - ] + "enum": ["standard"] }, { "type": "string", - "enum": [ - "open" - ] + "enum": ["open"] } ] } @@ -52,8 +48,5 @@ } } }, - "required": [ - "minStakedBalance", - "contracts" - ] + "required": ["minStakedBalance", "contracts"] } diff --git a/src/strategies/staked-defi-balance/types.ts b/src/strategies/staked-defi-balance/types.ts index 5fee9af20..f172d95be 100644 --- a/src/strategies/staked-defi-balance/types.ts +++ b/src/strategies/staked-defi-balance/types.ts @@ -1,17 +1,17 @@ // src/strategies/staked-defi-balance/types.ts export interface ABI { - inputs: { - internalType: string; - name: 'id' | 'staker' | 'account'; - type: string; - }[]; + inputs: { + internalType: string; + name: 'id' | 'staker' | 'account'; + type: string; + }[]; + name: string; + outputs: { + internalType: string; name: string; - outputs: { - internalType: string; - name: string; - type: string; - }[]; - stateMutability: string; type: string; - } \ No newline at end of file + }[]; + stateMutability: string; + type: string; +} From 0f1a32562a2ba2cac6961ad399d3622abd973fa2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 15 May 2023 14:14:46 +0530 Subject: [PATCH 387/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.83 (#1160) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 5d91b6516..fd6de7503 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.82", + "@snapshot-labs/snapshot.js": "^0.4.83", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 2d9461212..7db6c4ab1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.82": - version "0.4.82" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.82.tgz#5e37e7075fbacba9e4bed0fcc67461bf9f9d5751" - integrity sha512-JQPemFSPST+z4TPkpUTpzGzXJPJemp/xuDd2VY8btw7/SWtBZ+LupuLfzrNQzssELr0I5GkJJwUX5yyphnWuDg== +"@snapshot-labs/snapshot.js@^0.4.83": + version "0.4.83" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.83.tgz#28a07d968a64ee03e6085c77d3f675948c66c5f2" + integrity sha512-8sVSBv9yAK47v+geQ1TgSLku+KW+9Y8m+LKRmJzcBKBfLEUs2GDSsesc4X+gn4JZkufDI6JSXjDsowpd4bJy5A== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 0f9979c5f5fa1f3fadd22a50035c04b6c546bc02 Mon Sep 17 00:00:00 2001 From: Andrei Badea <105772011+andreibadea20@users.noreply.github.com> Date: Mon, 15 May 2023 13:29:17 +0300 Subject: [PATCH 388/815] [dps-nft-strategy-nova] Add dps nft stratey nova (#1156) * change dps-nft-strategy * add nova strategy for dps-nfts * remove dps-nft-strategy-nova * add new dps-nft-strategy for nova network * Update src/strategies/dps-nft-strategy-nova/README.md * Update src/strategies/dps-nft-strategy-nova/index.ts * change snapshot --------- Co-authored-by: Chaitanya --- .../dps-nft-strategy-nova/README.md | 15 ++++ .../dps-nft-strategy-nova/examples.json | 20 +++++ src/strategies/dps-nft-strategy-nova/index.ts | 88 +++++++++++++++++++ .../dps-nft-strategy-nova/schema.json | 17 ++++ src/strategies/index.ts | 2 + 5 files changed, 142 insertions(+) create mode 100644 src/strategies/dps-nft-strategy-nova/README.md create mode 100644 src/strategies/dps-nft-strategy-nova/examples.json create mode 100644 src/strategies/dps-nft-strategy-nova/index.ts create mode 100644 src/strategies/dps-nft-strategy-nova/schema.json diff --git a/src/strategies/dps-nft-strategy-nova/README.md b/src/strategies/dps-nft-strategy-nova/README.md new file mode 100644 index 000000000..a210779aa --- /dev/null +++ b/src/strategies/dps-nft-strategy-nova/README.md @@ -0,0 +1,15 @@ +# dps-nft-strategy-nova + +This is a strategy similar with ERC721, which it calculates the voting power as the balances of the voters for a specific ERC721 token, but this takes into account locked NFTs +and claimed NFTs. It is a strategy using for a game, where users can lock their NFTs in order to achive different things. + +Here is an example for calculating voting power: + +Bob balance: 40 NFTs + +Bob locked NFTs: 7 + +Bob claimed NFTs: 3 + +=> Bob voting power: 40 + 7 - 3 = 44 + diff --git a/src/strategies/dps-nft-strategy-nova/examples.json b/src/strategies/dps-nft-strategy-nova/examples.json new file mode 100644 index 000000000..f29dafede --- /dev/null +++ b/src/strategies/dps-nft-strategy-nova/examples.json @@ -0,0 +1,20 @@ +[ + { + "name": "DPS NFTs query Nova", + "strategy": { + "name": "dps-nft-strategy-nova", + "params": { + "symbol": "DPS" + } + }, + "network": "42170", + "addresses": [ + "0x926ce67776a621f64cce3bfdd8d7dcc627b5134e", + "0x5114e0a7a2fc85685bc114477d7c3035d47daf8b", + "0x73b0d4b2507f867c3ecf567128a2265b084d918c", + "0x8c6fdbca2070590d7f2ce5b2c1ed1c305d968e5d", + "0x899831d937937d011305e73ee782cce0455df15a" + ], + "snapshot": 8703862 + } +] diff --git a/src/strategies/dps-nft-strategy-nova/index.ts b/src/strategies/dps-nft-strategy-nova/index.ts new file mode 100644 index 000000000..2bef9ff88 --- /dev/null +++ b/src/strategies/dps-nft-strategy-nova/index.ts @@ -0,0 +1,88 @@ +import { getAddress } from '@ethersproject/address'; +import { subgraphRequest } from '../../utils'; + +export const author = 'andreibadea20'; +export const version = '0.1.0'; + +const DPS_SUBGRAPH_URL_NOVA = { + '42170': + 'https://api.goldsky.com/api/public/project_clg4w9cwqdk8c3rz73mqr0z91/subgraphs/voting-subgraph/1.0.0/gn' +}; + +const PAGE_SIZE = 1000; + +const params_nova = { + holders: { + __args: { + block: { number: 927357 }, + first: PAGE_SIZE, + skip: 0 + }, + id: true, + numberOfDPSOwned: true, + listOfDPSLocked: { + tokenId: true + }, + listOfDPSReturned: { + tokenId: true + } + } +}; + +export async function strategy( + space: any, + network: string | number, + provider: any, + addresses: any, + options: any, + snapshot: string +) { + //calculate score for moonbeam + const score = {}; + + // calculate score for nova + if (snapshot !== 'latest') { + // @ts-ignore + params_nova.holders.__args.block = { number: snapshot }; + } + + // eslint-disable-next-line prefer-const + let page_nova = 0; + + while (page_nova !== -1) { + params_nova.holders.__args.skip = page_nova * PAGE_SIZE; + + const result = await subgraphRequest( + DPS_SUBGRAPH_URL_NOVA[network], + params_nova + ); + + if (result && result.holders) { + result.holders.forEach( + (holder: { + id: string; + numberOfDPSOwned: string; + listOfDPSLocked: string | any[]; + listOfDPSReturned: string | any[]; + }) => { + const userAddress = getAddress(holder.id); + + let userScore = Number(holder.numberOfDPSOwned); + + const lockedNFTs = holder.listOfDPSLocked.length; + const claimedNFTs = holder.listOfDPSReturned.length; + + userScore = userScore + lockedNFTs - claimedNFTs; + + if (!score[userAddress]) score[userAddress] = 0; + score[userAddress] = userScore; + } + ); + page_nova = result.holders.length < PAGE_SIZE ? -1 : page_nova + 1; + } else { + page_nova = -1; + } + } + + return score || {}; +} diff --git a/src/strategies/dps-nft-strategy-nova/schema.json b/src/strategies/dps-nft-strategy-nova/schema.json new file mode 100644 index 000000000..09d5ee244 --- /dev/null +++ b/src/strategies/dps-nft-strategy-nova/schema.json @@ -0,0 +1,17 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "title": "DPS" + } + }, + "required": [], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 7ae4bc977..d53aaef67 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -3,6 +3,7 @@ import path from 'path'; import * as ecoVotingPower from './eco-voting-power'; import * as dpsNFTStrategy from './dps-nft-strategy'; +import * as dpsNFTStrategyNova from './dps-nft-strategy-nova'; import * as nounsPower from './nouns-rfp-power'; import * as erc20Votes from './erc20-votes'; import * as erc20VotesWithOverride from './erc20-votes-with-override'; @@ -471,6 +472,7 @@ const strategies = { 'dfyn-staked-in-farms': dfynFarms, 'dfyn-staked-in-vaults': dfynVaults, 'dps-nft-strategy': dpsNFTStrategy, + 'dps-nft-strategy-nova': dpsNFTStrategyNova, 'eth-received': ethReceived, 'eth-philanthropy': ethPhilanthropy, 'ens-domains-owned': ensDomainsOwned, From 606d67bef2721a0d765f3170a0351a4149f3b8d8 Mon Sep 17 00:00:00 2001 From: Mark Howard Date: Tue, 16 May 2023 12:08:07 +0100 Subject: [PATCH 389/815] [hedgey-delegate] adds strategy for hedgey vesting contracts (#1155) * feat: adds hedgey delegate with multiplier strategy * chore: updating README * Update src/strategies/hedgey-delegate/index.ts Co-authored-by: Chaitanya * Update src/strategies/hedgey-delegate/index.ts Co-authored-by: Chaitanya --------- Co-authored-by: Chaitanya --- src/strategies/hedgey-delegate/README.md | 17 ++++++++ src/strategies/hedgey-delegate/examples.json | 24 ++++++++++ src/strategies/hedgey-delegate/index.ts | 37 ++++++++++++++++ src/strategies/hedgey-delegate/schema.json | 46 ++++++++++++++++++++ src/strategies/index.ts | 2 + 5 files changed, 126 insertions(+) create mode 100644 src/strategies/hedgey-delegate/README.md create mode 100644 src/strategies/hedgey-delegate/examples.json create mode 100644 src/strategies/hedgey-delegate/index.ts create mode 100644 src/strategies/hedgey-delegate/schema.json diff --git a/src/strategies/hedgey-delegate/README.md b/src/strategies/hedgey-delegate/README.md new file mode 100644 index 000000000..c00950863 --- /dev/null +++ b/src/strategies/hedgey-delegate/README.md @@ -0,0 +1,17 @@ +# hedgey-delegate + +This strategy calls the delegatedBalances function on Hedgey Vesting contracts + +It can also apply a multiplier to the value returned + +Here is an example of parameters: + +```json +{ + "contract": "0xce7ac66e78aae01d899eb90b63d1f20be2e9c4b1", + "token": "0xE13FB676E9bdd7AFda91495eC4e027FC63212FC3", + "symbol": "TACO", + "decimals": 18, + "multiplier": 10 +} +``` diff --git a/src/strategies/hedgey-delegate/examples.json b/src/strategies/hedgey-delegate/examples.json new file mode 100644 index 000000000..69dc4ac6e --- /dev/null +++ b/src/strategies/hedgey-delegate/examples.json @@ -0,0 +1,24 @@ +[ + { + "name": "Example voting based on hedgey vesting token with delegation and multiplier", + "strategy": { + "name": "hedgey-delegate", + "params": { + "contract": "0xce7ac66e78aae01d899eb90b63d1f20be2e9c4b1", + "token": "0xE13FB676E9bdd7AFda91495eC4e027FC63212FC3", + "symbol": "TACO", + "decimals": 18, + "multiplier": 10 + } + }, + "network": "5", + "addresses": [ + "0xAa9c3a194C9E78085260dfC7EAcFef51653412Bf", + "0x92d9802eFcD0485876DDC13c16cEA67e6aD5EB35", + "0xF0138A76223d93192C9c903520f1cf95c9094065", + "0xDC13Ab880e2AB7b5544a7b927769B5CEc6d62a0b", + "0xe31D847B47465cC2745319dAc9E0c6ac711cA10b" + ], + "snapshot": 8974862 + } +] diff --git a/src/strategies/hedgey-delegate/index.ts b/src/strategies/hedgey-delegate/index.ts new file mode 100644 index 000000000..11bcb798a --- /dev/null +++ b/src/strategies/hedgey-delegate/index.ts @@ -0,0 +1,37 @@ +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'hedgey-finance'; +export const version = '1.0.0'; + +const abi = [ + 'function delegatedBalances(address delegate, address token) view returns (uint256 delegatedBalance)' +] + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multi = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => + multi.call(address, options.contract, 'delegatedBalances', [ + address, + options.token + ]) + ); + const result: Record = await multi.execute(); + + return Object.fromEntries( + Object.entries(result).map(([address, balance]) => [ + address, + parseFloat(formatUnits(balance, options.decimals)) * options.multiplier + ]) + ); +} diff --git a/src/strategies/hedgey-delegate/schema.json b/src/strategies/hedgey-delegate/schema.json new file mode 100644 index 000000000..6c04a1f57 --- /dev/null +++ b/src/strategies/hedgey-delegate/schema.json @@ -0,0 +1,46 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. UNI"], + "maxLength": 16 + }, + "contract": { + "type": "string", + "title": "Contract address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "token": { + "type": "string", + "title": "Contract address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 18"] + }, + "multiplier": { + "type": "number", + "title": "Multiplier", + "examples": ["e.g. 1"] + } + }, + "required": ["contract", "token", "decimals", "multiplier"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index d53aaef67..19309c77e 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -345,6 +345,7 @@ import * as ethermon721 from './ethermon-erc721'; import * as etherorcsComboBalanceOf from './etherorcs-combo-balanceof'; import * as hedgey from './hedgey'; import * as hedgeyMulti from './hedgey-multi'; +import * as hedgeyDelegate from './hedgey-delegate'; import * as sybilProtection from './sybil-protection'; import * as veBalanceOfAtNFT from './ve-balance-of-at-nft'; import * as genzeesFromSubgraph from './genzees-from-subgraph'; @@ -795,6 +796,7 @@ const strategies = { 'rowdy-roos': rowdyRoos, hedgey, 'hedgey-multi': hedgeyMulti, + 'hedgey-delegate': hedgeyDelegate, 've-balance-of-at-nft': veBalanceOfAtNFT, 'genzees-from-subgraph': genzeesFromSubgraph, 'gin-finance': ginFinance, From 55b820e6c1b4c30612a93472ceb919b26649f2a4 Mon Sep 17 00:00:00 2001 From: TANCREZ Yohan Date: Tue, 16 May 2023 20:27:18 +0200 Subject: [PATCH 390/815] Updated `README.md` of the math strategy (#1161) --- src/strategies/math/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategies/math/README.md b/src/strategies/math/README.md index cf0b8be8c..8a4340a90 100644 --- a/src/strategies/math/README.md +++ b/src/strategies/math/README.md @@ -21,7 +21,7 @@ Currently supported operations are: ## Examples -The following example takes the cube root of a user's DAI token balance as voting score. +The following example takes the square root of a user's DAI token balance as voting score. ```json { From 8e51396a2063198e3d4825f3fec8e36c578870b5 Mon Sep 17 00:00:00 2001 From: Mark Howard Date: Thu, 18 May 2023 06:42:41 +0100 Subject: [PATCH 391/815] fix: updates titles on schema [hedgey-delegate] (#1162) * fix: updates titles on schema * fix: should take an array of contracts --- src/strategies/hedgey-delegate/examples.json | 2 +- src/strategies/hedgey-delegate/index.ts | 17 +++++++++------- src/strategies/hedgey-delegate/schema.json | 21 +++++++++++--------- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/strategies/hedgey-delegate/examples.json b/src/strategies/hedgey-delegate/examples.json index 69dc4ac6e..92b14472f 100644 --- a/src/strategies/hedgey-delegate/examples.json +++ b/src/strategies/hedgey-delegate/examples.json @@ -4,7 +4,7 @@ "strategy": { "name": "hedgey-delegate", "params": { - "contract": "0xce7ac66e78aae01d899eb90b63d1f20be2e9c4b1", + "contracts": ["0xce7ac66e78aae01d899eb90b63d1f20be2e9c4b1", "0x24f4BC74C00412422C9D2A7c78033fc8Aea8Da18"], "token": "0xE13FB676E9bdd7AFda91495eC4e027FC63212FC3", "symbol": "TACO", "decimals": 18, diff --git a/src/strategies/hedgey-delegate/index.ts b/src/strategies/hedgey-delegate/index.ts index 11bcb798a..377ad96a5 100644 --- a/src/strategies/hedgey-delegate/index.ts +++ b/src/strategies/hedgey-delegate/index.ts @@ -7,7 +7,7 @@ export const version = '1.0.0'; const abi = [ 'function delegatedBalances(address delegate, address token) view returns (uint256 delegatedBalance)' -] +]; export async function strategy( space, @@ -20,12 +20,15 @@ export async function strategy( const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; const multi = new Multicaller(network, provider, abi, { blockTag }); - addresses.forEach((address) => - multi.call(address, options.contract, 'delegatedBalances', [ - address, - options.token - ]) - ); + options.contracts.forEach((contract) => { + addresses.forEach((address) => + multi.call(address, contract, 'delegatedBalances', [ + address, + options.token + ]) + ); + }); + const result: Record = await multi.execute(); return Object.fromEntries( diff --git a/src/strategies/hedgey-delegate/schema.json b/src/strategies/hedgey-delegate/schema.json index 6c04a1f57..c68efcf78 100644 --- a/src/strategies/hedgey-delegate/schema.json +++ b/src/strategies/hedgey-delegate/schema.json @@ -12,17 +12,20 @@ "examples": ["e.g. UNI"], "maxLength": 16 }, - "contract": { - "type": "string", - "title": "Contract address", - "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 + "contracts": { + "type": "array", + "title": "Hedgey Contract addresses", + "items": { + "type": "string", + "examples": ["e.g. 0xCe7Ac66E78aAE01d899eb90b63D1f20bE2E9c4B1"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } }, "token": { "type": "string", - "title": "Contract address", + "title": "Token Contract address", "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], "pattern": "^0x[a-fA-F0-9]{40}$", "minLength": 42, @@ -39,7 +42,7 @@ "examples": ["e.g. 1"] } }, - "required": ["contract", "token", "decimals", "multiplier"], + "required": ["contracts", "token", "decimals", "multiplier"], "additionalProperties": false } } From 9beacf5df5b1eaac371f30a6457374315b4214a7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 22 May 2023 06:50:33 +0530 Subject: [PATCH 392/815] Automated lint (#1164) Co-authored-by: ChaituVR --- src/strategies/hedgey-delegate/examples.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/strategies/hedgey-delegate/examples.json b/src/strategies/hedgey-delegate/examples.json index 92b14472f..aae572d3c 100644 --- a/src/strategies/hedgey-delegate/examples.json +++ b/src/strategies/hedgey-delegate/examples.json @@ -4,7 +4,10 @@ "strategy": { "name": "hedgey-delegate", "params": { - "contracts": ["0xce7ac66e78aae01d899eb90b63d1f20be2e9c4b1", "0x24f4BC74C00412422C9D2A7c78033fc8Aea8Da18"], + "contracts": [ + "0xce7ac66e78aae01d899eb90b63d1f20be2e9c4b1", + "0x24f4BC74C00412422C9D2A7c78033fc8Aea8Da18" + ], "token": "0xE13FB676E9bdd7AFda91495eC4e027FC63212FC3", "symbol": "TACO", "decimals": 18, From fd676ad75d3457cabe49bedf1d64f05f24e0d5d6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 22 May 2023 12:44:14 +0530 Subject: [PATCH 393/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.85 (#1165) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index fd6de7503..67cb9ef2b 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.83", + "@snapshot-labs/snapshot.js": "^0.4.85", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 7db6c4ab1..2ca448f60 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.83": - version "0.4.83" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.83.tgz#28a07d968a64ee03e6085c77d3f675948c66c5f2" - integrity sha512-8sVSBv9yAK47v+geQ1TgSLku+KW+9Y8m+LKRmJzcBKBfLEUs2GDSsesc4X+gn4JZkufDI6JSXjDsowpd4bJy5A== +"@snapshot-labs/snapshot.js@^0.4.85": + version "0.4.85" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.85.tgz#91beb160ea1929e4f911ed12de758f943a640263" + integrity sha512-HV16FB/8rvzGb+9qEulzbnomj0jaAOhm7wgFQl2/Z+1ZUAYzGks1KKfAlv73a0Vms2F1Z+f1n0SLgMlpIK8lbw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 6f5f718111cf8aa6d9a99e57d2f9519414a15f5b Mon Sep 17 00:00:00 2001 From: rsquare Date: Tue, 23 May 2023 20:45:57 +0200 Subject: [PATCH 394/815] Polygon network support for Otterspace (#1167) * Adding mainnet & opti-goerli. Pickign highest badge weight * Update src/strategies/otterspace-badges/index.ts Co-authored-by: Chaitanya * fix: schema change in badge owner * feat: adding polygon network --------- Co-authored-by: Chaitanya --- src/strategies/otterspace-badges/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/strategies/otterspace-badges/index.ts b/src/strategies/otterspace-badges/index.ts index 20bd5ec3a..e124d03c0 100644 --- a/src/strategies/otterspace-badges/index.ts +++ b/src/strategies/otterspace-badges/index.ts @@ -9,7 +9,8 @@ const OTTERSPACE_SUBGRAPH_API_URLS_BY_CHAIN_ID = { '5': 'https://api.thegraph.com/subgraphs/name/otterspace-xyz/badges-goerli', '10': 'https://api.thegraph.com/subgraphs/name/otterspace-xyz/badges-optimism-alpha', '420': - 'https://api.thegraph.com/subgraphs/name/otterspace-xyz/badges-optimism-goerli' + 'https://api.thegraph.com/subgraphs/name/otterspace-xyz/badges-optimism-goerli', + '137': 'https://api.thegraph.com/subgraphs/name/otterspace-xyz/badges-polygon' }; function fetchBadgesForRaft( From f50767cf55ae69f1bf478b05574dad4dcbb0e73b Mon Sep 17 00:00:00 2001 From: HaynarCool Date: Thu, 25 May 2023 21:09:51 +0800 Subject: [PATCH 395/815] [galxe-loyalty-points] feat: add snapshot id in params (#1166) * add galxe-loyalty-points strategy * Update src/strategies/galxe-loyalty-points/examples.json * fix example data * add README * use space url instead of space id * update to prd version * feat: support snapshot * feat: add snapshot id in params * Update index.ts * Update index.ts * Update src/strategies/galxe-loyalty-points/index.ts * Update src/strategies/galxe-loyalty-points/index.ts * Update src/strategies/galxe-loyalty-points/index.ts --------- Co-authored-by: Chaitanya --- src/strategies/galxe-loyalty-points/README.md | 3 ++- src/strategies/galxe-loyalty-points/examples.json | 12 +++++------- src/strategies/galxe-loyalty-points/index.ts | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/strategies/galxe-loyalty-points/README.md b/src/strategies/galxe-loyalty-points/README.md index b191b562f..488d28734 100644 --- a/src/strategies/galxe-loyalty-points/README.md +++ b/src/strategies/galxe-loyalty-points/README.md @@ -14,7 +14,8 @@ Here’s how to set it up: ``` { "symbol": "PTS", // Voting power unit shows in proposal - "space_url": "https://galxe.com/SummerSpace/campaigns" // Galxe space url + "space_url": "https://galxe.com/Galxe/campaigns", // Galxe space url + "snapshot_id": "chm75g3gm3qfltgb9av0" } ``` 4. Input some addresses to test the voting power of each address, and you’re good to go! diff --git a/src/strategies/galxe-loyalty-points/examples.json b/src/strategies/galxe-loyalty-points/examples.json index 448f43e81..775596916 100644 --- a/src/strategies/galxe-loyalty-points/examples.json +++ b/src/strategies/galxe-loyalty-points/examples.json @@ -5,17 +5,15 @@ "name": "galxe-loyalty-points", "params": { "symbol": "PTS", - "space_url": "https://galxe.com/SummerSpace/campaigns" + "space_url": "https://galxe.com/Galxe/campaigns", + "snapshot_id": "chm75g3gm3qfltgb9av0" } }, "network": "137", "addresses": [ - "0x09092D6eCF228F3ba3C639c8dD2540fe7E675255", - "0x69D0341d380a1229f4751a0A721345dBc716586C", - "0xe5fF2C80759db9408dC9fD22b155b851Cd5aAA94", - "0xBaE38Bf54f2aA0e6159f3d9B656300f61DBd2ED3", - "0x5924EB6A482CeA85e23403E448257FbE5c58A9ed", - "0xD02BAE47fD93325fd0cc3d660B73D8f93C4D7B5E", + "0xC229c465E08C4bbE5743B36F321A677D8a398062", + "0x447D24B00937BCc3fE5768c828fb2fae52c3e8C5", + "0x498d038C3F0aFA27D80B4A82e76dcEf5A1dE7840", "0xfDAc618DDB79f77eb2Ea5c52b7c50f8f728DAFce" ], "snapshot": 1 diff --git a/src/strategies/galxe-loyalty-points/index.ts b/src/strategies/galxe-loyalty-points/index.ts index 196384dfa..59092de18 100644 --- a/src/strategies/galxe-loyalty-points/index.ts +++ b/src/strategies/galxe-loyalty-points/index.ts @@ -38,7 +38,7 @@ export async function strategy( variables: { alias: parts[1], addresses: addresses, - snapshotId: typeof snapshot === 'number' ? snapshot : '' + snapshotId: options.snapshot_id ? options.snapshot_id : (typeof snapshot === 'number' ? snapshot : '') } }) }; From b693303fa09f8de7ca4f1b51be66ec89e846e7d3 Mon Sep 17 00:00:00 2001 From: Wolf Warrior Date: Fri, 26 May 2023 05:37:24 +0100 Subject: [PATCH 396/815] add new strategy starlay ve balance of locker [starlay-ve-balance-of-locker-id] (#1169) * make snapshot for starlay ve * get balance of locker id * Update src/strategies/starlay-ve-balance-of-locker-id/index.ts * Update src/strategies/starlay-ve-balance-of-locker-id/index.ts * Update src/strategies/starlay-ve-balance-of-locker-id/index.ts --------- Co-authored-by: Chaitanya --- src/strategies/index.ts | 4 +- .../starlay-ve-balance-of-locker-id/README.md | 13 ++++++ .../examples.json | 35 ++++++++++++++++ .../starlay-ve-balance-of-locker-id/index.ts | 40 +++++++++++++++++++ .../schema.json | 33 +++++++++++++++ 5 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 src/strategies/starlay-ve-balance-of-locker-id/README.md create mode 100644 src/strategies/starlay-ve-balance-of-locker-id/examples.json create mode 100644 src/strategies/starlay-ve-balance-of-locker-id/index.ts create mode 100644 src/strategies/starlay-ve-balance-of-locker-id/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 19309c77e..2b4cb5cbc 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -443,6 +443,7 @@ import * as degenzooErc721AnimalsWeighted from './degenzoo-erc721-animals-weight import * as capVotingPower from './cap-voting-power'; import * as zunamiPoolGaugeAggregatedBalanceOf from './zunami-pool-gauge-aggregated-balance-of'; import * as erc721CollateralHeld from './erc721-collateral-held'; +import * as starlayVeBalanceOfLockerId from './starlay-ve-balance-of-locker-id'; const strategies = { 'cap-voting-power': capVotingPower, @@ -892,7 +893,8 @@ const strategies = { 'staked-defi-balance': stakedDefiBalance, 'degenzoo-erc721-animals-weighted': degenzooErc721AnimalsWeighted, 'zunami-pool-gauge-aggregated-balance-of': zunamiPoolGaugeAggregatedBalanceOf, - 'erc721-collateral-held': erc721CollateralHeld + 'erc721-collateral-held': erc721CollateralHeld, + 'starlay-ve-balance-of-locker-id': starlayVeBalanceOfLockerId }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/starlay-ve-balance-of-locker-id/README.md b/src/strategies/starlay-ve-balance-of-locker-id/README.md new file mode 100644 index 000000000..43da74dae --- /dev/null +++ b/src/strategies/starlay-ve-balance-of-locker-id/README.md @@ -0,0 +1,13 @@ +# starlay-ve-balance-of-locker-id + +This is the strategy for starlay's Voting Escrow, it returns the balances of the voters for veLAY token. + +Here is an example of parameters: + +```json +{ + "address": "0xDf32D28c1BdF25c457E82797316d623C2fcB29C8", + "symbol": "veLAY", + "decimals": 18 +} +``` diff --git a/src/strategies/starlay-ve-balance-of-locker-id/examples.json b/src/strategies/starlay-ve-balance-of-locker-id/examples.json new file mode 100644 index 000000000..459f217bc --- /dev/null +++ b/src/strategies/starlay-ve-balance-of-locker-id/examples.json @@ -0,0 +1,35 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "starlay-ve-balance-of-locker-id", + "params": { + "address": "0xDf32D28c1BdF25c457E82797316d623C2fcB29C8", + "symbol": "veLAY", + "decimals": 18 + } + }, + "network": "592", + "addresses": [ + "0x3Ff1aD046Cf6B5F5fC035b909e0E4482186b8354", + "0x50414Ac6431279824df9968855181474c919a94B", + "0x00aa74a272603c502503b1F470F81F4D441A6413", + "0xa9Fc75f34c338f658bC0BeAA57f14D675301185f", + "0xCdfc500F7f0FCe1278aECb0340b523cD55b3EBbb", + "0x8114c31Cd93141DD6229553F622b85b06624957e", + "0xCB163C7A7D299c54F71144D02870eC0c9A82AB29", + "0x61709f32808EBCD44b0D7c9271a4A16D167A7AC4", + "0x145a89758F3f9e26ffb96a4eD853d4fEDfa3a87B", + "0x1b40f4f72618530cA1e560b201F0a608C736E43e", + "0x02E7b714fae84e4BA80f3CDa5508553e7CF5042A", + "0xb3ff54b7F24950945bA8f1778F52835a7aD30A7F", + "0x0Ba1Aa8e98257EFb07cCa9bDCC410a38056897d1", + "0x244C76c039Cc412826F9e4427Ce600DcFC013a6c", + "0x332d9CDf9fDA07C32622B9C7eDE52Eb1a851eC53", + "0x7457667ee63BCa3c134f246af687091e7E259Bc2", + "0xab4382aAdae5bF4b37B90b9dc07FC72D52e2a28A", + "0x94c74DFA070500E317DddE4d64007FE26ae8aB9A" + ], + "snapshot": 3642724 + } +] \ No newline at end of file diff --git a/src/strategies/starlay-ve-balance-of-locker-id/index.ts b/src/strategies/starlay-ve-balance-of-locker-id/index.ts new file mode 100644 index 000000000..7eef7d0fb --- /dev/null +++ b/src/strategies/starlay-ve-balance-of-locker-id/index.ts @@ -0,0 +1,40 @@ +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'wolfwarrier14'; +export const version = '0.1.0'; + +const abi = [ + 'function ownerToId(address) view returns (uint256)', + 'function balanceOfLockerId(uint256 _lockerId) view returns (uint256)' +] + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multi = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => + multi.call(address, options.address, 'ownerToId', [address]) + ); + const locker_id_result: Record = await multi.execute(); + + Object.entries(locker_id_result).map(([address, locker_id]) => + multi.call(address, options.address, 'balanceOfLockerId', [locker_id]) + ); + const balance_result: Record = await multi.execute(); + + return Object.fromEntries( + Object.entries(balance_result).map(([address, balance]) => [ + address, + parseFloat(formatUnits(balance, options.decimals)) + ]) + ); +} diff --git a/src/strategies/starlay-ve-balance-of-locker-id/schema.json b/src/strategies/starlay-ve-balance-of-locker-id/schema.json new file mode 100644 index 000000000..2113da8b8 --- /dev/null +++ b/src/strategies/starlay-ve-balance-of-locker-id/schema.json @@ -0,0 +1,33 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. UNI"], + "maxLength": 16 + }, + "address": { + "type": "string", + "title": "Contract address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 18"] + } + }, + "required": ["address", "decimals"], + "additionalProperties": false + } + } +} From 577edf5448a7863c456835053ac6672eae30227c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 26 May 2023 10:14:04 +0530 Subject: [PATCH 397/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.86 (#1170) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 67cb9ef2b..d48a2b36c 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.85", + "@snapshot-labs/snapshot.js": "^0.4.86", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 2ca448f60..5eb898df6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.85": - version "0.4.85" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.85.tgz#91beb160ea1929e4f911ed12de758f943a640263" - integrity sha512-HV16FB/8rvzGb+9qEulzbnomj0jaAOhm7wgFQl2/Z+1ZUAYzGks1KKfAlv73a0Vms2F1Z+f1n0SLgMlpIK8lbw== +"@snapshot-labs/snapshot.js@^0.4.86": + version "0.4.86" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.86.tgz#c2255aa8bb8cdd1cd20fd9b9db8954b847af286b" + integrity sha512-c7B0YrWQQfgzssbhVX/wb7EszA19v43lJbxysQumov5Z/HjvIPwHIBnaJDxai+nWU5vXGa+RX9yoYYywXKnNhw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 6673682a6caccd24aea7e060dc4a471885484222 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 28 May 2023 21:54:16 +0530 Subject: [PATCH 398/815] Automated lint (#1172) Co-authored-by: ChaituVR --- src/strategies/galxe-loyalty-points/index.ts | 6 +++++- .../starlay-ve-balance-of-locker-id/examples.json | 2 +- src/strategies/starlay-ve-balance-of-locker-id/index.ts | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/strategies/galxe-loyalty-points/index.ts b/src/strategies/galxe-loyalty-points/index.ts index 59092de18..5df3e24d2 100644 --- a/src/strategies/galxe-loyalty-points/index.ts +++ b/src/strategies/galxe-loyalty-points/index.ts @@ -38,7 +38,11 @@ export async function strategy( variables: { alias: parts[1], addresses: addresses, - snapshotId: options.snapshot_id ? options.snapshot_id : (typeof snapshot === 'number' ? snapshot : '') + snapshotId: options.snapshot_id + ? options.snapshot_id + : typeof snapshot === 'number' + ? snapshot + : '' } }) }; diff --git a/src/strategies/starlay-ve-balance-of-locker-id/examples.json b/src/strategies/starlay-ve-balance-of-locker-id/examples.json index 459f217bc..762f19c54 100644 --- a/src/strategies/starlay-ve-balance-of-locker-id/examples.json +++ b/src/strategies/starlay-ve-balance-of-locker-id/examples.json @@ -32,4 +32,4 @@ ], "snapshot": 3642724 } -] \ No newline at end of file +] diff --git a/src/strategies/starlay-ve-balance-of-locker-id/index.ts b/src/strategies/starlay-ve-balance-of-locker-id/index.ts index 7eef7d0fb..80ca71006 100644 --- a/src/strategies/starlay-ve-balance-of-locker-id/index.ts +++ b/src/strategies/starlay-ve-balance-of-locker-id/index.ts @@ -8,7 +8,7 @@ export const version = '0.1.0'; const abi = [ 'function ownerToId(address) view returns (uint256)', 'function balanceOfLockerId(uint256 _lockerId) view returns (uint256)' -] +]; export async function strategy( space, From 3a82c5a5b08bcbecb201f581ecb8d07d90f087a1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 29 May 2023 15:17:26 +0530 Subject: [PATCH 399/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.87 (#1173) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index d48a2b36c..30219f52e 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.86", + "@snapshot-labs/snapshot.js": "^0.4.87", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 5eb898df6..ba48484c7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.86": - version "0.4.86" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.86.tgz#c2255aa8bb8cdd1cd20fd9b9db8954b847af286b" - integrity sha512-c7B0YrWQQfgzssbhVX/wb7EszA19v43lJbxysQumov5Z/HjvIPwHIBnaJDxai+nWU5vXGa+RX9yoYYywXKnNhw== +"@snapshot-labs/snapshot.js@^0.4.87": + version "0.4.87" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.87.tgz#de996d7f0ed090241b86af70f85c7cca5b731cca" + integrity sha512-Q8l4xdCPyKSps/V/HRt7ONlgk6BgyTW8eUUgtrAOlXdP3OQfsC00RyezVYQl+X4JVxR5OrMKT3Zib737HXJE0A== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 243d1e428d3b7f45c449cb8dbd3298886d89d322 Mon Sep 17 00:00:00 2001 From: less Date: Mon, 29 May 2023 18:49:31 +0700 Subject: [PATCH 400/815] chore: update snapshot.js to v0.4.88 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 30219f52e..2c9166432 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.87", + "@snapshot-labs/snapshot.js": "^0.4.88", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index ba48484c7..0eba118b4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.87": - version "0.4.87" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.87.tgz#de996d7f0ed090241b86af70f85c7cca5b731cca" - integrity sha512-Q8l4xdCPyKSps/V/HRt7ONlgk6BgyTW8eUUgtrAOlXdP3OQfsC00RyezVYQl+X4JVxR5OrMKT3Zib737HXJE0A== +"@snapshot-labs/snapshot.js@^0.4.88": + version "0.4.88" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.88.tgz#381e36bf23e622f103e1a6fac56b6ace9fdf0b67" + integrity sha512-PJB1UJrSCWLsU+rdoYPoYfnWjOAdDPxK3oO671o5nqB/KiLGdqXzpL/OBRQQop2RqNCdPiH36tmkAYZ1irY+gw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 5f3d1adc9ab48e2bf5c79de445cc54d9f0b5fbdd Mon Sep 17 00:00:00 2001 From: less Date: Mon, 29 May 2023 19:27:18 +0700 Subject: [PATCH 401/815] chore: update snapshot.js to v0.4.89 --- package.json | 4 ++-- yarn.lock | 28 ++++++++++++++-------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/package.json b/package.json index 2c9166432..ae082b839 100755 --- a/package.json +++ b/package.json @@ -34,13 +34,13 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.88", + "@snapshot-labs/snapshot.js": "^0.4.89", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", "blakejs": "^1.2.1", "copyfiles": "^2.4.1", - "cross-fetch": "^3.1.5", + "cross-fetch": "^3.1.6", "eth-ens-namehash": "^2.0.8", "json-to-graphql-query": "^2.2.4", "tulons": "^0.0.7" diff --git a/yarn.lock b/yarn.lock index 0eba118b4..7840c4b64 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.88": - version "0.4.88" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.88.tgz#381e36bf23e622f103e1a6fac56b6ace9fdf0b67" - integrity sha512-PJB1UJrSCWLsU+rdoYPoYfnWjOAdDPxK3oO671o5nqB/KiLGdqXzpL/OBRQQop2RqNCdPiH36tmkAYZ1irY+gw== +"@snapshot-labs/snapshot.js@^0.4.89": + version "0.4.89" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.89.tgz#533b6d99ec90f889470821b6f6b755eca830b069" + integrity sha512-O2slv4S0fvtzz1ajuD+oOSY5RvkNLmHvAW7huxlzfgMhrNnM35Blgp8Uw1rLhkIwtF0GrhPn/m1VZninchPIYQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" @@ -1178,7 +1178,7 @@ "@ethersproject/wallet" "^5.6.2" ajv "^8.11.0" ajv-formats "^2.1.1" - cross-fetch "^3.1.5" + cross-fetch "^3.1.6" json-to-graphql-query "^2.2.4" lodash.set "^4.3.2" @@ -1901,12 +1901,12 @@ core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== -cross-fetch@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" - integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== +cross-fetch@^3.1.6: + version "3.1.6" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.6.tgz#bae05aa31a4da760969756318feeee6e70f15d6c" + integrity sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g== dependencies: - node-fetch "2.6.7" + node-fetch "^2.6.11" cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" @@ -3436,10 +3436,10 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -node-fetch@2.6.7: - version "2.6.7" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" - integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== +node-fetch@^2.6.11: + version "2.6.11" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.11.tgz#cde7fc71deef3131ef80a738919f999e6edfff25" + integrity sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w== dependencies: whatwg-url "^5.0.0" From f6c28f526a7e83a3128f064c64b2f0ea3349e96d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Tkaczy=C5=84ski?= Date: Mon, 29 May 2023 17:16:55 +0200 Subject: [PATCH 402/815] feat: cache stgdao delegates for 5 minutes [with-delegation] (#1176) * feat: cache stgdao delegates for 5 minutes * feat: remove expiry * fix: bring back second forEach loop * Add missing assignment --------- Co-authored-by: ChaituVR --- src/utils/delegation.ts | 59 ++++++++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 15 deletions(-) diff --git a/src/utils/delegation.ts b/src/utils/delegation.ts index 2ad4522d9..ebcd88e0c 100644 --- a/src/utils/delegation.ts +++ b/src/utils/delegation.ts @@ -1,6 +1,8 @@ import { getAddress } from '@ethersproject/address'; import { getDelegatesBySpace } from '../utils'; +const DELEGATION_DATA_CACHE = {}; + // delegations with overrides export async function getDelegations(space, network, addresses, snapshot) { const addressesLc = addresses.map((addresses) => addresses.toLowerCase()); @@ -35,31 +37,58 @@ export async function getDelegations(space, network, addresses, snapshot) { ); } +function getDelegationReverseData(delegation) { + return { + delegate: delegation.delegate, + delegateAddress: getAddress(delegation.delegate), + delegator: delegation.delegator, + delegatorAddress: getAddress(delegation.delegator) + }; +} + export async function getDelegationsData(space, network, addresses, snapshot) { - const delegatesBySpace = await getDelegatesBySpace(network, space, snapshot); - const delegationsReverse = {}; - delegatesBySpace.forEach( - (delegation: any) => - (delegationsReverse[delegation.delegator] = delegation.delegate) - ); - delegatesBySpace - .filter((delegation: any) => delegation.space !== '') - .forEach( + const cacheKey = `${space}-${network}-${snapshot}`; + let delegationsReverse = DELEGATION_DATA_CACHE[cacheKey]; + + if (!delegationsReverse) { + delegationsReverse = {}; + + const delegatesBySpace = await getDelegatesBySpace( + network, + space, + snapshot + ); + + delegatesBySpace.forEach( (delegation: any) => - (delegationsReverse[delegation.delegator] = delegation.delegate) + (delegationsReverse[delegation.delegator] = + getDelegationReverseData(delegation)) ); + delegatesBySpace + .filter((delegation: any) => delegation.space !== '') + .forEach( + (delegation: any) => + (delegationsReverse[delegation.delegator] = + getDelegationReverseData(delegation)) + ); + if (space === 'stgdao.eth' && snapshot !== 'latest') { + // TODO: implement LRU so memory doesn't explode + // we only cache stgdao for now + DELEGATION_DATA_CACHE[cacheKey] = delegationsReverse; + } + } return { delegations: Object.fromEntries( addresses.map((address) => [ address, - Object.entries(delegationsReverse) - .filter(([, delegate]) => address.toLowerCase() === delegate) - .map(([delegator]) => getAddress(delegator)) + Object.values(delegationsReverse) + .filter((data) => address.toLowerCase() === (data as any).delegate) + .map((data) => (data as any).delegatorAddress) ]) ), - allDelegators: Object.keys(delegationsReverse).map((delegator) => - getAddress(delegator) + allDelegators: Object.values(delegationsReverse).map( + (data) => (data as any).delegatorAddress ) }; } From e064bad4c2d66c4be4924854557612017f89112d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 30 May 2023 04:15:11 +0530 Subject: [PATCH 403/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.90 (#1178) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index ae082b839..36dfa5d09 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.89", + "@snapshot-labs/snapshot.js": "^0.4.90", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 7840c4b64..da485fddd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.89": - version "0.4.89" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.89.tgz#533b6d99ec90f889470821b6f6b755eca830b069" - integrity sha512-O2slv4S0fvtzz1ajuD+oOSY5RvkNLmHvAW7huxlzfgMhrNnM35Blgp8Uw1rLhkIwtF0GrhPn/m1VZninchPIYQ== +"@snapshot-labs/snapshot.js@^0.4.90": + version "0.4.90" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.90.tgz#810a3650470110cdc89f6b894f6a975f5814b135" + integrity sha512-xdbQE80+8y+WCFueU7g4Ns9Y8DfPtVPUDN1b4ifYimav+qWL6k6hIPt9EjJ0q7lvcYzdd1xlPeOeNJYJgQTCiw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 9f248ff4ae8768f731a9c06605c1305c00861411 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 30 May 2023 14:32:40 +0530 Subject: [PATCH 404/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.91 (#1180) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 36dfa5d09..e8c51fcf6 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.90", + "@snapshot-labs/snapshot.js": "^0.4.91", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index da485fddd..b9df1ea47 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.90": - version "0.4.90" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.90.tgz#810a3650470110cdc89f6b894f6a975f5814b135" - integrity sha512-xdbQE80+8y+WCFueU7g4Ns9Y8DfPtVPUDN1b4ifYimav+qWL6k6hIPt9EjJ0q7lvcYzdd1xlPeOeNJYJgQTCiw== +"@snapshot-labs/snapshot.js@^0.4.91": + version "0.4.91" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.91.tgz#6537cbcb8175dbe0e6f3e418b03f83bb35ebbe58" + integrity sha512-jaRl7t0T7csiWj1c1ao/B+W4arHLOeNvI+hVbfaItiCgVuL+/NIbGDMQam1xpDs+bJ82nQ3wbXRGnHVqGS7sYg== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 519e77559d2ea5b2a6a9e0190920dc820f5d2938 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 1 Jun 2023 12:58:42 +0530 Subject: [PATCH 405/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.93 (#1182) --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index e8c51fcf6..eeab574bf 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.91", + "@snapshot-labs/snapshot.js": "^0.4.93", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index b9df1ea47..8a32e07bc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1163,10 +1163,10 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@snapshot-labs/snapshot.js@^0.4.91": - version "0.4.91" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.91.tgz#6537cbcb8175dbe0e6f3e418b03f83bb35ebbe58" - integrity sha512-jaRl7t0T7csiWj1c1ao/B+W4arHLOeNvI+hVbfaItiCgVuL+/NIbGDMQam1xpDs+bJ82nQ3wbXRGnHVqGS7sYg== +"@snapshot-labs/snapshot.js@^0.4.93": + version "0.4.93" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.93.tgz#578f2152fabf57082875de958d58ed943fc3dada" + integrity sha512-Ih0c1EBrHtF8WeSkHSFcMeaniyuXiG7UMLfOLrVsJ5Vs9fFV1PYUhAd4p/lhiXNgMjMU32kwIoiwv9geaNDEqw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From e08497aee2855e4d56a82eaee8db3d3377dc810c Mon Sep 17 00:00:00 2001 From: Sophia <59624772+sophiahdew@users.noreply.github.com> Date: Thu, 1 Jun 2023 06:54:05 -0700 Subject: [PATCH 406/815] [passport-gated] Passport migration (#1158) * Passport API Integration Migrated the first version of using the Passport API instead of the SDK. * Passport API Validation Strategy Updated passport-gated and passport-weighted validation strategies to call the Passport API rather than the SDK. * updated passport API validation Updated passport-gated and passport-weighted validation strategies to call the Passport API rather than the SDK. * Updated .gitignore * Removed .history file * Update src/validations/basic/index.ts Co-authored-by: Chaitanya * Update src/validations/passport-weighted/schema.json Co-authored-by: Chaitanya * Update src/validations/passport-gated/examples.json Co-authored-by: Chaitanya * Removed submitting and signing passport We updated the passport API to no longer require a signed message by the user to submit a passport. I updated that functionality in the validation functions * Update package.json * Updated passport-gated Passport-gated now checks for specific stamps and a minimum threshold passport score * removed score check in passport-gated Passport-gated no longer checks for Passport score. Now passport-gated just checks if the stamps match. * Update src/validations/passport-gated/README.md Co-authored-by: Sam <51686767+samuveth@users.noreply.github.com> * Update src/validations/passport-gated/README.md * Update src/validations/passport-gated/README.md * Update src/validations/passport-gated/index.ts * Add back expiry and creation timestamp check and check operator * Update yarn.lock --------- Co-authored-by: Chaitanya Co-authored-by: Sam <51686767+samuveth@users.noreply.github.com> --- .gitignore | 2 + package.json | 7 +- src/index.ts | 1 + src/validations/passport-gated/README.md | 30 +- src/validations/passport-gated/examples.json | 2 +- src/validations/passport-gated/index.ts | 80 +- src/validations/passport-weighted/README.md | 30 + .../passport-weighted/examples.json | 1 + src/validations/passport-weighted/helper.ts | 117 --- src/validations/passport-weighted/index.ts | 66 +- src/validations/passport-weighted/schema.json | 5 + yarn.lock | 908 +++++++++--------- 12 files changed, 629 insertions(+), 620 deletions(-) delete mode 100644 src/validations/passport-weighted/helper.ts diff --git a/.gitignore b/.gitignore index 398039c40..112e93edf 100755 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ dist # Remove some common IDE working directories .idea .vscode +.env +.history \ No newline at end of file diff --git a/package.json b/package.json index eeab574bf..449cbb814 100755 --- a/package.json +++ b/package.json @@ -41,12 +41,13 @@ "blakejs": "^1.2.1", "copyfiles": "^2.4.1", "cross-fetch": "^3.1.6", + "dotenv": "^16.0.3", "eth-ens-namehash": "^2.0.8", "json-to-graphql-query": "^2.2.4", "tulons": "^0.0.7" }, "devDependencies": { - "@types/jest": "^28.1.4", + "@types/jest": "^29.5.1", "@types/node": "^18.0.3", "@typescript-eslint/eslint-plugin": "^5.30.5", "@typescript-eslint/parser": "^5.30.5", @@ -54,9 +55,9 @@ "eslint-config-airbnb-base": "^15.0.0", "eslint-plugin-import": "^2.26.0", "eslint-plugin-prettier": "^4.2.1", - "jest": "^28.1.2", + "jest": "^29.5.0", "prettier": "^2.7.1", - "ts-jest": "^28.0.5", + "ts-jest": "^29.1.0", "typescript": "^4.7.4" }, "engines": { diff --git a/src/index.ts b/src/index.ts index f12e35b07..e1e0f7e61 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,4 @@ +import 'dotenv/config'; import strategies from './strategies'; import validations from './validations'; import utils from './utils'; diff --git a/src/validations/passport-gated/README.md b/src/validations/passport-gated/README.md index 0153ab360..7cd6d0a05 100644 --- a/src/validations/passport-gated/README.md +++ b/src/validations/passport-gated/README.md @@ -1 +1,29 @@ -# Gitcoin passport gated validation +# Gitcoin Passport Gated Validation + +This repository provides a passport-gated validation strategy for Snapshot. The implementation integrates with the Gitcoin API to validate whether a user is authorized to vote on a proposal. + +## Prerequisites + +Before using this code, ensure that you have the following information stored in a `.env` file at the project root: + +- `PASSPORT_API_KEY=` + +## Overview + +This implementation uses the Gitcoin Passport API to check whether a user has a valid passport by looking for their stamps. + +## Code Explanation + +The main function in this codebase checks stamps for a user and returns a boolean value indicating whether the user has a valid passport. + +## Modifications + +The original code utilized the Passport SDK to check if the user has a valid passport and stamps. + +[Coming Soon] However, with the introduction of the Passport API, we can now simplify the process by checking for a score. + +## Last Modified + +This code was last modified on June 1, 2023. + +Feel free to customize and extend this implementation to suit your specific needs. diff --git a/src/validations/passport-gated/examples.json b/src/validations/passport-gated/examples.json index d10b35391..ba7428ae1 100644 --- a/src/validations/passport-gated/examples.json +++ b/src/validations/passport-gated/examples.json @@ -6,7 +6,7 @@ "network": "1", "snapshot": "latest", "params": { - "stamps": ["Ens", "Twitter", "Github", "POAP", "SnapshotVotesProvider"], + "stamps": ["Ens", "Github", "POAP", "SnapshotVotesProvider"], "operator": "OR" } } diff --git a/src/validations/passport-gated/index.ts b/src/validations/passport-gated/index.ts index 7f0b91b8a..bcf1d7f1c 100644 --- a/src/validations/passport-gated/index.ts +++ b/src/validations/passport-gated/index.ts @@ -1,10 +1,31 @@ -import snapshot from '@snapshot-labs/snapshot.js'; +import fetch from 'cross-fetch'; import Validation from '../validation'; -import { - getPassport, - getVerifiedStamps, - hasValidIssuanceAndExpiration -} from '../passport-weighted/helper'; +import snapshot from '@snapshot-labs/snapshot.js'; + +const API_KEY = + process.env.PASSPORT_API_KEY || '0cErnp4F.nRDEUU4Z8y5YyxcU32swrggDFNfWtXtI'; + +const headers = API_KEY + ? { + 'Content-Type': 'application/json', + 'X-API-Key': API_KEY + } + : undefined; + +const GET_PASSPORT_STAMPS_URI = `https://api.scorer.gitcoin.co/registry/stamps/`; + +function hasValidIssuanceAndExpiration(credential, proposalTs) { + const issuanceDate = Number( + new Date(credential.issuanceDate).getTime() / 1000 + ).toFixed(0); + const expirationDate = Number( + new Date(credential.expirationDate).getTime() / 1000 + ).toFixed(0); + if (issuanceDate <= proposalTs && expirationDate >= proposalTs) { + return true; + } + return false; +} export default class extends Validation { public id = 'passport-gated'; @@ -13,43 +34,40 @@ export default class extends Validation { public title = 'Gitcoin Passport Gated'; public description = 'Protect your proposals from spam and vote manipulation by requiring users to have a Gitcoin Passport.'; - async validate(): Promise { - const requiredStamps = this.params.stamps; - const passport: any = await getPassport(this.author); - if (!passport) return false; - if (!passport.stamps?.length || !requiredStamps?.length) return false; - - const verifiedStamps: any[] = await getVerifiedStamps( - passport, - this.author, - requiredStamps.map((stamp) => ({ - id: stamp - })) + + async validate(currentAddress = this.author): Promise { + const requiredStamps = this.params.stamps || []; + const operator = this.params.operator; + if (!operator) throw new Error('Operator is required'); + + const stampsResponse = await fetch( + GET_PASSPORT_STAMPS_URI + currentAddress, + { headers } ); - if (!verifiedStamps.length) return false; - const provider = snapshot.utils.getProvider(this.network); - const proposalTs = (await provider.getBlock(this.snapshot)).timestamp; + const stampsData = await stampsResponse.json(); - const operator = this.params.operator; + if (!stampsData?.items) { + // throw new Error( + // 'You do not have a valid Gitcoin Passport. Create one by visiting https://passport.gitcoin.co/ ' + // ); + return false; + } - // check issuance and expiration - const validStamps = verifiedStamps + const provider = snapshot.utils.getProvider(this.network); + const proposalTs = (await provider.getBlock(this.snapshot)).timestamp; + // check expiration for all stamps + const validStamps = stampsData.items .filter((stamp) => hasValidIssuanceAndExpiration(stamp.credential, proposalTs) ) - .map((stamp) => stamp.provider); - - // console.log('validStamps', validStamps); - // console.log('requiredStamps', requiredStamps); - // console.log('operator', operator); + .map((stamp) => stamp.credential.credentialSubject.provider); if (operator === 'AND') { return requiredStamps.every((stamp) => validStamps.includes(stamp)); } else if (operator === 'OR') { return requiredStamps.some((stamp) => validStamps.includes(stamp)); - } else { - return false; } + return false; } } diff --git a/src/validations/passport-weighted/README.md b/src/validations/passport-weighted/README.md index 37bbf166f..48a20f34c 100644 --- a/src/validations/passport-weighted/README.md +++ b/src/validations/passport-weighted/README.md @@ -1 +1,31 @@ # Gitcoin passport weighted validation + +This repository provides a passport-weighted validation strategy for Snapshot. The implementation integrates with the Gitcoin API to validate whether a user is authorized to vote on a proposal. + +## Prerequisites + +Before using this code, ensure that you have the following information stored in a `.env` file at the project root: + +- `NEXT_PUBLIC_GC_API_KEY=` +- `NEXT_PUBLIC_GC_SCORER_ID=` + +## Overview + +This implementation uses the Gitcoin Passport API to check whether a user has a passport score thats above the minScore threshold value. + +## Code Explanation + +The main function in this codebase returns a threshold score based on the user's passport. + +## Modifications + +The original code utilized the Passport SDK to check if the user meets the passport score threshold. However, with the introduction of the Passport API, we can now simplify the process by checking directly for the score. + +## Last Modified + +This code was last modified on May 11, 2023. + +Feel free to customize and extend this implementation to suit your specific needs. + + + diff --git a/src/validations/passport-weighted/examples.json b/src/validations/passport-weighted/examples.json index 8f8428b16..5e6c883c5 100644 --- a/src/validations/passport-weighted/examples.json +++ b/src/validations/passport-weighted/examples.json @@ -6,6 +6,7 @@ "network": "1", "snapshot": "latest", "params": { + "minScore": 10, "stamps": [ { "id": "Ens", "weight": 2 }, { "id": "Twitter", "weight": 0.5 }, diff --git a/src/validations/passport-weighted/helper.ts b/src/validations/passport-weighted/helper.ts deleted file mode 100644 index 4b7b05c45..000000000 --- a/src/validations/passport-weighted/helper.ts +++ /dev/null @@ -1,117 +0,0 @@ -import DIDKit from '@spruceid/didkit-wasm-node/didkit_wasm'; -import { Tulons } from 'tulons'; -import fetch from 'cross-fetch'; - -const CERAMIC_URL = 'https://ceramic.passport-iam.gitcoin.co'; -const CERAMIC_NETWORK_ID = 1; -const CERAMIC_GITCOIN_PASSPORT_STREAM_ID = - 'kjzl6cwe1jw148h1e14jb5fkf55xmqhmyorp29r9cq356c7ou74ulowf8czjlzs'; -const IAM_ISSUER_DID = - 'did:key:z6MkghvGHLobLEdj1bgRLhS4LPGJAvbMA1tn2zcRyqmYU5LC'; - -export const getPassport = async (address) => { - const tulons = new Tulons(CERAMIC_URL, CERAMIC_NETWORK_ID); - // Ceramic data is stored as address -> DID -> Genesis/IDX Stream -> Data Stream - const { streams } = await tulons.getGenesis(address); - if (streams[CERAMIC_GITCOIN_PASSPORT_STREAM_ID]) { - const passport: any = await tulons.getStream( - streams[CERAMIC_GITCOIN_PASSPORT_STREAM_ID] - ); - const streamIDs = passport.stamps.map((ceramicStamp) => { - return ceramicStamp.credential; - }); - // `stamps` is stored as ceramic URLs - must load actual VC data from URL - const stampsToLoad = passport.stamps.map(async (_stamp, idx) => { - const streamUrl = `${CERAMIC_URL}/api/v0/streams/${streamIDs[ - idx - ].substring(10)}`; - const response = await fetch(streamUrl); - const loadedCred = await response.json(); - const { provider } = _stamp; - - return { - provider, - credential: loadedCred.state.content, - streamId: streamIDs[idx] - }; - }); - // load all the stamps (unlike gitcoin UI, not ignoring any failing stamps) - const stamps = await Promise.all(stampsToLoad); - - return { - issuanceDate: new Date(passport.issuanceDate), - expiryDate: new Date(passport.expiryDate), - stamps - }; - } - return false; -}; - -export const getVerifiedStamps = async ( - passport, - address, - stampsRequired -): Promise => { - const stamps = passport.stamps || []; - - // filter out stamps with stampsRequired - const stampsFiltered = stamps.filter((stamp) => - stampsRequired.map((a) => a.id).includes(stamp.provider) - ); - - // verify stamps - let stampsVerified = await Promise.all( - stampsFiltered.map(async (stamp) => verifyStamp(stamp, address)) - ); - stampsVerified = stampsVerified.filter((s) => s.verified); - return stampsVerified; -}; - -const verifyStamp = async (stamp, address) => { - // given the stamp exists... - if (stamp) { - stamp.verified = true; - const stampAddress = stamp.credential.credentialSubject.id - .replace(`did:pkh:eip155:${CERAMIC_NETWORK_ID}:`, '') - .toLowerCase(); - - stamp.verified = - stampAddress !== address.toLowerCase() ? false : stamp.verified; - - // finally verify that the credential verifies with DIDKit - if (stamp.verified) { - stamp.verified = await verifyCredential(stamp.credential); - } - } - - return stamp; -}; - -const verifyCredential = async (credential) => { - const { proof } = credential; - try { - const verify = JSON.parse( - await DIDKit.verifyCredential( - JSON.stringify(credential), - `{"proofPurpose":"${proof.proofPurpose}"}` - ) - ) as { checks: string[]; warnings: string[]; errors: string[] }; - const has_correct_issuer = credential.issuer === IAM_ISSUER_DID; - return verify.errors.length === 0 && has_correct_issuer; - } catch (e) { - return false; - } -}; - -export const hasValidIssuanceAndExpiration = (credential, proposalTs) => { - const issuanceDate = Number( - new Date(credential.issuanceDate).getTime() / 1000 - ).toFixed(0); - const expirationDate = Number( - new Date(credential.expirationDate).getTime() / 1000 - ).toFixed(0); - if (issuanceDate <= proposalTs && expirationDate >= proposalTs) { - return true; - } - return false; -}; diff --git a/src/validations/passport-weighted/index.ts b/src/validations/passport-weighted/index.ts index 23a2e7421..fb77ec9b5 100644 --- a/src/validations/passport-weighted/index.ts +++ b/src/validations/passport-weighted/index.ts @@ -1,10 +1,15 @@ -import snapshot from '@snapshot-labs/snapshot.js'; +import fetch from 'cross-fetch'; import Validation from '../validation'; -import { - getPassport, - getVerifiedStamps, - hasValidIssuanceAndExpiration -} from './helper'; +import dotenv from 'dotenv'; +dotenv.config({ path: '.env' }); + +const API_KEY = process.env.NEXT_PUBLIC_GC_API_KEY +const SCORER_ID = process.env.NEXT_PUBLIC_GC_SCORER_ID + +const headers = API_KEY ? ({ + 'Content-Type': 'application/json', + 'X-API-Key': API_KEY +}) : undefined export default class extends Validation { public id = 'passport-weighted'; @@ -14,35 +19,28 @@ export default class extends Validation { public description = 'Protect your proposals from spam and vote manipulation by requiring users to have a Gitcoin Passport.'; - async validate(): Promise { - const passport: any = await getPassport(this.author); - if (!passport) return false; - if (!passport.stamps?.length || !this.params.stamps?.length) return false; - - const verifiedStamps: any[] = await getVerifiedStamps( - passport, - this.author, - this.params.stamps - ); - if (!verifiedStamps.length) return false; - - const provider = snapshot.utils.getProvider(this.network); - const proposalTs = (await provider.getBlock(this.snapshot)).timestamp; - - let weight = 0; - this.params.stamps.forEach((stamp: any) => { - const verifiedStamp = verifiedStamps.find( - (s: any) => s.provider === stamp.id - ); + async validate(currentAddress = this.author): Promise { + const GET_PASSPORT_SCORE_URI = `https://api.scorer.gitcoin.co/registry/score/${SCORER_ID}/${currentAddress}` - // check that the credential is still valid (created before snapshot block and not expired) - if ( - verifiedStamp && - hasValidIssuanceAndExpiration(verifiedStamp.credential, proposalTs) - ) - weight += stamp.weight; - }); + const THRESHOLD_NUMBER = this.params.minScore || 1; - return weight >= this.params.min_weight; + try { + const response = await fetch(GET_PASSPORT_SCORE_URI, { + headers + }) + const passportData = await response.json() + if (passportData.score) { + const roundedScore = Math.round(passportData.score * 100) / 100 + if (roundedScore >= THRESHOLD_NUMBER) return true; + console.log(`Your passport score (${roundedScore}) is lower than the threshold score (${THRESHOLD_NUMBER}).`); + return false; + } else { + console.log('You do not have a valid Gitcoin Passport. Create one by visiting https://passport.gitcoin.co/ ') + return false; + } + } catch (err) { + console.log('error: ', err) + throw err; + } } } diff --git a/src/validations/passport-weighted/schema.json b/src/validations/passport-weighted/schema.json index b3d95ba5b..ba9d66e81 100644 --- a/src/validations/passport-weighted/schema.json +++ b/src/validations/passport-weighted/schema.json @@ -6,6 +6,11 @@ "title": "Gitcoin passport weighted", "type": "object", "properties": { + "minScore": { + "type": "number", + "title": "Minimum score", + "minimum": 10 + }, "stamps": { "type": "array", "title": "Stamps", diff --git a/yarn.lock b/yarn.lock index 8a32e07bc..ade622b28 100644 --- a/yarn.lock +++ b/yarn.lock @@ -108,6 +108,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.17.12.tgz#86c2347da5acbf5583ba0a10aed4c9bf9da9cf96" integrity sha512-JDkf04mqtN3y4iAbO1hv9U2ARpPyPL1zqyWs/2WG1pgSq9llHFjStX5jdxb84himgJm+8Ng+x0oiWF/nw/XQKA== +"@babel/helper-plugin-utils@^7.20.2": + version "7.21.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.21.5.tgz#345f2377d05a720a4e5ecfa39cbf4474a4daed56" + integrity sha512-0WDaIlXKOX/3KfBK/dwP1oQGiPh6rjMkT7HIRv7i5RR2VUMwrx5ZL0dwBkKx7+SW1zwNdgjHd34IMk5ZjTeHVg== + "@babel/helper-simple-access@^7.17.7": version "7.18.2" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.18.2.tgz#4dc473c2169ac3a1c9f4a51cfcd091d1c36fcff9" @@ -190,6 +195,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" +"@babel/plugin-syntax-jsx@^7.7.2": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.21.4.tgz#f264ed7bf40ffc9ec239edabc17a50c4f5b6fea2" + integrity sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" @@ -872,110 +884,110 @@ resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== -"@jest/console@^28.1.1": - version "28.1.1" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-28.1.1.tgz#305f8ca50b6e70413839f54c0e002b60a0f2fd7d" - integrity sha512-0RiUocPVFEm3WRMOStIHbRWllG6iW6E3/gUPnf4lkrVFyXIIDeCe+vlKeYyFOMhB2EPE6FLFCNADSOOQMaqvyA== +"@jest/console@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.5.0.tgz#593a6c5c0d3f75689835f1b3b4688c4f8544cb57" + integrity sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ== dependencies: - "@jest/types" "^28.1.1" + "@jest/types" "^29.5.0" "@types/node" "*" chalk "^4.0.0" - jest-message-util "^28.1.1" - jest-util "^28.1.1" + jest-message-util "^29.5.0" + jest-util "^29.5.0" slash "^3.0.0" -"@jest/core@^28.1.2": - version "28.1.2" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-28.1.2.tgz#eac519b9acbd154313854b8823a47b5c645f785a" - integrity sha512-Xo4E+Sb/nZODMGOPt2G3cMmCBqL4/W2Ijwr7/mrXlq4jdJwcFQ/9KrrJZT2adQRk2otVBXXOz1GRQ4Z5iOgvRQ== +"@jest/core@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.5.0.tgz#76674b96904484e8214614d17261cc491e5f1f03" + integrity sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ== dependencies: - "@jest/console" "^28.1.1" - "@jest/reporters" "^28.1.2" - "@jest/test-result" "^28.1.1" - "@jest/transform" "^28.1.2" - "@jest/types" "^28.1.1" + "@jest/console" "^29.5.0" + "@jest/reporters" "^29.5.0" + "@jest/test-result" "^29.5.0" + "@jest/transform" "^29.5.0" + "@jest/types" "^29.5.0" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" ci-info "^3.2.0" exit "^0.1.2" graceful-fs "^4.2.9" - jest-changed-files "^28.0.2" - jest-config "^28.1.2" - jest-haste-map "^28.1.1" - jest-message-util "^28.1.1" - jest-regex-util "^28.0.2" - jest-resolve "^28.1.1" - jest-resolve-dependencies "^28.1.2" - jest-runner "^28.1.2" - jest-runtime "^28.1.2" - jest-snapshot "^28.1.2" - jest-util "^28.1.1" - jest-validate "^28.1.1" - jest-watcher "^28.1.1" + jest-changed-files "^29.5.0" + jest-config "^29.5.0" + jest-haste-map "^29.5.0" + jest-message-util "^29.5.0" + jest-regex-util "^29.4.3" + jest-resolve "^29.5.0" + jest-resolve-dependencies "^29.5.0" + jest-runner "^29.5.0" + jest-runtime "^29.5.0" + jest-snapshot "^29.5.0" + jest-util "^29.5.0" + jest-validate "^29.5.0" + jest-watcher "^29.5.0" micromatch "^4.0.4" - pretty-format "^28.1.1" - rimraf "^3.0.0" + pretty-format "^29.5.0" slash "^3.0.0" strip-ansi "^6.0.0" -"@jest/environment@^28.1.2": - version "28.1.2" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-28.1.2.tgz#94a052c0c5f9f8c8e6d13ea6da78dbc5d7d9b85b" - integrity sha512-I0CR1RUMmOzd0tRpz10oUfaChBWs+/Hrvn5xYhMEF/ZqrDaaeHwS8yDBqEWCrEnkH2g+WE/6g90oBv3nKpcm8Q== +"@jest/environment@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.5.0.tgz#9152d56317c1fdb1af389c46640ba74ef0bb4c65" + integrity sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ== dependencies: - "@jest/fake-timers" "^28.1.2" - "@jest/types" "^28.1.1" + "@jest/fake-timers" "^29.5.0" + "@jest/types" "^29.5.0" "@types/node" "*" - jest-mock "^28.1.1" + jest-mock "^29.5.0" -"@jest/expect-utils@^28.1.1": - version "28.1.1" - resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-28.1.1.tgz#d84c346025b9f6f3886d02c48a6177e2b0360587" - integrity sha512-n/ghlvdhCdMI/hTcnn4qV57kQuV9OTsZzH1TTCVARANKhl6hXJqLKUkwX69ftMGpsbpt96SsDD8n8LD2d9+FRw== +"@jest/expect-utils@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.5.0.tgz#f74fad6b6e20f924582dc8ecbf2cb800fe43a036" + integrity sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg== dependencies: - jest-get-type "^28.0.2" + jest-get-type "^29.4.3" -"@jest/expect@^28.1.2": - version "28.1.2" - resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-28.1.2.tgz#0b25acedff46e1e1e5606285306c8a399c12534f" - integrity sha512-HBzyZBeFBiOelNbBKN0pilWbbrGvwDUwAqMC46NVJmWm8AVkuE58NbG1s7DR4cxFt4U5cVLxofAoHxgvC5MyOw== +"@jest/expect@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.5.0.tgz#80952f5316b23c483fbca4363ce822af79c38fba" + integrity sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g== dependencies: - expect "^28.1.1" - jest-snapshot "^28.1.2" + expect "^29.5.0" + jest-snapshot "^29.5.0" -"@jest/fake-timers@^28.1.2": - version "28.1.2" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-28.1.2.tgz#d49e8ee4e02ba85a6e844a52a5e7c59c23e3b76f" - integrity sha512-xSYEI7Y0D5FbZN2LsCUj/EKRR1zfQYmGuAUVh6xTqhx7V5JhjgMcK5Pa0iR6WIk0GXiHDe0Ke4A+yERKE9saqg== +"@jest/fake-timers@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.5.0.tgz#d4d09ec3286b3d90c60bdcd66ed28d35f1b4dc2c" + integrity sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg== dependencies: - "@jest/types" "^28.1.1" - "@sinonjs/fake-timers" "^9.1.2" + "@jest/types" "^29.5.0" + "@sinonjs/fake-timers" "^10.0.2" "@types/node" "*" - jest-message-util "^28.1.1" - jest-mock "^28.1.1" - jest-util "^28.1.1" + jest-message-util "^29.5.0" + jest-mock "^29.5.0" + jest-util "^29.5.0" -"@jest/globals@^28.1.2": - version "28.1.2" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-28.1.2.tgz#92fab296e337c7309c25e4202fb724f62249d83f" - integrity sha512-cz0lkJVDOtDaYhvT3Fv2U1B6FtBnV+OpEyJCzTHM1fdoTsU4QNLAt/H4RkiwEUU+dL4g/MFsoTuHeT2pvbo4Hg== +"@jest/globals@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.5.0.tgz#6166c0bfc374c58268677539d0c181f9c1833298" + integrity sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ== dependencies: - "@jest/environment" "^28.1.2" - "@jest/expect" "^28.1.2" - "@jest/types" "^28.1.1" + "@jest/environment" "^29.5.0" + "@jest/expect" "^29.5.0" + "@jest/types" "^29.5.0" + jest-mock "^29.5.0" -"@jest/reporters@^28.1.2": - version "28.1.2" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-28.1.2.tgz#0327be4ce4d0d9ae49e7908656f89669d0c2a260" - integrity sha512-/whGLhiwAqeCTmQEouSigUZJPVl7sW8V26EiboImL+UyXznnr1a03/YZ2BX8OlFw0n+Zlwu+EZAITZtaeRTxyA== +"@jest/reporters@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.5.0.tgz#985dfd91290cd78ddae4914ba7921bcbabe8ac9b" + integrity sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA== dependencies: "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^28.1.1" - "@jest/test-result" "^28.1.1" - "@jest/transform" "^28.1.2" - "@jest/types" "^28.1.1" - "@jridgewell/trace-mapping" "^0.3.13" + "@jest/console" "^29.5.0" + "@jest/test-result" "^29.5.0" + "@jest/transform" "^29.5.0" + "@jest/types" "^29.5.0" + "@jridgewell/trace-mapping" "^0.3.15" "@types/node" "*" chalk "^4.0.0" collect-v8-coverage "^1.0.0" @@ -987,78 +999,77 @@ istanbul-lib-report "^3.0.0" istanbul-lib-source-maps "^4.0.0" istanbul-reports "^3.1.3" - jest-message-util "^28.1.1" - jest-util "^28.1.1" - jest-worker "^28.1.1" + jest-message-util "^29.5.0" + jest-util "^29.5.0" + jest-worker "^29.5.0" slash "^3.0.0" string-length "^4.0.1" strip-ansi "^6.0.0" - terminal-link "^2.0.0" v8-to-istanbul "^9.0.1" -"@jest/schemas@^28.0.2": - version "28.0.2" - resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-28.0.2.tgz#08c30df6a8d07eafea0aef9fb222c5e26d72e613" - integrity sha512-YVDJZjd4izeTDkij00vHHAymNXQ6WWsdChFRK86qck6Jpr3DCL5W3Is3vslviRlP+bLuMYRLbdp98amMvqudhA== +"@jest/schemas@^29.4.3": + version "29.4.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.4.3.tgz#39cf1b8469afc40b6f5a2baaa146e332c4151788" + integrity sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg== dependencies: - "@sinclair/typebox" "^0.23.3" + "@sinclair/typebox" "^0.25.16" -"@jest/source-map@^28.1.2": - version "28.1.2" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-28.1.2.tgz#7fe832b172b497d6663cdff6c13b0a920e139e24" - integrity sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww== +"@jest/source-map@^29.4.3": + version "29.4.3" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.4.3.tgz#ff8d05cbfff875d4a791ab679b4333df47951d20" + integrity sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w== dependencies: - "@jridgewell/trace-mapping" "^0.3.13" + "@jridgewell/trace-mapping" "^0.3.15" callsites "^3.0.0" graceful-fs "^4.2.9" -"@jest/test-result@^28.1.1": - version "28.1.1" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-28.1.1.tgz#c6f18d1bbb01aa88925dd687872a75f8414b317a" - integrity sha512-hPmkugBktqL6rRzwWAtp1JtYT4VHwv8OQ+9lE5Gymj6dHzubI/oJHMUpPOt8NrdVWSrz9S7bHjJUmv2ggFoUNQ== +"@jest/test-result@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.5.0.tgz#7c856a6ca84f45cc36926a4e9c6b57f1973f1408" + integrity sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ== dependencies: - "@jest/console" "^28.1.1" - "@jest/types" "^28.1.1" + "@jest/console" "^29.5.0" + "@jest/types" "^29.5.0" "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" -"@jest/test-sequencer@^28.1.1": - version "28.1.1" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-28.1.1.tgz#f594ee2331df75000afe0d1ae3237630ecec732e" - integrity sha512-nuL+dNSVMcWB7OOtgb0EGH5AjO4UBCt68SLP08rwmC+iRhyuJWS9MtZ/MpipxFwKAlHFftbMsydXqWre8B0+XA== +"@jest/test-sequencer@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz#34d7d82d3081abd523dbddc038a3ddcb9f6d3cc4" + integrity sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ== dependencies: - "@jest/test-result" "^28.1.1" + "@jest/test-result" "^29.5.0" graceful-fs "^4.2.9" - jest-haste-map "^28.1.1" + jest-haste-map "^29.5.0" slash "^3.0.0" -"@jest/transform@^28.1.2": - version "28.1.2" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-28.1.2.tgz#b367962c53fd53821269bde050ce373e111327c1" - integrity sha512-3o+lKF6iweLeJFHBlMJysdaPbpoMmtbHEFsjzSv37HIq/wWt5ijTeO2Yf7MO5yyczCopD507cNwNLeX8Y/CuIg== +"@jest/transform@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.5.0.tgz#cf9c872d0965f0cbd32f1458aa44a2b1988b00f9" + integrity sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw== dependencies: "@babel/core" "^7.11.6" - "@jest/types" "^28.1.1" - "@jridgewell/trace-mapping" "^0.3.13" + "@jest/types" "^29.5.0" + "@jridgewell/trace-mapping" "^0.3.15" babel-plugin-istanbul "^6.1.1" chalk "^4.0.0" - convert-source-map "^1.4.0" - fast-json-stable-stringify "^2.0.0" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" graceful-fs "^4.2.9" - jest-haste-map "^28.1.1" - jest-regex-util "^28.0.2" - jest-util "^28.1.1" + jest-haste-map "^29.5.0" + jest-regex-util "^29.4.3" + jest-util "^29.5.0" micromatch "^4.0.4" pirates "^4.0.4" slash "^3.0.0" - write-file-atomic "^4.0.1" + write-file-atomic "^4.0.2" -"@jest/types@^28.1.1": - version "28.1.1" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-28.1.1.tgz#d059bbc80e6da6eda9f081f293299348bd78ee0b" - integrity sha512-vRXVqSg1VhDnB8bWcmvLzmg0Bt9CRKVgHPXqYwvWMX3TvAjeO+nRuK6+VdTKCtWOvYlmkF/HqNAL/z+N3B53Kw== +"@jest/types@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.5.0.tgz#f59ef9b031ced83047c67032700d8c807d6e1593" + integrity sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog== dependencies: - "@jest/schemas" "^28.0.2" + "@jest/schemas" "^29.4.3" "@types/istanbul-lib-coverage" "^2.0.0" "@types/istanbul-reports" "^3.0.0" "@types/node" "*" @@ -1082,6 +1093,11 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.9" +"@jridgewell/resolve-uri@3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + "@jridgewell/resolve-uri@^3.0.3": version "3.0.7" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz#30cd49820a962aff48c8fffc5cd760151fca61fe" @@ -1092,12 +1108,17 @@ resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.1.tgz#36a6acc93987adcf0ba50c66908bd0b70de8afea" integrity sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ== +"@jridgewell/sourcemap-codec@1.4.14": + version "1.4.14" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + "@jridgewell/sourcemap-codec@^1.4.10": version "1.4.13" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz#b6461fb0c2964356c469e115f504c95ad97ab88c" integrity sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w== -"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.13": +"@jridgewell/trace-mapping@^0.3.12": version "0.3.14" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed" integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ== @@ -1105,6 +1126,14 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@jridgewell/trace-mapping@^0.3.15": + version "0.3.18" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6" + integrity sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA== + dependencies: + "@jridgewell/resolve-uri" "3.1.0" + "@jridgewell/sourcemap-codec" "1.4.14" + "@jridgewell/trace-mapping@^0.3.9": version "0.3.13" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz#dcfe3e95f224c8fe97a87a5235defec999aa92ea" @@ -1144,24 +1173,24 @@ resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.4.2-solc-0.7.tgz#38f4dbab672631034076ccdf2f3201fab1726635" integrity sha512-W6QmqgkADuFcTLzHL8vVoNBtkwjvQRpYIAom7KiUNoLKghyx3FgH0GBjt8NRvigV1ZmMOBllvE1By1C+bi8WpA== -"@sinclair/typebox@^0.23.3": - version "0.23.5" - resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.23.5.tgz#93f7b9f4e3285a7a9ade7557d9a8d36809cbc47d" - integrity sha512-AFBVi/iT4g20DHoujvMH1aEDn8fGJh4xsRGCP6d8RpLPMqsNPvW01Jcn0QysXTsg++/xj25NmJsGyH9xug/wKg== +"@sinclair/typebox@^0.25.16": + version "0.25.24" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.24.tgz#8c7688559979f7079aacaf31aa881c3aa410b718" + integrity sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ== -"@sinonjs/commons@^1.7.0": - version "1.8.3" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" - integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ== +"@sinonjs/commons@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-2.0.0.tgz#fd4ca5b063554307e8327b4564bd56d3b73924a3" + integrity sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg== dependencies: type-detect "4.0.8" -"@sinonjs/fake-timers@^9.1.2": - version "9.1.2" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz#4eaab737fab77332ab132d396a3c0d364bd0ea8c" - integrity sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw== +"@sinonjs/fake-timers@^10.0.2": + version "10.0.2" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz#d10549ed1f423d80639c528b6c7f5a1017747d0c" + integrity sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw== dependencies: - "@sinonjs/commons" "^1.7.0" + "@sinonjs/commons" "^2.0.0" "@snapshot-labs/snapshot.js@^0.4.93": version "0.4.93" @@ -1246,13 +1275,13 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@^28.1.4": - version "28.1.4" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-28.1.4.tgz#a11ee6c8fd0b52c19c9c18138b78bbcc201dad5a" - integrity sha512-telv6G5N7zRJiLcI3Rs3o+ipZ28EnE+7EvF0pSrt2pZOMnAVI/f+6/LucDxOvcBcTeTL3JMF744BbVQAVBUQRA== +"@types/jest@^29.5.1": + version "29.5.1" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.1.tgz#83c818aa9a87da27d6da85d3378e5a34d2f31a47" + integrity sha512-tEuVcHrpaixS36w7hpsfLBLpjtMRJUE09/MHXn923LOVojDwyC14cWcfc0rDs0VEfUyYmt/+iX1kxxp+gZMcaQ== dependencies: - jest-matcher-utils "^28.0.0" - pretty-format "^28.0.0" + expect "^29.0.0" + pretty-format "^29.0.0" "@types/json-schema@^7.0.9": version "7.0.11" @@ -1591,15 +1620,15 @@ axios@^0.27.2: follow-redirects "^1.14.9" form-data "^4.0.0" -babel-jest@^28.1.2: - version "28.1.2" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-28.1.2.tgz#2b37fb81439f14d34d8b2cc4a4bd7efabf9acbfe" - integrity sha512-pfmoo6sh4L/+5/G2OOfQrGJgvH7fTa1oChnuYH2G/6gA+JwDvO8PELwvwnofKBMNrQsam0Wy/Rw+QSrBNewq2Q== +babel-jest@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.5.0.tgz#3fe3ddb109198e78b1c88f9ebdecd5e4fc2f50a5" + integrity sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q== dependencies: - "@jest/transform" "^28.1.2" + "@jest/transform" "^29.5.0" "@types/babel__core" "^7.1.14" babel-plugin-istanbul "^6.1.1" - babel-preset-jest "^28.1.1" + babel-preset-jest "^29.5.0" chalk "^4.0.0" graceful-fs "^4.2.9" slash "^3.0.0" @@ -1615,10 +1644,10 @@ babel-plugin-istanbul@^6.1.1: istanbul-lib-instrument "^5.0.4" test-exclude "^6.0.0" -babel-plugin-jest-hoist@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.1.1.tgz#5e055cdcc47894f28341f87f5e35aad2df680b11" - integrity sha512-NovGCy5Hn25uMJSAU8FaHqzs13cFoOI4lhIujiepssjCKRsAo3TA734RDWSGxuFTsUJXerYOqQQodlxgmtqbzw== +babel-plugin-jest-hoist@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz#a97db437936f441ec196990c9738d4b88538618a" + integrity sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w== dependencies: "@babel/template" "^7.3.3" "@babel/types" "^7.3.3" @@ -1643,12 +1672,12 @@ babel-preset-current-node-syntax@^1.0.0: "@babel/plugin-syntax-optional-chaining" "^7.8.3" "@babel/plugin-syntax-top-level-await" "^7.8.3" -babel-preset-jest@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-28.1.1.tgz#5b6e5e69f963eb2d70f739c607b8f723c0ee75e4" - integrity sha512-FCq9Oud0ReTeWtcneYf/48981aTfXYuB9gbU4rBNNJVBSQ6ssv7E6v/qvbBxtOWwZFXjLZwpg+W3q7J6vhH25g== +babel-preset-jest@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz#57bc8cc88097af7ff6a5ab59d1cd29d52a5916e2" + integrity sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg== dependencies: - babel-plugin-jest-hoist "^28.1.1" + babel-plugin-jest-hoist "^29.5.0" babel-preset-current-node-syntax "^1.0.0" balanced-match@^1.0.0: @@ -1876,13 +1905,18 @@ confusing-browser-globals@^1.0.10: resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz#ae40e9b57cdd3915408a2805ebd3a5585608dc81" integrity sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA== -convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: +convert-source-map@^1.6.0, convert-source-map@^1.7.0: version "1.8.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== dependencies: safe-buffer "~5.1.1" +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + copyfiles@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/copyfiles/-/copyfiles-2.4.1.tgz#d2dcff60aaad1015f09d0b66e7f0f1c5cd3c5da5" @@ -1975,10 +2009,10 @@ detect-newline@^3.0.0: resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== -diff-sequences@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-28.1.1.tgz#9989dc731266dc2903457a70e996f3a041913ac6" - integrity sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw== +diff-sequences@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.3.tgz#9314bc1fabe09267ffeca9cbafc457d8499a13f2" + integrity sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA== dir-glob@^3.0.1: version "3.0.1" @@ -2006,6 +2040,11 @@ dotenv@^14.2.0: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-14.3.2.tgz#7c30b3a5f777c79a3429cb2db358eef6751e8369" integrity sha512-vwEppIphpFdvaMCaHfCEv9IgwcxMljMw2TnAQBB4VWPvzXQLTb82jwmdOKzlEVUL3gNFT4l4TPKO+Bn+sqcrVQ== +dotenv@^16.0.3: + version "16.0.3" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.3.tgz#115aec42bac5053db3c456db30cc243a5a836a07" + integrity sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ== + electron-to-chromium@^1.4.147: version "1.4.161" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.161.tgz#49cb5b35385bfee6cc439d0a04fbba7a7a7f08a1" @@ -2024,10 +2063,10 @@ elliptic@6.5.4: minimalistic-assert "^1.0.1" minimalistic-crypto-utils "^1.0.1" -emittery@^0.10.2: - version "0.10.2" - resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.10.2.tgz#902eec8aedb8c41938c46e9385e9db7e03182933" - integrity sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw== +emittery@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" + integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== emoji-regex@^8.0.0: version "8.0.0" @@ -2293,16 +2332,16 @@ exit@^0.1.2: resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== -expect@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/expect/-/expect-28.1.1.tgz#ca6fff65f6517cf7220c2e805a49c19aea30b420" - integrity sha512-/AANEwGL0tWBwzLNOvO0yUdy2D52jVdNXppOqswC49sxMN2cPWsGCQdzuIf9tj6hHoBQzNvx75JUYuQAckPo3w== +expect@^29.0.0, expect@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.5.0.tgz#68c0509156cb2a0adb8865d413b137eeaae682f7" + integrity sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg== dependencies: - "@jest/expect-utils" "^28.1.1" - jest-get-type "^28.0.2" - jest-matcher-utils "^28.1.1" - jest-message-util "^28.1.1" - jest-util "^28.1.1" + "@jest/expect-utils" "^29.5.0" + jest-get-type "^29.4.3" + jest-matcher-utils "^29.5.0" + jest-message-util "^29.5.0" + jest-util "^29.5.0" fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" @@ -2325,7 +2364,7 @@ fast-glob@^3.2.9: merge2 "^1.3.0" micromatch "^4.0.4" -fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -2833,363 +2872,366 @@ istanbul-reports@^3.1.3: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -jest-changed-files@^28.0.2: - version "28.0.2" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-28.0.2.tgz#7d7810660a5bd043af9e9cfbe4d58adb05e91531" - integrity sha512-QX9u+5I2s54ZnGoMEjiM2WeBvJR2J7w/8ZUmH2um/WLAuGAYFQcsVXY9+1YL6k0H/AGUdH8pXUAv6erDqEsvIA== +jest-changed-files@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.5.0.tgz#e88786dca8bf2aa899ec4af7644e16d9dcf9b23e" + integrity sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag== dependencies: execa "^5.0.0" - throat "^6.0.1" + p-limit "^3.1.0" -jest-circus@^28.1.2: - version "28.1.2" - resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-28.1.2.tgz#0d5a5623eccb244efe87d1edc365696e4fcf80ce" - integrity sha512-E2vdPIJG5/69EMpslFhaA46WkcrN74LI5V/cSJ59L7uS8UNoXbzTxmwhpi9XrIL3zqvMt5T0pl5k2l2u2GwBNQ== +jest-circus@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.5.0.tgz#b5926989449e75bff0d59944bae083c9d7fb7317" + integrity sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA== dependencies: - "@jest/environment" "^28.1.2" - "@jest/expect" "^28.1.2" - "@jest/test-result" "^28.1.1" - "@jest/types" "^28.1.1" + "@jest/environment" "^29.5.0" + "@jest/expect" "^29.5.0" + "@jest/test-result" "^29.5.0" + "@jest/types" "^29.5.0" "@types/node" "*" chalk "^4.0.0" co "^4.6.0" dedent "^0.7.0" is-generator-fn "^2.0.0" - jest-each "^28.1.1" - jest-matcher-utils "^28.1.1" - jest-message-util "^28.1.1" - jest-runtime "^28.1.2" - jest-snapshot "^28.1.2" - jest-util "^28.1.1" - pretty-format "^28.1.1" + jest-each "^29.5.0" + jest-matcher-utils "^29.5.0" + jest-message-util "^29.5.0" + jest-runtime "^29.5.0" + jest-snapshot "^29.5.0" + jest-util "^29.5.0" + p-limit "^3.1.0" + pretty-format "^29.5.0" + pure-rand "^6.0.0" slash "^3.0.0" stack-utils "^2.0.3" - throat "^6.0.1" -jest-cli@^28.1.2: - version "28.1.2" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-28.1.2.tgz#b89012e5bad14135e71b1628b85475d3773a1bbc" - integrity sha512-l6eoi5Do/IJUXAFL9qRmDiFpBeEJAnjJb1dcd9i/VWfVWbp3mJhuH50dNtX67Ali4Ecvt4eBkWb4hXhPHkAZTw== +jest-cli@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.5.0.tgz#b34c20a6d35968f3ee47a7437ff8e53e086b4a67" + integrity sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw== dependencies: - "@jest/core" "^28.1.2" - "@jest/test-result" "^28.1.1" - "@jest/types" "^28.1.1" + "@jest/core" "^29.5.0" + "@jest/test-result" "^29.5.0" + "@jest/types" "^29.5.0" chalk "^4.0.0" exit "^0.1.2" graceful-fs "^4.2.9" import-local "^3.0.2" - jest-config "^28.1.2" - jest-util "^28.1.1" - jest-validate "^28.1.1" + jest-config "^29.5.0" + jest-util "^29.5.0" + jest-validate "^29.5.0" prompts "^2.0.1" yargs "^17.3.1" -jest-config@^28.1.2: - version "28.1.2" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-28.1.2.tgz#ba00ad30caf62286c86e7c1099e915218a0ac8c6" - integrity sha512-g6EfeRqddVbjPVBVY4JWpUY4IvQoFRIZcv4V36QkqzE0IGhEC/VkugFeBMAeUE7PRgC8KJF0yvJNDeQRbamEVA== +jest-config@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.5.0.tgz#3cc972faec8c8aaea9ae158c694541b79f3748da" + integrity sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA== dependencies: "@babel/core" "^7.11.6" - "@jest/test-sequencer" "^28.1.1" - "@jest/types" "^28.1.1" - babel-jest "^28.1.2" + "@jest/test-sequencer" "^29.5.0" + "@jest/types" "^29.5.0" + babel-jest "^29.5.0" chalk "^4.0.0" ci-info "^3.2.0" deepmerge "^4.2.2" glob "^7.1.3" graceful-fs "^4.2.9" - jest-circus "^28.1.2" - jest-environment-node "^28.1.2" - jest-get-type "^28.0.2" - jest-regex-util "^28.0.2" - jest-resolve "^28.1.1" - jest-runner "^28.1.2" - jest-util "^28.1.1" - jest-validate "^28.1.1" + jest-circus "^29.5.0" + jest-environment-node "^29.5.0" + jest-get-type "^29.4.3" + jest-regex-util "^29.4.3" + jest-resolve "^29.5.0" + jest-runner "^29.5.0" + jest-util "^29.5.0" + jest-validate "^29.5.0" micromatch "^4.0.4" parse-json "^5.2.0" - pretty-format "^28.1.1" + pretty-format "^29.5.0" slash "^3.0.0" strip-json-comments "^3.1.1" -jest-diff@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-28.1.1.tgz#1a3eedfd81ae79810931c63a1d0f201b9120106c" - integrity sha512-/MUUxeR2fHbqHoMMiffe/Afm+U8U4olFRJ0hiVG2lZatPJcnGxx292ustVu7bULhjV65IYMxRdploAKLbcrsyg== +jest-diff@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.5.0.tgz#e0d83a58eb5451dcc1fa61b1c3ee4e8f5a290d63" + integrity sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw== dependencies: chalk "^4.0.0" - diff-sequences "^28.1.1" - jest-get-type "^28.0.2" - pretty-format "^28.1.1" + diff-sequences "^29.4.3" + jest-get-type "^29.4.3" + pretty-format "^29.5.0" -jest-docblock@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-28.1.1.tgz#6f515c3bf841516d82ecd57a62eed9204c2f42a8" - integrity sha512-3wayBVNiOYx0cwAbl9rwm5kKFP8yHH3d/fkEaL02NPTkDojPtheGB7HZSFY4wzX+DxyrvhXz0KSCVksmCknCuA== +jest-docblock@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.4.3.tgz#90505aa89514a1c7dceeac1123df79e414636ea8" + integrity sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg== dependencies: detect-newline "^3.0.0" -jest-each@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-28.1.1.tgz#ba5238dacf4f31d9fe23ddc2c44c01e7c23885c4" - integrity sha512-A042rqh17ZvEhRceDMi784ppoXR7MWGDEKTXEZXb4svt0eShMZvijGxzKsx+yIjeE8QYmHPrnHiTSQVhN4nqaw== +jest-each@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.5.0.tgz#fc6e7014f83eac68e22b7195598de8554c2e5c06" + integrity sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA== dependencies: - "@jest/types" "^28.1.1" + "@jest/types" "^29.5.0" chalk "^4.0.0" - jest-get-type "^28.0.2" - jest-util "^28.1.1" - pretty-format "^28.1.1" - -jest-environment-node@^28.1.2: - version "28.1.2" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-28.1.2.tgz#3e2eb47f6d173b0648d5f7c717cb1c26651d5c8a" - integrity sha512-oYsZz9Qw27XKmOgTtnl0jW7VplJkN2oeof+SwAwKFQacq3CLlG9u4kTGuuLWfvu3J7bVutWlrbEQMOCL/jughw== - dependencies: - "@jest/environment" "^28.1.2" - "@jest/fake-timers" "^28.1.2" - "@jest/types" "^28.1.1" + jest-get-type "^29.4.3" + jest-util "^29.5.0" + pretty-format "^29.5.0" + +jest-environment-node@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.5.0.tgz#f17219d0f0cc0e68e0727c58b792c040e332c967" + integrity sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw== + dependencies: + "@jest/environment" "^29.5.0" + "@jest/fake-timers" "^29.5.0" + "@jest/types" "^29.5.0" "@types/node" "*" - jest-mock "^28.1.1" - jest-util "^28.1.1" + jest-mock "^29.5.0" + jest-util "^29.5.0" -jest-get-type@^28.0.2: - version "28.0.2" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-28.0.2.tgz#34622e628e4fdcd793d46db8a242227901fcf203" - integrity sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA== +jest-get-type@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.4.3.tgz#1ab7a5207c995161100b5187159ca82dd48b3dd5" + integrity sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg== -jest-haste-map@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-28.1.1.tgz#471685f1acd365a9394745bb97c8fc16289adca3" - integrity sha512-ZrRSE2o3Ezh7sb1KmeLEZRZ4mgufbrMwolcFHNRSjKZhpLa8TdooXOOFlSwoUzlbVs1t0l7upVRW2K7RWGHzbQ== +jest-haste-map@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.5.0.tgz#69bd67dc9012d6e2723f20a945099e972b2e94de" + integrity sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA== dependencies: - "@jest/types" "^28.1.1" + "@jest/types" "^29.5.0" "@types/graceful-fs" "^4.1.3" "@types/node" "*" anymatch "^3.0.3" fb-watchman "^2.0.0" graceful-fs "^4.2.9" - jest-regex-util "^28.0.2" - jest-util "^28.1.1" - jest-worker "^28.1.1" + jest-regex-util "^29.4.3" + jest-util "^29.5.0" + jest-worker "^29.5.0" micromatch "^4.0.4" walker "^1.0.8" optionalDependencies: fsevents "^2.3.2" -jest-leak-detector@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-28.1.1.tgz#537f37afd610a4b3f4cab15e06baf60484548efb" - integrity sha512-4jvs8V8kLbAaotE+wFR7vfUGf603cwYtFf1/PYEsyX2BAjSzj8hQSVTP6OWzseTl0xL6dyHuKs2JAks7Pfubmw== +jest-leak-detector@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz#cf4bdea9615c72bac4a3a7ba7e7930f9c0610c8c" + integrity sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow== dependencies: - jest-get-type "^28.0.2" - pretty-format "^28.1.1" + jest-get-type "^29.4.3" + pretty-format "^29.5.0" -jest-matcher-utils@^28.0.0, jest-matcher-utils@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-28.1.1.tgz#a7c4653c2b782ec96796eb3088060720f1e29304" - integrity sha512-NPJPRWrbmR2nAJ+1nmnfcKKzSwgfaciCCrYZzVnNoxVoyusYWIjkBMNvu0RHJe7dNj4hH3uZOPZsQA+xAYWqsw== +jest-matcher-utils@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz#d957af7f8c0692c5453666705621ad4abc2c59c5" + integrity sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw== dependencies: chalk "^4.0.0" - jest-diff "^28.1.1" - jest-get-type "^28.0.2" - pretty-format "^28.1.1" + jest-diff "^29.5.0" + jest-get-type "^29.4.3" + pretty-format "^29.5.0" -jest-message-util@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-28.1.1.tgz#60aa0b475cfc08c8a9363ed2fb9108514dd9ab89" - integrity sha512-xoDOOT66fLfmTRiqkoLIU7v42mal/SqwDKvfmfiWAdJMSJiU+ozgluO7KbvoAgiwIrrGZsV7viETjc8GNrA/IQ== +jest-message-util@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.5.0.tgz#1f776cac3aca332ab8dd2e3b41625435085c900e" + integrity sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA== dependencies: "@babel/code-frame" "^7.12.13" - "@jest/types" "^28.1.1" + "@jest/types" "^29.5.0" "@types/stack-utils" "^2.0.0" chalk "^4.0.0" graceful-fs "^4.2.9" micromatch "^4.0.4" - pretty-format "^28.1.1" + pretty-format "^29.5.0" slash "^3.0.0" stack-utils "^2.0.3" -jest-mock@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-28.1.1.tgz#37903d269427fa1ef5b2447be874e1c62a39a371" - integrity sha512-bDCb0FjfsmKweAvE09dZT59IMkzgN0fYBH6t5S45NoJfd2DHkS3ySG2K+hucortryhO3fVuXdlxWcbtIuV/Skw== +jest-mock@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.5.0.tgz#26e2172bcc71d8b0195081ff1f146ac7e1518aed" + integrity sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw== dependencies: - "@jest/types" "^28.1.1" + "@jest/types" "^29.5.0" "@types/node" "*" + jest-util "^29.5.0" jest-pnp-resolver@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== -jest-regex-util@^28.0.2: - version "28.0.2" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-28.0.2.tgz#afdc377a3b25fb6e80825adcf76c854e5bf47ead" - integrity sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw== +jest-regex-util@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.4.3.tgz#a42616141e0cae052cfa32c169945d00c0aa0bb8" + integrity sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg== -jest-resolve-dependencies@^28.1.2: - version "28.1.2" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.2.tgz#ca528858e0c6642d5a1dda8fc7cda10230c275bc" - integrity sha512-OXw4vbOZuyRTBi3tapWBqdyodU+T33ww5cPZORuTWkg+Y8lmsxQlVu3MWtJh6NMlKRTHQetF96yGPv01Ye7Mbg== +jest-resolve-dependencies@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz#f0ea29955996f49788bf70996052aa98e7befee4" + integrity sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg== dependencies: - jest-regex-util "^28.0.2" - jest-snapshot "^28.1.2" + jest-regex-util "^29.4.3" + jest-snapshot "^29.5.0" -jest-resolve@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-28.1.1.tgz#bc2eaf384abdcc1aaf3ba7c50d1adf01e59095e5" - integrity sha512-/d1UbyUkf9nvsgdBildLe6LAD4DalgkgZcKd0nZ8XUGPyA/7fsnaQIlKVnDiuUXv/IeZhPEDrRJubVSulxrShA== +jest-resolve@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.5.0.tgz#b053cc95ad1d5f6327f0ac8aae9f98795475ecdc" + integrity sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w== dependencies: chalk "^4.0.0" graceful-fs "^4.2.9" - jest-haste-map "^28.1.1" + jest-haste-map "^29.5.0" jest-pnp-resolver "^1.2.2" - jest-util "^28.1.1" - jest-validate "^28.1.1" + jest-util "^29.5.0" + jest-validate "^29.5.0" resolve "^1.20.0" - resolve.exports "^1.1.0" + resolve.exports "^2.0.0" slash "^3.0.0" -jest-runner@^28.1.2: - version "28.1.2" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-28.1.2.tgz#f293409592a62234285a71237e38499a3554e350" - integrity sha512-6/k3DlAsAEr5VcptCMdhtRhOoYClZQmxnVMZvZ/quvPGRpN7OBQYPIC32tWSgOnbgqLXNs5RAniC+nkdFZpD4A== +jest-runner@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.5.0.tgz#6a57c282eb0ef749778d444c1d758c6a7693b6f8" + integrity sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ== dependencies: - "@jest/console" "^28.1.1" - "@jest/environment" "^28.1.2" - "@jest/test-result" "^28.1.1" - "@jest/transform" "^28.1.2" - "@jest/types" "^28.1.1" + "@jest/console" "^29.5.0" + "@jest/environment" "^29.5.0" + "@jest/test-result" "^29.5.0" + "@jest/transform" "^29.5.0" + "@jest/types" "^29.5.0" "@types/node" "*" chalk "^4.0.0" - emittery "^0.10.2" + emittery "^0.13.1" graceful-fs "^4.2.9" - jest-docblock "^28.1.1" - jest-environment-node "^28.1.2" - jest-haste-map "^28.1.1" - jest-leak-detector "^28.1.1" - jest-message-util "^28.1.1" - jest-resolve "^28.1.1" - jest-runtime "^28.1.2" - jest-util "^28.1.1" - jest-watcher "^28.1.1" - jest-worker "^28.1.1" + jest-docblock "^29.4.3" + jest-environment-node "^29.5.0" + jest-haste-map "^29.5.0" + jest-leak-detector "^29.5.0" + jest-message-util "^29.5.0" + jest-resolve "^29.5.0" + jest-runtime "^29.5.0" + jest-util "^29.5.0" + jest-watcher "^29.5.0" + jest-worker "^29.5.0" + p-limit "^3.1.0" source-map-support "0.5.13" - throat "^6.0.1" - -jest-runtime@^28.1.2: - version "28.1.2" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-28.1.2.tgz#d68f34f814a848555a345ceda23289f14d59a688" - integrity sha512-i4w93OsWzLOeMXSi9epmakb2+3z0AchZtUQVF1hesBmcQQy4vtaql5YdVe9KexdJaVRyPDw8DoBR0j3lYsZVYw== - dependencies: - "@jest/environment" "^28.1.2" - "@jest/fake-timers" "^28.1.2" - "@jest/globals" "^28.1.2" - "@jest/source-map" "^28.1.2" - "@jest/test-result" "^28.1.1" - "@jest/transform" "^28.1.2" - "@jest/types" "^28.1.1" + +jest-runtime@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.5.0.tgz#c83f943ee0c1da7eb91fa181b0811ebd59b03420" + integrity sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw== + dependencies: + "@jest/environment" "^29.5.0" + "@jest/fake-timers" "^29.5.0" + "@jest/globals" "^29.5.0" + "@jest/source-map" "^29.4.3" + "@jest/test-result" "^29.5.0" + "@jest/transform" "^29.5.0" + "@jest/types" "^29.5.0" + "@types/node" "*" chalk "^4.0.0" cjs-module-lexer "^1.0.0" collect-v8-coverage "^1.0.0" - execa "^5.0.0" glob "^7.1.3" graceful-fs "^4.2.9" - jest-haste-map "^28.1.1" - jest-message-util "^28.1.1" - jest-mock "^28.1.1" - jest-regex-util "^28.0.2" - jest-resolve "^28.1.1" - jest-snapshot "^28.1.2" - jest-util "^28.1.1" + jest-haste-map "^29.5.0" + jest-message-util "^29.5.0" + jest-mock "^29.5.0" + jest-regex-util "^29.4.3" + jest-resolve "^29.5.0" + jest-snapshot "^29.5.0" + jest-util "^29.5.0" slash "^3.0.0" strip-bom "^4.0.0" -jest-snapshot@^28.1.2: - version "28.1.2" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-28.1.2.tgz#93d31b87b11b384f5946fe0767541496135f8d52" - integrity sha512-wzrieFttZYfLvrCVRJxX+jwML2YTArOUqFpCoSVy1QUapx+LlV9uLbV/mMEhYj4t7aMeE9aSQFHSvV/oNoDAMA== +jest-snapshot@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.5.0.tgz#c9c1ce0331e5b63cd444e2f95a55a73b84b1e8ce" + integrity sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g== dependencies: "@babel/core" "^7.11.6" "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-jsx" "^7.7.2" "@babel/plugin-syntax-typescript" "^7.7.2" "@babel/traverse" "^7.7.2" "@babel/types" "^7.3.3" - "@jest/expect-utils" "^28.1.1" - "@jest/transform" "^28.1.2" - "@jest/types" "^28.1.1" + "@jest/expect-utils" "^29.5.0" + "@jest/transform" "^29.5.0" + "@jest/types" "^29.5.0" "@types/babel__traverse" "^7.0.6" "@types/prettier" "^2.1.5" babel-preset-current-node-syntax "^1.0.0" chalk "^4.0.0" - expect "^28.1.1" + expect "^29.5.0" graceful-fs "^4.2.9" - jest-diff "^28.1.1" - jest-get-type "^28.0.2" - jest-haste-map "^28.1.1" - jest-matcher-utils "^28.1.1" - jest-message-util "^28.1.1" - jest-util "^28.1.1" + jest-diff "^29.5.0" + jest-get-type "^29.4.3" + jest-matcher-utils "^29.5.0" + jest-message-util "^29.5.0" + jest-util "^29.5.0" natural-compare "^1.4.0" - pretty-format "^28.1.1" + pretty-format "^29.5.0" semver "^7.3.5" -jest-util@^28.0.0, jest-util@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-28.1.1.tgz#ff39e436a1aca397c0ab998db5a51ae2b7080d05" - integrity sha512-FktOu7ca1DZSyhPAxgxB6hfh2+9zMoJ7aEQA759Z6p45NuO8mWcqujH+UdHlCm/V6JTWwDztM2ITCzU1ijJAfw== +jest-util@^29.0.0, jest-util@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.5.0.tgz#24a4d3d92fc39ce90425311b23c27a6e0ef16b8f" + integrity sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ== dependencies: - "@jest/types" "^28.1.1" + "@jest/types" "^29.5.0" "@types/node" "*" chalk "^4.0.0" ci-info "^3.2.0" graceful-fs "^4.2.9" picomatch "^2.2.3" -jest-validate@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-28.1.1.tgz#59b7b339b3c85b5144bd0c06ad3600f503a4acc8" - integrity sha512-Kpf6gcClqFCIZ4ti5++XemYJWUPCFUW+N2gknn+KgnDf549iLul3cBuKVe1YcWRlaF8tZV8eJCap0eECOEE3Ug== +jest-validate@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.5.0.tgz#8e5a8f36178d40e47138dc00866a5f3bd9916ffc" + integrity sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ== dependencies: - "@jest/types" "^28.1.1" + "@jest/types" "^29.5.0" camelcase "^6.2.0" chalk "^4.0.0" - jest-get-type "^28.0.2" + jest-get-type "^29.4.3" leven "^3.1.0" - pretty-format "^28.1.1" + pretty-format "^29.5.0" -jest-watcher@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-28.1.1.tgz#533597fb3bfefd52b5cd115cd916cffd237fb60c" - integrity sha512-RQIpeZ8EIJMxbQrXpJQYIIlubBnB9imEHsxxE41f54ZwcqWLysL/A0ZcdMirf+XsMn3xfphVQVV4EW0/p7i7Ug== +jest-watcher@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.5.0.tgz#cf7f0f949828ba65ddbbb45c743a382a4d911363" + integrity sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA== dependencies: - "@jest/test-result" "^28.1.1" - "@jest/types" "^28.1.1" + "@jest/test-result" "^29.5.0" + "@jest/types" "^29.5.0" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" - emittery "^0.10.2" - jest-util "^28.1.1" + emittery "^0.13.1" + jest-util "^29.5.0" string-length "^4.0.1" -jest-worker@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-28.1.1.tgz#3480c73247171dfd01eda77200f0063ab6a3bf28" - integrity sha512-Au7slXB08C6h+xbJPp7VIb6U0XX5Kc9uel/WFc6/rcTzGiaVCBRngBExSYuXSLFPULPSYU3cJ3ybS988lNFQhQ== +jest-worker@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.5.0.tgz#bdaefb06811bd3384d93f009755014d8acb4615d" + integrity sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA== dependencies: "@types/node" "*" + jest-util "^29.5.0" merge-stream "^2.0.0" supports-color "^8.0.0" -jest@^28.1.2: - version "28.1.2" - resolved "https://registry.yarnpkg.com/jest/-/jest-28.1.2.tgz#451ff24081ce31ca00b07b60c61add13aa96f8eb" - integrity sha512-Tuf05DwLeCh2cfWCQbcz9UxldoDyiR1E9Igaei5khjonKncYdc6LDfynKCEWozK0oLE3GD+xKAo2u8x/0s6GOg== +jest@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-29.5.0.tgz#f75157622f5ce7ad53028f2f8888ab53e1f1f24e" + integrity sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ== dependencies: - "@jest/core" "^28.1.2" - "@jest/types" "^28.1.1" + "@jest/core" "^29.5.0" + "@jest/types" "^29.5.0" import-local "^3.0.2" - jest-cli "^28.1.2" + jest-cli "^29.5.0" js-sha3@0.8.0: version "0.8.0" @@ -3268,6 +3310,11 @@ json5@^2.2.1: resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + kleur@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" @@ -3551,6 +3598,13 @@ p-limit@^2.2.0: dependencies: p-try "^2.0.0" +p-limit@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + p-locate@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" @@ -3661,13 +3715,12 @@ prettier@^2.7.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== -pretty-format@^28.0.0, pretty-format@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-28.1.1.tgz#f731530394e0f7fcd95aba6b43c50e02d86b95cb" - integrity sha512-wwJbVTGFHeucr5Jw2bQ9P+VYHyLdAqedFLEkdQUVaBF/eiidDwH5OpilINq4mEfhbCjLnirt6HTTDhv1HaTIQw== +pretty-format@^29.0.0, pretty-format@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.5.0.tgz#283134e74f70e2e3e7229336de0e4fce94ccde5a" + integrity sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw== dependencies: - "@jest/schemas" "^28.0.2" - ansi-regex "^5.0.1" + "@jest/schemas" "^29.4.3" ansi-styles "^5.0.0" react-is "^18.0.0" @@ -3694,6 +3747,11 @@ punycode@^2.1.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== +pure-rand@^6.0.0: + version "6.0.2" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.0.2.tgz#a9c2ddcae9b68d736a8163036f088a2781c8b306" + integrity sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ== + queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" @@ -3766,10 +3824,10 @@ resolve-from@^5.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== -resolve.exports@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9" - integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ== +resolve.exports@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" + integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== resolve@^1.20.0: version "1.21.0" @@ -3794,7 +3852,7 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rimraf@^3.0.0, rimraf@^3.0.2: +rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== @@ -3977,7 +4035,7 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" -supports-color@^7.0.0, supports-color@^7.1.0: +supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== @@ -3991,27 +4049,11 @@ supports-color@^8.0.0: dependencies: has-flag "^4.0.0" -supports-hyperlinks@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" - integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ== - dependencies: - has-flag "^4.0.0" - supports-color "^7.0.0" - supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -terminal-link@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" - integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== - dependencies: - ansi-escapes "^4.2.1" - supports-hyperlinks "^2.0.0" - test-exclude@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" @@ -4026,11 +4068,6 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= -throat@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.1.tgz#d514fedad95740c12c2d7fc70ea863eb51ade375" - integrity sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w== - through2@^2.0.1: version "2.0.5" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" @@ -4076,15 +4113,15 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== -ts-jest@^28.0.5: - version "28.0.5" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-28.0.5.tgz#31776f768fba6dfc8c061d488840ed0c8eeac8b9" - integrity sha512-Sx9FyP9pCY7pUzQpy4FgRZf2bhHY3za576HMKJFs+OnQ9jS96Du5vNsDKkyedQkik+sEabbKAnCliv9BEsHZgQ== +ts-jest@^29.1.0: + version "29.1.0" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.1.0.tgz#4a9db4104a49b76d2b368ea775b6c9535c603891" + integrity sha512-ZhNr7Z4PcYa+JjMl62ir+zPiNJfXJN6E8hSLnaUKhOgqcn8vb3e537cpkd0FuAfRK3sR1LSqM1MOhliXNgOFPA== dependencies: bs-logger "0.x" fast-json-stable-stringify "2.x" - jest-util "^28.0.0" - json5 "^2.2.1" + jest-util "^29.0.0" + json5 "^2.2.3" lodash.memoize "4.x" make-error "1.x" semver "7.x" @@ -4244,10 +4281,10 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -write-file-atomic@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.1.tgz#9faa33a964c1c85ff6f849b80b42a88c2c537c8f" - integrity sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ== +write-file-atomic@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" + integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== dependencies: imurmurhash "^0.1.4" signal-exit "^3.0.7" @@ -4307,3 +4344,8 @@ yargs@^17.3.1: string-width "^4.2.3" y18n "^5.0.5" yargs-parser "^21.0.0" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== From 440c4d760a5378e826f8be44e8b028d23510dbed Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Thu, 1 Jun 2023 20:37:55 +0530 Subject: [PATCH 407/815] Fix type (#1183) --- src/validations/passport-gated/schema.json | 2 +- src/validations/passport-weighted/schema.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/validations/passport-gated/schema.json b/src/validations/passport-gated/schema.json index 44a3e35de..76ada86d9 100644 --- a/src/validations/passport-gated/schema.json +++ b/src/validations/passport-gated/schema.json @@ -53,7 +53,7 @@ }, { "const": "POAP", - "title": "POAP onwer" + "title": "POAP owner" }, { "const": "Facebook", diff --git a/src/validations/passport-weighted/schema.json b/src/validations/passport-weighted/schema.json index ba9d66e81..0d741f6a1 100644 --- a/src/validations/passport-weighted/schema.json +++ b/src/validations/passport-weighted/schema.json @@ -62,7 +62,7 @@ }, { "const": "POAP", - "title": "POAP onwer" + "title": "POAP owner" }, { "const": "Facebook", From 2d716a1ac9aa72b4523f1e783e6cae351b04b676 Mon Sep 17 00:00:00 2001 From: fextr <34183870+fextr@users.noreply.github.com> Date: Fri, 2 Jun 2023 10:47:25 +0400 Subject: [PATCH 408/815] [zunami-pool-gauge-aggregated-balance-of] add frax staking balances (#1174) * [zunami-pool-gauge-aggregated-balance-of] add frax staking balances * Update index.ts --------- Co-authored-by: Chaitanya --- .../examples.json | 4 +- .../index.ts | 115 ++++++++++++++++-- .../schema.json | 8 ++ 3 files changed, 114 insertions(+), 13 deletions(-) diff --git a/src/strategies/zunami-pool-gauge-aggregated-balance-of/examples.json b/src/strategies/zunami-pool-gauge-aggregated-balance-of/examples.json index 98c1d21de..e401bfe94 100644 --- a/src/strategies/zunami-pool-gauge-aggregated-balance-of/examples.json +++ b/src/strategies/zunami-pool-gauge-aggregated-balance-of/examples.json @@ -5,6 +5,7 @@ "name": "zunami-pool-gauge-aggregated-balance-of", "params": { "address": "0x0AD930970b60d24bd30F612D287f188A7626B147", + "fraxStakingAddress": "0xb8ebc210BCF78be8Ef3F09Dd0d8e85Fa5e252e86", "decimals": 18, "lpPriceDecimals": 18, "curvePoolAddress": "0x68934F60758243eafAf4D2cFeD27BF8010bede3a", @@ -24,11 +25,12 @@ "0xa6dC407C39bd07F6D6C3780C2F5a53e690387F4a", "0x287CDD0A59d69E9F101E90BDBCC892607DF08CF9", "0x2d34816C3c83554CE97144c623C381b303Aba732", + "0x6De72e5568CfbB9d0fb91Fb384D2E52d7e5C1E94", "0xBdCA4F610e7101Cc172E2135ba025737B99AbD30", "0xbc61f6973cE564eFFB16Cd79B5BC3916eaD592E2", "0x989AEb4d175e16225E39E87d0D97A3360524AD80" ], - "snapshot": 17116797 + "snapshot": 17330743 } ] diff --git a/src/strategies/zunami-pool-gauge-aggregated-balance-of/index.ts b/src/strategies/zunami-pool-gauge-aggregated-balance-of/index.ts index 258d3526e..2409c175b 100644 --- a/src/strategies/zunami-pool-gauge-aggregated-balance-of/index.ts +++ b/src/strategies/zunami-pool-gauge-aggregated-balance-of/index.ts @@ -1,14 +1,16 @@ -import { BigNumberish } from '@ethersproject/bignumber'; +import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; import { formatUnits } from '@ethersproject/units'; import { call, Multicaller } from '../../utils'; export const author = 'fextr'; -export const version = '1.0.0'; +export const version = '1.0.1'; const zunamiSnapshotHelperAbi = [ 'function aggregatedBalanceOf(address _account) external view returns (uint256)' ]; - +const fraxStakingAbi = [ + 'function lockedLiquidityOf(address account) external view returns (uint256)' +]; const curveAbi = ['function get_virtual_price() view returns (uint256)']; interface StrategyOptions { @@ -16,6 +18,7 @@ interface StrategyOptions { decimals: number; lpPriceDecimals: number; curvePoolAddress: string; + fraxStakingAddress: string; blackListAddresses: string[]; } @@ -41,23 +44,111 @@ export async function strategy( ) ); - const multi = new Multicaller(network, provider, zunamiSnapshotHelperAbi, { - blockTag - }); const blackListAddressesArr = Array.from(options.blackListAddresses).map( (address) => address.toLowerCase() ); - addresses - .filter((address) => !blackListAddressesArr.includes(address.toLowerCase())) - .forEach((address) => - multi.call(address, options.address, 'aggregatedBalanceOf', [address]) + const filteredAddresses = addresses.filter( + (address) => !blackListAddressesArr.includes(address.toLowerCase()) + ); + + const aggregatedResult: Record = + await getAggregatedBalance( + network, + provider, + blockTag, + filteredAddresses, + options.address + ); + + const fraxStakingResult: Record = + await getFraxStakingBalance( + network, + provider, + blockTag, + filteredAddresses, + options.fraxStakingAddress ); - const result: Record = await multi.execute(); + + const result: [string, BigNumberish][] = mergeResults( + aggregatedResult, + fraxStakingResult + ); return Object.fromEntries( - Object.entries(result).map(([address, balance]) => [ + result.map(([address, balance]) => [ address, parseFloat(formatUnits(balance, options.decimals)) * lpPrice ]) ); } + +async function getFraxStakingBalance( + network, + provider, + blockTag, + filteredAddresses: string[], + fraxStakingAddress: string +): Promise> { + const fraxStakingMulti = new Multicaller(network, provider, fraxStakingAbi, { + blockTag + }); + filteredAddresses.forEach((address) => + fraxStakingMulti.call(address, fraxStakingAddress, 'lockedLiquidityOf', [ + address + ]) + ); + const fraxStakingResult: Record = + await fraxStakingMulti.execute(); + + return fraxStakingResult; +} + +async function getAggregatedBalance( + network, + provider, + blockTag, + filteredAddresses: string[], + contractAddress: string +): Promise> { + const multi = new Multicaller(network, provider, zunamiSnapshotHelperAbi, { + blockTag + }); + filteredAddresses.forEach((address) => + multi.call(address, contractAddress, 'aggregatedBalanceOf', [address]) + ); + const aggregatedResult: Record = await multi.execute(); + + return aggregatedResult; +} + +function mergeResults( + aggregatedResult: Record, + fraxStakingResult: Record +): [string, BigNumberish][] { + const fraxStakingEntries = Object.entries(fraxStakingResult); + const fraxStakingResultMap: Map = new Map( + fraxStakingEntries + ); + const aggregatedPlusStaking: [string, BigNumberish][] = Object.entries( + aggregatedResult + ).map(([address, balance]) => { + const fraxStakingBalance = fraxStakingResultMap.get(address); + if (fraxStakingBalance) { + return [ + address, + BigNumber.from(balance).add(BigNumber.from(fraxStakingBalance)) + ]; + } + return [address, balance]; + }); + const aggregatedPluStakingMap: Map = new Map( + aggregatedPlusStaking + ); + fraxStakingEntries.map(([address, balance]) => { + if (!aggregatedPluStakingMap.has(address)) { + aggregatedPlusStaking.push([address, balance]); + } + }); + + return aggregatedPlusStaking; +} diff --git a/src/strategies/zunami-pool-gauge-aggregated-balance-of/schema.json b/src/strategies/zunami-pool-gauge-aggregated-balance-of/schema.json index 59426c1fa..d6eb62404 100644 --- a/src/strategies/zunami-pool-gauge-aggregated-balance-of/schema.json +++ b/src/strategies/zunami-pool-gauge-aggregated-balance-of/schema.json @@ -14,6 +14,14 @@ "minLength": 42, "maxLength": 42 }, + "fraxStakingAddress": { + "type": "string", + "title": "Zunami convex frax staking address", + "examples": ["e.g. 0xb8ebc210BCF78be8Ef3F09Dd0d8e85Fa5e252e86"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, "decimals": { "type": "number", "title": "Decimals", From 1b35365de0eaa22df8c83681d60296ee22920462 Mon Sep 17 00:00:00 2001 From: Marcus Date: Fri, 2 Jun 2023 16:38:39 +0800 Subject: [PATCH 409/815] [spaceid] feat: spaceid strategy (#1171) * feat: spaceid strategy * Update src/strategies/spaceid/index.ts Co-authored-by: Chaitanya * fix: remove delegation voting power calculation * fix: chain id type * fix: change chainId in examples --------- Co-authored-by: Marcus Co-authored-by: Chaitanya --- src/strategies/index.ts | 4 +- src/strategies/spaceid/README.md | 1 + src/strategies/spaceid/examples.json | 19 ++++++ src/strategies/spaceid/index.ts | 94 ++++++++++++++++++++++++++++ src/strategies/spaceid/schema.json | 14 +++++ 5 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 src/strategies/spaceid/README.md create mode 100644 src/strategies/spaceid/examples.json create mode 100644 src/strategies/spaceid/index.ts create mode 100644 src/strategies/spaceid/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 2b4cb5cbc..20febe2a8 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -444,6 +444,7 @@ import * as capVotingPower from './cap-voting-power'; import * as zunamiPoolGaugeAggregatedBalanceOf from './zunami-pool-gauge-aggregated-balance-of'; import * as erc721CollateralHeld from './erc721-collateral-held'; import * as starlayVeBalanceOfLockerId from './starlay-ve-balance-of-locker-id'; +import * as spaceid from './spaceid'; const strategies = { 'cap-voting-power': capVotingPower, @@ -894,7 +895,8 @@ const strategies = { 'degenzoo-erc721-animals-weighted': degenzooErc721AnimalsWeighted, 'zunami-pool-gauge-aggregated-balance-of': zunamiPoolGaugeAggregatedBalanceOf, 'erc721-collateral-held': erc721CollateralHeld, - 'starlay-ve-balance-of-locker-id': starlayVeBalanceOfLockerId + 'starlay-ve-balance-of-locker-id': starlayVeBalanceOfLockerId, + spaceid }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/spaceid/README.md b/src/strategies/spaceid/README.md new file mode 100644 index 000000000..bdd0e29cb --- /dev/null +++ b/src/strategies/spaceid/README.md @@ -0,0 +1 @@ +This is SPACEID strategy, it returns the voting power of the voters. \ No newline at end of file diff --git a/src/strategies/spaceid/examples.json b/src/strategies/spaceid/examples.json new file mode 100644 index 000000000..857f3eb9f --- /dev/null +++ b/src/strategies/spaceid/examples.json @@ -0,0 +1,19 @@ +[ + { + "name": "spaceid query on ethers", + "strategy": { + "name": "spaceid", + "params": { + } + }, + "network": "1", + "addresses": [ + "0xad3d542ACD90A3492B41AF49399BAeb755A11e59", + "0xD0303ee7CC8607D7d483E20BA41A1Ea978287D91", + "0xb85b3D61439a3d70D3DF7913a3A764F352b32C55", + "0xb2C2325B93b1a3C882fe47C453622f1D75801D72", + "0xfcc21059e5c6aead385b421344c9a4e9f8d2a238" + ], + "snapshot": 17320694 + } +] diff --git a/src/strategies/spaceid/index.ts b/src/strategies/spaceid/index.ts new file mode 100644 index 000000000..3a15baf96 --- /dev/null +++ b/src/strategies/spaceid/index.ts @@ -0,0 +1,94 @@ +import { strategy as UniswapV3Strategy } from '../uniswap-v3'; +import { subgraphRequest } from '../../utils'; +import { BigNumber } from '@ethersproject/bignumber'; +import { WeiPerEther } from '@ethersproject/constants'; +import { getAddress } from '@ethersproject/address'; + +export const author = 'SID-Marcus'; +export const version = '0.0.1'; + +const pancakeV3Subgraph = + 'https://api.thegraph.com/subgraphs/name/messari/pancakeswap-v3-bsc'; + +const UNISWAP_ID_USDC_PAIR = '0x6ac6b053a2858bea8ad758db680198c16e523184'; +const PANCAKE_ID_USDT_PAIR = '0x4e1f9aDf96dBA6Dc09c973228c286568F1315ea8'; + +async function getLpTokenOnBsc(addresses, snapshot) { + const params = { + accounts: { + __args: { + where: { + id_in: addresses + }, + block: snapshot !== 'latest' ? { number: snapshot } : { number_gte: 0 } + }, + id: true, + withdraws: { + __args: { + where: { pool: PANCAKE_ID_USDT_PAIR } + }, + inputTokenAmounts: true, + timestamp: true + }, + deposits: { + __args: { + where: { pool: PANCAKE_ID_USDT_PAIR } + }, + inputTokenAmounts: true, + timestamp: true + } + } + }; + + const pools = await subgraphRequest(pancakeV3Subgraph, params); + + const pancakeIDLPScore = {}; + for (const account of pools.accounts) { + let IdLPToken: BigNumber = BigNumber.from(0); + for (const withdraw of account.withdraws) { + IdLPToken = IdLPToken.add(BigNumber.from(withdraw.inputTokenAmounts[0])); + } + for (const deposit of account.deposits) { + IdLPToken = IdLPToken.sub(BigNumber.from(deposit.inputTokenAmounts[0])); + } + pancakeIDLPScore[account.id] = IdLPToken.div(WeiPerEther).toNumber(); + pancakeIDLPScore[account.id] < 0 && (pancakeIDLPScore[account.id] = 0); + } + return pancakeIDLPScore; +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + let LPScore = {}; + switch (network) { + case '1': + LPScore = await UniswapV3Strategy( + space, + network, + provider, + addresses, + { + poolAddress: UNISWAP_ID_USDC_PAIR, + tokenReserve: 0 + }, + snapshot + ); + break; + case '56': + LPScore = await getLpTokenOnBsc(addresses, snapshot); + break; + } + return Object.fromEntries( + addresses.map((address) => { + const addressScore = LPScore[address] ?? 0; + // console.log(address, LPScore[address], delegationPower[address]); + return [getAddress(address), addressScore]; + }) + ); +} diff --git a/src/strategies/spaceid/schema.json b/src/strategies/spaceid/schema.json new file mode 100644 index 000000000..2c7d650f5 --- /dev/null +++ b/src/strategies/spaceid/schema.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "SPACEID", + "type": "object", + "properties": { + }, + "required": [], + "additionalProperties": false + } + } + } \ No newline at end of file From 6262b48116f23777fed93b3869a35d28c5d1f897 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 5 Jun 2023 12:29:01 +0530 Subject: [PATCH 410/815] Automated lint (#1184) Co-authored-by: ChaituVR --- src/strategies/spaceid/examples.json | 3 +- src/strategies/spaceid/schema.json | 23 +++++++-------- src/validations/passport-weighted/index.ts | 34 +++++++++++++--------- 3 files changed, 32 insertions(+), 28 deletions(-) diff --git a/src/strategies/spaceid/examples.json b/src/strategies/spaceid/examples.json index 857f3eb9f..daa39ad60 100644 --- a/src/strategies/spaceid/examples.json +++ b/src/strategies/spaceid/examples.json @@ -3,8 +3,7 @@ "name": "spaceid query on ethers", "strategy": { "name": "spaceid", - "params": { - } + "params": {} }, "network": "1", "addresses": [ diff --git a/src/strategies/spaceid/schema.json b/src/strategies/spaceid/schema.json index 2c7d650f5..0a7e60796 100644 --- a/src/strategies/spaceid/schema.json +++ b/src/strategies/spaceid/schema.json @@ -1,14 +1,13 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", - "$ref": "#/definitions/Strategy", - "definitions": { - "Strategy": { - "title": "SPACEID", - "type": "object", - "properties": { - }, - "required": [], - "additionalProperties": false - } + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "SPACEID", + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false } - } \ No newline at end of file + } +} diff --git a/src/validations/passport-weighted/index.ts b/src/validations/passport-weighted/index.ts index fb77ec9b5..d72299e25 100644 --- a/src/validations/passport-weighted/index.ts +++ b/src/validations/passport-weighted/index.ts @@ -3,13 +3,15 @@ import Validation from '../validation'; import dotenv from 'dotenv'; dotenv.config({ path: '.env' }); -const API_KEY = process.env.NEXT_PUBLIC_GC_API_KEY -const SCORER_ID = process.env.NEXT_PUBLIC_GC_SCORER_ID +const API_KEY = process.env.NEXT_PUBLIC_GC_API_KEY; +const SCORER_ID = process.env.NEXT_PUBLIC_GC_SCORER_ID; -const headers = API_KEY ? ({ - 'Content-Type': 'application/json', - 'X-API-Key': API_KEY -}) : undefined +const headers = API_KEY + ? { + 'Content-Type': 'application/json', + 'X-API-Key': API_KEY + } + : undefined; export default class extends Validation { public id = 'passport-weighted'; @@ -20,26 +22,30 @@ export default class extends Validation { 'Protect your proposals from spam and vote manipulation by requiring users to have a Gitcoin Passport.'; async validate(currentAddress = this.author): Promise { - const GET_PASSPORT_SCORE_URI = `https://api.scorer.gitcoin.co/registry/score/${SCORER_ID}/${currentAddress}` + const GET_PASSPORT_SCORE_URI = `https://api.scorer.gitcoin.co/registry/score/${SCORER_ID}/${currentAddress}`; const THRESHOLD_NUMBER = this.params.minScore || 1; try { const response = await fetch(GET_PASSPORT_SCORE_URI, { headers - }) - const passportData = await response.json() + }); + const passportData = await response.json(); if (passportData.score) { - const roundedScore = Math.round(passportData.score * 100) / 100 + const roundedScore = Math.round(passportData.score * 100) / 100; if (roundedScore >= THRESHOLD_NUMBER) return true; - console.log(`Your passport score (${roundedScore}) is lower than the threshold score (${THRESHOLD_NUMBER}).`); + console.log( + `Your passport score (${roundedScore}) is lower than the threshold score (${THRESHOLD_NUMBER}).` + ); return false; } else { - console.log('You do not have a valid Gitcoin Passport. Create one by visiting https://passport.gitcoin.co/ ') + console.log( + 'You do not have a valid Gitcoin Passport. Create one by visiting https://passport.gitcoin.co/ ' + ); return false; - } + } } catch (err) { - console.log('error: ', err) + console.log('error: ', err); throw err; } } From 408f14c2abc81f94c952537f80dcfd9696fb935b Mon Sep 17 00:00:00 2001 From: Flush <127896036+flushjb@users.noreply.github.com> Date: Tue, 6 Jun 2023 18:30:15 +0300 Subject: [PATCH 411/815] Add WINRProtocol Governance Voting Strategy [winr-staking] (#1179) * feat(winr-staking): add new strategy for Winr governance staking This commit adds a new strategy for Winr governance staking. The strategy allows users that staked WINR and vWINR to vote on proposals by delegating their voting power to a delegatee. The strategy calculates the total staked amount for each user by summing up the staked amount from each active index, dividend stakes, and vested dividend stakes. The strategy is implemented in the `src/strategies/winr-staking` directory and includes a README.md file, examples.json file, index.ts file, and schema.json file. * refactor(winr-staking): replace Promise.all with map to improve performance The Promise.all function is replaced with map to improve performance. The multicaller.call function is now called for each address in the addresses array. This change allows multicaller to make the calls concurrently, which can improve performance. * refactor(winr-staking): remove unnecessary Promise.all() and await from addresses.map() The Promise.all() and await are not necessary in the addresses.map() function as the multicaller2.call() function returns a Promise. Removing the Promise.all() and await will not affect the functionality of the code and will make it more concise. --------- Co-authored-by: Chaitanya --- src/strategies/index.ts | 2 + src/strategies/winr-staking/README.md | 20 ++++++ src/strategies/winr-staking/examples.json | 23 ++++++ src/strategies/winr-staking/index.ts | 88 +++++++++++++++++++++++ src/strategies/winr-staking/schema.json | 22 ++++++ 5 files changed, 155 insertions(+) create mode 100644 src/strategies/winr-staking/README.md create mode 100644 src/strategies/winr-staking/examples.json create mode 100644 src/strategies/winr-staking/index.ts create mode 100644 src/strategies/winr-staking/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 20febe2a8..25e4271cf 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -444,6 +444,7 @@ import * as capVotingPower from './cap-voting-power'; import * as zunamiPoolGaugeAggregatedBalanceOf from './zunami-pool-gauge-aggregated-balance-of'; import * as erc721CollateralHeld from './erc721-collateral-held'; import * as starlayVeBalanceOfLockerId from './starlay-ve-balance-of-locker-id'; +import * as winrStaking from './winr-staking'; import * as spaceid from './spaceid'; const strategies = { @@ -896,6 +897,7 @@ const strategies = { 'zunami-pool-gauge-aggregated-balance-of': zunamiPoolGaugeAggregatedBalanceOf, 'erc721-collateral-held': erc721CollateralHeld, 'starlay-ve-balance-of-locker-id': starlayVeBalanceOfLockerId, + 'winr-staking': winrStaking, spaceid }; diff --git a/src/strategies/winr-staking/README.md b/src/strategies/winr-staking/README.md new file mode 100644 index 000000000..2cfa71755 --- /dev/null +++ b/src/strategies/winr-staking/README.md @@ -0,0 +1,20 @@ +# Winr Governance Staking Strategy + +## Overview + +This strategy is used for Winr governance staking. It allows users that staked WINR and vWINR to vote on proposals by delegating their voting power to a delegatee. + +## Parameters + +- `address`: Address of the staking contract + +## Example + +```json +{ + "name": "winr-staking", + "params": { + "address": "0xddAEcf4B02A3e45b96FC2d7339c997E072b0d034" + } +} +``` diff --git a/src/strategies/winr-staking/examples.json b/src/strategies/winr-staking/examples.json new file mode 100644 index 000000000..1c138f4a3 --- /dev/null +++ b/src/strategies/winr-staking/examples.json @@ -0,0 +1,23 @@ +[ + { + "name": "WINR Staking", + "strategy": { + "name": "winr-staking", + "params": { + "address": "0xddAEcf4B02A3e45b96FC2d7339c997E072b0d034" + } + }, + "network": "42161", + "addresses": [ + "0x954B6dE2E9C58B0ca7B21e9A048fD0A6CEa6f92C", + "0x40Db8365d1252bcb06598927698238a99D39228E", + "0xd2f5b5fECc86b02F1A77823fb96a7052C62571D1", + "0xc0d4499A3E452bEd3CE794c2360916452bFbf6A5", + "0x9dC2aEa18955DD9F898d7ef130e4e166B9800354", + "0x3EC3486f491f16B7A325F15380090eD1A9Dc79D6", + "0x52caB1b95fb1049c76ED0f72c27B37D1B63F4691", + "0x6035507146b6B5B96e3Fe5A093c83714f27898ED" + ], + "snapshot": 95804680 + } +] diff --git a/src/strategies/winr-staking/index.ts b/src/strategies/winr-staking/index.ts new file mode 100644 index 000000000..70f4c57cc --- /dev/null +++ b/src/strategies/winr-staking/index.ts @@ -0,0 +1,88 @@ +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; +import { BigNumber } from '@ethersproject/bignumber'; + +export const author = 'flushjb'; +export const version = '0.1.0'; + +const abi = [ + 'function getActiveIndexes(address staker) external view returns (uint256[])', + 'function vestingStakedAmount(address _account, uint256[] _indexes) external view returns (uint256 _totalStaked)', + 'function getDividendStake(address _account, bool _isVested) external view returns (uint256 amount, uint256 profitDebt, uint256 weight, uint128 depositTime)' +]; + +// 'function getActiveIndexes(address staker) external view returns (uint256[])', + +type VotingPowers = Record; + +export async function strategy( + space, + network, + provider, + addresses: string[], + options, + snapshot +): Promise { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multicaller = new Multicaller(network, provider, abi, { blockTag }); + + // Get each user's active indexes and dividend stakes + addresses.map(async (address) => { + multicaller.call( + `activeIndexes.${address}`, + options.address, + 'getActiveIndexes', + [address] + ); + multicaller.call( + `dividendStakes.${address}`, + options.address, + 'getDividendStake', + [address, true] + ); + multicaller.call( + `dividendStakesVested.${address}`, + options.address, + 'getDividendStake', + [address, false] + ); + }); + + const result: { + activeIndexes: Record; + dividendStakes: Record; + dividendStakesVested: Record; + } = await multicaller.execute(); + + const multicaller2 = new Multicaller(network, provider, abi, { blockTag }); + + // Get each user's staked amount from each active index + addresses.map(async (address) => { + const activeIndexes = result.activeIndexes[address]; + multicaller2.call( + `stakedAmount.${address}`, + options.address, + 'vestingStakedAmount', + [address, activeIndexes] + ); + }); + + const result2: { + stakedAmount: Record; + } = await multicaller2.execute(); + + // Calculate the total staked amount for each user and map it to the address + return Object.fromEntries( + Object.entries(result2.stakedAmount).map(([address, stakedAmount]) => { + const dividendStakes = result.dividendStakes[address].amount; + const dividendStakesVested = result.dividendStakesVested[address].amount; + const totalStaked = + parseFloat(formatUnits(stakedAmount, 18)) + + parseFloat(formatUnits(dividendStakes, 18)) + + parseFloat(formatUnits(dividendStakesVested, 18)); + + return [address, totalStaked]; + }) + ); +} diff --git a/src/strategies/winr-staking/schema.json b/src/strategies/winr-staking/schema.json new file mode 100644 index 000000000..dab2305a2 --- /dev/null +++ b/src/strategies/winr-staking/schema.json @@ -0,0 +1,22 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "address": { + "type": "string", + "title": "WINR Staking Contract address", + "examples": ["e.g. 0xddAEcf4B02A3e45b96FC2d7339c997E072b0d034"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } + }, + "required": ["address"], + "additionalProperties": false + } + } +} From 731afa6efd7dacf0e4ef00df24ecaca9c9efa97e Mon Sep 17 00:00:00 2001 From: Marcus Date: Tue, 6 Jun 2023 23:32:38 +0800 Subject: [PATCH 412/815] fix: checksum address bug (#1185) Co-authored-by: Marcus --- src/strategies/spaceid/examples.json | 8 +++----- src/strategies/spaceid/index.ts | 1 + 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/strategies/spaceid/examples.json b/src/strategies/spaceid/examples.json index daa39ad60..21cf99918 100644 --- a/src/strategies/spaceid/examples.json +++ b/src/strategies/spaceid/examples.json @@ -5,14 +5,12 @@ "name": "spaceid", "params": {} }, - "network": "1", + "network": "56", "addresses": [ "0xad3d542ACD90A3492B41AF49399BAeb755A11e59", - "0xD0303ee7CC8607D7d483E20BA41A1Ea978287D91", - "0xb85b3D61439a3d70D3DF7913a3A764F352b32C55", "0xb2C2325B93b1a3C882fe47C453622f1D75801D72", - "0xfcc21059e5c6aead385b421344c9a4e9f8d2a238" + "0x5d8CeEDdf7881f962a9354Ab5c187655fC3dec3F" ], - "snapshot": 17320694 + "snapshot": 28831785 } ] diff --git a/src/strategies/spaceid/index.ts b/src/strategies/spaceid/index.ts index 3a15baf96..60a64ae7b 100644 --- a/src/strategies/spaceid/index.ts +++ b/src/strategies/spaceid/index.ts @@ -44,6 +44,7 @@ async function getLpTokenOnBsc(addresses, snapshot) { const pancakeIDLPScore = {}; for (const account of pools.accounts) { + account.id = getAddress(account.id); let IdLPToken: BigNumber = BigNumber.from(0); for (const withdraw of account.withdraws) { IdLPToken = IdLPToken.add(BigNumber.from(withdraw.inputTokenAmounts[0])); From 462d99fff5f8fee50eedd2a61e85a4add39b5495 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 7 Jun 2023 23:21:00 +0530 Subject: [PATCH 413/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.94 (#1186) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 449cbb814..1a12850f9 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.93", + "@snapshot-labs/snapshot.js": "^0.4.94", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index ade622b28..7c310bb3a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1192,10 +1192,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.4.93": - version "0.4.93" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.93.tgz#578f2152fabf57082875de958d58ed943fc3dada" - integrity sha512-Ih0c1EBrHtF8WeSkHSFcMeaniyuXiG7UMLfOLrVsJ5Vs9fFV1PYUhAd4p/lhiXNgMjMU32kwIoiwv9geaNDEqw== +"@snapshot-labs/snapshot.js@^0.4.94": + version "0.4.94" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.94.tgz#1e335c524c1c24f404fa118ad6a133d7dc10b39a" + integrity sha512-GIckMS9Qd2yiEGWnbHKqktGJezDjTgwXY4B2Uy4+c/TI4RC8jlkbRY7pMi3DKhmAO6WQw0ce0v+878lvyLcxlw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 4993512043971f439dd913aa07b4071431d8d9ad Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 8 Jun 2023 14:15:57 +0530 Subject: [PATCH 414/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.96 (#1187) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 1a12850f9..ab66c8a64 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.94", + "@snapshot-labs/snapshot.js": "^0.4.96", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 7c310bb3a..0239901bc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1192,10 +1192,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.4.94": - version "0.4.94" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.94.tgz#1e335c524c1c24f404fa118ad6a133d7dc10b39a" - integrity sha512-GIckMS9Qd2yiEGWnbHKqktGJezDjTgwXY4B2Uy4+c/TI4RC8jlkbRY7pMi3DKhmAO6WQw0ce0v+878lvyLcxlw== +"@snapshot-labs/snapshot.js@^0.4.96": + version "0.4.96" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.96.tgz#141be3285ab0b25053ace6963f70b4225b2407ca" + integrity sha512-ZilCjKSHx4j6gl4g0+ABCYSsK/5zo4jjNz+DaeimXDZIH+e5mtT1HHFaR+kI14hqYNxTkyTinxJ39q5/gSuzjw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From b9abbf61a1d949b80d204d40e60896589ce431f2 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Fri, 9 Jun 2023 00:16:36 +0530 Subject: [PATCH 415/815] Print errors from API (Also if it return html) (#1188) --- src/strategies/api-v2/index.ts | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/strategies/api-v2/index.ts b/src/strategies/api-v2/index.ts index 7f89f0b91..a7903c608 100644 --- a/src/strategies/api-v2/index.ts +++ b/src/strategies/api-v2/index.ts @@ -46,18 +46,27 @@ export async function strategy( }, body }); + let responseData: any = await response.text(); + try { + responseData = JSON.parse(responseData); + } catch (e) { + throw new Error( + `[api-v2] Errors found in API: URL: ${url}, Status: ${ + response.status + }, Response: ${responseData.substring(0, 512)}` + ); + } - const data = await response.json(); - - if (!data.score) throw new Error('Invalid response from API'); + if (!responseData?.score) throw new Error('Invalid response from API'); return Object.fromEntries( addresses.map((address) => [ getAddress(address), parseFloat( formatUnits( - data.score.find((s) => s.address === address)?.score?.toString() || - '0', + responseData.score + .find((s) => s.address === address) + ?.score?.toString() || '0', options.hasOwnProperty('decimals') ? options.decimals : 0 ) ) From 192d963346a1cbf666feafaf17818a150e2edfc8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 9 Jun 2023 19:13:43 +0530 Subject: [PATCH 416/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.97 (#1189) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 46 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index ab66c8a64..f068d9756 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.96", + "@snapshot-labs/snapshot.js": "^0.4.97", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 0239901bc..c44332b45 100644 --- a/yarn.lock +++ b/yarn.lock @@ -456,6 +456,15 @@ "@ethersproject/logger" "^5.6.0" bn.js "^5.2.1" +"@ethersproject/bignumber@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz#e2f03837f268ba655ffba03a57853e18a18dc9c2" + integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + bn.js "^5.2.1" + "@ethersproject/bytes@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.5.0.tgz#cb11c526de657e7b45d2e0f0246fb3b9d29a601c" @@ -470,6 +479,13 @@ dependencies: "@ethersproject/logger" "^5.6.0" +"@ethersproject/bytes@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.7.0.tgz#a00f6ea8d7e7534d6d87f47188af1148d71f155d" + integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== + dependencies: + "@ethersproject/logger" "^5.7.0" + "@ethersproject/constants@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.5.0.tgz#d2a2cd7d94bd1d58377d1d66c4f53c9be4d0a45e" @@ -484,6 +500,13 @@ dependencies: "@ethersproject/bignumber" "^5.6.2" +"@ethersproject/constants@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.7.0.tgz#df80a9705a7e08984161f09014ea012d1c75295e" + integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/contracts@^5.6.2": version "5.6.2" resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.6.2.tgz#20b52e69ebc1b74274ff8e3d4e508de971c287bc" @@ -591,6 +614,11 @@ resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.6.0.tgz#d7db1bfcc22fd2e4ab574cba0bb6ad779a9a3e7a" integrity sha512-BiBWllUROH9w+P21RzoxJKzqoqpkyM1pRnEKG69bulE9TSQD8SAIvTQqIMZmmCO8pUNkgLP1wndX1gKghSpBmg== +"@ethersproject/logger@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892" + integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== + "@ethersproject/networks@^5.5.0": version "5.5.2" resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.5.2.tgz#784c8b1283cd2a931114ab428dae1bd00c07630b" @@ -800,6 +828,15 @@ "@ethersproject/constants" "^5.6.1" "@ethersproject/logger" "^5.6.0" +"@ethersproject/units@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.7.0.tgz#637b563d7e14f42deeee39245275d477aae1d8b1" + integrity sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/wallet@^5.6.2": version "5.6.2" resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.6.2.tgz#cd61429d1e934681e413f4bc847a5f2f87e3a03c" @@ -1192,10 +1229,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.4.96": - version "0.4.96" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.96.tgz#141be3285ab0b25053ace6963f70b4225b2407ca" - integrity sha512-ZilCjKSHx4j6gl4g0+ABCYSsK/5zo4jjNz+DaeimXDZIH+e5mtT1HHFaR+kI14hqYNxTkyTinxJ39q5/gSuzjw== +"@snapshot-labs/snapshot.js@^0.4.97": + version "0.4.97" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.97.tgz#1df919e4c3a7b97f3ea2c82478400981c6702a50" + integrity sha512-EdEyZ7r5SQo2FBjnDM9rzULQz6wMTo1sZFnFpYRSDSddNk+bn16SqosI5amr7o9UHqz1aZPltv3ivjqNszr9hg== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" @@ -1204,6 +1241,7 @@ "@ethersproject/contracts" "^5.6.2" "@ethersproject/hash" "^5.6.1" "@ethersproject/providers" "^5.6.8" + "@ethersproject/units" "^5.7.0" "@ethersproject/wallet" "^5.6.2" ajv "^8.11.0" ajv-formats "^2.1.1" From 4db358465d5447aca2fda30b63c4d3a303f8ad06 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 14 Jun 2023 11:15:36 +0530 Subject: [PATCH 417/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.98 (#1191) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f068d9756..ccee49621 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.97", + "@snapshot-labs/snapshot.js": "^0.4.98", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index c44332b45..9418782b3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1229,10 +1229,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.4.97": - version "0.4.97" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.97.tgz#1df919e4c3a7b97f3ea2c82478400981c6702a50" - integrity sha512-EdEyZ7r5SQo2FBjnDM9rzULQz6wMTo1sZFnFpYRSDSddNk+bn16SqosI5amr7o9UHqz1aZPltv3ivjqNszr9hg== +"@snapshot-labs/snapshot.js@^0.4.98": + version "0.4.98" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.98.tgz#6e2e85c09015a28cc6024b6ae98304d41833960d" + integrity sha512-4slGeX1TW+R3dsTZfn/GrfgfuRMVW7d9HUsX5bqBMH3RPV57PtMCrKagvZZiaHQcNh7jww5I+pW69Q05n6lOrg== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From db7acc2520e56d3d602463179191e162f322f46a Mon Sep 17 00:00:00 2001 From: ChaituVR Date: Thu, 15 Jun 2023 17:42:28 +0530 Subject: [PATCH 418/815] [with-delegation] Log cache key --- src/utils/delegation.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/delegation.ts b/src/utils/delegation.ts index ebcd88e0c..f38a02e42 100644 --- a/src/utils/delegation.ts +++ b/src/utils/delegation.ts @@ -75,6 +75,7 @@ export async function getDelegationsData(space, network, addresses, snapshot) { if (space === 'stgdao.eth' && snapshot !== 'latest') { // TODO: implement LRU so memory doesn't explode // we only cache stgdao for now + console.log(`[with-delegation] Caching ${cacheKey}`); DELEGATION_DATA_CACHE[cacheKey] = delegationsReverse; } } From f351bec9cf75ced4522f40b37ba6309d710745a5 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Fri, 16 Jun 2023 16:31:48 +0530 Subject: [PATCH 419/815] [passport-gated] Fix validation in case of error in response (#1195) --- src/validations/passport-gated/index.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/validations/passport-gated/index.ts b/src/validations/passport-gated/index.ts index bcf1d7f1c..9fa100b32 100644 --- a/src/validations/passport-gated/index.ts +++ b/src/validations/passport-gated/index.ts @@ -48,11 +48,10 @@ export default class extends Validation { const stampsData = await stampsResponse.json(); if (!stampsData?.items) { - // throw new Error( - // 'You do not have a valid Gitcoin Passport. Create one by visiting https://passport.gitcoin.co/ ' - // ); - return false; + console.log('[passport] Unknown error', stampsData); + throw new Error('Unknown error'); } + if (stampsData.items.length === 0) return false; const provider = snapshot.utils.getProvider(this.network); const proposalTs = (await provider.getBlock(this.snapshot)).timestamp; From cc261940b751ae8d4affb74785288c50bdb97cad Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 19 Jun 2023 17:38:29 +0530 Subject: [PATCH 420/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.99 (#1197) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index ccee49621..1b01f5d0b 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.98", + "@snapshot-labs/snapshot.js": "^0.4.99", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 9418782b3..aff61095a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1229,10 +1229,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.4.98": - version "0.4.98" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.98.tgz#6e2e85c09015a28cc6024b6ae98304d41833960d" - integrity sha512-4slGeX1TW+R3dsTZfn/GrfgfuRMVW7d9HUsX5bqBMH3RPV57PtMCrKagvZZiaHQcNh7jww5I+pW69Q05n6lOrg== +"@snapshot-labs/snapshot.js@^0.4.99": + version "0.4.99" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.99.tgz#b2faa4d699082978e1be0cc81f116489e5a3948f" + integrity sha512-qx1k/G3hmiE0rzCD8uTcaebfKW8oOMbnWcolD3upGbd8lai3+cgsXwrwsTRc88Z1AaUeOf5vqT/Zi2qVunrmmA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 8509e615d654ea1948d9eea4f7a729785e00db8a Mon Sep 17 00:00:00 2001 From: George Pickett Date: Mon, 19 Jun 2023 13:34:44 -0500 Subject: [PATCH 421/815] Add sepolia (#1192) Co-authored-by: Chaitanya --- src/strategies/otterspace-badges/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/strategies/otterspace-badges/index.ts b/src/strategies/otterspace-badges/index.ts index e124d03c0..20a75b326 100644 --- a/src/strategies/otterspace-badges/index.ts +++ b/src/strategies/otterspace-badges/index.ts @@ -10,7 +10,8 @@ const OTTERSPACE_SUBGRAPH_API_URLS_BY_CHAIN_ID = { '10': 'https://api.thegraph.com/subgraphs/name/otterspace-xyz/badges-optimism-alpha', '420': 'https://api.thegraph.com/subgraphs/name/otterspace-xyz/badges-optimism-goerli', - '137': 'https://api.thegraph.com/subgraphs/name/otterspace-xyz/badges-polygon' + '137': 'https://api.thegraph.com/subgraphs/name/otterspace-xyz/badges-polygon', + '11155111': 'https://api.studio.thegraph.com/query/44988/badges-sepolia/version/latest' }; function fetchBadgesForRaft( From 023a25db310452fd8d9e73e3d22efabe5e888b1f Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Wed, 21 Jun 2023 15:06:23 +0530 Subject: [PATCH 422/815] Fix timers in strategy tests (#1198) --- jest.config.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/jest.config.js b/jest.config.js index 54b6941a8..42c36375a 100644 --- a/jest.config.js +++ b/jest.config.js @@ -4,5 +4,8 @@ module.exports = { transform: { '^.+\\.tsx?$': 'ts-jest' }, - testRegex: '/test(/(integration|unit))?/.*\\.test\\.ts$' + testRegex: '/test(/(integration|unit))?/.*\\.test\\.ts$', + fakeTimers: { + enableGlobally: true + } }; From ca4e43bde2c0edbc0e5a2a6a8f4aa86da7c0efb7 Mon Sep 17 00:00:00 2001 From: ChaituVR Date: Wed, 21 Jun 2023 15:13:40 +0530 Subject: [PATCH 423/815] Fix fake timers in jest --- test/strategy.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/strategy.test.ts b/test/strategy.test.ts index 618f69598..081d1de12 100644 --- a/test/strategy.test.ts +++ b/test/strategy.test.ts @@ -5,6 +5,8 @@ import snapshot from '../src'; import snapshotjs from '@snapshot-labs/snapshot.js'; import addresses from './addresses.json'; +jest.useFakeTimers({ advanceTimers: true }); + const strategyArg = process.env['npm_config_strategy'] || ( From ea6acf011d453809211c4b448a3efb12306f0250 Mon Sep 17 00:00:00 2001 From: Artem Payvin Date: Wed, 21 Jun 2023 10:50:08 +0100 Subject: [PATCH 424/815] [skale-delegation-weighted] Improve skale delegation weighted strategy (#1193) * Improve skale delegation weighted strategy * Simplify code due to requested changes --------- Co-authored-by: Chaitanya --- .../skale-delegation-weighted/README.md | 10 +- .../skale-delegation-weighted/examples.json | 11 +- .../skale-delegation-weighted/index.ts | 217 ++++++++++++++---- 3 files changed, 187 insertions(+), 51 deletions(-) diff --git a/src/strategies/skale-delegation-weighted/README.md b/src/strategies/skale-delegation-weighted/README.md index c47b88c51..1010bcba7 100644 --- a/src/strategies/skale-delegation-weighted/README.md +++ b/src/strategies/skale-delegation-weighted/README.md @@ -6,11 +6,15 @@ Holder can delegate directly or with Escrow contract(provided by SKALE) Required params in `example.json`: - addressSKL - address of SKL token - addressAllocator - address of Allocator contract + - validatorPower - enable validator voting(will count as amount of delegated to this validator minus holders who delegated) - +optional param default is `true` + - onlyValidator - enable only validator voting - optional param default is `false` ```json { - "addressSKL": "0x6b175474e89094c44da98b954eedeac495271d0f", - "symbol": "SKL", - "decimals": 18 + "addressSKL": "0x00c83aeCC790e8a4453e5dD3B0B4b3680501a7A7", + "addressAllocator": "0xB575c158399227b6ef4Dcfb05AA3bCa30E12a7ba", + "validatorPower": false, + "onlyValidator": true } ``` diff --git a/src/strategies/skale-delegation-weighted/examples.json b/src/strategies/skale-delegation-weighted/examples.json index bb63dd6a4..47414ebd7 100644 --- a/src/strategies/skale-delegation-weighted/examples.json +++ b/src/strategies/skale-delegation-weighted/examples.json @@ -5,9 +5,7 @@ "name": "skale-delegation-weighted", "params": { "addressSKL": "0x00c83aeCC790e8a4453e5dD3B0B4b3680501a7A7", - "addressAllocator": "0xB575c158399227b6ef4Dcfb05AA3bCa30E12a7ba", - "symbol": "SKL", - "decimals": 18 + "addressAllocator": "0xB575c158399227b6ef4Dcfb05AA3bCa30E12a7ba" } }, "network": "1", @@ -21,11 +19,14 @@ "0x2B3C7D1eF5FDfC0557934019c531d3E70D6200AE", "0x80F41289795F122C82b83D8C3A760E01FDBF5C76", "0x0BC34C33880a45d7Aa3bfDafE37Fd157E1Dca9bb", + "0x34F3833b540947b24A7F6f482a9FF62cD11a47CF", "0x864521f4A31f1C893f8414697dFb6D3A2d949AC5", "0xFdD2245Fa2B7881AB78C171Cc84F088e520450E2", "0xd753854eA19B204E6Ee9b5544239Fcc7d40f932A", - "0xfFd22b84fB1d46ef74Ed6530b2635BE61340f347" + "0xfFd22b84fB1d46ef74Ed6530b2635BE61340f347", + "0x7e32a321A9a0c8B06058CA0230a3E4D11d2a9411", + "0x2E11D2bd07583bAE4B8337e5982384dF16BcB4e1" ], - "snapshot": 16048934 + "snapshot": 17487103 } ] diff --git a/src/strategies/skale-delegation-weighted/index.ts b/src/strategies/skale-delegation-weighted/index.ts index 9ed2f69b3..9453cbc9f 100644 --- a/src/strategies/skale-delegation-weighted/index.ts +++ b/src/strategies/skale-delegation-weighted/index.ts @@ -1,15 +1,88 @@ import { BigNumberish, BigNumber } from '@ethersproject/bignumber'; import { formatUnits } from '@ethersproject/units'; -import { Multicaller, multicall } from '../../utils'; +import { Multicaller, multicall, subgraphRequest } from '../../utils'; +import { getAddress } from '@ethersproject/address'; export const author = 'payvint'; -export const version = '1.0.0'; +export const version = '2.0.0'; const abi = [ 'function getAndUpdateDelegatedAmount(address wallet) external returns (uint)', 'function getEscrowAddress(address beneficiary) external view returns (address)' ]; +const GRAPH_API_URL = + 'https://api.thegraph.com/subgraphs/name/ministry-of-decentralization/skale-manager-subgraph'; + +function returnGraphParamsValidatorPower( + snapshot: number | string, + addresses: string[] +) { + const output = { + delegations: { + __args: { + where: { + and: [ + { + or: [{ state: 'DELEGATED' }] + }, + { + holder_: { + id_not_in: addresses.map((address: string) => + address.toLowerCase() + ) + } + }, + { + validator_: { + address_in: addresses.map((address: string) => + address.toLowerCase() + ) + } + } + ] + }, + first: 1000 + }, + holder: { + id: true + }, + validator: { + address: true + }, + amount: true + } + }; + if (snapshot !== 'latest') { + // @ts-ignore + output.delegations.__args.block = { number: snapshot }; + } + return output; +} + +function returnGraphParamsValidatorOnly( + snapshot: number | string, + addresses: string[] +) { + const output = { + validators: { + __args: { + where: { + address_in: addresses.map((address: string) => address.toLowerCase()) + }, + first: 1000 + }, + address: true, + currentDelegationAmount: true + } + }; + if (snapshot !== 'latest') { + // @ts-ignore + output.validators.__args.block = { number: snapshot }; + } + return output; +} + export async function strategy( space, network, @@ -21,52 +94,110 @@ export async function strategy( const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; const multi = new Multicaller(network, provider, abi, { blockTag }); - addresses.forEach((address) => { - multi.call(address, options.addressSKL, 'getAndUpdateDelegatedAmount', [ - address - ]); - }); - const resultAccounts: Record = await multi.execute(); - - console.log(resultAccounts); - - const escrowAddressCallsQuery = addresses.map((address: any) => [ - options.addressAllocator, - 'getEscrowAddress', - [address] - ]); - - const escrowAddressesFromAccount = await multicall( - network, - provider, - abi, - [...escrowAddressCallsQuery], - { - blockTag - } - ); + const combinedAddresses = [...addresses]; + const votePower = {}; - const addressToEscrow = new Map(); - addresses.forEach((address: any, index: number) => { - addressToEscrow[address] = escrowAddressesFromAccount[index][0]; - }); + if (!options.validatorOnly || options.validatorOnly === false) { + addresses.forEach((address) => { + multi.call(address, options.addressSKL, 'getAndUpdateDelegatedAmount', [ + address + ]); + }); + const resultAccounts: Record = await multi.execute(); - addresses.forEach((address: any) => { - multi.call(address, options.addressSKL, 'getAndUpdateDelegatedAmount', [ - addressToEscrow[address] + const escrowAddressCallsQuery = addresses.map((address: any) => [ + options.addressAllocator, + 'getEscrowAddress', + [address] ]); - }); - const resultEscrows: Record = await multi.execute(); + const escrowAddressesFromAccount = await multicall( + network, + provider, + abi, + [...escrowAddressCallsQuery], + { + blockTag + } + ); + + escrowAddressesFromAccount.forEach((obj: any) => { + if (obj[0] !== '0x0000000000000000000000000000000000000000') { + combinedAddresses.push(obj[0]); + } + }); - return Object.fromEntries( - Object.entries(resultAccounts).map(([address, balance]) => [ - address, - parseFloat( + const addressToEscrow = new Map(); + addresses.forEach((address: any, index: number) => { + addressToEscrow[address] = escrowAddressesFromAccount[index][0]; + }); + + addresses.forEach((address: any) => { + multi.call(address, options.addressSKL, 'getAndUpdateDelegatedAmount', [ + addressToEscrow[address] + ]); + }); + + const resultEscrows: Record = await multi.execute(); + + Object.keys(resultAccounts).forEach((address: string) => { + votePower[address] = parseFloat( formatUnits( - BigNumber.from(balance).add(BigNumber.from(resultEscrows[address])) + BigNumber.from(resultAccounts[address]).add( + BigNumber.from(resultEscrows[address]) + ) ) - ) - ]) - ); + ); + }); + } + + if (options.validatorPower !== false && !options.validatorOnly) { + const results = await subgraphRequest( + GRAPH_API_URL, + returnGraphParamsValidatorPower(blockTag, combinedAddresses) + ); + + const validatorsVotePower = new Map(); + + results.delegations.forEach((delegation: any) => { + if (!validatorsVotePower[getAddress(delegation.validator.address)]) { + validatorsVotePower[getAddress(delegation.validator.address)] = + BigNumber.from(0); + } + validatorsVotePower[getAddress(delegation.validator.address)] = + BigNumber.from( + validatorsVotePower[getAddress(delegation.validator.address)] + ).add(BigNumber.from(delegation.amount)); + }); + Object.keys(validatorsVotePower).forEach((address: string) => { + if (!votePower[address]) votePower[address] = 0; + votePower[address] += parseFloat( + formatUnits(BigNumber.from(validatorsVotePower[address])) + ); + }); + } else if (options.validatorOnly) { + const results = await subgraphRequest( + GRAPH_API_URL, + returnGraphParamsValidatorOnly(blockTag, combinedAddresses) + ); + + const validatorsVotePower = new Map(); + + results.validators.forEach((validator: any) => { + if (!validatorsVotePower[getAddress(validator.address)]) { + validatorsVotePower[getAddress(validator.address)] = BigNumber.from(0); + } + validatorsVotePower[getAddress(validator.address)] = BigNumber.from( + validatorsVotePower[getAddress(validator.address)] + ).add(BigNumber.from(validator.currentDelegationAmount)); + }); + Object.keys(validatorsVotePower).forEach((address: string) => { + if (!votePower[address]) votePower[address] = 0; + votePower[address] += parseFloat( + formatUnits(BigNumber.from(validatorsVotePower[address])) + ); + }); + } + + return votePower; } From 346edf4e1ce1d37547336b68b5d236ee20efa7fe Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 21 Jun 2023 17:59:53 +0530 Subject: [PATCH 425/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.100 (#1199) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 1b01f5d0b..bc1a1a6f9 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.99", + "@snapshot-labs/snapshot.js": "^0.4.100", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index aff61095a..0785cb1ca 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1229,10 +1229,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.4.99": - version "0.4.99" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.99.tgz#b2faa4d699082978e1be0cc81f116489e5a3948f" - integrity sha512-qx1k/G3hmiE0rzCD8uTcaebfKW8oOMbnWcolD3upGbd8lai3+cgsXwrwsTRc88Z1AaUeOf5vqT/Zi2qVunrmmA== +"@snapshot-labs/snapshot.js@^0.4.100": + version "0.4.100" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.100.tgz#cb735ac043035a0d1bda121e3bf84c4d8d958bf9" + integrity sha512-/ATqoRGLBNGSSohmezyxSr6in/5dAA2KP+q4Dau/R76UuR0xRp0PvJaERzQYeqNUBcgMuAyXw0GOyl9E2TWAJw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 6f074e5b3371383f20e7ff3a478a5f8910780dd1 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Thu, 22 Jun 2023 23:53:03 +0530 Subject: [PATCH 426/815] [uniswap] Change uniswap subgraph (#1202) --- src/strategies/uniswap/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategies/uniswap/index.ts b/src/strategies/uniswap/index.ts index 4ce5d925c..0278d2f71 100644 --- a/src/strategies/uniswap/index.ts +++ b/src/strategies/uniswap/index.ts @@ -2,7 +2,7 @@ import { getAddress } from '@ethersproject/address'; import { subgraphRequest } from '../../utils'; const UNISWAP_SUBGRAPH_URL = { - '1': 'https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2' + '1': 'https://api.thegraph.com/subgraphs/name/ianlapham/uniswap-v2-dev' }; export const author = 'vfatouros'; From 6e438f79d15f83fc8e4c2155cf34b3ad6a5549d1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 26 Jun 2023 10:31:58 +0530 Subject: [PATCH 427/815] Automated lint (#1203) Co-authored-by: ChaituVR --- src/strategies/otterspace-badges/index.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/strategies/otterspace-badges/index.ts b/src/strategies/otterspace-badges/index.ts index 20a75b326..224a2079b 100644 --- a/src/strategies/otterspace-badges/index.ts +++ b/src/strategies/otterspace-badges/index.ts @@ -10,8 +10,10 @@ const OTTERSPACE_SUBGRAPH_API_URLS_BY_CHAIN_ID = { '10': 'https://api.thegraph.com/subgraphs/name/otterspace-xyz/badges-optimism-alpha', '420': 'https://api.thegraph.com/subgraphs/name/otterspace-xyz/badges-optimism-goerli', - '137': 'https://api.thegraph.com/subgraphs/name/otterspace-xyz/badges-polygon', - '11155111': 'https://api.studio.thegraph.com/query/44988/badges-sepolia/version/latest' + '137': + 'https://api.thegraph.com/subgraphs/name/otterspace-xyz/badges-polygon', + '11155111': + 'https://api.studio.thegraph.com/query/44988/badges-sepolia/version/latest' }; function fetchBadgesForRaft( From e293e5ab73cb0f06473384dc756ebf13027c1ca3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 29 Jun 2023 02:43:53 +0530 Subject: [PATCH 428/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.101 (#1204) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index bc1a1a6f9..279d8e22c 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.100", + "@snapshot-labs/snapshot.js": "^0.4.101", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 0785cb1ca..93bd24eda 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1229,10 +1229,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.4.100": - version "0.4.100" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.100.tgz#cb735ac043035a0d1bda121e3bf84c4d8d958bf9" - integrity sha512-/ATqoRGLBNGSSohmezyxSr6in/5dAA2KP+q4Dau/R76UuR0xRp0PvJaERzQYeqNUBcgMuAyXw0GOyl9E2TWAJw== +"@snapshot-labs/snapshot.js@^0.4.101": + version "0.4.101" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.101.tgz#4d6914d6b2c7026577fea3eab2277c5c40cfbe45" + integrity sha512-Zy6qXyUznFpzfQNjhs/ej0ORX5KYM/JyH2GGqe9cXJMS1PxJwxFz3olhaoiMNCmDhAif/TXcWusim+k72wO2qA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 628a4e892c97e7088ff7c537b4ca9e5e158b507a Mon Sep 17 00:00:00 2001 From: Marcus Aurelius <91024694+0xAurelius@users.noreply.github.com> Date: Sun, 2 Jul 2023 12:47:19 -0400 Subject: [PATCH 429/815] Implement divide in MATH strategy (#1201) Co-authored-by: Chaitanya --- src/strategies/math/README.md | 1 + src/strategies/math/index.ts | 15 +++++++++++++++ src/strategies/math/options.ts | 9 ++++++--- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/strategies/math/README.md b/src/strategies/math/README.md index 8a4340a90..36f506c43 100644 --- a/src/strategies/math/README.md +++ b/src/strategies/math/README.md @@ -18,6 +18,7 @@ Currently supported operations are: | `a-if-gt-b` | 3 | (x, a, b) = x > b ? a : x | | `a-if-gte-b` | 3 | (x, a, b) = x >= b ? a : x | | `minus` | 2 | x - a | +| `divide` | 2 | x / a | ## Examples diff --git a/src/strategies/math/index.ts b/src/strategies/math/index.ts index 5a302628f..0b149841b 100644 --- a/src/strategies/math/index.ts +++ b/src/strategies/math/index.ts @@ -43,6 +43,10 @@ export async function strategy( return finalResult; } +function throwDivZero() { + throw Error("Cannot divide by zero!") +} + function resolveOperation( operation: Operation, resolvedOperands: Record[] @@ -151,6 +155,17 @@ function resolveOperation( ); return Object.fromEntries(arr); } + case Operation.Divide: { + const arr = Object.entries(resolvedOperands[0]).map( + ([address, score]: [string, number]) => [ + address, + resolvedOperands[1][address] != 0 + ? score / resolvedOperands[1][address] + : throwDivZero() + ] + ); + return Object.fromEntries(arr); + } } } diff --git a/src/strategies/math/options.ts b/src/strategies/math/options.ts index 82ba85ed3..712e1e9f2 100644 --- a/src/strategies/math/options.ts +++ b/src/strategies/math/options.ts @@ -30,7 +30,8 @@ export enum Operation { AIfGtB = 'a-if-gt-b', AIfGteB = 'a-if-gte-b', Multiply = 'multiply', - MINUS = 'minus' + MINUS = 'minus', + Divide = 'divide' } interface LegacyFields { @@ -64,7 +65,8 @@ const operandCountByOperation: Record = { [Operation.AIfLteB]: 3, [Operation.AIfGtB]: 3, [Operation.AIfGteB]: 3, - [Operation.MINUS]: 2 + [Operation.MINUS]: 2, + [Operation.Divide]: 2 }; export function validateOptions(rawOptions: OptionalOptions): Options { @@ -84,7 +86,8 @@ export function validateOptions(rawOptions: OptionalOptions): Options { rawOptions.operation !== Operation.AIfGtB && rawOptions.operation !== Operation.AIfGteB && rawOptions.operation !== Operation.Multiply && - rawOptions.operation !== Operation.MINUS + rawOptions.operation !== Operation.MINUS && + rawOptions.operation !== Operation.Divide ) { throw new Error('Invalid `operation`'); } From 974f35e54458f6a29cc66d41213b34617472b834 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 2 Jul 2023 23:37:35 +0530 Subject: [PATCH 430/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.102 (#1206) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 279d8e22c..4e775338e 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.101", + "@snapshot-labs/snapshot.js": "^0.4.102", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 93bd24eda..6df09a7e5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1229,10 +1229,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.4.101": - version "0.4.101" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.101.tgz#4d6914d6b2c7026577fea3eab2277c5c40cfbe45" - integrity sha512-Zy6qXyUznFpzfQNjhs/ej0ORX5KYM/JyH2GGqe9cXJMS1PxJwxFz3olhaoiMNCmDhAif/TXcWusim+k72wO2qA== +"@snapshot-labs/snapshot.js@^0.4.102": + version "0.4.102" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.102.tgz#b8d5b3f8171e6c4844109287515373475f14f1b7" + integrity sha512-R3OiYB3QO8Jyz060b2lHzqBzm3VuT7Z+FNBfacNJqrLgaWFYX/XIrSEa/9WR9wzTInGAcFSpyrKTrVwDnmTByA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 008ebac2c18c054b2a9fc52dc379c9a9c5552802 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 4 Jul 2023 00:42:39 +0530 Subject: [PATCH 431/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.103 (#1207) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 4e775338e..6c5e99520 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.102", + "@snapshot-labs/snapshot.js": "^0.4.103", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 6df09a7e5..52d255db3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1229,10 +1229,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.4.102": - version "0.4.102" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.102.tgz#b8d5b3f8171e6c4844109287515373475f14f1b7" - integrity sha512-R3OiYB3QO8Jyz060b2lHzqBzm3VuT7Z+FNBfacNJqrLgaWFYX/XIrSEa/9WR9wzTInGAcFSpyrKTrVwDnmTByA== +"@snapshot-labs/snapshot.js@^0.4.103": + version "0.4.103" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.103.tgz#73c0ffd97b2f2554cf91629d315ecd0e07f99e67" + integrity sha512-ZC6uIvtt0R9mkBN1hgjLLafW6K2Fyz1iHuq7+FU7uiwUX6xRXYqz1Z0M8BIWXKaX1ZLyB2FU8n3+gwjDkH42SQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 236bb91f63c06117ac1ceed71b8fc6994130d9e4 Mon Sep 17 00:00:00 2001 From: less Date: Thu, 6 Jul 2023 04:40:00 +0700 Subject: [PATCH 432/815] fix: change basic validation minimum to > 0 --- src/validations/basic/schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/validations/basic/schema.json b/src/validations/basic/schema.json index 9a2822c19..7214e26d9 100644 --- a/src/validations/basic/schema.json +++ b/src/validations/basic/schema.json @@ -9,7 +9,7 @@ "minScore": { "title": "Minimum score", "type": "number", - "minimum": 1 + "exclusiveMinimum": 0 }, "strategies": { "title": "Strategies", From 90456237041f33f67301cca4fbad281b6fa9e7e4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 9 Jul 2023 16:28:14 +0530 Subject: [PATCH 433/815] Automated lint (#1212) Co-authored-by: ChaituVR --- src/strategies/math/index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/strategies/math/index.ts b/src/strategies/math/index.ts index 0b149841b..6d6444832 100644 --- a/src/strategies/math/index.ts +++ b/src/strategies/math/index.ts @@ -44,7 +44,7 @@ export async function strategy( } function throwDivZero() { - throw Error("Cannot divide by zero!") + throw Error('Cannot divide by zero!'); } function resolveOperation( @@ -159,8 +159,8 @@ function resolveOperation( const arr = Object.entries(resolvedOperands[0]).map( ([address, score]: [string, number]) => [ address, - resolvedOperands[1][address] != 0 - ? score / resolvedOperands[1][address] + resolvedOperands[1][address] != 0 + ? score / resolvedOperands[1][address] : throwDivZero() ] ); From 7ba0d793e4e31ae92180e031c70b435ce0752cd2 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Tue, 11 Jul 2023 00:04:27 +0530 Subject: [PATCH 434/815] [balancer] Paginate subgraph request to balancer (#1213) * [balancer] Paginate subgraph request to balancer * Reduce pagination size to make sure we get first 1000 * revert tests --- src/strategies/balancer/examples.json | 9 +-- src/strategies/balancer/index.ts | 81 ++++++++++++++++----------- test/strategy-with-params.test.ts | 5 ++ 3 files changed, 57 insertions(+), 38 deletions(-) diff --git a/src/strategies/balancer/examples.json b/src/strategies/balancer/examples.json index 6d7c78f02..009d4ad20 100644 --- a/src/strategies/balancer/examples.json +++ b/src/strategies/balancer/examples.json @@ -26,13 +26,10 @@ "0x6D7f23A509E212Ba7773EC1b2505d1A134f54fbe", "0x07a1f6fc89223c5ebD4e4ddaE89Ac97629856A0f", "0x8d5F05270da470e015b67Ab5042BDbE2D2FEFB48", - "0x8d07D225a769b7Af3A923481E1FdF49180e6A265", - "0x8f60501dE5b9b01F9EAf1214dbE1924aA97F7fd0", + "0x09e3Ab1Ce8126bc411d7132cb4673409a60023cD", "0x9B8e8dD9151260c21CB6D7cc59067cd8DF306D58", - "0x17ea92D6FfbAA1c7F6B117c1E9D0c88ABdc8b84C", - "0x38C0039247A31F3939baE65e953612125cB88268", - "0xd109b2a304587569c84308c55465cd9ff0317bfb", - "0x1d2c4cd9bee9dfe088430b95d274e765151c32db" + "0x3F9E2c33B07a2153313e4a3D828fD4dC7fA53230", + "0x2E23c126921d5707e729ECF9D38B5e7819a0eB5F" ], "snapshot": 12424932 } diff --git a/src/strategies/balancer/index.ts b/src/strategies/balancer/index.ts index 348d0453a..e59adfb3d 100644 --- a/src/strategies/balancer/index.ts +++ b/src/strategies/balancer/index.ts @@ -20,6 +20,50 @@ function buildBalancerSubgraphUrl(chainId, version) { return `${BALANCER_SUBGRAPH_URL_ROOT}${networkString}${versionString}`; } +async function subgraphRequestWithPagination(subgraphURL, addresses, snapshot) { + const chunkSize = 1000; + const chunks: string[][] = []; + for (let i = 0; i < addresses.length; i += chunkSize) { + chunks.push(addresses.slice(i, i + chunkSize)); + } + + const results = { poolShares: [] }; + for (const chunk of chunks) { + const params = { + poolShares: { + __args: { + where: { + userAddress_in: chunk.map((address) => address.toLowerCase()), + balance_gt: 0 + }, + first: 1000, + orderBy: 'balance', + orderDirection: 'desc' + }, + userAddress: { + id: true + }, + balance: true, + poolId: { + totalShares: true, + tokens: { + id: true, + balance: true + } + } + } + }; + if (snapshot !== 'latest') { + // @ts-ignore + params.poolShares.__args.block = { number: snapshot }; + } + const result = await subgraphRequest(subgraphURL, params); + results.poolShares = results.poolShares.concat(result.poolShares); + } + console.log('results', results); + return results; +} + export async function strategy( space, network, @@ -28,44 +72,17 @@ export async function strategy( options, snapshot ) { - const params = { - poolShares: { - __args: { - where: { - userAddress_in: addresses.map((address) => address.toLowerCase()), - balance_gt: 0 - }, - first: 1000, - orderBy: 'balance', - orderDirection: 'desc' - }, - userAddress: { - id: true - }, - balance: true, - poolId: { - totalShares: true, - tokens: { - id: true, - balance: true - } - } - } - }; - if (snapshot !== 'latest') { - // @ts-ignore - params.poolShares.__args.block = { number: snapshot }; - } - // iterate through Balancer V1 & V2 Subgraphs const score = {}; for (let version = 1; version <= 2; version++) { // Skip attempt to query subgraph on networks where V1 isn't deployed if (network != 1 && network != 42 && version === 1) continue; - const result = await subgraphRequest( - buildBalancerSubgraphUrl(network, version), - params + const subgraphURL = buildBalancerSubgraphUrl(network, version); + const result: any = await subgraphRequestWithPagination( + subgraphURL, + addresses, + snapshot ); if (result && result.poolShares) { result.poolShares.forEach((poolShare) => diff --git a/test/strategy-with-params.test.ts b/test/strategy-with-params.test.ts index 2b01b6227..3ebdc1065 100644 --- a/test/strategy-with-params.test.ts +++ b/test/strategy-with-params.test.ts @@ -1349,4 +1349,9 @@ snapshot.utils scoreAPIObj.params.snapshot ) .then(console.log) + .then(() => { + setTimeout(() => { + process.exit(0); + }, 1000); + }) .catch(console.error); From 902eb709151ffc0456d6f2fe05cbddbdff00f50c Mon Sep 17 00:00:00 2001 From: ChaituVR Date: Tue, 11 Jul 2023 00:12:34 +0530 Subject: [PATCH 435/815] Remove log --- src/strategies/balancer/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategies/balancer/index.ts b/src/strategies/balancer/index.ts index e59adfb3d..15635acf8 100644 --- a/src/strategies/balancer/index.ts +++ b/src/strategies/balancer/index.ts @@ -60,7 +60,7 @@ async function subgraphRequestWithPagination(subgraphURL, addresses, snapshot) { const result = await subgraphRequest(subgraphURL, params); results.poolShares = results.poolShares.concat(result.poolShares); } - console.log('results', results); + return results; } From 45e01ca64b11c02f01237c01b3014ed3ec02b6cc Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Tue, 11 Jul 2023 00:43:43 +0530 Subject: [PATCH 436/815] [uniswap] Fix pagination to subgraph (#1214) * [uniswap] Fix pagination to subgraph * Fix tests * Revert test file --- src/strategies/uniswap/examples.json | 4 +- src/strategies/uniswap/index.ts | 96 +++++++++++++++++----------- 2 files changed, 61 insertions(+), 39 deletions(-) diff --git a/src/strategies/uniswap/examples.json b/src/strategies/uniswap/examples.json index a3b2cdbe5..f15bcf833 100644 --- a/src/strategies/uniswap/examples.json +++ b/src/strategies/uniswap/examples.json @@ -4,12 +4,12 @@ "strategy": { "name": "uniswap", "params": { - "address": "0x6b175474e89094c44da98b954eedeac495271d0f", + "address": "0xde30da39c46104798bb5aa3fe8b9e0e1f348163f", "symbol": "DAI" } }, "network": "1", - "addresses": ["0x79317fc0fb17bc0ce213a2b50f343e4d4c277704"], + "addresses": ["0x0DE92626498717585F06E5bF5B85A7A88872F5B3", "0x76F780c336dAc20a4A5e73677f98B6B3a78FBd86", "0xe0d0527fFC6D7D64A03c9509911323D4D15E5966"], "snapshot": 1111000 } ] diff --git a/src/strategies/uniswap/index.ts b/src/strategies/uniswap/index.ts index 0278d2f71..52acbe540 100644 --- a/src/strategies/uniswap/index.ts +++ b/src/strategies/uniswap/index.ts @@ -5,54 +5,76 @@ const UNISWAP_SUBGRAPH_URL = { '1': 'https://api.thegraph.com/subgraphs/name/ianlapham/uniswap-v2-dev' }; -export const author = 'vfatouros'; +export const author = 'snapshot-labs'; export const version = '0.1.0'; -export async function strategy( - _space, - network, - _provider, - addresses, - options, - snapshot -) { - const params = { - users: { - __args: { - where: { - id_in: addresses.map((address) => address.toLowerCase()) - }, - first: 1000 - }, - id: true, - liquidityPositions: { +async function subgraphRequestWithPagination(subgraphURL, addresses, snapshot) { + const chunkSize = 1000; + const chunks: string[][] = []; + for (let i = 0; i < addresses.length; i += chunkSize) { + chunks.push(addresses.slice(i, i + chunkSize)); + } + + const results = { users: [] }; + for (const chunk of chunks) { + const params = { + users: { __args: { where: { - liquidityTokenBalance_gt: 0 - } - }, - liquidityTokenBalance: true, - pair: { - id: true, - token0: { - id: true + id_in: chunk.map((address) => address.toLowerCase()) }, - reserve0: true, - token1: { - id: true + first: 1000 + }, + id: true, + liquidityPositions: { + __args: { + where: { + liquidityTokenBalance_gt: 0 + } }, - reserve1: true, - totalSupply: true + liquidityTokenBalance: true, + pair: { + id: true, + token0: { + id: true + }, + reserve0: true, + token1: { + id: true + }, + reserve1: true, + totalSupply: true + } } } + }; + + if (snapshot !== 'latest') { + // @ts-ignore + params.users.liquidityPositions.__args.block = { number: snapshot }; } - }; - if (snapshot !== 'latest') { - // @ts-ignore - params.users.liquidityPositions.__args.block = { number: snapshot }; + const result = await subgraphRequest(subgraphURL, params); + results.users = results.users.concat(result.users); } + + return results; +} + +export async function strategy( + _space, + network, + _provider, + addresses, + options, + snapshot +) { const tokenAddress = options.address.toLowerCase(); - const result = await subgraphRequest(UNISWAP_SUBGRAPH_URL[network], params); + const subgraphURL = UNISWAP_SUBGRAPH_URL[network]; + const result: any = await subgraphRequestWithPagination( + subgraphURL, + addresses, + snapshot + ); const score = {}; if (result && result.users) { result.users.forEach((u) => { From 941e3b238f4425d94f4d5f3a829207bc6e830d28 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 11 Jul 2023 10:23:53 +0530 Subject: [PATCH 437/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.104 (#1215) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 6c5e99520..d17acd9d9 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.103", + "@snapshot-labs/snapshot.js": "^0.4.104", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 52d255db3..8d08eac60 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1229,10 +1229,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.4.103": - version "0.4.103" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.103.tgz#73c0ffd97b2f2554cf91629d315ecd0e07f99e67" - integrity sha512-ZC6uIvtt0R9mkBN1hgjLLafW6K2Fyz1iHuq7+FU7uiwUX6xRXYqz1Z0M8BIWXKaX1ZLyB2FU8n3+gwjDkH42SQ== +"@snapshot-labs/snapshot.js@^0.4.104": + version "0.4.104" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.104.tgz#f14083a1406bb0cd60833bbf60388f6104427fad" + integrity sha512-GQ7eoR991GgBlJ2R5d/M5jqLXqEUAdrBaq4sjxpCDj/43Fk4Ot6echrsbq+2llerdyRqJsRxM+whktL2TXE9Bw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 034553f949c3cf95429205866f84cd5af9e15533 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Tue, 11 Jul 2023 19:20:59 +0530 Subject: [PATCH 438/815] Remove test API key from passport-gated strategy (#1216) --- src/validations/passport-gated/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/validations/passport-gated/index.ts b/src/validations/passport-gated/index.ts index 9fa100b32..bdf4538c1 100644 --- a/src/validations/passport-gated/index.ts +++ b/src/validations/passport-gated/index.ts @@ -2,8 +2,9 @@ import fetch from 'cross-fetch'; import Validation from '../validation'; import snapshot from '@snapshot-labs/snapshot.js'; +// Create one from https://scorer.gitcoin.co/#/dashboard/api-keys const API_KEY = - process.env.PASSPORT_API_KEY || '0cErnp4F.nRDEUU4Z8y5YyxcU32swrggDFNfWtXtI'; + process.env.PASSPORT_API_KEY || ''; const headers = API_KEY ? { From 96a048dcf98c7b6aa562b5ce01a342a76c8baa5b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 12 Jul 2023 01:06:00 +0530 Subject: [PATCH 439/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.105 (#1217) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index d17acd9d9..8d0c9c206 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.104", + "@snapshot-labs/snapshot.js": "^0.4.105", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 8d08eac60..3915744d1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1229,10 +1229,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.4.104": - version "0.4.104" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.104.tgz#f14083a1406bb0cd60833bbf60388f6104427fad" - integrity sha512-GQ7eoR991GgBlJ2R5d/M5jqLXqEUAdrBaq4sjxpCDj/43Fk4Ot6echrsbq+2llerdyRqJsRxM+whktL2TXE9Bw== +"@snapshot-labs/snapshot.js@^0.4.105": + version "0.4.105" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.105.tgz#7b3484828730f3751d97e1839601520b0b29284a" + integrity sha512-eA+3eiYc5Ml6nbzb53J9+tFmf//zgKjua4I+AViYvr30IXc4DYVoa1L5ET99rfBQ8g9AmhNZnPE9o8eeSo2Q1A== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 8628171d222392eede4cee8f8459e64b8088ef07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20RICHARD?= Date: Wed, 12 Jul 2023 23:22:04 +0200 Subject: [PATCH 440/815] [seedify-cumulative-voting-power-hodl-staking-farming] cumulative voting power for SFUND holders, stakers and farmers (#1196) * feat: check SFUND balance and new staking for 270d * feat: calculate SFUND for a user farming LP * refactor: addresses in json instead TS file * refactor: rename getStakedBalance to getBalanceOf * feat: calculate SFUND from legacy farming contract * refactor: re-order calls * feat: calculate SFUND from staking contract * feat: legacy staking calculation * feat: calculate SNFTS from LP staked in farming * fix: update variables after multicall result * fix: calculate SFUND in SNFTS_SFUND pool * docs: update README * refactor: provide staking addresses in array * refactor: generic function for multicall * docs: update README * docs: update comments * chore: add schema.json * refactor: rename strategy * fix: schema.json properties issues * refactor: create utils.ts * refactor: less than 5 calls (#2) * refactor: one multicall for all farming contract * refactor: single multical for all staking contracts * refactor: erc20 calls in single `multicall` * fix: `getStakingBalanceOf` * docs: update `examples.json` * feat: throw error when > 10 addresses in arrays * docs: update README * fix(test): make legacy farming address optional --- src/strategies/index.ts | 5 +- .../README.md | 55 ++++++ .../examples.json | 32 ++++ .../index.ts | 165 ++++++++++++++++++ .../schema.json | 101 +++++++++++ .../utils.ts | 70 ++++++++ 6 files changed, 427 insertions(+), 1 deletion(-) create mode 100644 src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/README.md create mode 100644 src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/examples.json create mode 100644 src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/index.ts create mode 100644 src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/schema.json create mode 100644 src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/utils.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 25e4271cf..b5de2e8a8 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -446,6 +446,7 @@ import * as erc721CollateralHeld from './erc721-collateral-held'; import * as starlayVeBalanceOfLockerId from './starlay-ve-balance-of-locker-id'; import * as winrStaking from './winr-staking'; import * as spaceid from './spaceid'; +import * as seedifyHoldStakingFarming from './seedify-cumulative-voting-power-hodl-staking-farming'; const strategies = { 'cap-voting-power': capVotingPower, @@ -898,7 +899,9 @@ const strategies = { 'erc721-collateral-held': erc721CollateralHeld, 'starlay-ve-balance-of-locker-id': starlayVeBalanceOfLockerId, 'winr-staking': winrStaking, - spaceid + spaceid, + 'seedify-cumulative-voting-power-hodl-staking-farming': + seedifyHoldStakingFarming }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/README.md b/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/README.md new file mode 100644 index 000000000..863062dcd --- /dev/null +++ b/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/README.md @@ -0,0 +1,55 @@ +# seedify-cumulative-voting-power-hodl-staking-farming + +Strategy which calculates SFUND Cumulative Voting Power (hodl, farming & staking): + +- SFUND (raw balance) +- Farming + - SFUND-BNB farming: + - LP_CONTRACT_SFUND_BNB = 0x74fA517715C4ec65EF01d55ad5335f90dce7CC87 + - SFUND_FARM_CONTRACT_LEGACY = 0x1F10564BAD9367CfF4247A138eBbA9a9aaeb789E + - SFUND_FARM_CONTRACT_NEW = 0x71d058369D39a8488D8e9F5FD5B050610ca788C0 + - SFUND-SNFTS farming (only calculates SFUND amount): + - LP_CONTRACT_SNFTS_SFUND = 0xe4399d0c968fBc3f5449525146ea98B0dC7Fc203 + - SNFTS_FARM_CONTRACT = 0x19ee35c5B2CcaBaAE367B6f99b2f5747E6a6C0d0 +- Staking: + - SFUND_STAKE_CONTRACT_7_DAYS_LEGACY = 0xb667c499b88AC66899E54e27Ad830d423d9Fba69 + - SFUND_STAKE_CONTRACT_14_DAYS_LEGACY = 0x027fC3A49383D0E7Bd6b81ef6C7512aFD7d22a9e + - SFUND_STAKE_CONTRACT_30_DAYS_LEGACY = 0x8900475BF7ed42eFcAcf9AE8CfC24Aa96098f776 + - SFUND_STAKE_CONTRACT_60_DAYS_LEGACY = 0x66b8c1f8DE0574e68366E8c4e47d0C8883A6Ad0b + - SFUND_STAKE_CONTRACT_90_DAYS_LEGACY = 0x5745b7E077a76bE7Ba37208ff71d843347441576 + - SFUND_STAKE_CONTRACT_180_DAYS_LEGACY = 0xf420F0951F0F50f50C741f6269a4816985670054 + - SFUND_STAKE_CONTRACT_30_DAYS_NEW = 0x60b9F788F4436f0B5c33785b3499b2ee1D8dbFd4 + - SFUND_STAKE_CONTRACT_90_DAYS_NEW = 0x5b384955ac3460c996402Bf03736624A33e55273 + - SFUND_STAKE_CONTRACT_180_DAYS_NEW = 0xd01650999BB5740F9bb41168401e9664B28FF47f + - SFUND_STAKE_CONTRACT_270_DAYS_NEW = 0x89aaaB217272C89dA91825D9Effbe65dEd384859 + +Here is an example of parameters that can be usde in `examples.json`: + +```json +{ + "sfundAddress": "0x477bC8d23c634C154061869478bce96BE6045D12", + "symbol": "SFUND", + "decimals": 18 + // Calculate SFUND from staked LP tokens use: + "lpAddress_SFUND_BNB": "0x74fA517715C4ec65EF01d55ad5335f90dce7CC87", + "farmingAddress_SFUND_BNB": "0x71d058369D39a8488D8e9F5FD5B050610ca788C0", + "legacyfarmingAddress_SFUND_BNB": "0x1f10564bad9367cff4247a138ebba9a9aaeb789e", + "lpAddress_SNFTS_SFUND": "0xe4399d0c968fBc3f5449525146ea98B0dC7Fc203", + "farmingAddress_SNFTS_SFUND": "0x19ee35c5B2CcaBaAE367B6f99b2f5747E6a6C0d0", + // Calculate SFUND staked in ALL staking contracts use: + "sfundStakingAddresses": [ + "0x60b9F788F4436f0B5c33785b3499b2ee1D8dbFd4", + ... + ], + "legacySfundStakingAddresses": [ + "0xb667c499b88AC66899E54e27Ad830d423d9Fba69", + ... + ] +} +``` + +All fields above are required except `legacyfarmingAddress_SFUND_BNB`. + +Run tests: `yarn test --strategy=seedify-cumulative-voting-power-hodl-staking-farming` + +Tests fails with current data in `examples.json` as wallet addresses do not hold any funds in `legacyfarmingAddress_SFUND_BNB` anymore. To prevent tests from failing them comment calculation for `legacyfarmingAddress_SFUND_BNB`. diff --git a/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/examples.json b/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/examples.json new file mode 100644 index 000000000..002b494d9 --- /dev/null +++ b/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/examples.json @@ -0,0 +1,32 @@ +[ + { + "name": "Seedify: SFUND Cumulative Voting Power (hodl, farming & staking)", + "strategy": { + "name": "seedify-cumulative-voting-power-hodl-staking-farming", + "params": { + "sfundAddress": "0x477bC8d23c634C154061869478bce96BE6045D12", + "symbol": "SFUND", + "decimals": 18, + "lpAddress_SFUND_BNB": "0x74fA517715C4ec65EF01d55ad5335f90dce7CC87", + "farmingAddress_SFUND_BNB": "0x71d058369D39a8488D8e9F5FD5B050610ca788C0", + "lpAddress_SNFTS_SFUND": "0xe4399d0c968fBc3f5449525146ea98B0dC7Fc203", + "farmingAddress_SNFTS_SFUND": "0x19ee35c5B2CcaBaAE367B6f99b2f5747E6a6C0d0", + "sfundStakingAddresses": [ + "0x60b9F788F4436f0B5c33785b3499b2ee1D8dbFd4" + ], + "legacySfundStakingAddresses": [ + "0xb667c499b88AC66899E54e27Ad830d423d9Fba69" + ] + } + }, + "network": "56", + "addresses": [ + "0x63c089DFD1aFf7a677C9a2caCFBd29d8B9E5FA3b", + "0x3108fC89729016b3199DD8b5adAc3085E7e002f0", + "0x9f2566125e1eA778BACA0fa3b8A826caA2806A62", + "0x8B3b9710A1452Abbe6e673cd276eC9515e3BE77A", + "0x1bcf2B5262e4147540Fd2F2fE796F03BFfD47337" + ], + "snapshot": 29042360 + } +] diff --git a/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/index.ts b/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/index.ts new file mode 100644 index 000000000..a6924d679 --- /dev/null +++ b/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/index.ts @@ -0,0 +1,165 @@ +import { BigNumber } from '@ethersproject/bignumber'; + +import { multicall } from '../../utils'; +import { strategy as erc20BalanceOfStrategy } from '../erc20-balance-of'; +import { + createCallToReadUsersData, + createCallsToReadUsersData, + toDecimals, + calculateBep20InLPForUser, + sfundStakingAbi, + getStakingBalanceOf +} from './utils'; +import { farmingAbi, bep20Abi } from './utils'; + +export const author = 'theo6890'; +export const version = '0.1.0'; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + if (options.sfundStakingAddresses.length > 10) { + throw new Error('More than 10 staking addresses'); + } + if (options.legacySfundStakingAddresses.length > 10) { + throw new Error('More than 10 LEGACY staking addresses'); + } + + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const isUsingLegacyFarming = + options.farmingAddress_SFUND_BNB_legacy != undefined; + + const zeroBalance = [ + BigNumber.from('0'), + BigNumber.from('0'), + BigNumber.from('0'), + BigNumber.from('0') + ]; + + // required to use: erc20BalanceOfStrategy + options.address = options.sfundAddress; + + //////// return SFUND, in user's wallet //////// + let score: any = await erc20BalanceOfStrategy( + space, + network, + provider, + addresses, + options, + snapshot + ); + + //////// return LP deposited into farming contract //////// + const farmingCalls = [ + // from SNFTS-SFUND pool + ...createCallToReadUsersData( + addresses, + options.farmingAddress_SNFTS_SFUND, + 'userDeposits' + ), + // from SFUND-BNB pool + ...createCallToReadUsersData( + addresses, + options.farmingAddress_SFUND_BNB, + 'userDeposits' + ) + ]; + if (isUsingLegacyFarming) { + farmingCalls.push( + ...createCallToReadUsersData( + addresses, + options.legacyfarmingAddress_SFUND_BNB, + 'userDeposits' + ) + ); + } + const farming = await multicall(network, provider, farmingAbi, farmingCalls, { + blockTag + }); + const snftsSfundFarming = farming.slice(0, addresses.length); + const sfundBnbCurrentFarming = farming.slice( + addresses.length, + 1 + addresses.length * 2 + ); + const sfundBnbLegacyFarming = isUsingLegacyFarming + ? farming.slice(1 + addresses.length * 2, farming.length) + : sfundBnbCurrentFarming; + + const staking = await multicall( + network, + provider, + sfundStakingAbi, + [ + ...createCallsToReadUsersData( + addresses, + options.sfundStakingAddresses, + 'userDeposits' + ), + ...createCallsToReadUsersData( + addresses, + options.legacySfundStakingAddresses, + 'userDeposits' + ) + ], + { blockTag } + ); + const sfundStaking = staking.slice( + 0, + addresses.length * options.sfundStakingAddresses.length + ); + const legacySfundStaking = staking.slice( + addresses.length * options.sfundStakingAddresses.length, + staking.length + ); + + const erc20Res = await multicall( + network, + provider, + bep20Abi, + [ + [options.lpAddress_SFUND_BNB, 'totalSupply'], + [options.sfundAddress, 'balanceOf', [options.lpAddress_SFUND_BNB]], + [options.lpAddress_SNFTS_SFUND, 'totalSupply'], + [options.sfundAddress, 'balanceOf', [options.lpAddress_SNFTS_SFUND]] + ], + { blockTag } + ); + + const sfundBnbTotalSupply = toDecimals(erc20Res[0]); + const sfundInSfundBnbPool = toDecimals(erc20Res[1]); + const snftsSfundTotalSupply = toDecimals(erc20Res[2]); + const sfundInSnftsSfundPool = toDecimals(erc20Res[3]); + + return Object.fromEntries( + Object.entries(score).map((sfundBalance: any, userIndex) => [ + sfundBalance[0], + sfundBalance[1] + + ////// SFUND from SFUND-BNB farming contracts (current & legacy) ////// + calculateBep20InLPForUser( + sfundBnbCurrentFarming[userIndex], + sfundBnbTotalSupply, + sfundInSfundBnbPool + ) + + calculateBep20InLPForUser( + isUsingLegacyFarming ? sfundBnbLegacyFarming[userIndex] : zeroBalance, + sfundBnbTotalSupply, + sfundInSfundBnbPool + ) + + ////// SFUND from SNFTS-SFUND farming contract ////// + calculateBep20InLPForUser( + snftsSfundFarming[userIndex], + snftsSfundTotalSupply, + sfundInSnftsSfundPool + ) + + //// SFUND from staking contracts (current & legacy) ////// + getStakingBalanceOf(sfundStaking, userIndex) + + getStakingBalanceOf(legacySfundStaking, userIndex) + ]) + ); +} diff --git a/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/schema.json b/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/schema.json new file mode 100644 index 000000000..de49f2026 --- /dev/null +++ b/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/schema.json @@ -0,0 +1,101 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "seedify-cumulative-voting-power-hodl-staking-farming", + "type": "object", + "properties": { + "sfundAddress": { + "type": "string", + "title": "SFUND address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. UNI"], + "maxLength": 16 + }, + "lpAddress_SFUND_BNB": { + "type": "string", + "title": "LP address of SFUND-BNB pool", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "farmingAddress_SFUND_BNB": { + "type": "string", + "title": "Farming address of SFUND-BNB LP token", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "legacyfarmingAddress_SFUND_BNB": { + "type": "string", + "title": "Farming address of SFUND-BNB LP token (legacy)", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "lpAddress_SNFTS_SFUND": { + "type": "string", + "title": "LP address of SNFTS-SFUND pool", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "farmingAddress_SNFTS_SFUND": { + "type": "string", + "title": "Farming address of SNFTS-SFUND LP token", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "sfundStakingAddresses": { + "type": "array", + "title": "SFUND staking addresses", + "items": { + "type": "string", + "title": "SFUND staking address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } + }, + "sfundStakingAddressesLegacy": { + "type": "array", + "title": "SFUND staking addresses (legacy)", + "items": { + "type": "string", + "title": "SFUND staking address (legacy)", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } + } + }, + "required": [ + "sfundAddress", + "decimals", + "lpAddress_SFUND_BNB", + "farmingAddress_SFUND_BNB", + "lpAddress_SNFTS_SFUND", + "farmingAddress_SNFTS_SFUND", + "sfundStakingAddresses", + "legacySfundStakingAddresses" + ], + "additionalProperties": true + } + } +} diff --git a/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/utils.ts b/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/utils.ts new file mode 100644 index 000000000..e6891ad30 --- /dev/null +++ b/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/utils.ts @@ -0,0 +1,70 @@ +import { formatUnits } from '@ethersproject/units'; + +export const sfundStakingAbi = [ + 'function userDeposits(address) external view returns (uint256, uint256, uint256, uint256, uint256, bool)' +]; +export const farmingAbi = [ + 'function userDeposits(address from) external view returns (uint256, uint256, uint256, uint256)' +]; +export const bep20Abi = [ + 'function totalSupply() view returns (uint256)', + 'function balanceOf(address) view returns (uint256)' +]; + +export const getStakingBalanceOf = (stakedBalances: any, userIndex: any) => { + let sum: number = 0; + let balance: any; + for ( + let stakingContractIndex = 0; + stakingContractIndex < stakedBalances.length; + stakingContractIndex++ + ) { + balance = toDecimals(stakedBalances[userIndex]['0']); + sum += balance; + } + return sum; +}; + +export const toDecimals = (bigNumber: any) => { + return parseFloat(formatUnits(bigNumber.toString(), 18)); +}; + +export const calculateBep20InLPForUser = ( + lpStaked: any, + totalLPSupply: any, + totalBep20InPool: any +) => { + lpStaked = toDecimals(lpStaked['0']); + + return (lpStaked / totalLPSupply) * totalBep20InPool; +}; + +export const createCallsToReadUsersData: any = ( + addresses: any[], + stakingAddresses: any[], + functionToCall: string +) => { + const promises: any = []; + for (let i = 0; i < stakingAddresses.length; i++) { + promises.push( + ...createCallToReadUsersData( + addresses, + stakingAddresses[i], + functionToCall + ) + ); + } + return promises; +}; + +export const createCallToReadUsersData: any = ( + addresses: any, + contractAddress: any, + functionToCall: any +) => { + return addresses.map((address: any) => [ + contractAddress, + functionToCall, + [address] + ]); +}; From e3ab2759b8187e063f3c15e53e1ec410d273282b Mon Sep 17 00:00:00 2001 From: Kanta | 5000e12 Date: Tue, 18 Jul 2023 18:50:03 +0900 Subject: [PATCH 441/815] add staked morekudasai (#1219) --- src/strategies/index.ts | 4 +- src/strategies/staked-morekudasai/README.md | 13 +++ .../staked-morekudasai/examples.json | 21 +++++ src/strategies/staked-morekudasai/index.ts | 89 +++++++++++++++++++ src/strategies/staked-morekudasai/schema.json | 33 +++++++ 5 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 src/strategies/staked-morekudasai/README.md create mode 100644 src/strategies/staked-morekudasai/examples.json create mode 100644 src/strategies/staked-morekudasai/index.ts create mode 100644 src/strategies/staked-morekudasai/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index b5de2e8a8..c6dfae57b 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -447,6 +447,7 @@ import * as starlayVeBalanceOfLockerId from './starlay-ve-balance-of-locker-id'; import * as winrStaking from './winr-staking'; import * as spaceid from './spaceid'; import * as seedifyHoldStakingFarming from './seedify-cumulative-voting-power-hodl-staking-farming'; +import * as stakedMoreKudasai from './staked-morekudasai'; const strategies = { 'cap-voting-power': capVotingPower, @@ -901,7 +902,8 @@ const strategies = { 'winr-staking': winrStaking, spaceid, 'seedify-cumulative-voting-power-hodl-staking-farming': - seedifyHoldStakingFarming + seedifyHoldStakingFarming, + 'staked-morekudasai': stakedMoreKudasai }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/staked-morekudasai/README.md b/src/strategies/staked-morekudasai/README.md new file mode 100644 index 000000000..94f821b85 --- /dev/null +++ b/src/strategies/staked-morekudasai/README.md @@ -0,0 +1,13 @@ +# staked-morekudasai + +This strategy is used for KudasaiJP governance. It allows users to vote with vote power based on staking duration. + +Here is an example of parameters: + +```json +{ + "address": "0x954521ba40a377f5433cb9a6d2b7ee7660be487a", + "symbol": "stMK", + "decimals": 18 +} +``` diff --git a/src/strategies/staked-morekudasai/examples.json b/src/strategies/staked-morekudasai/examples.json new file mode 100644 index 000000000..ca220aba3 --- /dev/null +++ b/src/strategies/staked-morekudasai/examples.json @@ -0,0 +1,21 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "staked-morekudasai", + "params": { + "address": "0x954521ba40a377f5433cb9a6d2b7ee7660be487a", + "symbol": "stMK", + "decimals": 18 + } + }, + "network": "1", + "addresses": [ + "0x04CD9cC35601bb748cBC98B549545F44068cDDeB", + "0x76aa21a8Baef91B5c031A03E951f530E7F9489d3", + "0xbA1DD0D124231E6e059ff2f08A50af100C51679b", + "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C" + ], + "snapshot": 17683972 + } +] diff --git a/src/strategies/staked-morekudasai/index.ts b/src/strategies/staked-morekudasai/index.ts new file mode 100644 index 000000000..f1b465f11 --- /dev/null +++ b/src/strategies/staked-morekudasai/index.ts @@ -0,0 +1,89 @@ +import { formatUnits } from '@ethersproject/units'; +import { multicall } from '../../utils'; + +export const author = 'otomarukanta'; +export const version = '0.0.1'; + +const abi = [ + 'function balanceOf(address account) external view returns (uint256)', + 'function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256)', + 'function getStakingDuration(uint256 tokenId) public view returns(uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + // get token balance by address + const balances = await multicall( + network, + provider, + abi, + addresses.map((address) => [options.address, 'balanceOf', [address]]), + { blockTag } + ); + const addressWithIndexes = addresses.flatMap((address, index) => + Array.from(Array(Number(balances[index].toString())).keys()).map((_, i) => [ + address, + i + ]) + ); + + // get token id by address and index + const tokenIds = await multicall( + network, + provider, + abi, + addressWithIndexes.map(([address, i]) => [ + options.address, + 'tokenOfOwnerByIndex', + [address, i] + ]), + { blockTag } + ); + + // get staking duraion by token id + const stakingDurations = await multicall( + network, + provider, + abi, + tokenIds.map(([tokenId]) => [ + options.address, + 'getStakingDuration', + [tokenId] + ]), + { blockTag } + ); + + // aggregate + const ret = addressWithIndexes + .map(([address, _], index) => { + return { + address: address, + vp: stakingDurations[index][0] + }; + }) + .reduce((result, current) => { + const element = result.find((p) => p.address === current.address); + if (element) { + element.vp += current.vp; + } else { + result.push(current); + } + return result; + }, []); + + return ret.reduce( + (obj, item) => + Object.assign(obj, { + [item.address]: parseFloat(formatUnits(item.vp, options.decimals)) + }), + {} + ); +} diff --git a/src/strategies/staked-morekudasai/schema.json b/src/strategies/staked-morekudasai/schema.json new file mode 100644 index 000000000..2113da8b8 --- /dev/null +++ b/src/strategies/staked-morekudasai/schema.json @@ -0,0 +1,33 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. UNI"], + "maxLength": 16 + }, + "address": { + "type": "string", + "title": "Contract address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 18"] + } + }, + "required": ["address", "decimals"], + "additionalProperties": false + } + } +} From 7d23684bb7fb1ea49742dd35043ec413a13fa53a Mon Sep 17 00:00:00 2001 From: Arthur <32548365+Arthh@users.noreply.github.com> Date: Tue, 18 Jul 2023 06:57:33 -0300 Subject: [PATCH 442/815] [karma-discord-roles] feature: add karma-discord-roles (#1210) * init * feat: readme * feat: improve to run tests * fix: version * fix: missing comma * fix: update version Co-authored-by: Chaitanya * fix: update author Co-authored-by: Chaitanya --------- Co-authored-by: Chaitanya --- src/strategies/index.ts | 2 + src/strategies/karma-discord-roles/README.md | 41 +++++++++++++++++ .../karma-discord-roles/examples.json | 21 +++++++++ src/strategies/karma-discord-roles/index.ts | 46 +++++++++++++++++++ .../karma-discord-roles/schema.json | 24 ++++++++++ 5 files changed, 134 insertions(+) create mode 100644 src/strategies/karma-discord-roles/README.md create mode 100644 src/strategies/karma-discord-roles/examples.json create mode 100644 src/strategies/karma-discord-roles/index.ts create mode 100644 src/strategies/karma-discord-roles/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index c6dfae57b..782527e45 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -446,6 +446,7 @@ import * as erc721CollateralHeld from './erc721-collateral-held'; import * as starlayVeBalanceOfLockerId from './starlay-ve-balance-of-locker-id'; import * as winrStaking from './winr-staking'; import * as spaceid from './spaceid'; +import * as karmaDiscordRoles from './karma-discord-roles'; import * as seedifyHoldStakingFarming from './seedify-cumulative-voting-power-hodl-staking-farming'; import * as stakedMoreKudasai from './staked-morekudasai'; @@ -901,6 +902,7 @@ const strategies = { 'starlay-ve-balance-of-locker-id': starlayVeBalanceOfLockerId, 'winr-staking': winrStaking, spaceid, + 'karma-discord-roles': karmaDiscordRoles, 'seedify-cumulative-voting-power-hodl-staking-farming': seedifyHoldStakingFarming, 'staked-morekudasai': stakedMoreKudasai diff --git a/src/strategies/karma-discord-roles/README.md b/src/strategies/karma-discord-roles/README.md new file mode 100644 index 000000000..e77a813a5 --- /dev/null +++ b/src/strategies/karma-discord-roles/README.md @@ -0,0 +1,41 @@ +# karma-discord-roles + +**Karma Discord role strategy can be used by DAOs to provide voting power to contributors with a specific role on Discord.** + +## Prerequisites + +Below are the prerequisites to enable this strategy for your Snapshot space. + +1. For this strategy to work, the DAO needs to be set up in Karma's platform. Send us an email at dao@karmahq.xyz for onboarding on to Karma. + +2. Have Karma Discord Bot installed in your Discord server. You can install the bot through the following link: (https://discord.com/api/oauth2/authorize?client_id=986699463164846100&permissions=1101927561248&scope=bot%20applications.commands). + +## Usage + +json +{ +"name": , +"roles": [] +} + +**Example 1** +json +{ +"name": "Karma", +"roles": ["Moderator"] +} + +This will assign voting power of 1 to anyone in Karma's discord server who has "Moderator" role assigned to them. + +**Example 2** +json +{ +"name": "Karma", +"roles": ["Moderator"], +"addresses": [ +"0xa768f5F340e89698465Fc7C12F31cB485fAf98B2" +] +} +This will assign voting power of 1 to anyone in Karma's discord server who has "Moderator" role assigned to them. It will also assign voting power to any address in "addresses" list. + +If you have trouble setting up the strategy, please email us at dao@karmahq.xyz. diff --git a/src/strategies/karma-discord-roles/examples.json b/src/strategies/karma-discord-roles/examples.json new file mode 100644 index 000000000..154ce0488 --- /dev/null +++ b/src/strategies/karma-discord-roles/examples.json @@ -0,0 +1,21 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "karma-discord-roles", + "params": { + "name": "apecoin", + "roles": ["Assembly"] + } + }, + "network": "1", + "addresses": [ + "0x10cCD4136471c7c266a9Fc4569622989Fb4caB99", + "0x95e1eeb014eeB6c8709f2Ce4F19B847138fd5685", + "0x7B124228eC8e9C9C9ddC3278bb0ee4a6dAa5dDee" + ], + + "snapshot": 11437846 + } +] + diff --git a/src/strategies/karma-discord-roles/index.ts b/src/strategies/karma-discord-roles/index.ts new file mode 100644 index 000000000..bf8adee0a --- /dev/null +++ b/src/strategies/karma-discord-roles/index.ts @@ -0,0 +1,46 @@ +import fetch from 'cross-fetch'; +import { getAddress } from '@ethersproject/address'; + +export const author = 'show-karma'; +export const version = '1.0.0'; + +const KARMA_API = 'https://api.karmahq.xyz/api/dao/discordUsers'; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise<{ + [k: string]: any; +}> { + const { name, roles } = options; + + if (!name || !roles) return {}; + + const response = await fetch(`${KARMA_API}/${name}/${roles.join(',')}`, { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + } + }); + + const parsedResponse = !response.ok ? [] : await response.json(); + const delegates = parsedResponse.data?.delegates || []; + + const votingPower = {}; + + const userAddresses = delegates.map((user) => user.publicAddress); + const paramAddresses = addresses.length ? addresses : []; + const allAddresses = [...userAddresses, ...paramAddresses]; + + allAddresses.forEach((address) => { + const checksumAddress = getAddress(address); + votingPower[checksumAddress] = 1; + }); + + return votingPower; +} diff --git a/src/strategies/karma-discord-roles/schema.json b/src/strategies/karma-discord-roles/schema.json new file mode 100644 index 000000000..6b500f426 --- /dev/null +++ b/src/strategies/karma-discord-roles/schema.json @@ -0,0 +1,24 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "name": { + "type": "string", + "title": "DAO Name", + "examples": ["e.g. apecoin, ens, gitcoin"], + }, + "roles": { + "type": "array", + "title": "Discord Roles", + "examples": ["e.g. Assembly, Trader, Moderator"] + } + }, + "required": ["name","roles"], + "additionalProperties": false + } + } +} From f4c803c036b6617ce98597c2a1c3863c58883cb9 Mon Sep 17 00:00:00 2001 From: Chris Stellesky <90011102+stzky@users.noreply.github.com> Date: Wed, 19 Jul 2023 14:32:48 +0200 Subject: [PATCH 443/815] include vaulted assets (#1223) --- src/strategies/genart/examples.json | 13 +++++---- src/strategies/genart/index.ts | 44 ++++++++++++++++++++++------- 2 files changed, 42 insertions(+), 15 deletions(-) diff --git a/src/strategies/genart/examples.json b/src/strategies/genart/examples.json index 6241ca128..0a69955b5 100644 --- a/src/strategies/genart/examples.json +++ b/src/strategies/genart/examples.json @@ -4,17 +4,20 @@ "strategy": { "name": "genart", "params": { - "tokenAddress": "0xccdcfced87f8d91028b4fbbb589fb4cdc24d08fa", + "tokenAddress": "0x12e56851ec22874520dc4c7fa0a8a8d7dba1bac8", "membershipAddress": "0xbadc470f2e159f01396a546fc63d8c0db2697f3b", + "vaultAddress": "0xB8a5465BFC06fc8C82385dCFf949673D7b068D1a", + "interfaceAddress": "0x6bB38a82E3479f474d2985805B49B04881d8203c", "symbol": "GENART", "decimals": 18 } }, - "network": "4", + "network": "1", "addresses": [ - "0x8939a7106957dD14bf3D3aCc9151b96E4bD81bC6", - "0x7C804f539De39Fd3E7d6F2834eebA24d52a30Ca4" + "0x1c2Ca609CB72b05A23d1539acba6C594c87E304e", + "0x8DCb640e52a9556DE2f1bE9656792698b859E616", + "0x166f2E250ac6c8EF7aAAaDf9853720376a6C4b86" ], - "snapshot": 9787953 + "snapshot": 17721721 } ] diff --git a/src/strategies/genart/index.ts b/src/strategies/genart/index.ts index d2a832fe6..fe772d804 100644 --- a/src/strategies/genart/index.ts +++ b/src/strategies/genart/index.ts @@ -3,10 +3,12 @@ import { formatUnits } from '@ethersproject/units'; import { Multicaller } from '../../utils'; export const author = 'stzky'; -export const version = '0.1.0'; +export const version = '0.2.0'; const abi = [ - 'function balanceOf(address account) external view returns (uint256)' + 'function balanceOf(address account) external view returns (uint256)', + 'function getMembershipsOf(address account) external view returns (uint256[] memory)', + 'function getStake(address user) external view returns (uint256,uint256[] memory,uint256,uint256)' ]; export async function strategy( @@ -25,23 +27,45 @@ export async function strategy( const multiToken = new Multicaller(network, provider, abi, { blockTag }); + const multiStake = new Multicaller(network, provider, abi, { + blockTag + }); + addresses.forEach((address) => - multiMembership.call(address, options.membershipAddress, 'balanceOf', [ - address - ]) + multiMembership.call( + address, + options.interfaceAddress, + 'getMembershipsOf', + [address] + ) ); - const members: Record = await multiMembership.execute(); addresses.forEach((address) => multiToken.call(address, options.tokenAddress, 'balanceOf', [address]) ); - const result: Record = await multiToken.execute(); + + addresses.forEach((address) => + multiStake.call(address, options.vaultAddress, 'getStake', [address]) + ); + + const members: Record< + string, + BigNumberish[] + > = await multiMembership.execute(); + + const tokens: Record = await multiToken.execute(); + + const stakes: Record< + string, + [BigNumberish, BigNumberish[], BigNumberish, BigNumberish] + > = await multiStake.execute(); return Object.fromEntries( - Object.entries(result).map(([address, balance]) => [ + Object.entries(tokens).map(([address, balance]) => [ address, - parseFloat(formatUnits(balance, options.decimals)) * - (Number(members[address].toString()) > 0 ? 1 : 0) + (Number(formatUnits(balance, options.decimals)) + + Number(formatUnits(stakes[address][0], options.decimals))) * + (members[address].length > 0 ? 1 : 0) ]) ); } From 24e524d4639e66b93e27cde03897582b0951505b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20RICHARD?= Date: Wed, 19 Jul 2023 14:41:00 +0200 Subject: [PATCH 444/815] fix: staking balance calculation (#1224) --- .../README.md | 9 +++++++++ .../examples.json | 14 +++++++------- .../index.ts | 14 ++++++++++++-- .../utils.ts | 14 ++++++++++---- 4 files changed, 38 insertions(+), 13 deletions(-) diff --git a/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/README.md b/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/README.md index 863062dcd..10419bc52 100644 --- a/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/README.md +++ b/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/README.md @@ -53,3 +53,12 @@ All fields above are required except `legacyfarmingAddress_SFUND_BNB`. Run tests: `yarn test --strategy=seedify-cumulative-voting-power-hodl-staking-farming` Tests fails with current data in `examples.json` as wallet addresses do not hold any funds in `legacyfarmingAddress_SFUND_BNB` anymore. To prevent tests from failing them comment calculation for `legacyfarmingAddress_SFUND_BNB`. + +``` +"addresses": [ + "0x756ea9Ae4866B962326d588CdF39d558e671dF61", // 30, 90 days sataking & SFUND-BNB farming + "0x000F06844e849E39E9661cAd08Bf39e1E762f99D", // 270 days & SFUND-BNB + SNFTS-SFUND farming + "0xf6320ae5459332C2dCDE9abB8F1708232D7Bed3E", // hodl + "0x043a0199506E671Ed03e883e64288E5cf003EF93" // 7 staking legacy +] +``` diff --git a/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/examples.json b/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/examples.json index 002b494d9..6c1f59d6e 100644 --- a/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/examples.json +++ b/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/examples.json @@ -12,7 +12,8 @@ "lpAddress_SNFTS_SFUND": "0xe4399d0c968fBc3f5449525146ea98B0dC7Fc203", "farmingAddress_SNFTS_SFUND": "0x19ee35c5B2CcaBaAE367B6f99b2f5747E6a6C0d0", "sfundStakingAddresses": [ - "0x60b9F788F4436f0B5c33785b3499b2ee1D8dbFd4" + "0x60b9F788F4436f0B5c33785b3499b2ee1D8dbFd4", + "0x89aaaB217272C89dA91825D9Effbe65dEd384859" ], "legacySfundStakingAddresses": [ "0xb667c499b88AC66899E54e27Ad830d423d9Fba69" @@ -21,12 +22,11 @@ }, "network": "56", "addresses": [ - "0x63c089DFD1aFf7a677C9a2caCFBd29d8B9E5FA3b", - "0x3108fC89729016b3199DD8b5adAc3085E7e002f0", - "0x9f2566125e1eA778BACA0fa3b8A826caA2806A62", - "0x8B3b9710A1452Abbe6e673cd276eC9515e3BE77A", - "0x1bcf2B5262e4147540Fd2F2fE796F03BFfD47337" + "0x756ea9Ae4866B962326d588CdF39d558e671dF61", + "0x000F06844e849E39E9661cAd08Bf39e1E762f99D", + "0xf6320ae5459332C2dCDE9abB8F1708232D7Bed3E", + "0x043a0199506E671Ed03e883e64288E5cf003EF93" ], - "snapshot": 29042360 + "snapshot": 30042368 } ] diff --git a/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/index.ts b/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/index.ts index a6924d679..979121865 100644 --- a/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/index.ts +++ b/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/index.ts @@ -158,8 +158,18 @@ export async function strategy( sfundInSnftsSfundPool ) + //// SFUND from staking contracts (current & legacy) ////// - getStakingBalanceOf(sfundStaking, userIndex) + - getStakingBalanceOf(legacySfundStaking, userIndex) + getStakingBalanceOf( + sfundStaking, + userIndex, + options.sfundStakingAddresses.length, + addresses.length + ) + + getStakingBalanceOf( + legacySfundStaking, + userIndex, + options.legacySfundStakingAddresses.length, + addresses.length + ) ]) ); } diff --git a/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/utils.ts b/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/utils.ts index e6891ad30..d93fb6079 100644 --- a/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/utils.ts +++ b/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/utils.ts @@ -11,15 +11,21 @@ export const bep20Abi = [ 'function balanceOf(address) view returns (uint256)' ]; -export const getStakingBalanceOf = (stakedBalances: any, userIndex: any) => { +export const getStakingBalanceOf = ( + stakedBalances: any, + userIndex: any, + stakingAddrAmount: any, + userAmount: any +) => { let sum: number = 0; - let balance: any; + let balance: any, userPosition: any; for ( let stakingContractIndex = 0; - stakingContractIndex < stakedBalances.length; + stakingContractIndex < stakingAddrAmount; stakingContractIndex++ ) { - balance = toDecimals(stakedBalances[userIndex]['0']); + userPosition = userAmount * stakingContractIndex; + balance = toDecimals(stakedBalances[userPosition + userIndex]['0']); sum += balance; } return sum; From 2bbd8c8922a01514e3d38b1bc332bd48fca1f9df Mon Sep 17 00:00:00 2001 From: Alan Sapede Date: Wed, 19 Jul 2023 19:43:10 +0200 Subject: [PATCH 445/815] Fixes support for snapshot block hash (#1225) --- src/strategies/moonbeam-free-balance/index.ts | 44 +++++++++++++------ 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/src/strategies/moonbeam-free-balance/index.ts b/src/strategies/moonbeam-free-balance/index.ts index 9225e01b5..02cd97c07 100644 --- a/src/strategies/moonbeam-free-balance/index.ts +++ b/src/strategies/moonbeam-free-balance/index.ts @@ -11,13 +11,40 @@ export function readLittleEndianBigInt(hex: string) { return BigInt(`0x${hex.match(/../g)?.reverse().join('')}`); } +function processPayload(payload: { + id: number; + error?: { code?: number; data?: any; message?: string }; + result: any; +}) { + if (payload.error) { + const error: any = new Error(payload.error.message); + error.code = payload.error.code; + error.data = payload.error.data; + throw error; + } + return payload; +} + export async function strategy( space: string, network: string, provider: JsonRpcProvider, addresses: string[], - options: { decimals } + options: { decimals }, + snapshot: string | number | undefined ) { + // Retrieve the blockhash for the snapshot + const { result: blockHash }: { result: string } = await fetchJson( + provider.connection, + JSON.stringify({ + method: 'chain_getBlockHash', + params: typeof snapshot === 'number' ? [snapshot] : [], + id: 0, + jsonrpc: '2.0' + }), + processPayload + ); + // Pre-encoded key prefix for "system.account" storage const accountPrefix = `0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9`; const { decimals } = options; @@ -53,7 +80,7 @@ export async function strategy( // Build batch request for all the storage keys of the batch. const reqs = keys.map((key, index) => ({ method: 'state_getStorage', - params: [key], + params: [key, blockHash], id: batchIndex * batchSize + index + 1, jsonrpc: '2.0' })); @@ -62,18 +89,7 @@ export async function strategy( const payloads: { id: number; result: string }[] = await fetchJson( provider.connection, JSON.stringify(reqs), - (payload: { - error?: { code?: number; data?: any; message?: string }; - result?: any; - }) => { - if (payload.error) { - const error: any = new Error(payload.error.message); - error.code = payload.error.code; - error.data = payload.error.data; - throw error; - } - return payload; - } + processPayload ); for (const payload of payloads) { From f6f009f782f2684ca1d47799f0916febe0598a14 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Thu, 20 Jul 2023 01:00:33 +0530 Subject: [PATCH 446/815] Remove unwanted logs (#1226) --- src/strategies/hopr-staking-by-season/index.ts | 1 - src/strategies/hopr-staking-s2/index.ts | 1 - src/strategies/the-graph/baseStrategy.ts | 1 - src/strategies/wagdie-subgraph/index.ts | 1 - 4 files changed, 4 deletions(-) diff --git a/src/strategies/hopr-staking-by-season/index.ts b/src/strategies/hopr-staking-by-season/index.ts index 11770eded..b0305398d 100644 --- a/src/strategies/hopr-staking-by-season/index.ts +++ b/src/strategies/hopr-staking-by-season/index.ts @@ -85,7 +85,6 @@ export async function strategy( const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; const isXdai = network === '100'; // either xDAI or ETH mainnet const block = await provider.getBlock(blockTag); - console.log(block.number); // get the block number for subgraph query const subgraphBlock = isXdai diff --git a/src/strategies/hopr-staking-s2/index.ts b/src/strategies/hopr-staking-s2/index.ts index c89576f53..58b5df33c 100644 --- a/src/strategies/hopr-staking-s2/index.ts +++ b/src/strategies/hopr-staking-s2/index.ts @@ -73,7 +73,6 @@ export async function strategy( const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; const isXdai = network === '100'; // either xDAI or ETH mainnet const block = await provider.getBlock(blockTag); - console.log(block.number); // get the block number for subgraph query const subgraphBlock = isXdai diff --git a/src/strategies/the-graph/baseStrategy.ts b/src/strategies/the-graph/baseStrategy.ts index 480cdfef0..e493b6f30 100644 --- a/src/strategies/the-graph/baseStrategy.ts +++ b/src/strategies/the-graph/baseStrategy.ts @@ -103,7 +103,6 @@ export async function baseStrategy( const pages = splitArray(addresses, pageSize); let pageNum = 1; for (const addressesPage of pages) { - console.info(`Processing page ${pageNum} of ${pages.length}`); const pageScores = await getScoresPage( _space, network, diff --git a/src/strategies/wagdie-subgraph/index.ts b/src/strategies/wagdie-subgraph/index.ts index 90de39f67..6f970f6af 100644 --- a/src/strategies/wagdie-subgraph/index.ts +++ b/src/strategies/wagdie-subgraph/index.ts @@ -63,7 +63,6 @@ export async function strategy( const characters = result && result.characters ? result.characters : []; const latest = characters[characters.length - 1]; - console.log(options.location); for (const character of characters) { const userAddress = getAddress(character.owner.id); From 8401860bcf3ce10fc635442e496426777d3ae48e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 21 Jul 2023 02:21:10 +0530 Subject: [PATCH 447/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.106 (#1228) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 8d0c9c206..1326fdd2e 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.105", + "@snapshot-labs/snapshot.js": "^0.4.106", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 3915744d1..ea0d1fb13 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1229,10 +1229,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.4.105": - version "0.4.105" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.105.tgz#7b3484828730f3751d97e1839601520b0b29284a" - integrity sha512-eA+3eiYc5Ml6nbzb53J9+tFmf//zgKjua4I+AViYvr30IXc4DYVoa1L5ET99rfBQ8g9AmhNZnPE9o8eeSo2Q1A== +"@snapshot-labs/snapshot.js@^0.4.106": + version "0.4.106" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.106.tgz#1861b0346a93f1caf35e89c0dcff95945407dc31" + integrity sha512-sWQzBmEYl9d5LE1p7ZZRx5+0M/DylcLuh1RLlpbNLYmGM01LFi+bThjB4lsnj/BvyAYFHKNIZam9OHPV2fA+uw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 48e1f784def87a64a3e3dceb860a00cb93cb788a Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Fri, 21 Jul 2023 02:47:56 +0530 Subject: [PATCH 448/815] Remove unused variable --- src/strategies/the-graph/baseStrategy.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/strategies/the-graph/baseStrategy.ts b/src/strategies/the-graph/baseStrategy.ts index e493b6f30..2c04b7bdb 100644 --- a/src/strategies/the-graph/baseStrategy.ts +++ b/src/strategies/the-graph/baseStrategy.ts @@ -101,7 +101,6 @@ export async function baseStrategy( // Paginate and get combined scores const pageSize = options.pageSize || DEFAULT_PAGE_SIZE; const pages = splitArray(addresses, pageSize); - let pageNum = 1; for (const addressesPage of pages) { const pageScores = await getScoresPage( _space, @@ -113,7 +112,6 @@ export async function baseStrategy( graphStrategy ); combinedScores = { ...combinedScores, ...pageScores }; - pageNum += 1; } } else { console.error('ERROR: Strategy does not exist'); From 9f6435fc307b9cafdb16d1085a8aec2abd176393 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 23 Jul 2023 23:57:29 +0530 Subject: [PATCH 449/815] Automated lint (#1220) Co-authored-by: ChaituVR --- src/strategies/genart/index.ts | 6 ++---- src/strategies/karma-discord-roles/examples.json | 3 +-- src/strategies/karma-discord-roles/schema.json | 4 ++-- .../index.ts | 2 +- .../utils.ts | 2 +- src/strategies/uniswap/examples.json | 6 +++++- src/validations/passport-gated/index.ts | 3 +-- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/strategies/genart/index.ts b/src/strategies/genart/index.ts index fe772d804..19b3c759c 100644 --- a/src/strategies/genart/index.ts +++ b/src/strategies/genart/index.ts @@ -48,10 +48,8 @@ export async function strategy( multiStake.call(address, options.vaultAddress, 'getStake', [address]) ); - const members: Record< - string, - BigNumberish[] - > = await multiMembership.execute(); + const members: Record = + await multiMembership.execute(); const tokens: Record = await multiToken.execute(); diff --git a/src/strategies/karma-discord-roles/examples.json b/src/strategies/karma-discord-roles/examples.json index 154ce0488..a08521164 100644 --- a/src/strategies/karma-discord-roles/examples.json +++ b/src/strategies/karma-discord-roles/examples.json @@ -14,8 +14,7 @@ "0x95e1eeb014eeB6c8709f2Ce4F19B847138fd5685", "0x7B124228eC8e9C9C9ddC3278bb0ee4a6dAa5dDee" ], - + "snapshot": 11437846 } ] - diff --git a/src/strategies/karma-discord-roles/schema.json b/src/strategies/karma-discord-roles/schema.json index 6b500f426..74e0b97fc 100644 --- a/src/strategies/karma-discord-roles/schema.json +++ b/src/strategies/karma-discord-roles/schema.json @@ -9,7 +9,7 @@ "name": { "type": "string", "title": "DAO Name", - "examples": ["e.g. apecoin, ens, gitcoin"], + "examples": ["e.g. apecoin, ens, gitcoin"] }, "roles": { "type": "array", @@ -17,7 +17,7 @@ "examples": ["e.g. Assembly, Trader, Moderator"] } }, - "required": ["name","roles"], + "required": ["name", "roles"], "additionalProperties": false } } diff --git a/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/index.ts b/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/index.ts index 979121865..644f8cc2b 100644 --- a/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/index.ts +++ b/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/index.ts @@ -46,7 +46,7 @@ export async function strategy( options.address = options.sfundAddress; //////// return SFUND, in user's wallet //////// - let score: any = await erc20BalanceOfStrategy( + const score: any = await erc20BalanceOfStrategy( space, network, provider, diff --git a/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/utils.ts b/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/utils.ts index d93fb6079..f038266bc 100644 --- a/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/utils.ts +++ b/src/strategies/seedify-cumulative-voting-power-hodl-staking-farming/utils.ts @@ -17,7 +17,7 @@ export const getStakingBalanceOf = ( stakingAddrAmount: any, userAmount: any ) => { - let sum: number = 0; + let sum = 0; let balance: any, userPosition: any; for ( let stakingContractIndex = 0; diff --git a/src/strategies/uniswap/examples.json b/src/strategies/uniswap/examples.json index f15bcf833..891558f95 100644 --- a/src/strategies/uniswap/examples.json +++ b/src/strategies/uniswap/examples.json @@ -9,7 +9,11 @@ } }, "network": "1", - "addresses": ["0x0DE92626498717585F06E5bF5B85A7A88872F5B3", "0x76F780c336dAc20a4A5e73677f98B6B3a78FBd86", "0xe0d0527fFC6D7D64A03c9509911323D4D15E5966"], + "addresses": [ + "0x0DE92626498717585F06E5bF5B85A7A88872F5B3", + "0x76F780c336dAc20a4A5e73677f98B6B3a78FBd86", + "0xe0d0527fFC6D7D64A03c9509911323D4D15E5966" + ], "snapshot": 1111000 } ] diff --git a/src/validations/passport-gated/index.ts b/src/validations/passport-gated/index.ts index bdf4538c1..1344aaf51 100644 --- a/src/validations/passport-gated/index.ts +++ b/src/validations/passport-gated/index.ts @@ -3,8 +3,7 @@ import Validation from '../validation'; import snapshot from '@snapshot-labs/snapshot.js'; // Create one from https://scorer.gitcoin.co/#/dashboard/api-keys -const API_KEY = - process.env.PASSPORT_API_KEY || ''; +const API_KEY = process.env.PASSPORT_API_KEY || ''; const headers = API_KEY ? { From 4faf23c1d37aa71106b4befe237dce7d12416511 Mon Sep 17 00:00:00 2001 From: Nick Doherty Date: Wed, 26 Jul 2023 15:31:37 +1000 Subject: [PATCH 450/815] added rocketpool node operator v2 strategy (#1229) --- src/strategies/index.ts | 2 + .../rocketpool-node-operator-v2/README.md | 13 +++++ .../rocketpool-node-operator-v2/examples.json | 33 +++++++++++++ .../rocketpool-node-operator-v2/index.ts | 48 +++++++++++++++++++ 4 files changed, 96 insertions(+) create mode 100644 src/strategies/rocketpool-node-operator-v2/README.md create mode 100644 src/strategies/rocketpool-node-operator-v2/examples.json create mode 100644 src/strategies/rocketpool-node-operator-v2/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 782527e45..50db9d887 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -359,6 +359,7 @@ import * as auraFinanceWithOverrides from './aura-vlaura-vebal-with-overrides'; import * as auraBalanceOfVlauraVebal from './aura-balance-of-vlaura-vebal'; import * as auraBalanceOfSingleAsset from './aura-vault-balance-of-single-asset'; import * as rocketpoolNodeOperator from './rocketpool-node-operator'; +import * as rocketpoolNodeOperatorv2 from './rocketpool-node-operator-v2'; import * as earthfundChildDaoStakingBalance from './earthfund-child-dao-staking-balance'; import * as unipilotVaultPilotBalance from './unipilot-vault-pilot-balance'; import * as sdBoostTWAVP from './sd-boost-twavp'; @@ -815,6 +816,7 @@ const strategies = { 'aura-balance-of-vlaura-vebal': auraBalanceOfVlauraVebal, 'aura-vault-balance-of-single-asset': auraBalanceOfSingleAsset, 'rocketpool-node-operator': rocketpoolNodeOperator, + 'rocketpool-node-operator-v2': rocketpoolNodeOperatorv2, 'earthfund-child-dao-staking-balance': earthfundChildDaoStakingBalance, 'sd-boost-twavp': sdBoostTWAVP, 'unipilot-vault-pilot-balance': unipilotVaultPilotBalance, diff --git a/src/strategies/rocketpool-node-operator-v2/README.md b/src/strategies/rocketpool-node-operator-v2/README.md new file mode 100644 index 000000000..1f07deceb --- /dev/null +++ b/src/strategies/rocketpool-node-operator-v2/README.md @@ -0,0 +1,13 @@ +# rocketpool-node-operator-v2 + +This is a strategy for staking node operators, it returns the half square rooted node effective stake balance given a node address. + +Here is an example of parameters: + +```json +{ + "address": "0xD33526068D116cE69F19A9ee46F0bd304F21A51f", + "symbol": "RPL", + "decimals": 18 +} +``` diff --git a/src/strategies/rocketpool-node-operator-v2/examples.json b/src/strategies/rocketpool-node-operator-v2/examples.json new file mode 100644 index 000000000..dbdf2aaad --- /dev/null +++ b/src/strategies/rocketpool-node-operator-v2/examples.json @@ -0,0 +1,33 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "rocketpool-node-operator-v2", + "params": { + "address": "0xD33526068D116cE69F19A9ee46F0bd304F21A51f", + "symbol": "RPL", + "decimals": 18 + } + }, + "network": "1", + "addresses": [ + "0x17Fa597cEc16Ab63A7ca00Fb351eb4B29Ffa6f46", + "0xca317A4ecCbe0Dd5832dE2A7407e3c03F88b2CdD", + "0x327260c50634136551bfE4e4eB082281555AAfAE", + "0x5d8172792a9e649053c07366E3a7C24a37F0C534", + "0x701F4dcEAD1049FA01F321d49F6dca525cF4A5A5", + "0xb8ed9ea221bf33d37360A76DDD52bA7b1E66AA5C", + "0xbfaf9BFa09F26EF8104A6d5FF09afdCC9300E5bc", + "0x174E0b45C03318B0C9bc03573028605B26764931", + "0x5f4cB66c9B1Ed8A4758A059FDB10E0F72C307D8A", + "0x24609303B67051eF77735E34D671e2A13E3Da35d", + "0xE35854CdE18A3cC4706134b4850Dd861a55B9A30", + "0x53938f795AB6c57070AAd32905a70A2E5961A887", + "0xD6527Bd3d62f1Da520E6f74B89EBD8F8cD04564f", + "0xf8bFf17a1C9dfC632F6C905d12C404AfE451B16c", + "0x689C6853f3deBac91b72f32BafA83200eeC9613C", + "0xaEbb400542598E6ee58b2FDF2E7425c07E8Ba68D" + ], + "snapshot": 17761214 + } +] diff --git a/src/strategies/rocketpool-node-operator-v2/index.ts b/src/strategies/rocketpool-node-operator-v2/index.ts new file mode 100644 index 000000000..576be693c --- /dev/null +++ b/src/strategies/rocketpool-node-operator-v2/index.ts @@ -0,0 +1,48 @@ +import { BigNumberish } from "@ethersproject/bignumber"; +import { formatUnits } from "@ethersproject/units"; +import { Multicaller } from "../../utils"; + +export const author = "rocket-pool"; +export const version = "0.1.2"; + +const rocketNodeStakingAddress = "0x0d8D8f8541B12A0e1194B7CC4b6D954b90AB82ec"; +const rocketNodeStakingContractAbi = [ + "function getNodeEffectiveRPLStake(address _nodeAddress) external view returns (uint256)", +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === "number" ? snapshot : "latest"; + + const effectiveStake = new Multicaller( + network, + provider, + rocketNodeStakingContractAbi, + { blockTag } + ); + + addresses.forEach((address) => { + effectiveStake.call( + address, + rocketNodeStakingAddress, + "getNodeEffectiveRPLStake", + [address] + ); + }); + + const effectiveStakeResponse: Record = + await effectiveStake.execute(); + + return Object.fromEntries( + Object.entries(effectiveStakeResponse).map(([address, balance]) => [ + address, + Math.sqrt(parseFloat(formatUnits(balance, options.decimals))) / 2, + ]) + ); +} From a5908e9ab1a9702309bdea71c8338c6ac1b0e4c3 Mon Sep 17 00:00:00 2001 From: ChaituVR Date: Wed, 26 Jul 2023 11:22:29 +0530 Subject: [PATCH 451/815] remove unwanted logs --- src/strategies/curio-cards-erc20-weighted/index.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/strategies/curio-cards-erc20-weighted/index.ts b/src/strategies/curio-cards-erc20-weighted/index.ts index de47b5fc8..66b4f82a7 100644 --- a/src/strategies/curio-cards-erc20-weighted/index.ts +++ b/src/strategies/curio-cards-erc20-weighted/index.ts @@ -153,12 +153,12 @@ export async function strategy( cardBalances.forEach((cb) => { const cbWeighted = applyWeightForCard(cb.context, cb.rv); - console.debug( - 'Weighting for card ' + - cb.context + - ':\n' + - JSON.stringify(cbWeighted, null, 2) - ); + // console.debug( + // 'Weighting for card ' + + // cb.context + + // ':\n' + + // JSON.stringify(cbWeighted, null, 2) + // ); cardBalancesWeighted.push(cbWeighted); }); From b4fde5c89344c077b93bd6448c520d1945351609 Mon Sep 17 00:00:00 2001 From: johnmark13 Date: Wed, 26 Jul 2023 15:23:16 +0100 Subject: [PATCH 452/815] [nation3-passport-coop-with-delegations] Add Cooperative voting strategy for Nation3 Passport holders (#1230) * Make sure we have all the ERc20 balances that we need. * I think this is more simple.... * Still not beautiful, but in testing I believe that this is simplified and covers our use cases * Update index.ts Bump version as requested! * How cooperative model might work * Strip out the ERC20 * Update src/strategies/nation3-passport-coop-with-delegations/index.ts Co-authored-by: Chaitanya * Update src/strategies/nation3-passport-coop-with-delegations/index.ts Co-authored-by: Chaitanya * Update src/strategies/nation3-passport-coop-with-delegations/index.ts Co-authored-by: Chaitanya * Update index.ts As requested * Fix from breaking PR suggestions --------- Co-authored-by: JohnMark13 Co-authored-by: Chaitanya --- src/strategies/index.ts | 2 + .../README.md | 9 ++++ .../examples.json | 21 ++++++++ .../index.ts | 51 +++++++++++++++++++ .../schema.json | 22 ++++++++ .../examples.json | 2 +- 6 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 src/strategies/nation3-passport-coop-with-delegations/README.md create mode 100644 src/strategies/nation3-passport-coop-with-delegations/examples.json create mode 100644 src/strategies/nation3-passport-coop-with-delegations/index.ts create mode 100644 src/strategies/nation3-passport-coop-with-delegations/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 50db9d887..4cbe2ea32 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -401,6 +401,7 @@ import * as syntheticNounsClaimerOwner from './synthetic-nouns-with-claimer'; import * as depositInSablierStream from './deposit-in-sablier-stream'; import * as echelonWalletPrimeAndCachedKey from './echelon-wallet-prime-and-cached-key'; import * as nation3VotesWIthDelegations from './nation3-votes-with-delegations'; +import * as nation3CoopPassportWithDelegations from './nation3-passport-coop-with-delegations' import * as aavegotchiAgip37WapGhst from './aavegotchi-agip-37-wap-ghst'; import * as aavegotchiAgip37GltrStakedLp from './aavegotchi-agip-37-gltr-staked-lp'; import * as posichainStaking from './posichain-staking'; @@ -861,6 +862,7 @@ const strategies = { 'deposit-in-sablier-stream': depositInSablierStream, 'echelon-wallet-prime-and-cached-key': echelonWalletPrimeAndCachedKey, 'nation3-votes-with-delegations': nation3VotesWIthDelegations, + 'nation3-passport-coop-with-delegations':nation3CoopPassportWithDelegations, 'aavegotchi-agip-37-wap-ghst': aavegotchiAgip37WapGhst, 'aavegotchi-agip-37-gltr-staked-lp': aavegotchiAgip37GltrStakedLp, 'erc20-tokens-per-uni': erc20TokensPerUni, diff --git a/src/strategies/nation3-passport-coop-with-delegations/README.md b/src/strategies/nation3-passport-coop-with-delegations/README.md new file mode 100644 index 000000000..f6b726178 --- /dev/null +++ b/src/strategies/nation3-passport-coop-with-delegations/README.md @@ -0,0 +1,9 @@ +# Nation3 voting power strategy + +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: + +**erc721** + +The address of nation3 passport tokens contract \ No newline at end of file diff --git a/src/strategies/nation3-passport-coop-with-delegations/examples.json b/src/strategies/nation3-passport-coop-with-delegations/examples.json new file mode 100644 index 000000000..91f7dd490 --- /dev/null +++ b/src/strategies/nation3-passport-coop-with-delegations/examples.json @@ -0,0 +1,21 @@ +[ + { + "name": "One Person One Vote (only for ERC721 Holders or Delegates) ", + "strategy": { + "name": "nation3-passport-coop-with-delegations", + "params": { + "erc721": "0x3337dac9f251d4e403d6030e18e3cfb6a2cb1333" + } + }, + "network": "1", + "addresses": [ + "0xEdd000B7Db3cb8931d4E0cb1D0DBe6B947Ceb09A", + "0x47d80912400ef8f8224531EBEB1ce8f2ACf4b75a", + "0x636d65212C815b93B8E5b069f7082169cec851b7", + "0x460AF11e497dc273fC163414943C6fd95d17B1fd", + "0xfafda3727fe0406e50230bf6092be5ded68cd9e9", + "0x79438224Bc21b0E6B45ECF9F8caADfBdB874DedD" + ], + "snapshot": 17683972 + } +] diff --git a/src/strategies/nation3-passport-coop-with-delegations/index.ts b/src/strategies/nation3-passport-coop-with-delegations/index.ts new file mode 100644 index 000000000..cf49b910a --- /dev/null +++ b/src/strategies/nation3-passport-coop-with-delegations/index.ts @@ -0,0 +1,51 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import { Multicaller } from '../../utils'; + +export const author = 'nation3'; +export const version = '0.2.0'; + +const signerAbi = [ + 'function signerOf(uint256 id) external view returns (address)' +]; + +const lastTokenIdAbi = ['function getNextId() external view returns (uint256)']; + +export async function strategy( + space, + network, + provider, + addresses: string[], + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const erc721SignerCaller = new Multicaller(network, provider, signerAbi, { + blockTag + }); + const erc721LastTokenIdCaller = new Multicaller( + network, + provider, + lastTokenIdAbi, + { blockTag } + ); + + erc721LastTokenIdCaller.call('lastTokenId', options.erc721, 'getNextId'); + + const lastIndex = await erc721LastTokenIdCaller.execute(); + const lastTokenId = BigNumber.from(lastIndex.lastTokenId).toNumber(); + + for (let i = 0; i < lastTokenId; i++) { + erc721SignerCaller.call(i, options.erc721, 'signerOf', [i]); + } + + const erc721Signers : Record = await erc721SignerCaller.execute(); + + const erc721SignersArr = Object.entries(erc721Signers); + + const eligibleAddresses = erc721SignersArr + .map(([, address]) => address) + .filter((address) => addresses.includes(address)); + + return Object.fromEntries(eligibleAddresses.map(value => [value, 1])); +} diff --git a/src/strategies/nation3-passport-coop-with-delegations/schema.json b/src/strategies/nation3-passport-coop-with-delegations/schema.json new file mode 100644 index 000000000..6fc8cdccd --- /dev/null +++ b/src/strategies/nation3-passport-coop-with-delegations/schema.json @@ -0,0 +1,22 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "erc721": { + "type": "string", + "title": "nation3 passport", + "examples": ["e.g. 0x3337dac9f251d4e403d6030e18e3cfb6a2cb1333"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } + }, + "required": ["erc721"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/nation3-votes-with-delegations/examples.json b/src/strategies/nation3-votes-with-delegations/examples.json index 602c1130c..5a927f0a6 100644 --- a/src/strategies/nation3-votes-with-delegations/examples.json +++ b/src/strategies/nation3-votes-with-delegations/examples.json @@ -14,7 +14,7 @@ "0x47d80912400ef8f8224531EBEB1ce8f2ACf4b75a", "0x636d65212C815b93B8E5b069f7082169cec851b7", "0x460AF11e497dc273fC163414943C6fd95d17B1fd", - "0x1512BB3b85696Fa4D85Cb4bbf78e9C4FE95DB90F", + "0xfafda3727fe0406e50230bf6092be5ded68cd9e9", "0x79438224Bc21b0E6B45ECF9F8caADfBdB874DedD" ], "snapshot": 16399660 From cdfcdc73afbf7c41b00af2efdc16318e00ed6b12 Mon Sep 17 00:00:00 2001 From: Jacob Homanics <32080359+Hotmanics@users.noreply.github.com> Date: Thu, 27 Jul 2023 00:59:01 -0500 Subject: [PATCH 453/815] [hats-protocol-single-vote-per-org] Implements hats protocol strategy (#1221) * added in hats protocol strategy * updted readme * Revert "updted readme" This reverts commit 8746d5d68b67105013af51fb9a685b51194c5a1c. * added in simulated project, updated README, added documentation * functional implementation before eligibility * functional but dirty * fully functional - still dirty * added support for different chains * updated readme and removed unnecessary files * removed console messages and fixed strategies/index.ts * Revert "removed console messages and fixed strategies/index.ts" This reverts commit e92e3df90f5b802b4c933bd9d73144f15be4f4c0. * Revert "Merge branch 'master' into master" This reverts commit c48ccff95e4643d4244f91ffcc0ea7f8aa0c9326, reversing changes made to 612687e5e5d97e310d09b787749be83be2b3e6c2. * Revert "Revert "Merge branch 'master' into master"" This reverts commit f15c406c549ac92f0f5d808aec497fb6145e63e4. * Revert "Revert "removed console messages and fixed strategies/index.ts"" This reverts commit 74cf341c373d385c327f8d9405f4035fab548675. * reverted yarn lock back to original commit and removed package-lock.json * Update yarn.lock * Update src/strategies/hats-protocol-single-vote-per-org/index.ts * Update src/strategies/hats-protocol-single-vote-per-org/index.ts * Update src/strategies/hats-protocol-single-vote-per-org/index.ts * added snapshot to subgraph requests * fixed ethers error and updated yarn lock to match snapshot-strategies main * updated yarn.lock * Update yarn.lock * Update src/strategies/hats-protocol-single-vote-per-org/index.ts --------- Co-authored-by: Chaitanya --- .../README.md | 12 + .../examples.json | 20 + .../index.ts | 192 + .../schema.json | 27 + .../utils.ts | 33 + src/strategies/index.ts | 2 + yarn.lock | 8778 ++++++++--------- 7 files changed, 4675 insertions(+), 4389 deletions(-) create mode 100644 src/strategies/hats-protocol-single-vote-per-org/README.md create mode 100644 src/strategies/hats-protocol-single-vote-per-org/examples.json create mode 100644 src/strategies/hats-protocol-single-vote-per-org/index.ts create mode 100644 src/strategies/hats-protocol-single-vote-per-org/schema.json create mode 100644 src/strategies/hats-protocol-single-vote-per-org/utils.ts diff --git a/src/strategies/hats-protocol-single-vote-per-org/README.md b/src/strategies/hats-protocol-single-vote-per-org/README.md new file mode 100644 index 000000000..399061d96 --- /dev/null +++ b/src/strategies/hats-protocol-single-vote-per-org/README.md @@ -0,0 +1,12 @@ +# hsts-protocol-single-vote-per-org + +A strategy to get a single voting power based on checking to see if the addresses own at least one hat within a tree. + +Here is an example of parameters: + +```json +{ + "address": "0x3bc1A0Ad72417f2d411118085256fC53CBdDd137", + "humanReadableTreeId": 2 +} +``` diff --git a/src/strategies/hats-protocol-single-vote-per-org/examples.json b/src/strategies/hats-protocol-single-vote-per-org/examples.json new file mode 100644 index 000000000..45c0e1bd5 --- /dev/null +++ b/src/strategies/hats-protocol-single-vote-per-org/examples.json @@ -0,0 +1,20 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "hats-protocol-single-vote-per-org", + "params": { + "address": "0x3bc1A0Ad72417f2d411118085256fC53CBdDd137", + "humanReadableTreeId" : 2 + } + }, + "network": "10", + "addresses": [ + "0xbeC26FFa12c90217943D1b2958f60A821aE6E549", + "0xa6aF0566EF4eF7E8f38913f69d4e55c06F00A5aC", + "0x00e7332F9Cd4C05a0645AC959Fb1Be60ec24F94f", + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + ], + "snapshot": 107031024 + } +] diff --git a/src/strategies/hats-protocol-single-vote-per-org/index.ts b/src/strategies/hats-protocol-single-vote-per-org/index.ts new file mode 100644 index 000000000..1d5cba91e --- /dev/null +++ b/src/strategies/hats-protocol-single-vote-per-org/index.ts @@ -0,0 +1,192 @@ +import { subgraphRequest } from '../../utils'; +import { getAddress } from '@ethersproject/address'; +import { StaticJsonRpcProvider } from '@ethersproject/providers'; +import { multicall } from '../../utils'; + +export const author = 'hotmanics'; +export const version = '0.1.1'; + +const abi = [ + 'function isWearerOfHat(address _user, uint256 _hatId) external view returns (bool isWearer)' +]; + +async function subgraphRequestHats(url, snapshot, humanReadableTreeId) { + const str1 = '0x'; + const length = humanReadableTreeId.toString().length; + let resultString = str1.padEnd(10 - length, '0'); + resultString = resultString + humanReadableTreeId.toString(); + + const params = { + tree: { + __args: { + id: resultString + }, + id: true, + hats: { + id: true, + wearers: { + id: true + } + } + } + }; + + if (snapshot !== 'latest') { + // @ts-ignore + params.tree.__args.block = { number: snapshot }; + } + const result = await subgraphRequest(url, params); + return result; +} + +function checkIfExists(address, tree) { + const addressWithHats = []; + tree.hats.forEach((hat) => { + hat.wearers.forEach((wearer) => { + if (getAddress(wearer.id) === address) { + const addressWithHat = { + address: getAddress(wearer.id), + hat: BigInt(hat.id) + }; + addressWithHats.push(addressWithHat); + } + }); + }); + return addressWithHats; +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + let result; + + switch (network) { + case '1': + result = await subgraphRequestHats( + 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-ethereum', + snapshot, + options.humanReadableTreeId + ); + break; + case '10': + result = await subgraphRequestHats( + 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-optimism', + snapshot, + options.humanReadableTreeId + ); + break; + case '5': + result = await subgraphRequestHats( + 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-goerli', + snapshot, + options.humanReadableTreeId + ); + break; + case '137': + result = await subgraphRequestHats( + 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-polygon', + snapshot, + options.humanReadableTreeId + ); + break; + case '100': + result = await subgraphRequestHats( + 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-gnosis-chain', + snapshot, + options.humanReadableTreeId + ); + break; + case '42161': + result = await subgraphRequestHats( + 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-arbitrum', + snapshot, + options.humanReadableTreeId + ); + break; + } + + let wearersInAddresses = []; + + addresses.forEach((address) => { + const wearer = checkIfExists(address, result.tree); + wearersInAddresses = wearersInAddresses.concat(wearer); + }); + + const multi = new Multicaller(network, provider, abi, { blockTag }); + + wearersInAddresses.forEach((wearer) => { + multi.call(wearer.address, options.address, 'isWearerOfHat', [ + wearer.address, + wearer.hat + ]); + }); + + const multiResult = await multi.execute(); + + const myObj = {}; + wearersInAddresses.forEach((wearer) => { + myObj[wearer.address] = 0; + for (const result of multiResult) { + if (wearer.address === result.address) { + myObj[wearer.address] = 1; + break; + } + } + }); + + return myObj; +} + +class Multicaller { + public network: string; + public provider: StaticJsonRpcProvider; + public abi: any[]; + public options: any = {}; + public calls: any[] = []; + public paths: any[] = []; + + constructor( + network: string, + provider: StaticJsonRpcProvider, + abi: any[], + options? + ) { + this.network = network; + this.provider = provider; + this.abi = abi; + this.options = options || {}; + } + + call(path, address, fn, params?): Multicaller { + this.calls.push([address, fn, params]); + this.paths.push(path); + return this; + } + + async execute(): Promise { + const obj = []; + const result = await multicall( + this.network, + this.provider, + this.abi, + this.calls, + this.options + ); + result.forEach((r, i) => { + obj.push({ + address: this.paths[i], + value: r + }); + }); + this.calls = []; + this.paths = []; + return obj; + } +} diff --git a/src/strategies/hats-protocol-single-vote-per-org/schema.json b/src/strategies/hats-protocol-single-vote-per-org/schema.json new file mode 100644 index 000000000..7a9777dd1 --- /dev/null +++ b/src/strategies/hats-protocol-single-vote-per-org/schema.json @@ -0,0 +1,27 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "address": { + "type": "string", + "title": "Contract address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "humanReadableTreeId": { + "type": "number", + "title": "Human Readable Tree Id", + "examples": ["e.g. 2, 221"] + } + }, + "required": ["address", "humanReadableTreeId"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/hats-protocol-single-vote-per-org/utils.ts b/src/strategies/hats-protocol-single-vote-per-org/utils.ts new file mode 100644 index 000000000..5b43b35c6 --- /dev/null +++ b/src/strategies/hats-protocol-single-vote-per-org/utils.ts @@ -0,0 +1,33 @@ +export function hatIdDecimalToHex(hatId) { + return `0x` + BigInt(hatId).toString(16).padStart(64, `0`); +} + +export function treeIdDecimalToHex(treeId) { + return `0x` + treeId.toString(16).padStart(8, `0`); +} + +export function hatIdHexToDecimal(hatId) { + return BigInt(hatId); +} + +export function treeIdHexToDecimal(treeId) { + return parseInt(treeId, 16); +} + +export function setCharAt(str, index, chr) { + if (index > str.length - 1) return str; + return str.substring(0, index) + chr + str.substring(index + 1); +} + +export function hatIdDecimalToIp(hatId) { + const hexId = hatIdDecimalToHex(hatId); + let ip = treeIdHexToDecimal(hexId.substring(0, 10)).toString(); + for (let i = 10; i < hexId.length; i += 4) { + const domainAtLevel = hexId.substring(i, i + 4); + if (domainAtLevel === `0000`) { + break; + } + ip += `.` + parseInt(domainAtLevel, 16); + } + return ip; +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 4cbe2ea32..a3c394835 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -448,6 +448,7 @@ import * as erc721CollateralHeld from './erc721-collateral-held'; import * as starlayVeBalanceOfLockerId from './starlay-ve-balance-of-locker-id'; import * as winrStaking from './winr-staking'; import * as spaceid from './spaceid'; +import * as hatsProtocolSingleVotePerOrg from './hats-protocol-single-vote-per-org'; import * as karmaDiscordRoles from './karma-discord-roles'; import * as seedifyHoldStakingFarming from './seedify-cumulative-voting-power-hodl-staking-farming'; import * as stakedMoreKudasai from './staked-morekudasai'; @@ -906,6 +907,7 @@ const strategies = { 'starlay-ve-balance-of-locker-id': starlayVeBalanceOfLockerId, 'winr-staking': winrStaking, spaceid, + 'hats-protocol-single-vote-per-org': hatsProtocolSingleVotePerOrg, 'karma-discord-roles': karmaDiscordRoles, 'seedify-cumulative-voting-power-hodl-staking-farming': seedifyHoldStakingFarming, diff --git a/yarn.lock b/yarn.lock index ea0d1fb13..915a3d8e0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1,4389 +1,4389 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@ampproject/remapping@^2.1.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" - integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== - dependencies: - "@jridgewell/gen-mapping" "^0.1.0" - "@jridgewell/trace-mapping" "^0.3.9" - -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" - integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== - dependencies: - "@babel/highlight" "^7.16.7" - -"@babel/compat-data@^7.17.10": - version "7.18.5" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.5.tgz#acac0c839e317038c73137fbb6ef71a1d6238471" - integrity sha512-BxhE40PVCBxVEJsSBhB6UWyAuqJRxGsAw8BdHMJ3AKGydcwuWW4kOO3HmqBQAdcq/OP+/DlTVxLvsCzRTnZuGg== - -"@babel/core@^7.11.6", "@babel/core@^7.12.3": - version "7.18.5" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.5.tgz#c597fa680e58d571c28dda9827669c78cdd7f000" - integrity sha512-MGY8vg3DxMnctw0LdvSEojOsumc70g0t18gNyUdAZqB1Rpd1Bqo/svHGvt+UJ6JcGX+DIekGFDxxIWofBxLCnQ== - dependencies: - "@ampproject/remapping" "^2.1.0" - "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.18.2" - "@babel/helper-compilation-targets" "^7.18.2" - "@babel/helper-module-transforms" "^7.18.0" - "@babel/helpers" "^7.18.2" - "@babel/parser" "^7.18.5" - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.18.5" - "@babel/types" "^7.18.4" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.2.1" - semver "^6.3.0" - -"@babel/generator@^7.18.2", "@babel/generator@^7.7.2": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.2.tgz#33873d6f89b21efe2da63fe554460f3df1c5880d" - integrity sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw== - dependencies: - "@babel/types" "^7.18.2" - "@jridgewell/gen-mapping" "^0.3.0" - jsesc "^2.5.1" - -"@babel/helper-compilation-targets@^7.18.2": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.2.tgz#67a85a10cbd5fc7f1457fec2e7f45441dc6c754b" - integrity sha512-s1jnPotJS9uQnzFtiZVBUxe67CuBa679oWFHpxYYnTpRL/1ffhyX44R9uYiXoa/pLXcY9H2moJta0iaanlk/rQ== - dependencies: - "@babel/compat-data" "^7.17.10" - "@babel/helper-validator-option" "^7.16.7" - browserslist "^4.20.2" - semver "^6.3.0" - -"@babel/helper-environment-visitor@^7.16.7", "@babel/helper-environment-visitor@^7.18.2": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.2.tgz#8a6d2dedb53f6bf248e31b4baf38739ee4a637bd" - integrity sha512-14GQKWkX9oJzPiQQ7/J36FTXcD4kSp8egKjO9nINlSKiHITRA9q/R74qu8S9xlc/b/yjsJItQUeeh3xnGN0voQ== - -"@babel/helper-function-name@^7.17.9": - version "7.17.9" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz#136fcd54bc1da82fcb47565cf16fd8e444b1ff12" - integrity sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg== - dependencies: - "@babel/template" "^7.16.7" - "@babel/types" "^7.17.0" - -"@babel/helper-hoist-variables@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246" - integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg== - dependencies: - "@babel/types" "^7.16.7" - -"@babel/helper-module-imports@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" - integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== - dependencies: - "@babel/types" "^7.16.7" - -"@babel/helper-module-transforms@^7.18.0": - version "7.18.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.18.0.tgz#baf05dec7a5875fb9235bd34ca18bad4e21221cd" - integrity sha512-kclUYSUBIjlvnzN2++K9f2qzYKFgjmnmjwL4zlmU5f8ZtzgWe8s0rUPSTGy2HmK4P8T52MQsS+HTQAgZd3dMEA== - dependencies: - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-simple-access" "^7.17.7" - "@babel/helper-split-export-declaration" "^7.16.7" - "@babel/helper-validator-identifier" "^7.16.7" - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.18.0" - "@babel/types" "^7.18.0" - -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.17.12", "@babel/helper-plugin-utils@^7.8.0": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.17.12.tgz#86c2347da5acbf5583ba0a10aed4c9bf9da9cf96" - integrity sha512-JDkf04mqtN3y4iAbO1hv9U2ARpPyPL1zqyWs/2WG1pgSq9llHFjStX5jdxb84himgJm+8Ng+x0oiWF/nw/XQKA== - -"@babel/helper-plugin-utils@^7.20.2": - version "7.21.5" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.21.5.tgz#345f2377d05a720a4e5ecfa39cbf4474a4daed56" - integrity sha512-0WDaIlXKOX/3KfBK/dwP1oQGiPh6rjMkT7HIRv7i5RR2VUMwrx5ZL0dwBkKx7+SW1zwNdgjHd34IMk5ZjTeHVg== - -"@babel/helper-simple-access@^7.17.7": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.18.2.tgz#4dc473c2169ac3a1c9f4a51cfcd091d1c36fcff9" - integrity sha512-7LIrjYzndorDY88MycupkpQLKS1AFfsVRm2k/9PtKScSy5tZq0McZTj+DiMRynboZfIqOKvo03pmhTaUgiD6fQ== - dependencies: - "@babel/types" "^7.18.2" - -"@babel/helper-split-export-declaration@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b" - integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw== - dependencies: - "@babel/types" "^7.16.7" - -"@babel/helper-validator-identifier@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" - integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== - -"@babel/helper-validator-option@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23" - integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ== - -"@babel/helpers@^7.18.2": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.18.2.tgz#970d74f0deadc3f5a938bfa250738eb4ac889384" - integrity sha512-j+d+u5xT5utcQSzrh9p+PaJX94h++KN+ng9b9WEJq7pkUPAd61FGqhjuUEdfknb3E/uDBb7ruwEeKkIxNJPIrg== - dependencies: - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.18.2" - "@babel/types" "^7.18.2" - -"@babel/highlight@^7.16.7": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.17.12.tgz#257de56ee5afbd20451ac0a75686b6b404257351" - integrity sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg== - dependencies: - "@babel/helper-validator-identifier" "^7.16.7" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.7", "@babel/parser@^7.18.5": - version "7.18.5" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.5.tgz#337062363436a893a2d22faa60be5bb37091c83c" - integrity sha512-YZWVaglMiplo7v8f1oMQ5ZPQr0vn7HPeZXxXWsxXJRjGVrzUFn9OxFQl1sb5wzfootjA/yChhW84BV+383FSOw== - -"@babel/plugin-syntax-async-generators@^7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" - integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-bigint@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" - integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-class-properties@^7.8.3": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" - integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - -"@babel/plugin-syntax-import-meta@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" - integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-json-strings@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" - integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-jsx@^7.7.2": - version "7.21.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.21.4.tgz#f264ed7bf40ffc9ec239edabc17a50c4f5b6fea2" - integrity sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - -"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" - integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" - integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-numeric-separator@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" - integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-object-rest-spread@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" - integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-catch-binding@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" - integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-chaining@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" - integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-top-level-await@^7.8.3": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" - integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-typescript@^7.7.2": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.17.12.tgz#b54fc3be6de734a56b87508f99d6428b5b605a7b" - integrity sha512-TYY0SXFiO31YXtNg3HtFwNJHjLsAyIIhAhNWkQ5whPPS7HWUFlg9z0Ta4qAQNjQbP1wsSt/oKkmZ/4/WWdMUpw== - dependencies: - "@babel/helper-plugin-utils" "^7.17.12" - -"@babel/template@^7.16.7", "@babel/template@^7.3.3": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" - integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== - dependencies: - "@babel/code-frame" "^7.16.7" - "@babel/parser" "^7.16.7" - "@babel/types" "^7.16.7" - -"@babel/traverse@^7.18.0", "@babel/traverse@^7.18.2", "@babel/traverse@^7.18.5", "@babel/traverse@^7.7.2": - version "7.18.5" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.5.tgz#94a8195ad9642801837988ab77f36e992d9a20cd" - integrity sha512-aKXj1KT66sBj0vVzk6rEeAO6Z9aiiQ68wfDgge3nHhA/my6xMM/7HGQUNumKZaoa2qUPQ5whJG9aAifsxUKfLA== - dependencies: - "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.18.2" - "@babel/helper-environment-visitor" "^7.18.2" - "@babel/helper-function-name" "^7.17.9" - "@babel/helper-hoist-variables" "^7.16.7" - "@babel/helper-split-export-declaration" "^7.16.7" - "@babel/parser" "^7.18.5" - "@babel/types" "^7.18.4" - debug "^4.1.0" - globals "^11.1.0" - -"@babel/types@^7.0.0", "@babel/types@^7.16.7", "@babel/types@^7.17.0", "@babel/types@^7.18.0", "@babel/types@^7.18.2", "@babel/types@^7.18.4", "@babel/types@^7.3.0", "@babel/types@^7.3.3": - version "7.18.4" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.4.tgz#27eae9b9fd18e9dccc3f9d6ad051336f307be354" - integrity sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw== - dependencies: - "@babel/helper-validator-identifier" "^7.16.7" - to-fast-properties "^2.0.0" - -"@bcoe/v8-coverage@^0.2.3": - version "0.2.3" - resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" - integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== - -"@ensdomains/eth-ens-namehash@^2.0.15": - version "2.0.15" - resolved "https://registry.yarnpkg.com/@ensdomains/eth-ens-namehash/-/eth-ens-namehash-2.0.15.tgz#5e5f2f24ba802aff8bc19edd822c9a11200cdf4a" - integrity sha512-JRDFP6+Hczb1E0/HhIg0PONgBYasfGfDheujmfxaZaAv/NAH4jE6Kf48WbqfRZdxt4IZI3jl3Ri7sZ1nP09lgw== - -"@eslint/eslintrc@^1.3.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.0.tgz#29f92c30bb3e771e4a2048c95fa6855392dfac4f" - integrity sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw== - dependencies: - ajv "^6.12.4" - debug "^4.3.2" - espree "^9.3.2" - globals "^13.15.0" - ignore "^5.2.0" - import-fresh "^3.2.1" - js-yaml "^4.1.0" - minimatch "^3.1.2" - strip-json-comments "^3.1.1" - -"@ethersproject/abi@^5.0.12": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.5.0.tgz#fb52820e22e50b854ff15ce1647cc508d6660613" - integrity sha512-loW7I4AohP5KycATvc0MgujU6JyCHPqHdeoo9z3Nr9xEiNioxa65ccdm1+fsoJhkuhdRtfcL8cfyGamz2AxZ5w== - dependencies: - "@ethersproject/address" "^5.5.0" - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/constants" "^5.5.0" - "@ethersproject/hash" "^5.5.0" - "@ethersproject/keccak256" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/strings" "^5.5.0" - -"@ethersproject/abi@^5.6.3", "@ethersproject/abi@^5.6.4": - version "5.6.4" - resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.6.4.tgz#f6e01b6ed391a505932698ecc0d9e7a99ee60362" - integrity sha512-TTeZUlCeIHG6527/2goZA6gW5F8Emoc7MrZDC7hhP84aRGvW3TEdTnZR08Ls88YXM1m2SuK42Osw/jSi3uO8gg== - dependencies: - "@ethersproject/address" "^5.6.1" - "@ethersproject/bignumber" "^5.6.2" - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/constants" "^5.6.1" - "@ethersproject/hash" "^5.6.1" - "@ethersproject/keccak256" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/strings" "^5.6.1" - -"@ethersproject/abstract-provider@^5.5.0": - version "5.5.1" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.5.1.tgz#2f1f6e8a3ab7d378d8ad0b5718460f85649710c5" - integrity sha512-m+MA/ful6eKbxpr99xUYeRvLkfnlqzrF8SZ46d/xFB1A7ZVknYc/sXJG0RcufF52Qn2jeFj1hhcoQ7IXjNKUqg== - dependencies: - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/networks" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/transactions" "^5.5.0" - "@ethersproject/web" "^5.5.0" - -"@ethersproject/abstract-provider@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.6.1.tgz#02ddce150785caf0c77fe036a0ebfcee61878c59" - integrity sha512-BxlIgogYJtp1FS8Muvj8YfdClk3unZH0vRMVX791Z9INBNT/kuACZ9GzaY1Y4yFq+YSy6/w4gzj3HCRKrK9hsQ== - dependencies: - "@ethersproject/bignumber" "^5.6.2" - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/networks" "^5.6.3" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/transactions" "^5.6.2" - "@ethersproject/web" "^5.6.1" - -"@ethersproject/abstract-signer@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.5.0.tgz#590ff6693370c60ae376bf1c7ada59eb2a8dd08d" - integrity sha512-lj//7r250MXVLKI7sVarXAbZXbv9P50lgmJQGr2/is82EwEb8r7HrxsmMqAjTsztMYy7ohrIhGMIml+Gx4D3mA== - dependencies: - "@ethersproject/abstract-provider" "^5.5.0" - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - -"@ethersproject/abstract-signer@^5.6.2": - version "5.6.2" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.6.2.tgz#491f07fc2cbd5da258f46ec539664713950b0b33" - integrity sha512-n1r6lttFBG0t2vNiI3HoWaS/KdOt8xyDjzlP2cuevlWLG6EX0OwcKLyG/Kp/cuwNxdy/ous+R/DEMdTUwWQIjQ== - dependencies: - "@ethersproject/abstract-provider" "^5.6.1" - "@ethersproject/bignumber" "^5.6.2" - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - -"@ethersproject/address@^5.0.2", "@ethersproject/address@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.5.0.tgz#bcc6f576a553f21f3dd7ba17248f81b473c9c78f" - integrity sha512-l4Nj0eWlTUh6ro5IbPTgbpT4wRbdH5l8CQf7icF7sb/SI3Nhd9Y9HzhonTSTi6CefI0necIw7LJqQPopPLZyWw== - dependencies: - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/keccak256" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/rlp" "^5.5.0" - -"@ethersproject/address@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.6.1.tgz#ab57818d9aefee919c5721d28cd31fd95eff413d" - integrity sha512-uOgF0kS5MJv9ZvCz7x6T2EXJSzotiybApn4XlOgoTX0xdtyVIJ7pF+6cGPxiEq/dpBiTfMiw7Yc81JcwhSYA0Q== - dependencies: - "@ethersproject/bignumber" "^5.6.2" - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/keccak256" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/rlp" "^5.6.1" - -"@ethersproject/base64@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.5.0.tgz#881e8544e47ed976930836986e5eb8fab259c090" - integrity sha512-tdayUKhU1ljrlHzEWbStXazDpsx4eg1dBXUSI6+mHlYklOXoXF6lZvw8tnD6oVaWfnMxAgRSKROg3cVKtCcppA== - dependencies: - "@ethersproject/bytes" "^5.5.0" - -"@ethersproject/base64@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.6.1.tgz#2c40d8a0310c9d1606c2c37ae3092634b41d87cb" - integrity sha512-qB76rjop6a0RIYYMiB4Eh/8n+Hxu2NIZm8S/Q7kNo5pmZfXhHGHmS4MinUainiBC54SCyRnwzL+KZjj8zbsSsw== - dependencies: - "@ethersproject/bytes" "^5.6.1" - -"@ethersproject/basex@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.6.1.tgz#badbb2f1d4a6f52ce41c9064f01eab19cc4c5305" - integrity sha512-a52MkVz4vuBXR06nvflPMotld1FJWSj2QT0985v7P/emPZO00PucFAkbcmq2vpVU7Ts7umKiSI6SppiLykVWsA== - dependencies: - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/properties" "^5.6.0" - -"@ethersproject/bignumber@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.5.0.tgz#875b143f04a216f4f8b96245bde942d42d279527" - integrity sha512-6Xytlwvy6Rn3U3gKEc1vP7nR92frHkv6wtVr95LFR3jREXiCPzdWxKQ1cx4JGQBXxcguAwjA8murlYN2TSiEbg== - dependencies: - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - bn.js "^4.11.9" - -"@ethersproject/bignumber@^5.6.2": - version "5.6.2" - resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.6.2.tgz#72a0717d6163fab44c47bcc82e0c550ac0315d66" - integrity sha512-v7+EEUbhGqT3XJ9LMPsKvXYHFc8eHxTowFCG/HgJErmq4XHJ2WR7aeyICg3uTOAQ7Icn0GFHAohXEhxQHq4Ubw== - dependencies: - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - bn.js "^5.2.1" - -"@ethersproject/bignumber@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz#e2f03837f268ba655ffba03a57853e18a18dc9c2" - integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - bn.js "^5.2.1" - -"@ethersproject/bytes@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.5.0.tgz#cb11c526de657e7b45d2e0f0246fb3b9d29a601c" - integrity sha512-ABvc7BHWhZU9PNM/tANm/Qx4ostPGadAuQzWTr3doklZOhDlmcBqclrQe/ZXUIj3K8wC28oYeuRa+A37tX9kog== - dependencies: - "@ethersproject/logger" "^5.5.0" - -"@ethersproject/bytes@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.6.1.tgz#24f916e411f82a8a60412344bf4a813b917eefe7" - integrity sha512-NwQt7cKn5+ZE4uDn+X5RAXLp46E1chXoaMmrxAyA0rblpxz8t58lVkrHXoRIn0lz1joQElQ8410GqhTqMOwc6g== - dependencies: - "@ethersproject/logger" "^5.6.0" - -"@ethersproject/bytes@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.7.0.tgz#a00f6ea8d7e7534d6d87f47188af1148d71f155d" - integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== - dependencies: - "@ethersproject/logger" "^5.7.0" - -"@ethersproject/constants@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.5.0.tgz#d2a2cd7d94bd1d58377d1d66c4f53c9be4d0a45e" - integrity sha512-2MsRRVChkvMWR+GyMGY4N1sAX9Mt3J9KykCsgUFd/1mwS0UH1qw+Bv9k1UJb3X3YJYFco9H20pjSlOIfCG5HYQ== - dependencies: - "@ethersproject/bignumber" "^5.5.0" - -"@ethersproject/constants@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.6.1.tgz#e2e974cac160dd101cf79fdf879d7d18e8cb1370" - integrity sha512-QSq9WVnZbxXYFftrjSjZDUshp6/eKp6qrtdBtUCm0QxCV5z1fG/w3kdlcsjMCQuQHUnAclKoK7XpXMezhRDOLg== - dependencies: - "@ethersproject/bignumber" "^5.6.2" - -"@ethersproject/constants@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.7.0.tgz#df80a9705a7e08984161f09014ea012d1c75295e" - integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - -"@ethersproject/contracts@^5.6.2": - version "5.6.2" - resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.6.2.tgz#20b52e69ebc1b74274ff8e3d4e508de971c287bc" - integrity sha512-hguUA57BIKi6WY0kHvZp6PwPlWF87MCeB4B7Z7AbUpTxfFXFdn/3b0GmjZPagIHS+3yhcBJDnuEfU4Xz+Ks/8g== - dependencies: - "@ethersproject/abi" "^5.6.3" - "@ethersproject/abstract-provider" "^5.6.1" - "@ethersproject/abstract-signer" "^5.6.2" - "@ethersproject/address" "^5.6.1" - "@ethersproject/bignumber" "^5.6.2" - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/constants" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/transactions" "^5.6.2" - -"@ethersproject/hash@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.5.0.tgz#7cee76d08f88d1873574c849e0207dcb32380cc9" - integrity sha512-dnGVpK1WtBjmnp3mUT0PlU2MpapnwWI0PibldQEq1408tQBAbZpPidkWoVVuNMOl/lISO3+4hXZWCL3YV7qzfg== - dependencies: - "@ethersproject/abstract-signer" "^5.5.0" - "@ethersproject/address" "^5.5.0" - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/keccak256" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/strings" "^5.5.0" - -"@ethersproject/hash@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.6.1.tgz#224572ea4de257f05b4abf8ae58b03a67e99b0f4" - integrity sha512-L1xAHurbaxG8VVul4ankNX5HgQ8PNCTrnVXEiFnE9xoRnaUcgfD12tZINtDinSllxPLCtGwguQxJ5E6keE84pA== - dependencies: - "@ethersproject/abstract-signer" "^5.6.2" - "@ethersproject/address" "^5.6.1" - "@ethersproject/bignumber" "^5.6.2" - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/keccak256" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/strings" "^5.6.1" - -"@ethersproject/hdnode@^5.6.2": - version "5.6.2" - resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.6.2.tgz#26f3c83a3e8f1b7985c15d1db50dc2903418b2d2" - integrity sha512-tERxW8Ccf9CxW2db3WsN01Qao3wFeRsfYY9TCuhmG0xNpl2IO8wgXU3HtWIZ49gUWPggRy4Yg5axU0ACaEKf1Q== - dependencies: - "@ethersproject/abstract-signer" "^5.6.2" - "@ethersproject/basex" "^5.6.1" - "@ethersproject/bignumber" "^5.6.2" - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/pbkdf2" "^5.6.1" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/sha2" "^5.6.1" - "@ethersproject/signing-key" "^5.6.2" - "@ethersproject/strings" "^5.6.1" - "@ethersproject/transactions" "^5.6.2" - "@ethersproject/wordlists" "^5.6.1" - -"@ethersproject/json-wallets@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.6.1.tgz#3f06ba555c9c0d7da46756a12ac53483fe18dd91" - integrity sha512-KfyJ6Zwz3kGeX25nLihPwZYlDqamO6pfGKNnVMWWfEVVp42lTfCZVXXy5Ie8IZTN0HKwAngpIPi7gk4IJzgmqQ== - dependencies: - "@ethersproject/abstract-signer" "^5.6.2" - "@ethersproject/address" "^5.6.1" - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/hdnode" "^5.6.2" - "@ethersproject/keccak256" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/pbkdf2" "^5.6.1" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/random" "^5.6.1" - "@ethersproject/strings" "^5.6.1" - "@ethersproject/transactions" "^5.6.2" - aes-js "3.0.0" - scrypt-js "3.0.1" - -"@ethersproject/keccak256@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.5.0.tgz#e4b1f9d7701da87c564ffe336f86dcee82983492" - integrity sha512-5VoFCTjo2rYbBe1l2f4mccaRFN/4VQEYFwwn04aJV2h7qf4ZvI2wFxUE1XOX+snbwCLRzIeikOqtAoPwMza9kg== - dependencies: - "@ethersproject/bytes" "^5.5.0" - js-sha3 "0.8.0" - -"@ethersproject/keccak256@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.6.1.tgz#b867167c9b50ba1b1a92bccdd4f2d6bd168a91cc" - integrity sha512-bB7DQHCTRDooZZdL3lk9wpL0+XuG3XLGHLh3cePnybsO3V0rdCAOQGpn/0R3aODmnTOOkCATJiD2hnL+5bwthA== - dependencies: - "@ethersproject/bytes" "^5.6.1" - js-sha3 "0.8.0" - -"@ethersproject/logger@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.5.0.tgz#0c2caebeff98e10aefa5aef27d7441c7fd18cf5d" - integrity sha512-rIY/6WPm7T8n3qS2vuHTUBPdXHl+rGxWxW5okDfo9J4Z0+gRRZT0msvUdIJkE4/HS29GUMziwGaaKO2bWONBrg== - -"@ethersproject/logger@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.6.0.tgz#d7db1bfcc22fd2e4ab574cba0bb6ad779a9a3e7a" - integrity sha512-BiBWllUROH9w+P21RzoxJKzqoqpkyM1pRnEKG69bulE9TSQD8SAIvTQqIMZmmCO8pUNkgLP1wndX1gKghSpBmg== - -"@ethersproject/logger@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892" - integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== - -"@ethersproject/networks@^5.5.0": - version "5.5.2" - resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.5.2.tgz#784c8b1283cd2a931114ab428dae1bd00c07630b" - integrity sha512-NEqPxbGBfy6O3x4ZTISb90SjEDkWYDUbEeIFhJly0F7sZjoQMnj5KYzMSkMkLKZ+1fGpx00EDpHQCy6PrDupkQ== - dependencies: - "@ethersproject/logger" "^5.5.0" - -"@ethersproject/networks@^5.6.3": - version "5.6.4" - resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.6.4.tgz#51296d8fec59e9627554f5a8a9c7791248c8dc07" - integrity sha512-KShHeHPahHI2UlWdtDMn2lJETcbtaJge4k7XSjDR9h79QTd6yQJmv6Cp2ZA4JdqWnhszAOLSuJEd9C0PRw7hSQ== - dependencies: - "@ethersproject/logger" "^5.6.0" - -"@ethersproject/pbkdf2@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.6.1.tgz#f462fe320b22c0d6b1d72a9920a3963b09eb82d1" - integrity sha512-k4gRQ+D93zDRPNUfmduNKq065uadC2YjMP/CqwwX5qG6R05f47boq6pLZtV/RnC4NZAYOPH1Cyo54q0c9sshRQ== - dependencies: - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/sha2" "^5.6.1" - -"@ethersproject/properties@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.5.0.tgz#61f00f2bb83376d2071baab02245f92070c59995" - integrity sha512-l3zRQg3JkD8EL3CPjNK5g7kMx4qSwiR60/uk5IVjd3oq1MZR5qUg40CNOoEJoX5wc3DyY5bt9EbMk86C7x0DNA== - dependencies: - "@ethersproject/logger" "^5.5.0" - -"@ethersproject/properties@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.6.0.tgz#38904651713bc6bdd5bdd1b0a4287ecda920fa04" - integrity sha512-szoOkHskajKePTJSZ46uHUWWkbv7TzP2ypdEK6jGMqJaEt2sb0jCgfBo0gH0m2HBpRixMuJ6TBRaQCF7a9DoCg== - dependencies: - "@ethersproject/logger" "^5.6.0" - -"@ethersproject/providers@^5.6.8": - version "5.6.8" - resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.6.8.tgz#22e6c57be215ba5545d3a46cf759d265bb4e879d" - integrity sha512-Wf+CseT/iOJjrGtAOf3ck9zS7AgPmr2fZ3N97r4+YXN3mBePTG2/bJ8DApl9mVwYL+RpYbNxMEkEp4mPGdwG/w== - dependencies: - "@ethersproject/abstract-provider" "^5.6.1" - "@ethersproject/abstract-signer" "^5.6.2" - "@ethersproject/address" "^5.6.1" - "@ethersproject/base64" "^5.6.1" - "@ethersproject/basex" "^5.6.1" - "@ethersproject/bignumber" "^5.6.2" - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/constants" "^5.6.1" - "@ethersproject/hash" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/networks" "^5.6.3" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/random" "^5.6.1" - "@ethersproject/rlp" "^5.6.1" - "@ethersproject/sha2" "^5.6.1" - "@ethersproject/strings" "^5.6.1" - "@ethersproject/transactions" "^5.6.2" - "@ethersproject/web" "^5.6.1" - bech32 "1.1.4" - ws "7.4.6" - -"@ethersproject/random@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.6.1.tgz#66915943981bcd3e11bbd43733f5c3ba5a790255" - integrity sha512-/wtPNHwbmng+5yi3fkipA8YBT59DdkGRoC2vWk09Dci/q5DlgnMkhIycjHlavrvrjJBkFjO/ueLyT+aUDfc4lA== - dependencies: - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - -"@ethersproject/rlp@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.5.0.tgz#530f4f608f9ca9d4f89c24ab95db58ab56ab99a0" - integrity sha512-hLv8XaQ8PTI9g2RHoQGf/WSxBfTB/NudRacbzdxmst5VHAqd1sMibWG7SENzT5Dj3yZ3kJYx+WiRYEcQTAkcYA== - dependencies: - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - -"@ethersproject/rlp@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.6.1.tgz#df8311e6f9f24dcb03d59a2bac457a28a4fe2bd8" - integrity sha512-uYjmcZx+DKlFUk7a5/W9aQVaoEC7+1MOBgNtvNg13+RnuUwT4F0zTovC0tmay5SmRslb29V1B7Y5KCri46WhuQ== - dependencies: - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - -"@ethersproject/sha2@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.5.0.tgz#a40a054c61f98fd9eee99af2c3cc6ff57ec24db7" - integrity sha512-B5UBoglbCiHamRVPLA110J+2uqsifpZaTmid2/7W5rbtYVz6gus6/hSDieIU/6gaKIDcOj12WnOdiymEUHIAOA== - dependencies: - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - hash.js "1.1.7" - -"@ethersproject/sha2@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.6.1.tgz#211f14d3f5da5301c8972a8827770b6fd3e51656" - integrity sha512-5K2GyqcW7G4Yo3uenHegbXRPDgARpWUiXc6RiF7b6i/HXUoWlb7uCARh7BAHg7/qT/Q5ydofNwiZcim9qpjB6g== - dependencies: - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - hash.js "1.1.7" - -"@ethersproject/signing-key@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.5.0.tgz#2aa37169ce7e01e3e80f2c14325f624c29cedbe0" - integrity sha512-5VmseH7qjtNmDdZBswavhotYbWB0bOwKIlOTSlX14rKn5c11QmJwGt4GHeo7NrL/Ycl7uo9AHvEqs5xZgFBTng== - dependencies: - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - bn.js "^4.11.9" - elliptic "6.5.4" - hash.js "1.1.7" - -"@ethersproject/signing-key@^5.6.2": - version "5.6.2" - resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.6.2.tgz#8a51b111e4d62e5a62aee1da1e088d12de0614a3" - integrity sha512-jVbu0RuP7EFpw82vHcL+GP35+KaNruVAZM90GxgQnGqB6crhBqW/ozBfFvdeImtmb4qPko0uxXjn8l9jpn0cwQ== - dependencies: - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - bn.js "^5.2.1" - elliptic "6.5.4" - hash.js "1.1.7" - -"@ethersproject/solidity@^5.0.9": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.5.0.tgz#2662eb3e5da471b85a20531e420054278362f93f" - integrity sha512-9NgZs9LhGMj6aCtHXhtmFQ4AN4sth5HuFXVvAQtzmm0jpSCNOTGtrHZJAeYTh7MBjRR8brylWZxBZR9zDStXbw== - dependencies: - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/keccak256" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/sha2" "^5.5.0" - "@ethersproject/strings" "^5.5.0" - -"@ethersproject/solidity@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.6.1.tgz#5845e71182c66d32e6ec5eefd041fca091a473e2" - integrity sha512-KWqVLkUUoLBfL1iwdzUVlkNqAUIFMpbbeH0rgCfKmJp0vFtY4AsaN91gHKo9ZZLkC4UOm3cI3BmMV4N53BOq4g== - dependencies: - "@ethersproject/bignumber" "^5.6.2" - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/keccak256" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/sha2" "^5.6.1" - "@ethersproject/strings" "^5.6.1" - -"@ethersproject/strings@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.5.0.tgz#e6784d00ec6c57710755699003bc747e98c5d549" - integrity sha512-9fy3TtF5LrX/wTrBaT8FGE6TDJyVjOvXynXJz5MT5azq+E6D92zuKNx7i29sWW2FjVOaWjAsiZ1ZWznuduTIIQ== - dependencies: - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/constants" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - -"@ethersproject/strings@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.6.1.tgz#dbc1b7f901db822b5cafd4ebf01ca93c373f8952" - integrity sha512-2X1Lgk6Jyfg26MUnsHiT456U9ijxKUybz8IM1Vih+NJxYtXhmvKBcHOmvGqpFSVJ0nQ4ZCoIViR8XlRw1v/+Cw== - dependencies: - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/constants" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - -"@ethersproject/transactions@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.5.0.tgz#7e9bf72e97bcdf69db34fe0d59e2f4203c7a2908" - integrity sha512-9RZYSKX26KfzEd/1eqvv8pLauCKzDTub0Ko4LfIgaERvRuwyaNV78mJs7cpIgZaDl6RJui4o49lHwwCM0526zA== - dependencies: - "@ethersproject/address" "^5.5.0" - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/constants" "^5.5.0" - "@ethersproject/keccak256" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/rlp" "^5.5.0" - "@ethersproject/signing-key" "^5.5.0" - -"@ethersproject/transactions@^5.6.2": - version "5.6.2" - resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.6.2.tgz#793a774c01ced9fe7073985bb95a4b4e57a6370b" - integrity sha512-BuV63IRPHmJvthNkkt9G70Ullx6AcM+SDc+a8Aw/8Yew6YwT51TcBKEp1P4oOQ/bP25I18JJr7rcFRgFtU9B2Q== - dependencies: - "@ethersproject/address" "^5.6.1" - "@ethersproject/bignumber" "^5.6.2" - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/constants" "^5.6.1" - "@ethersproject/keccak256" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/rlp" "^5.6.1" - "@ethersproject/signing-key" "^5.6.2" - -"@ethersproject/units@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.6.1.tgz#ecc590d16d37c8f9ef4e89e2005bda7ddc6a4e6f" - integrity sha512-rEfSEvMQ7obcx3KWD5EWWx77gqv54K6BKiZzKxkQJqtpriVsICrktIQmKl8ReNToPeIYPnFHpXvKpi068YFZXw== - dependencies: - "@ethersproject/bignumber" "^5.6.2" - "@ethersproject/constants" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - -"@ethersproject/units@^5.7.0": - version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.7.0.tgz#637b563d7e14f42deeee39245275d477aae1d8b1" - integrity sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - -"@ethersproject/wallet@^5.6.2": - version "5.6.2" - resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.6.2.tgz#cd61429d1e934681e413f4bc847a5f2f87e3a03c" - integrity sha512-lrgh0FDQPuOnHcF80Q3gHYsSUODp6aJLAdDmDV0xKCN/T7D99ta1jGVhulg3PY8wiXEngD0DfM0I2XKXlrqJfg== - dependencies: - "@ethersproject/abstract-provider" "^5.6.1" - "@ethersproject/abstract-signer" "^5.6.2" - "@ethersproject/address" "^5.6.1" - "@ethersproject/bignumber" "^5.6.2" - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/hash" "^5.6.1" - "@ethersproject/hdnode" "^5.6.2" - "@ethersproject/json-wallets" "^5.6.1" - "@ethersproject/keccak256" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/random" "^5.6.1" - "@ethersproject/signing-key" "^5.6.2" - "@ethersproject/transactions" "^5.6.2" - "@ethersproject/wordlists" "^5.6.1" - -"@ethersproject/web@^5.5.0": - version "5.5.1" - resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.5.1.tgz#cfcc4a074a6936c657878ac58917a61341681316" - integrity sha512-olvLvc1CB12sREc1ROPSHTdFCdvMh0J5GSJYiQg2D0hdD4QmJDy8QYDb1CvoqD/bF1c++aeKv2sR5uduuG9dQg== - dependencies: - "@ethersproject/base64" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/strings" "^5.5.0" - -"@ethersproject/web@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.6.1.tgz#6e2bd3ebadd033e6fe57d072db2b69ad2c9bdf5d" - integrity sha512-/vSyzaQlNXkO1WV+RneYKqCJwualcUdx/Z3gseVovZP0wIlOFcCE1hkRhKBH8ImKbGQbMl9EAAyJFrJu7V0aqA== - dependencies: - "@ethersproject/base64" "^5.6.1" - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/strings" "^5.6.1" - -"@ethersproject/wordlists@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.6.1.tgz#1e78e2740a8a21e9e99947e47979d72e130aeda1" - integrity sha512-wiPRgBpNbNwCQFoCr8bcWO8o5I810cqO6mkdtKfLKFlLxeCWcnzDi4Alu8iyNzlhYuS9npCwivMbRWF19dyblw== - dependencies: - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/hash" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/strings" "^5.6.1" - -"@humanwhocodes/config-array@^0.9.2": - version "0.9.5" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.5.tgz#2cbaf9a89460da24b5ca6531b8bbfc23e1df50c7" - integrity sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw== - dependencies: - "@humanwhocodes/object-schema" "^1.2.1" - debug "^4.1.1" - minimatch "^3.0.4" - -"@humanwhocodes/object-schema@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" - integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== - -"@istanbuljs/load-nyc-config@^1.0.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" - integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== - dependencies: - camelcase "^5.3.1" - find-up "^4.1.0" - get-package-type "^0.1.0" - js-yaml "^3.13.1" - resolve-from "^5.0.0" - -"@istanbuljs/schema@^0.1.2": - version "0.1.3" - resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" - integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== - -"@jest/console@^29.5.0": - version "29.5.0" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.5.0.tgz#593a6c5c0d3f75689835f1b3b4688c4f8544cb57" - integrity sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ== - dependencies: - "@jest/types" "^29.5.0" - "@types/node" "*" - chalk "^4.0.0" - jest-message-util "^29.5.0" - jest-util "^29.5.0" - slash "^3.0.0" - -"@jest/core@^29.5.0": - version "29.5.0" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.5.0.tgz#76674b96904484e8214614d17261cc491e5f1f03" - integrity sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ== - dependencies: - "@jest/console" "^29.5.0" - "@jest/reporters" "^29.5.0" - "@jest/test-result" "^29.5.0" - "@jest/transform" "^29.5.0" - "@jest/types" "^29.5.0" - "@types/node" "*" - ansi-escapes "^4.2.1" - chalk "^4.0.0" - ci-info "^3.2.0" - exit "^0.1.2" - graceful-fs "^4.2.9" - jest-changed-files "^29.5.0" - jest-config "^29.5.0" - jest-haste-map "^29.5.0" - jest-message-util "^29.5.0" - jest-regex-util "^29.4.3" - jest-resolve "^29.5.0" - jest-resolve-dependencies "^29.5.0" - jest-runner "^29.5.0" - jest-runtime "^29.5.0" - jest-snapshot "^29.5.0" - jest-util "^29.5.0" - jest-validate "^29.5.0" - jest-watcher "^29.5.0" - micromatch "^4.0.4" - pretty-format "^29.5.0" - slash "^3.0.0" - strip-ansi "^6.0.0" - -"@jest/environment@^29.5.0": - version "29.5.0" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.5.0.tgz#9152d56317c1fdb1af389c46640ba74ef0bb4c65" - integrity sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ== - dependencies: - "@jest/fake-timers" "^29.5.0" - "@jest/types" "^29.5.0" - "@types/node" "*" - jest-mock "^29.5.0" - -"@jest/expect-utils@^29.5.0": - version "29.5.0" - resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.5.0.tgz#f74fad6b6e20f924582dc8ecbf2cb800fe43a036" - integrity sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg== - dependencies: - jest-get-type "^29.4.3" - -"@jest/expect@^29.5.0": - version "29.5.0" - resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.5.0.tgz#80952f5316b23c483fbca4363ce822af79c38fba" - integrity sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g== - dependencies: - expect "^29.5.0" - jest-snapshot "^29.5.0" - -"@jest/fake-timers@^29.5.0": - version "29.5.0" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.5.0.tgz#d4d09ec3286b3d90c60bdcd66ed28d35f1b4dc2c" - integrity sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg== - dependencies: - "@jest/types" "^29.5.0" - "@sinonjs/fake-timers" "^10.0.2" - "@types/node" "*" - jest-message-util "^29.5.0" - jest-mock "^29.5.0" - jest-util "^29.5.0" - -"@jest/globals@^29.5.0": - version "29.5.0" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.5.0.tgz#6166c0bfc374c58268677539d0c181f9c1833298" - integrity sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ== - dependencies: - "@jest/environment" "^29.5.0" - "@jest/expect" "^29.5.0" - "@jest/types" "^29.5.0" - jest-mock "^29.5.0" - -"@jest/reporters@^29.5.0": - version "29.5.0" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.5.0.tgz#985dfd91290cd78ddae4914ba7921bcbabe8ac9b" - integrity sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA== - dependencies: - "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^29.5.0" - "@jest/test-result" "^29.5.0" - "@jest/transform" "^29.5.0" - "@jest/types" "^29.5.0" - "@jridgewell/trace-mapping" "^0.3.15" - "@types/node" "*" - chalk "^4.0.0" - collect-v8-coverage "^1.0.0" - exit "^0.1.2" - glob "^7.1.3" - graceful-fs "^4.2.9" - istanbul-lib-coverage "^3.0.0" - istanbul-lib-instrument "^5.1.0" - istanbul-lib-report "^3.0.0" - istanbul-lib-source-maps "^4.0.0" - istanbul-reports "^3.1.3" - jest-message-util "^29.5.0" - jest-util "^29.5.0" - jest-worker "^29.5.0" - slash "^3.0.0" - string-length "^4.0.1" - strip-ansi "^6.0.0" - v8-to-istanbul "^9.0.1" - -"@jest/schemas@^29.4.3": - version "29.4.3" - resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.4.3.tgz#39cf1b8469afc40b6f5a2baaa146e332c4151788" - integrity sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg== - dependencies: - "@sinclair/typebox" "^0.25.16" - -"@jest/source-map@^29.4.3": - version "29.4.3" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.4.3.tgz#ff8d05cbfff875d4a791ab679b4333df47951d20" - integrity sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w== - dependencies: - "@jridgewell/trace-mapping" "^0.3.15" - callsites "^3.0.0" - graceful-fs "^4.2.9" - -"@jest/test-result@^29.5.0": - version "29.5.0" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.5.0.tgz#7c856a6ca84f45cc36926a4e9c6b57f1973f1408" - integrity sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ== - dependencies: - "@jest/console" "^29.5.0" - "@jest/types" "^29.5.0" - "@types/istanbul-lib-coverage" "^2.0.0" - collect-v8-coverage "^1.0.0" - -"@jest/test-sequencer@^29.5.0": - version "29.5.0" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz#34d7d82d3081abd523dbddc038a3ddcb9f6d3cc4" - integrity sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ== - dependencies: - "@jest/test-result" "^29.5.0" - graceful-fs "^4.2.9" - jest-haste-map "^29.5.0" - slash "^3.0.0" - -"@jest/transform@^29.5.0": - version "29.5.0" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.5.0.tgz#cf9c872d0965f0cbd32f1458aa44a2b1988b00f9" - integrity sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw== - dependencies: - "@babel/core" "^7.11.6" - "@jest/types" "^29.5.0" - "@jridgewell/trace-mapping" "^0.3.15" - babel-plugin-istanbul "^6.1.1" - chalk "^4.0.0" - convert-source-map "^2.0.0" - fast-json-stable-stringify "^2.1.0" - graceful-fs "^4.2.9" - jest-haste-map "^29.5.0" - jest-regex-util "^29.4.3" - jest-util "^29.5.0" - micromatch "^4.0.4" - pirates "^4.0.4" - slash "^3.0.0" - write-file-atomic "^4.0.2" - -"@jest/types@^29.5.0": - version "29.5.0" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.5.0.tgz#f59ef9b031ced83047c67032700d8c807d6e1593" - integrity sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog== - dependencies: - "@jest/schemas" "^29.4.3" - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^17.0.8" - chalk "^4.0.0" - -"@jridgewell/gen-mapping@^0.1.0": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" - integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== - dependencies: - "@jridgewell/set-array" "^1.0.0" - "@jridgewell/sourcemap-codec" "^1.4.10" - -"@jridgewell/gen-mapping@^0.3.0": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz#cf92a983c83466b8c0ce9124fadeaf09f7c66ea9" - integrity sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg== - dependencies: - "@jridgewell/set-array" "^1.0.0" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.9" - -"@jridgewell/resolve-uri@3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" - integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== - -"@jridgewell/resolve-uri@^3.0.3": - version "3.0.7" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz#30cd49820a962aff48c8fffc5cd760151fca61fe" - integrity sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA== - -"@jridgewell/set-array@^1.0.0": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.1.tgz#36a6acc93987adcf0ba50c66908bd0b70de8afea" - integrity sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ== - -"@jridgewell/sourcemap-codec@1.4.14": - version "1.4.14" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" - integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== - -"@jridgewell/sourcemap-codec@^1.4.10": - version "1.4.13" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz#b6461fb0c2964356c469e115f504c95ad97ab88c" - integrity sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w== - -"@jridgewell/trace-mapping@^0.3.12": - version "0.3.14" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed" - integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ== - dependencies: - "@jridgewell/resolve-uri" "^3.0.3" - "@jridgewell/sourcemap-codec" "^1.4.10" - -"@jridgewell/trace-mapping@^0.3.15": - version "0.3.18" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6" - integrity sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA== - dependencies: - "@jridgewell/resolve-uri" "3.1.0" - "@jridgewell/sourcemap-codec" "1.4.14" - -"@jridgewell/trace-mapping@^0.3.9": - version "0.3.13" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz#dcfe3e95f224c8fe97a87a5235defec999aa92ea" - integrity sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w== - dependencies: - "@jridgewell/resolve-uri" "^3.0.3" - "@jridgewell/sourcemap-codec" "^1.4.10" - -"@nodelib/fs.scandir@2.1.5": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" - integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== - dependencies: - "@nodelib/fs.stat" "2.0.5" - run-parallel "^1.1.9" - -"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" - integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== - -"@nodelib/fs.walk@^1.2.3": - version "1.2.8" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" - integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== - dependencies: - "@nodelib/fs.scandir" "2.1.5" - fastq "^1.6.0" - -"@openzeppelin/contracts@3.4.1-solc-0.7-2": - version "3.4.1-solc-0.7-2" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.4.1-solc-0.7-2.tgz#371c67ebffe50f551c3146a9eec5fe6ffe862e92" - integrity sha512-tAG9LWg8+M2CMu7hIsqHPaTyG4uDzjr6mhvH96LvOpLZZj6tgzTluBt+LsCf1/QaYrlis6pITvpIaIhE+iZB+Q== - -"@openzeppelin/contracts@3.4.2-solc-0.7": - version "3.4.2-solc-0.7" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.4.2-solc-0.7.tgz#38f4dbab672631034076ccdf2f3201fab1726635" - integrity sha512-W6QmqgkADuFcTLzHL8vVoNBtkwjvQRpYIAom7KiUNoLKghyx3FgH0GBjt8NRvigV1ZmMOBllvE1By1C+bi8WpA== - -"@sinclair/typebox@^0.25.16": - version "0.25.24" - resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.24.tgz#8c7688559979f7079aacaf31aa881c3aa410b718" - integrity sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ== - -"@sinonjs/commons@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-2.0.0.tgz#fd4ca5b063554307e8327b4564bd56d3b73924a3" - integrity sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg== - dependencies: - type-detect "4.0.8" - -"@sinonjs/fake-timers@^10.0.2": - version "10.0.2" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz#d10549ed1f423d80639c528b6c7f5a1017747d0c" - integrity sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw== - dependencies: - "@sinonjs/commons" "^2.0.0" - -"@snapshot-labs/snapshot.js@^0.4.106": - version "0.4.106" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.106.tgz#1861b0346a93f1caf35e89c0dcff95945407dc31" - integrity sha512-sWQzBmEYl9d5LE1p7ZZRx5+0M/DylcLuh1RLlpbNLYmGM01LFi+bThjB4lsnj/BvyAYFHKNIZam9OHPV2fA+uw== - dependencies: - "@ensdomains/eth-ens-namehash" "^2.0.15" - "@ethersproject/abi" "^5.6.4" - "@ethersproject/address" "^5.6.1" - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/contracts" "^5.6.2" - "@ethersproject/hash" "^5.6.1" - "@ethersproject/providers" "^5.6.8" - "@ethersproject/units" "^5.7.0" - "@ethersproject/wallet" "^5.6.2" - ajv "^8.11.0" - ajv-formats "^2.1.1" - cross-fetch "^3.1.6" - json-to-graphql-query "^2.2.4" - lodash.set "^4.3.2" - -"@spruceid/didkit-wasm-node@^0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@spruceid/didkit-wasm-node/-/didkit-wasm-node-0.2.1.tgz#85f7023979b4ef84bd6de16c79c67b6e9a08e1db" - integrity sha512-c8e3u5FIRS/2Gf6UHnRPnfRozgKgby4avZzlvIiaJRDVLl1LaX1SE13vEvKV2rAq6NMfZrV4YG908M4uVlT90Q== - -"@types/babel__core@^7.1.14": - version "7.1.19" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.19.tgz#7b497495b7d1b4812bdb9d02804d0576f43ee460" - integrity sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw== - dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - "@types/babel__generator" "*" - "@types/babel__template" "*" - "@types/babel__traverse" "*" - -"@types/babel__generator@*": - version "7.6.4" - resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.4.tgz#1f20ce4c5b1990b37900b63f050182d28c2439b7" - integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== - dependencies: - "@babel/types" "^7.0.0" - -"@types/babel__template@*": - version "7.4.1" - resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" - integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== - dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - -"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": - version "7.17.1" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.17.1.tgz#1a0e73e8c28c7e832656db372b779bfd2ef37314" - integrity sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA== - dependencies: - "@babel/types" "^7.3.0" - -"@types/graceful-fs@^4.1.3": - version "4.1.5" - resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" - integrity sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw== - dependencies: - "@types/node" "*" - -"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" - integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== - -"@types/istanbul-lib-report@*": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" - integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== - dependencies: - "@types/istanbul-lib-coverage" "*" - -"@types/istanbul-reports@^3.0.0": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" - integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== - dependencies: - "@types/istanbul-lib-report" "*" - -"@types/jest@^29.5.1": - version "29.5.1" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.1.tgz#83c818aa9a87da27d6da85d3378e5a34d2f31a47" - integrity sha512-tEuVcHrpaixS36w7hpsfLBLpjtMRJUE09/MHXn923LOVojDwyC14cWcfc0rDs0VEfUyYmt/+iX1kxxp+gZMcaQ== - dependencies: - expect "^29.0.0" - pretty-format "^29.0.0" - -"@types/json-schema@^7.0.9": - version "7.0.11" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" - integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== - -"@types/json5@^0.0.29": - version "0.0.29" - resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" - integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= - -"@types/node@*": - version "18.0.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.0.0.tgz#67c7b724e1bcdd7a8821ce0d5ee184d3b4dd525a" - integrity sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA== - -"@types/node@^18.0.3": - version "18.0.3" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.0.3.tgz#463fc47f13ec0688a33aec75d078a0541a447199" - integrity sha512-HzNRZtp4eepNitP+BD6k2L6DROIDG4Q0fm4x+dwfsr6LGmROENnok75VGw40628xf+iR24WeMFcHuuBDUAzzsQ== - -"@types/prettier@^2.1.5": - version "2.6.3" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.6.3.tgz#68ada76827b0010d0db071f739314fa429943d0a" - integrity sha512-ymZk3LEC/fsut+/Q5qejp6R9O1rMxz3XaRHDV6kX8MrGAhOSPqVARbDi+EZvInBpw+BnCX3TD240byVkOfQsHg== - -"@types/stack-utils@^2.0.0": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" - integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== - -"@types/yargs-parser@*": - version "21.0.0" - resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" - integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== - -"@types/yargs@^17.0.8": - version "17.0.10" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.10.tgz#591522fce85d8739bca7b8bb90d048e4478d186a" - integrity sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA== - dependencies: - "@types/yargs-parser" "*" - -"@typescript-eslint/eslint-plugin@^5.30.5": - version "5.30.5" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.5.tgz#e9a0afd6eb3b1d663db91cf1e7bc7584d394503d" - integrity sha512-lftkqRoBvc28VFXEoRgyZuztyVUQ04JvUnATSPtIRFAccbXTWL6DEtXGYMcbg998kXw1NLUJm7rTQ9eUt+q6Ig== - dependencies: - "@typescript-eslint/scope-manager" "5.30.5" - "@typescript-eslint/type-utils" "5.30.5" - "@typescript-eslint/utils" "5.30.5" - debug "^4.3.4" - functional-red-black-tree "^1.0.1" - ignore "^5.2.0" - regexpp "^3.2.0" - semver "^7.3.7" - tsutils "^3.21.0" - -"@typescript-eslint/parser@^5.30.5": - version "5.30.5" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.30.5.tgz#f667c34e4e4c299d98281246c9b1e68c03a92522" - integrity sha512-zj251pcPXI8GO9NDKWWmygP6+UjwWmrdf9qMW/L/uQJBM/0XbU2inxe5io/234y/RCvwpKEYjZ6c1YrXERkK4Q== - dependencies: - "@typescript-eslint/scope-manager" "5.30.5" - "@typescript-eslint/types" "5.30.5" - "@typescript-eslint/typescript-estree" "5.30.5" - debug "^4.3.4" - -"@typescript-eslint/scope-manager@5.30.5": - version "5.30.5" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.30.5.tgz#7f90b9d6800552c856a5f3644f5e55dd1469d964" - integrity sha512-NJ6F+YHHFT/30isRe2UTmIGGAiXKckCyMnIV58cE3JkHmaD6e5zyEYm5hBDv0Wbin+IC0T1FWJpD3YqHUG/Ydg== - dependencies: - "@typescript-eslint/types" "5.30.5" - "@typescript-eslint/visitor-keys" "5.30.5" - -"@typescript-eslint/type-utils@5.30.5": - version "5.30.5" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.30.5.tgz#7a9656f360b4b1daea635c4621dab053d08bf8a9" - integrity sha512-k9+ejlv1GgwN1nN7XjVtyCgE0BTzhzT1YsQF0rv4Vfj2U9xnslBgMYYvcEYAFVdvhuEscELJsB7lDkN7WusErw== - dependencies: - "@typescript-eslint/utils" "5.30.5" - debug "^4.3.4" - tsutils "^3.21.0" - -"@typescript-eslint/types@5.30.5": - version "5.30.5" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.30.5.tgz#36a0c05a72af3623cdf9ee8b81ea743b7de75a98" - integrity sha512-kZ80w/M2AvsbRvOr3PjaNh6qEW1LFqs2pLdo2s5R38B2HYXG8Z0PP48/4+j1QHJFL3ssHIbJ4odPRS8PlHrFfw== - -"@typescript-eslint/typescript-estree@5.30.5": - version "5.30.5" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.5.tgz#c520e4eba20551c4ec76af8d344a42eb6c9767bb" - integrity sha512-qGTc7QZC801kbYjAr4AgdOfnokpwStqyhSbiQvqGBLixniAKyH+ib2qXIVo4P9NgGzwyfD9I0nlJN7D91E1VpQ== - dependencies: - "@typescript-eslint/types" "5.30.5" - "@typescript-eslint/visitor-keys" "5.30.5" - debug "^4.3.4" - globby "^11.1.0" - is-glob "^4.0.3" - semver "^7.3.7" - tsutils "^3.21.0" - -"@typescript-eslint/utils@5.30.5": - version "5.30.5" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.30.5.tgz#3999cbd06baad31b9e60d084f20714d1b2776765" - integrity sha512-o4SSUH9IkuA7AYIfAvatldovurqTAHrfzPApOZvdUq01hHojZojCFXx06D/aFpKCgWbMPRdJBWAC3sWp3itwTA== - dependencies: - "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.30.5" - "@typescript-eslint/types" "5.30.5" - "@typescript-eslint/typescript-estree" "5.30.5" - eslint-scope "^5.1.1" - eslint-utils "^3.0.0" - -"@typescript-eslint/visitor-keys@5.30.5": - version "5.30.5" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.5.tgz#d4bb969202019d5d5d849a0aaedc7370cc044b14" - integrity sha512-D+xtGo9HUMELzWIUqcQc0p2PO4NyvTrgIOK/VnSH083+8sq0tiLozNRKuLarwHYGRuA6TVBQSuuLwJUDWd3aaA== - dependencies: - "@typescript-eslint/types" "5.30.5" - eslint-visitor-keys "^3.3.0" - -"@uniswap/lib@^4.0.1-alpha": - version "4.0.1-alpha" - resolved "https://registry.yarnpkg.com/@uniswap/lib/-/lib-4.0.1-alpha.tgz#2881008e55f075344675b3bca93f020b028fbd02" - integrity sha512-f6UIliwBbRsgVLxIaBANF6w09tYqc6Y/qXdsrbEmXHyFA7ILiKrIwRFXe1yOg8M3cksgVsO9N7yuL2DdCGQKBA== - -"@uniswap/sdk-core@^3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@uniswap/sdk-core/-/sdk-core-3.0.1.tgz#d08dd68257983af64b9a5f4d6b9cf26124b4138f" - integrity sha512-WbeDkhZ9myVR0VnHOdTrb8nHKKkqTFa5uE9RvUbG3eyDt2NWWDwhhqGHwAWJEHG405l30Fa1u3PogHDFsIOQlA== - dependencies: - "@ethersproject/address" "^5.0.2" - big.js "^5.2.2" - decimal.js-light "^2.5.0" - jsbi "^3.1.4" - tiny-invariant "^1.1.0" - toformat "^2.0.0" - -"@uniswap/swap-router-contracts@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@uniswap/swap-router-contracts/-/swap-router-contracts-1.2.1.tgz#223c8b6672b7754080d95ca917763d98feb5e696" - integrity sha512-aRNiZYIOpJ0uYxujPxvQsUEuNJWLC4bvnmU40TlNej1rGWHPyDL1PmnVzebu8UpW9EGeKlvDjsNGTyo53dih9Q== - dependencies: - "@openzeppelin/contracts" "3.4.2-solc-0.7" - "@uniswap/v2-core" "1.0.1" - "@uniswap/v3-core" "1.0.0" - "@uniswap/v3-periphery" "1.4.1" - dotenv "^14.2.0" - hardhat-watcher "^2.1.1" - -"@uniswap/v2-core@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@uniswap/v2-core/-/v2-core-1.0.1.tgz#af8f508bf183204779938969e2e54043e147d425" - integrity sha512-MtybtkUPSyysqLY2U210NBDeCHX+ltHt3oADGdjqoThZaFRDKwM6k1Nb3F0A3hk5hwuQvytFWhrWHOEq6nVJ8Q== - -"@uniswap/v3-core@1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@uniswap/v3-core/-/v3-core-1.0.0.tgz#6c24adacc4c25dceee0ba3ca142b35adbd7e359d" - integrity sha512-kSC4djMGKMHj7sLMYVnn61k9nu+lHjMIxgg9CDQT+s2QYLoA56GbSK9Oxr+qJXzzygbkrmuY6cwgP6cW2JXPFA== - -"@uniswap/v3-periphery@1.4.1", "@uniswap/v3-periphery@^1.0.1", "@uniswap/v3-periphery@^1.1.1": - version "1.4.1" - resolved "https://registry.yarnpkg.com/@uniswap/v3-periphery/-/v3-periphery-1.4.1.tgz#b90f08b7386163c0abfd7258831caef6339c7862" - integrity sha512-Ab0ZCKOQrQMKIcpBTezTsEhWfQjItd0TtkCG8mPhoQu+wC67nPaf4hYUhM6wGHeFUmDiYY5MpEQuokB0ENvoTg== - dependencies: - "@openzeppelin/contracts" "3.4.2-solc-0.7" - "@uniswap/lib" "^4.0.1-alpha" - "@uniswap/v2-core" "1.0.1" - "@uniswap/v3-core" "1.0.0" - base64-sol "1.0.1" - hardhat-watcher "^2.1.1" - -"@uniswap/v3-sdk@^3.9.0": - version "3.9.0" - resolved "https://registry.yarnpkg.com/@uniswap/v3-sdk/-/v3-sdk-3.9.0.tgz#de93fa19f89c29d460996aa4d0b4bb6531641105" - integrity sha512-LuoF3UcY1DxSAQKJ3E4/1Eq4HaNp+x+7q9mvbpiu+/PBj+O1DjLforAMrKxu+RsA0aarmZtz7yBnAPy+akgfgQ== - dependencies: - "@ethersproject/abi" "^5.0.12" - "@ethersproject/solidity" "^5.0.9" - "@uniswap/sdk-core" "^3.0.1" - "@uniswap/swap-router-contracts" "^1.2.1" - "@uniswap/v3-periphery" "^1.1.1" - "@uniswap/v3-staker" "1.0.0" - tiny-invariant "^1.1.0" - tiny-warning "^1.0.3" - -"@uniswap/v3-staker@1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@uniswap/v3-staker/-/v3-staker-1.0.0.tgz#9a6915ec980852479dfc903f50baf822ff8fa66e" - integrity sha512-JV0Qc46Px5alvg6YWd+UIaGH9lDuYG/Js7ngxPit1SPaIP30AlVer1UYB7BRYeUVVxE+byUyIeN5jeQ7LLDjIw== - dependencies: - "@openzeppelin/contracts" "3.4.1-solc-0.7-2" - "@uniswap/v3-core" "1.0.0" - "@uniswap/v3-periphery" "^1.0.1" - -acorn-jsx@^5.3.2: - version "5.3.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" - integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== - -acorn@^8.7.1: - version "8.7.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" - integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== - -aes-js@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" - integrity sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0= - -ajv-formats@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" - integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== - dependencies: - ajv "^8.0.0" - -ajv@^6.10.0, ajv@^6.12.4: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ajv@^8.0.0: - version "8.9.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.9.0.tgz#738019146638824dea25edcf299dcba1b0e7eb18" - integrity sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ== - dependencies: - fast-deep-equal "^3.1.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - uri-js "^4.2.2" - -ajv@^8.11.0: - version "8.11.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" - integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== - dependencies: - fast-deep-equal "^3.1.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - uri-js "^4.2.2" - -ansi-escapes@^4.2.1: - version "4.3.2" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" - integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== - dependencies: - type-fest "^0.21.3" - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -ansi-styles@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" - integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== - -anymatch@^3.0.3, anymatch@~3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" - integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -argparse@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" - integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== - -array-includes@^3.1.4: - version "3.1.4" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.4.tgz#f5b493162c760f3539631f005ba2bb46acb45ba9" - integrity sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - get-intrinsic "^1.1.1" - is-string "^1.0.7" - -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - -array.prototype.flat@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz#07e0975d84bbc7c48cd1879d609e682598d33e13" - integrity sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.0" - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== - -axios@^0.27.2: - version "0.27.2" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972" - integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ== - dependencies: - follow-redirects "^1.14.9" - form-data "^4.0.0" - -babel-jest@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.5.0.tgz#3fe3ddb109198e78b1c88f9ebdecd5e4fc2f50a5" - integrity sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q== - dependencies: - "@jest/transform" "^29.5.0" - "@types/babel__core" "^7.1.14" - babel-plugin-istanbul "^6.1.1" - babel-preset-jest "^29.5.0" - chalk "^4.0.0" - graceful-fs "^4.2.9" - slash "^3.0.0" - -babel-plugin-istanbul@^6.1.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" - integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@istanbuljs/load-nyc-config" "^1.0.0" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-instrument "^5.0.4" - test-exclude "^6.0.0" - -babel-plugin-jest-hoist@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz#a97db437936f441ec196990c9738d4b88538618a" - integrity sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w== - dependencies: - "@babel/template" "^7.3.3" - "@babel/types" "^7.3.3" - "@types/babel__core" "^7.1.14" - "@types/babel__traverse" "^7.0.6" - -babel-preset-current-node-syntax@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" - integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== - dependencies: - "@babel/plugin-syntax-async-generators" "^7.8.4" - "@babel/plugin-syntax-bigint" "^7.8.3" - "@babel/plugin-syntax-class-properties" "^7.8.3" - "@babel/plugin-syntax-import-meta" "^7.8.3" - "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.8.3" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-top-level-await" "^7.8.3" - -babel-preset-jest@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz#57bc8cc88097af7ff6a5ab59d1cd29d52a5916e2" - integrity sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg== - dependencies: - babel-plugin-jest-hoist "^29.5.0" - babel-preset-current-node-syntax "^1.0.0" - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -base64-sol@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/base64-sol/-/base64-sol-1.0.1.tgz#91317aa341f0bc763811783c5729f1c2574600f6" - integrity sha512-ld3cCNMeXt4uJXmLZBHFGMvVpK9KsLVEhPpFRXnvSVAqABKbuNZg/+dsq3NuM+wxFLb/UrVkz7m1ciWmkMfTbg== - -bech32@1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" - integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== - -big.js@^5.2.2: - version "5.2.2" - resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" - integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== - -binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" - integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== - -blakejs@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.2.1.tgz#5057e4206eadb4a97f7c0b6e197a505042fc3814" - integrity sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ== - -bn.js@^4.11.9: - version "4.12.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== - -bn.js@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" - integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^3.0.1, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - dependencies: - fill-range "^7.0.1" - -brorand@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= - -browserslist@^4.20.2: - version "4.20.4" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.4.tgz#98096c9042af689ee1e0271333dbc564b8ce4477" - integrity sha512-ok1d+1WpnU24XYN7oC3QWgTyMhY/avPJ/r9T00xxvUOIparA/gc+UPUMaod3i+G6s+nI2nUb9xZ5k794uIwShw== - dependencies: - caniuse-lite "^1.0.30001349" - electron-to-chromium "^1.4.147" - escalade "^3.1.1" - node-releases "^2.0.5" - picocolors "^1.0.0" - -bs-logger@0.x: - version "0.2.6" - resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" - integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== - dependencies: - fast-json-stable-stringify "2.x" - -bser@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" - integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== - dependencies: - node-int64 "^0.4.0" - -buffer-from@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" - integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== - -call-bind@^1.0.0, call-bind@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== - dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -camelcase@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - -camelcase@^6.2.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" - integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== - -caniuse-lite@^1.0.30001349: - version "1.0.30001357" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001357.tgz#dec7fc4158ef6ad24690d0eec7b91f32b8cb1b5d" - integrity sha512-b+KbWHdHePp+ZpNj+RDHFChZmuN+J5EvuQUlee9jOQIUAdhv9uvAZeEtUeLAknXbkiu1uxjQ9NLp1ie894CuWg== - -chalk@^2.0.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^4.0.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -char-regex@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" - integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== - -chokidar@^3.4.3: - version "3.5.3" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" - integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" - -ci-info@^3.2.0: - version "3.3.2" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.2.tgz#6d2967ffa407466481c6c90b6e16b3098f080128" - integrity sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg== - -cjs-module-lexer@^1.0.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" - integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== - -cliui@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" - integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^7.0.0" - -co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== - -collect-v8-coverage@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" - integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -combined-stream@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== - -confusing-browser-globals@^1.0.10: - version "1.0.11" - resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz#ae40e9b57cdd3915408a2805ebd3a5585608dc81" - integrity sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA== - -convert-source-map@^1.6.0, convert-source-map@^1.7.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" - integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== - dependencies: - safe-buffer "~5.1.1" - -convert-source-map@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" - integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== - -copyfiles@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/copyfiles/-/copyfiles-2.4.1.tgz#d2dcff60aaad1015f09d0b66e7f0f1c5cd3c5da5" - integrity sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg== - dependencies: - glob "^7.0.5" - minimatch "^3.0.3" - mkdirp "^1.0.4" - noms "0.0.0" - through2 "^2.0.1" - untildify "^4.0.0" - yargs "^16.1.0" - -core-util-is@~1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" - integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== - -cross-fetch@^3.1.6: - version "3.1.6" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.6.tgz#bae05aa31a4da760969756318feeee6e70f15d6c" - integrity sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g== - dependencies: - node-fetch "^2.6.11" - -cross-spawn@^7.0.2, cross-spawn@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -debug@^2.6.9: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@^3.2.7: - version "3.2.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" - integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== - dependencies: - ms "^2.1.1" - -debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - -decimal.js-light@^2.5.0: - version "2.5.1" - resolved "https://registry.yarnpkg.com/decimal.js-light/-/decimal.js-light-2.5.1.tgz#134fd32508f19e208f4fb2f8dac0d2626a867934" - integrity sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg== - -dedent@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" - integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== - -deep-is@^0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" - integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== - -deepmerge@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" - integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== - -define-properties@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== - dependencies: - object-keys "^1.0.12" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== - -detect-newline@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" - integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== - -diff-sequences@^29.4.3: - version "29.4.3" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.3.tgz#9314bc1fabe09267ffeca9cbafc457d8499a13f2" - integrity sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA== - -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - -doctrine@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" - integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== - dependencies: - esutils "^2.0.2" - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - -dotenv@^14.2.0: - version "14.3.2" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-14.3.2.tgz#7c30b3a5f777c79a3429cb2db358eef6751e8369" - integrity sha512-vwEppIphpFdvaMCaHfCEv9IgwcxMljMw2TnAQBB4VWPvzXQLTb82jwmdOKzlEVUL3gNFT4l4TPKO+Bn+sqcrVQ== - -dotenv@^16.0.3: - version "16.0.3" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.3.tgz#115aec42bac5053db3c456db30cc243a5a836a07" - integrity sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ== - -electron-to-chromium@^1.4.147: - version "1.4.161" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.161.tgz#49cb5b35385bfee6cc439d0a04fbba7a7a7f08a1" - integrity sha512-sTjBRhqh6wFodzZtc5Iu8/R95OkwaPNn7tj/TaDU5nu/5EFiQDtADGAXdR4tJcTEHlYfJpHqigzJqHvPgehP8A== - -elliptic@6.5.4: - version "6.5.4" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" - integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== - dependencies: - bn.js "^4.11.9" - brorand "^1.1.0" - hash.js "^1.0.0" - hmac-drbg "^1.0.1" - inherits "^2.0.4" - minimalistic-assert "^1.0.1" - minimalistic-crypto-utils "^1.0.1" - -emittery@^0.13.1: - version "0.13.1" - resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" - integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== - dependencies: - is-arrayish "^0.2.1" - -es-abstract@^1.19.0, es-abstract@^1.19.1: - version "1.19.1" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" - integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w== - dependencies: - call-bind "^1.0.2" - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - get-intrinsic "^1.1.1" - get-symbol-description "^1.0.0" - has "^1.0.3" - has-symbols "^1.0.2" - internal-slot "^1.0.3" - is-callable "^1.2.4" - is-negative-zero "^2.0.1" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.1" - is-string "^1.0.7" - is-weakref "^1.0.1" - object-inspect "^1.11.0" - object-keys "^1.1.1" - object.assign "^4.1.2" - string.prototype.trimend "^1.0.4" - string.prototype.trimstart "^1.0.4" - unbox-primitive "^1.0.1" - -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== - -escape-string-regexp@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" - integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== - -escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - -eslint-config-airbnb-base@^15.0.0: - version "15.0.0" - resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz#6b09add90ac79c2f8d723a2580e07f3925afd236" - integrity sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig== - dependencies: - confusing-browser-globals "^1.0.10" - object.assign "^4.1.2" - object.entries "^1.1.5" - semver "^6.3.0" - -eslint-import-resolver-node@^0.3.6: - version "0.3.6" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd" - integrity sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw== - dependencies: - debug "^3.2.7" - resolve "^1.20.0" - -eslint-module-utils@^2.7.3: - version "2.7.3" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz#ad7e3a10552fdd0642e1e55292781bd6e34876ee" - integrity sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ== - dependencies: - debug "^3.2.7" - find-up "^2.1.0" - -eslint-plugin-import@^2.26.0: - version "2.26.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz#f812dc47be4f2b72b478a021605a59fc6fe8b88b" - integrity sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA== - dependencies: - array-includes "^3.1.4" - array.prototype.flat "^1.2.5" - debug "^2.6.9" - doctrine "^2.1.0" - eslint-import-resolver-node "^0.3.6" - eslint-module-utils "^2.7.3" - has "^1.0.3" - is-core-module "^2.8.1" - is-glob "^4.0.3" - minimatch "^3.1.2" - object.values "^1.1.5" - resolve "^1.22.0" - tsconfig-paths "^3.14.1" - -eslint-plugin-prettier@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz#651cbb88b1dab98bfd42f017a12fa6b2d993f94b" - integrity sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ== - dependencies: - prettier-linter-helpers "^1.0.0" - -eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - -eslint-scope@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" - integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== - dependencies: - esrecurse "^4.3.0" - estraverse "^5.2.0" - -eslint-utils@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" - integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== - dependencies: - eslint-visitor-keys "^2.0.0" - -eslint-visitor-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" - integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== - -eslint-visitor-keys@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" - integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== - -eslint@^8.19.0: - version "8.19.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.19.0.tgz#7342a3cbc4fbc5c106a1eefe0fd0b50b6b1a7d28" - integrity sha512-SXOPj3x9VKvPe81TjjUJCYlV4oJjQw68Uek+AM0X4p+33dj2HY5bpTZOgnQHcG2eAm1mtCU9uNMnJi7exU/kYw== - dependencies: - "@eslint/eslintrc" "^1.3.0" - "@humanwhocodes/config-array" "^0.9.2" - ajv "^6.10.0" - chalk "^4.0.0" - cross-spawn "^7.0.2" - debug "^4.3.2" - doctrine "^3.0.0" - escape-string-regexp "^4.0.0" - eslint-scope "^7.1.1" - eslint-utils "^3.0.0" - eslint-visitor-keys "^3.3.0" - espree "^9.3.2" - esquery "^1.4.0" - esutils "^2.0.2" - fast-deep-equal "^3.1.3" - file-entry-cache "^6.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^6.0.1" - globals "^13.15.0" - ignore "^5.2.0" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - is-glob "^4.0.0" - js-yaml "^4.1.0" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" - lodash.merge "^4.6.2" - minimatch "^3.1.2" - natural-compare "^1.4.0" - optionator "^0.9.1" - regexpp "^3.2.0" - strip-ansi "^6.0.1" - strip-json-comments "^3.1.0" - text-table "^0.2.0" - v8-compile-cache "^2.0.3" - -espree@^9.3.2: - version "9.3.2" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.2.tgz#f58f77bd334731182801ced3380a8cc859091596" - integrity sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA== - dependencies: - acorn "^8.7.1" - acorn-jsx "^5.3.2" - eslint-visitor-keys "^3.3.0" - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esquery@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" - integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - -estraverse@^5.1.0, estraverse@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -eth-ens-namehash@^2.0.8: - version "2.0.8" - resolved "https://registry.yarnpkg.com/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz#229ac46eca86d52e0c991e7cb2aef83ff0f68bcf" - integrity sha1-IprEbsqG1S4MmR58sq74P/D2i88= - dependencies: - idna-uts46-hx "^2.3.1" - js-sha3 "^0.5.7" - -execa@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" - integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.0" - human-signals "^2.1.0" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.1" - onetime "^5.1.2" - signal-exit "^3.0.3" - strip-final-newline "^2.0.0" - -exit@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" - integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== - -expect@^29.0.0, expect@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/expect/-/expect-29.5.0.tgz#68c0509156cb2a0adb8865d413b137eeaae682f7" - integrity sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg== - dependencies: - "@jest/expect-utils" "^29.5.0" - jest-get-type "^29.4.3" - jest-matcher-utils "^29.5.0" - jest-message-util "^29.5.0" - jest-util "^29.5.0" - -fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-diff@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" - integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== - -fast-glob@^3.2.9: - version "3.2.11" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" - integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.4" - -fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fast-levenshtein@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== - -fastq@^1.6.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" - integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== - dependencies: - reusify "^1.0.4" - -fb-watchman@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" - integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== - dependencies: - bser "2.1.1" - -file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== - dependencies: - flat-cache "^3.0.4" - -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - dependencies: - to-regex-range "^5.0.1" - -find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= - dependencies: - locate-path "^2.0.0" - -find-up@^4.0.0, find-up@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" - integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== - dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" - -flat-cache@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" - integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== - dependencies: - flatted "^3.1.0" - rimraf "^3.0.2" - -flatted@^3.1.0: - version "3.2.6" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.6.tgz#022e9218c637f9f3fc9c35ab9c9193f05add60b2" - integrity sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ== - -follow-redirects@^1.14.9: - version "1.15.2" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" - integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== - -form-data@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" - integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== - -fsevents@^2.3.2, fsevents@~2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - -gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== - -get-caller-file@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - -get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" - integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - -get-package-type@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" - integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== - -get-stream@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" - integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== - -get-symbol-description@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" - integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" - -glob-parent@^5.1.2, glob-parent@~5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -glob-parent@^6.0.1: - version "6.0.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" - integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== - dependencies: - is-glob "^4.0.3" - -glob@^7.0.5: - version "7.2.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" - integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@^7.1.3, glob@^7.1.4: - version "7.2.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" - integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.1.1" - once "^1.3.0" - path-is-absolute "^1.0.0" - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -globals@^13.15.0: - version "13.16.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.16.0.tgz#9be4aca28f311aaeb974ea54978ebbb5e35ce46a" - integrity sha512-A1lrQfpNF+McdPOnnFqY3kSN0AFTy485bTi1bkLk4mVPODIUEcSfhHgRqA+QdXPksrSTTztYXx37NFV+GpGk3Q== - dependencies: - type-fest "^0.20.2" - -globby@^11.1.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" - integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.2.9" - ignore "^5.2.0" - merge2 "^1.4.1" - slash "^3.0.0" - -graceful-fs@^4.2.9: - version "4.2.10" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" - integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== - -hardhat-watcher@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/hardhat-watcher/-/hardhat-watcher-2.1.1.tgz#8b05fec429ed45da11808bbf6054a90f3e34c51a" - integrity sha512-zilmvxAYD34IofBrwOliQn4z92UiDmt2c949DW4Gokf0vS0qk4YTfVCi/LmUBICThGygNANE3WfnRTpjCJGtDA== - dependencies: - chokidar "^3.4.3" - -has-bigints@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" - integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -has-symbols@^1.0.1, has-symbols@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" - integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== - -has-tostringtag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" - integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== - dependencies: - has-symbols "^1.0.2" - -has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - -hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" - integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" - -hmac-drbg@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - -html-escaper@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" - integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== - -human-signals@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" - integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== - -idna-uts46-hx@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz#a1dc5c4df37eee522bf66d969cc980e00e8711f9" - integrity sha512-PWoF9Keq6laYdIRwwCdhTPl60xRqAloYNMQLiyUnG42VjT53oW07BXIRM+NK7eQjzXjAk2gUvX9caRxlnF9TAA== - dependencies: - punycode "2.1.0" - -ignore@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" - integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== - -import-fresh@^3.0.0, import-fresh@^3.2.1: - version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -import-local@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" - integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== - dependencies: - pkg-dir "^4.2.0" - resolve-cwd "^3.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -internal-slot@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" - integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== - dependencies: - get-intrinsic "^1.1.0" - has "^1.0.3" - side-channel "^1.0.4" - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== - -is-bigint@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" - integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== - dependencies: - has-bigints "^1.0.1" - -is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" - integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== - dependencies: - binary-extensions "^2.0.0" - -is-boolean-object@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" - integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-callable@^1.1.4, is-callable@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" - integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== - -is-core-module@^2.8.0, is-core-module@^2.8.1, is-core-module@^2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69" - integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A== - dependencies: - has "^1.0.3" - -is-date-object@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" - integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== - dependencies: - has-tostringtag "^1.0.0" - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-generator-fn@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" - integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== - -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" - integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - dependencies: - is-extglob "^2.1.1" - -is-negative-zero@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" - integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== - -is-number-object@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" - integrity sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g== - dependencies: - has-tostringtag "^1.0.0" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -is-regex@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" - integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-shared-array-buffer@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" - integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== - -is-stream@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" - integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== - -is-string@^1.0.5, is-string@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" - integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== - dependencies: - has-tostringtag "^1.0.0" - -is-symbol@^1.0.2, is-symbol@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" - integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== - dependencies: - has-symbols "^1.0.2" - -is-weakref@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" - integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== - dependencies: - call-bind "^1.0.2" - -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= - -isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== - -istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" - integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== - -istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz#31d18bdd127f825dd02ea7bfdfd906f8ab840e9f" - integrity sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A== - dependencies: - "@babel/core" "^7.12.3" - "@babel/parser" "^7.14.7" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.2.0" - semver "^6.3.0" - -istanbul-lib-report@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" - integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== - dependencies: - istanbul-lib-coverage "^3.0.0" - make-dir "^3.0.0" - supports-color "^7.1.0" - -istanbul-lib-source-maps@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" - integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== - dependencies: - debug "^4.1.1" - istanbul-lib-coverage "^3.0.0" - source-map "^0.6.1" - -istanbul-reports@^3.1.3: - version "3.1.4" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.4.tgz#1b6f068ecbc6c331040aab5741991273e609e40c" - integrity sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw== - dependencies: - html-escaper "^2.0.0" - istanbul-lib-report "^3.0.0" - -jest-changed-files@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.5.0.tgz#e88786dca8bf2aa899ec4af7644e16d9dcf9b23e" - integrity sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag== - dependencies: - execa "^5.0.0" - p-limit "^3.1.0" - -jest-circus@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.5.0.tgz#b5926989449e75bff0d59944bae083c9d7fb7317" - integrity sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA== - dependencies: - "@jest/environment" "^29.5.0" - "@jest/expect" "^29.5.0" - "@jest/test-result" "^29.5.0" - "@jest/types" "^29.5.0" - "@types/node" "*" - chalk "^4.0.0" - co "^4.6.0" - dedent "^0.7.0" - is-generator-fn "^2.0.0" - jest-each "^29.5.0" - jest-matcher-utils "^29.5.0" - jest-message-util "^29.5.0" - jest-runtime "^29.5.0" - jest-snapshot "^29.5.0" - jest-util "^29.5.0" - p-limit "^3.1.0" - pretty-format "^29.5.0" - pure-rand "^6.0.0" - slash "^3.0.0" - stack-utils "^2.0.3" - -jest-cli@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.5.0.tgz#b34c20a6d35968f3ee47a7437ff8e53e086b4a67" - integrity sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw== - dependencies: - "@jest/core" "^29.5.0" - "@jest/test-result" "^29.5.0" - "@jest/types" "^29.5.0" - chalk "^4.0.0" - exit "^0.1.2" - graceful-fs "^4.2.9" - import-local "^3.0.2" - jest-config "^29.5.0" - jest-util "^29.5.0" - jest-validate "^29.5.0" - prompts "^2.0.1" - yargs "^17.3.1" - -jest-config@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.5.0.tgz#3cc972faec8c8aaea9ae158c694541b79f3748da" - integrity sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA== - dependencies: - "@babel/core" "^7.11.6" - "@jest/test-sequencer" "^29.5.0" - "@jest/types" "^29.5.0" - babel-jest "^29.5.0" - chalk "^4.0.0" - ci-info "^3.2.0" - deepmerge "^4.2.2" - glob "^7.1.3" - graceful-fs "^4.2.9" - jest-circus "^29.5.0" - jest-environment-node "^29.5.0" - jest-get-type "^29.4.3" - jest-regex-util "^29.4.3" - jest-resolve "^29.5.0" - jest-runner "^29.5.0" - jest-util "^29.5.0" - jest-validate "^29.5.0" - micromatch "^4.0.4" - parse-json "^5.2.0" - pretty-format "^29.5.0" - slash "^3.0.0" - strip-json-comments "^3.1.1" - -jest-diff@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.5.0.tgz#e0d83a58eb5451dcc1fa61b1c3ee4e8f5a290d63" - integrity sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw== - dependencies: - chalk "^4.0.0" - diff-sequences "^29.4.3" - jest-get-type "^29.4.3" - pretty-format "^29.5.0" - -jest-docblock@^29.4.3: - version "29.4.3" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.4.3.tgz#90505aa89514a1c7dceeac1123df79e414636ea8" - integrity sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg== - dependencies: - detect-newline "^3.0.0" - -jest-each@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.5.0.tgz#fc6e7014f83eac68e22b7195598de8554c2e5c06" - integrity sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA== - dependencies: - "@jest/types" "^29.5.0" - chalk "^4.0.0" - jest-get-type "^29.4.3" - jest-util "^29.5.0" - pretty-format "^29.5.0" - -jest-environment-node@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.5.0.tgz#f17219d0f0cc0e68e0727c58b792c040e332c967" - integrity sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw== - dependencies: - "@jest/environment" "^29.5.0" - "@jest/fake-timers" "^29.5.0" - "@jest/types" "^29.5.0" - "@types/node" "*" - jest-mock "^29.5.0" - jest-util "^29.5.0" - -jest-get-type@^29.4.3: - version "29.4.3" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.4.3.tgz#1ab7a5207c995161100b5187159ca82dd48b3dd5" - integrity sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg== - -jest-haste-map@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.5.0.tgz#69bd67dc9012d6e2723f20a945099e972b2e94de" - integrity sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA== - dependencies: - "@jest/types" "^29.5.0" - "@types/graceful-fs" "^4.1.3" - "@types/node" "*" - anymatch "^3.0.3" - fb-watchman "^2.0.0" - graceful-fs "^4.2.9" - jest-regex-util "^29.4.3" - jest-util "^29.5.0" - jest-worker "^29.5.0" - micromatch "^4.0.4" - walker "^1.0.8" - optionalDependencies: - fsevents "^2.3.2" - -jest-leak-detector@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz#cf4bdea9615c72bac4a3a7ba7e7930f9c0610c8c" - integrity sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow== - dependencies: - jest-get-type "^29.4.3" - pretty-format "^29.5.0" - -jest-matcher-utils@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz#d957af7f8c0692c5453666705621ad4abc2c59c5" - integrity sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw== - dependencies: - chalk "^4.0.0" - jest-diff "^29.5.0" - jest-get-type "^29.4.3" - pretty-format "^29.5.0" - -jest-message-util@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.5.0.tgz#1f776cac3aca332ab8dd2e3b41625435085c900e" - integrity sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA== - dependencies: - "@babel/code-frame" "^7.12.13" - "@jest/types" "^29.5.0" - "@types/stack-utils" "^2.0.0" - chalk "^4.0.0" - graceful-fs "^4.2.9" - micromatch "^4.0.4" - pretty-format "^29.5.0" - slash "^3.0.0" - stack-utils "^2.0.3" - -jest-mock@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.5.0.tgz#26e2172bcc71d8b0195081ff1f146ac7e1518aed" - integrity sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw== - dependencies: - "@jest/types" "^29.5.0" - "@types/node" "*" - jest-util "^29.5.0" - -jest-pnp-resolver@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" - integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== - -jest-regex-util@^29.4.3: - version "29.4.3" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.4.3.tgz#a42616141e0cae052cfa32c169945d00c0aa0bb8" - integrity sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg== - -jest-resolve-dependencies@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz#f0ea29955996f49788bf70996052aa98e7befee4" - integrity sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg== - dependencies: - jest-regex-util "^29.4.3" - jest-snapshot "^29.5.0" - -jest-resolve@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.5.0.tgz#b053cc95ad1d5f6327f0ac8aae9f98795475ecdc" - integrity sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w== - dependencies: - chalk "^4.0.0" - graceful-fs "^4.2.9" - jest-haste-map "^29.5.0" - jest-pnp-resolver "^1.2.2" - jest-util "^29.5.0" - jest-validate "^29.5.0" - resolve "^1.20.0" - resolve.exports "^2.0.0" - slash "^3.0.0" - -jest-runner@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.5.0.tgz#6a57c282eb0ef749778d444c1d758c6a7693b6f8" - integrity sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ== - dependencies: - "@jest/console" "^29.5.0" - "@jest/environment" "^29.5.0" - "@jest/test-result" "^29.5.0" - "@jest/transform" "^29.5.0" - "@jest/types" "^29.5.0" - "@types/node" "*" - chalk "^4.0.0" - emittery "^0.13.1" - graceful-fs "^4.2.9" - jest-docblock "^29.4.3" - jest-environment-node "^29.5.0" - jest-haste-map "^29.5.0" - jest-leak-detector "^29.5.0" - jest-message-util "^29.5.0" - jest-resolve "^29.5.0" - jest-runtime "^29.5.0" - jest-util "^29.5.0" - jest-watcher "^29.5.0" - jest-worker "^29.5.0" - p-limit "^3.1.0" - source-map-support "0.5.13" - -jest-runtime@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.5.0.tgz#c83f943ee0c1da7eb91fa181b0811ebd59b03420" - integrity sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw== - dependencies: - "@jest/environment" "^29.5.0" - "@jest/fake-timers" "^29.5.0" - "@jest/globals" "^29.5.0" - "@jest/source-map" "^29.4.3" - "@jest/test-result" "^29.5.0" - "@jest/transform" "^29.5.0" - "@jest/types" "^29.5.0" - "@types/node" "*" - chalk "^4.0.0" - cjs-module-lexer "^1.0.0" - collect-v8-coverage "^1.0.0" - glob "^7.1.3" - graceful-fs "^4.2.9" - jest-haste-map "^29.5.0" - jest-message-util "^29.5.0" - jest-mock "^29.5.0" - jest-regex-util "^29.4.3" - jest-resolve "^29.5.0" - jest-snapshot "^29.5.0" - jest-util "^29.5.0" - slash "^3.0.0" - strip-bom "^4.0.0" - -jest-snapshot@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.5.0.tgz#c9c1ce0331e5b63cd444e2f95a55a73b84b1e8ce" - integrity sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g== - dependencies: - "@babel/core" "^7.11.6" - "@babel/generator" "^7.7.2" - "@babel/plugin-syntax-jsx" "^7.7.2" - "@babel/plugin-syntax-typescript" "^7.7.2" - "@babel/traverse" "^7.7.2" - "@babel/types" "^7.3.3" - "@jest/expect-utils" "^29.5.0" - "@jest/transform" "^29.5.0" - "@jest/types" "^29.5.0" - "@types/babel__traverse" "^7.0.6" - "@types/prettier" "^2.1.5" - babel-preset-current-node-syntax "^1.0.0" - chalk "^4.0.0" - expect "^29.5.0" - graceful-fs "^4.2.9" - jest-diff "^29.5.0" - jest-get-type "^29.4.3" - jest-matcher-utils "^29.5.0" - jest-message-util "^29.5.0" - jest-util "^29.5.0" - natural-compare "^1.4.0" - pretty-format "^29.5.0" - semver "^7.3.5" - -jest-util@^29.0.0, jest-util@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.5.0.tgz#24a4d3d92fc39ce90425311b23c27a6e0ef16b8f" - integrity sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ== - dependencies: - "@jest/types" "^29.5.0" - "@types/node" "*" - chalk "^4.0.0" - ci-info "^3.2.0" - graceful-fs "^4.2.9" - picomatch "^2.2.3" - -jest-validate@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.5.0.tgz#8e5a8f36178d40e47138dc00866a5f3bd9916ffc" - integrity sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ== - dependencies: - "@jest/types" "^29.5.0" - camelcase "^6.2.0" - chalk "^4.0.0" - jest-get-type "^29.4.3" - leven "^3.1.0" - pretty-format "^29.5.0" - -jest-watcher@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.5.0.tgz#cf7f0f949828ba65ddbbb45c743a382a4d911363" - integrity sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA== - dependencies: - "@jest/test-result" "^29.5.0" - "@jest/types" "^29.5.0" - "@types/node" "*" - ansi-escapes "^4.2.1" - chalk "^4.0.0" - emittery "^0.13.1" - jest-util "^29.5.0" - string-length "^4.0.1" - -jest-worker@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.5.0.tgz#bdaefb06811bd3384d93f009755014d8acb4615d" - integrity sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA== - dependencies: - "@types/node" "*" - jest-util "^29.5.0" - merge-stream "^2.0.0" - supports-color "^8.0.0" - -jest@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest/-/jest-29.5.0.tgz#f75157622f5ce7ad53028f2f8888ab53e1f1f24e" - integrity sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ== - dependencies: - "@jest/core" "^29.5.0" - "@jest/types" "^29.5.0" - import-local "^3.0.2" - jest-cli "^29.5.0" - -js-sha3@0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" - integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== - -js-sha3@^0.5.7: - version "0.5.7" - resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" - integrity sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc= - -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -js-yaml@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== - dependencies: - argparse "^2.0.1" - -jsbi@^3.1.4: - version "3.2.5" - resolved "https://registry.yarnpkg.com/jsbi/-/jsbi-3.2.5.tgz#b37bb90e0e5c2814c1c2a1bcd8c729888a2e37d6" - integrity sha512-aBE4n43IPvjaddScbvWRA2YlTzKEynHzu7MqOyTipdHucf/VxS63ViCjxYRg86M8Rxwbt/GfzHl1kKERkt45fQ== - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -json-parse-even-better-errors@^2.3.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" - integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-schema-traverse@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" - integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= - -json-to-graphql-query@^2.2.4: - version "2.2.4" - resolved "https://registry.yarnpkg.com/json-to-graphql-query/-/json-to-graphql-query-2.2.4.tgz#ada9cfdbb9bf38589fd2661e1588d1edd0a882cc" - integrity sha512-vNvsOKDSlEqYCzejI1xHS9Hm738dSnG4Upy09LUGqyybZXSIIb7NydDphB/6WxW2EEVpPU4JeU/Yo63Nw9dEJg== - -json5@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" - integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== - dependencies: - minimist "^1.2.0" - -json5@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" - integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== - -json5@^2.2.3: - version "2.2.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" - integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== - -kleur@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" - integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== - -leven@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" - integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== - -levn@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" - integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== - dependencies: - prelude-ls "^1.2.1" - type-check "~0.4.0" - -lines-and-columns@^1.1.6: - version "1.2.4" - resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" - integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== - -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - -locate-path@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" - integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== - dependencies: - p-locate "^4.1.0" - -lodash.memoize@4.x: - version "4.1.2" - resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" - integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== - -lodash.merge@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" - integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== - -lodash.set@^4.3.2: - version "4.3.2" - resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23" - integrity sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM= - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -make-dir@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" - integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== - dependencies: - semver "^6.0.0" - -make-error@1.x: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - -makeerror@1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" - integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== - dependencies: - tmpl "1.0.5" - -merge-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" - integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== - -merge2@^1.3.0, merge2@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - -micromatch@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" - integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== - dependencies: - braces "^3.0.1" - picomatch "^2.2.3" - -mime-db@1.52.0: - version "1.52.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" - integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== - -mime-types@^2.1.12: - version "2.1.35" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" - integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== - dependencies: - mime-db "1.52.0" - -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - -minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" - integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== - -minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= - -minimatch@^3.0.3: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimist@^1.2.0, minimist@^1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" - integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== - -mkdirp@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -ms@^2.1.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== - -node-fetch@^2.6.11: - version "2.6.11" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.11.tgz#cde7fc71deef3131ef80a738919f999e6edfff25" - integrity sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w== - dependencies: - whatwg-url "^5.0.0" - -node-int64@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" - integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== - -node-releases@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.5.tgz#280ed5bc3eba0d96ce44897d8aee478bfb3d9666" - integrity sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q== - -noms@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/noms/-/noms-0.0.0.tgz#da8ebd9f3af9d6760919b27d9cdc8092a7332859" - integrity sha1-2o69nzr51nYJGbJ9nNyAkqczKFk= - dependencies: - inherits "^2.0.1" - readable-stream "~1.0.31" - -normalize-path@^3.0.0, normalize-path@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -npm-run-path@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" - integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== - dependencies: - path-key "^3.0.0" - -object-inspect@^1.11.0, object-inspect@^1.9.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" - integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== - -object-keys@^1.0.12, object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -object.assign@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" - integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - has-symbols "^1.0.1" - object-keys "^1.1.1" - -object.entries@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.5.tgz#e1acdd17c4de2cd96d5a08487cfb9db84d881861" - integrity sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - -object.values@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac" - integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== - dependencies: - wrappy "1" - -onetime@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - -optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== - dependencies: - deep-is "^0.1.3" - fast-levenshtein "^2.0.6" - levn "^0.4.1" - prelude-ls "^1.2.1" - type-check "^0.4.0" - word-wrap "^1.2.3" - -p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - dependencies: - p-try "^1.0.0" - -p-limit@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== - dependencies: - p-try "^2.0.0" - -p-limit@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" - integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== - dependencies: - yocto-queue "^0.1.0" - -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= - dependencies: - p-limit "^1.1.0" - -p-locate@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" - integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== - dependencies: - p-limit "^2.2.0" - -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= - -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - -parse-json@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" - integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== - dependencies: - "@babel/code-frame" "^7.0.0" - error-ex "^1.3.1" - json-parse-even-better-errors "^2.3.0" - lines-and-columns "^1.1.6" - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= - -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== - -path-key@^3.0.0, path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-parse@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== - -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: - version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - -pirates@^4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" - integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== - -pkg-dir@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" - integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== - dependencies: - find-up "^4.0.0" - -prelude-ls@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" - integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== - -prettier-linter-helpers@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" - integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== - dependencies: - fast-diff "^1.1.2" - -prettier@^2.7.1: - version "2.7.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" - integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== - -pretty-format@^29.0.0, pretty-format@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.5.0.tgz#283134e74f70e2e3e7229336de0e4fce94ccde5a" - integrity sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw== - dependencies: - "@jest/schemas" "^29.4.3" - ansi-styles "^5.0.0" - react-is "^18.0.0" - -process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" - integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== - -prompts@^2.0.1: - version "2.4.2" - resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" - integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== - dependencies: - kleur "^3.0.3" - sisteransi "^1.0.5" - -punycode@2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" - integrity sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0= - -punycode@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -pure-rand@^6.0.0: - version "6.0.2" - resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.0.2.tgz#a9c2ddcae9b68d736a8163036f088a2781c8b306" - integrity sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ== - -queue-microtask@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" - integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== - -react-is@^18.0.0: - version "18.2.0" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" - integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== - -readable-stream@~1.0.31: - version "1.0.34" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" - integrity sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw= - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readable-stream@~2.3.6: - version "2.3.7" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" - integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -readdirp@~3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" - integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== - dependencies: - picomatch "^2.2.1" - -regexpp@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" - integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== - -require-from-string@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" - integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== - -resolve-cwd@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" - integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== - dependencies: - resolve-from "^5.0.0" - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -resolve-from@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" - integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== - -resolve.exports@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" - integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== - -resolve@^1.20.0: - version "1.21.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.21.0.tgz#b51adc97f3472e6a5cf4444d34bc9d6b9037591f" - integrity sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA== - dependencies: - is-core-module "^2.8.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -resolve@^1.22.0: - version "1.22.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" - integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== - dependencies: - is-core-module "^2.9.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -run-parallel@^1.1.9: - version "1.2.0" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" - integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== - dependencies: - queue-microtask "^1.2.2" - -safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -scrypt-js@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" - integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== - -semver@7.x, semver@^7.3.7: - version "7.3.7" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" - integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== - dependencies: - lru-cache "^6.0.0" - -semver@^6.0.0, semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -semver@^7.3.5: - version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== - dependencies: - lru-cache "^6.0.0" - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== - dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" - -signal-exit@^3.0.3, signal-exit@^3.0.7: - version "3.0.7" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" - integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== - -sisteransi@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" - integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== - -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - -source-map-support@0.5.13: - version "0.5.13" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" - integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map@^0.6.0, source-map@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== - -stack-utils@^2.0.3: - version "2.0.5" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" - integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA== - dependencies: - escape-string-regexp "^2.0.0" - -string-length@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" - integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== - dependencies: - char-regex "^1.0.2" - strip-ansi "^6.0.0" - -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string.prototype.trimend@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" - integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -string.prototype.trimstart@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" - integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= - -strip-bom@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" - integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== - -strip-final-newline@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" - integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== - -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -supports-color@^8.0.0: - version "8.1.1" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== - dependencies: - has-flag "^4.0.0" - -supports-preserve-symlinks-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" - integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== - -test-exclude@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" - integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== - dependencies: - "@istanbuljs/schema" "^0.1.2" - glob "^7.1.4" - minimatch "^3.0.4" - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - -through2@^2.0.1: - version "2.0.5" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" - integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== - dependencies: - readable-stream "~2.3.6" - xtend "~4.0.1" - -tiny-invariant@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.2.0.tgz#a1141f86b672a9148c72e978a19a73b9b94a15a9" - integrity sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg== - -tiny-warning@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" - integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== - -tmpl@1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" - integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -toformat@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/toformat/-/toformat-2.0.0.tgz#7a043fd2dfbe9021a4e36e508835ba32056739d8" - integrity sha512-03SWBVop6nU8bpyZCx7SodpYznbZF5R4ljwNLBcTQzKOD9xuihRo/psX58llS1BMFhhAI08H3luot5GoXJz2pQ== - -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== - -ts-jest@^29.1.0: - version "29.1.0" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.1.0.tgz#4a9db4104a49b76d2b368ea775b6c9535c603891" - integrity sha512-ZhNr7Z4PcYa+JjMl62ir+zPiNJfXJN6E8hSLnaUKhOgqcn8vb3e537cpkd0FuAfRK3sR1LSqM1MOhliXNgOFPA== - dependencies: - bs-logger "0.x" - fast-json-stable-stringify "2.x" - jest-util "^29.0.0" - json5 "^2.2.3" - lodash.memoize "4.x" - make-error "1.x" - semver "7.x" - yargs-parser "^21.0.1" - -tsconfig-paths@^3.14.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" - integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ== - dependencies: - "@types/json5" "^0.0.29" - json5 "^1.0.1" - minimist "^1.2.6" - strip-bom "^3.0.0" - -tslib@^1.8.1: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - -tsutils@^3.21.0: - version "3.21.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" - integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== - dependencies: - tslib "^1.8.1" - -tulons@^0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/tulons/-/tulons-0.0.7.tgz#31677402ab51dc51478d375f90df76ea2ca8cbb9" - integrity sha512-JyL9Vn4PPG2TTEJS35yqQgAMLd3IX9pFIlbiLmv47HuHTo2F3ihYg2yfMqde4hqGY1nGk77iJ/lvsTbAURJ8rg== - dependencies: - axios "^0.27.2" - -type-check@^0.4.0, type-check@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" - integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== - dependencies: - prelude-ls "^1.2.1" - -type-detect@4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" - integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== - -type-fest@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - -type-fest@^0.21.3: - version "0.21.3" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" - integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== - -typescript@^4.7.4: - version "4.7.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235" - integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== - -unbox-primitive@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" - integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== - dependencies: - function-bind "^1.1.1" - has-bigints "^1.0.1" - has-symbols "^1.0.2" - which-boxed-primitive "^1.0.2" - -untildify@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" - integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== - -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - -util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - -v8-compile-cache@^2.0.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" - integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== - -v8-to-istanbul@^9.0.1: - version "9.0.1" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz#b6f994b0b5d4ef255e17a0d17dc444a9f5132fa4" - integrity sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w== - dependencies: - "@jridgewell/trace-mapping" "^0.3.12" - "@types/istanbul-lib-coverage" "^2.0.1" - convert-source-map "^1.6.0" - -walker@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" - integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== - dependencies: - makeerror "1.0.12" - -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== - -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" - -which-boxed-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" - integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== - dependencies: - is-bigint "^1.0.1" - is-boolean-object "^1.1.0" - is-number-object "^1.0.4" - is-string "^1.0.5" - is-symbol "^1.0.3" - -which@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -word-wrap@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== - -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== - -write-file-atomic@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" - integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== - dependencies: - imurmurhash "^0.1.4" - signal-exit "^3.0.7" - -ws@7.4.6: - version "7.4.6" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" - integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== - -xtend@~4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - -y18n@^5.0.5: - version "5.0.8" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" - integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yargs-parser@^20.2.2: - version "20.2.9" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" - integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== - -yargs-parser@^21.0.0, yargs-parser@^21.0.1: - version "21.0.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.1.tgz#0267f286c877a4f0f728fceb6f8a3e4cb95c6e35" - integrity sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg== - -yargs@^16.1.0: - version "16.2.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" - integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.0" - y18n "^5.0.5" - yargs-parser "^20.2.2" - -yargs@^17.3.1: - version "17.5.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.5.1.tgz#e109900cab6fcb7fd44b1d8249166feb0b36e58e" - integrity sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.3" - y18n "^5.0.5" - yargs-parser "^21.0.0" - -yocto-queue@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@^2.1.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" + integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== + dependencies: + "@jridgewell/gen-mapping" "^0.1.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" + integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== + dependencies: + "@babel/highlight" "^7.16.7" + +"@babel/compat-data@^7.17.10": + version "7.18.5" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.5.tgz#acac0c839e317038c73137fbb6ef71a1d6238471" + integrity sha512-BxhE40PVCBxVEJsSBhB6UWyAuqJRxGsAw8BdHMJ3AKGydcwuWW4kOO3HmqBQAdcq/OP+/DlTVxLvsCzRTnZuGg== + +"@babel/core@^7.11.6", "@babel/core@^7.12.3": + version "7.18.5" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.5.tgz#c597fa680e58d571c28dda9827669c78cdd7f000" + integrity sha512-MGY8vg3DxMnctw0LdvSEojOsumc70g0t18gNyUdAZqB1Rpd1Bqo/svHGvt+UJ6JcGX+DIekGFDxxIWofBxLCnQ== + dependencies: + "@ampproject/remapping" "^2.1.0" + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.18.2" + "@babel/helper-compilation-targets" "^7.18.2" + "@babel/helper-module-transforms" "^7.18.0" + "@babel/helpers" "^7.18.2" + "@babel/parser" "^7.18.5" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.18.5" + "@babel/types" "^7.18.4" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.1" + semver "^6.3.0" + +"@babel/generator@^7.18.2", "@babel/generator@^7.7.2": + version "7.18.2" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.2.tgz#33873d6f89b21efe2da63fe554460f3df1c5880d" + integrity sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw== + dependencies: + "@babel/types" "^7.18.2" + "@jridgewell/gen-mapping" "^0.3.0" + jsesc "^2.5.1" + +"@babel/helper-compilation-targets@^7.18.2": + version "7.18.2" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.2.tgz#67a85a10cbd5fc7f1457fec2e7f45441dc6c754b" + integrity sha512-s1jnPotJS9uQnzFtiZVBUxe67CuBa679oWFHpxYYnTpRL/1ffhyX44R9uYiXoa/pLXcY9H2moJta0iaanlk/rQ== + dependencies: + "@babel/compat-data" "^7.17.10" + "@babel/helper-validator-option" "^7.16.7" + browserslist "^4.20.2" + semver "^6.3.0" + +"@babel/helper-environment-visitor@^7.16.7", "@babel/helper-environment-visitor@^7.18.2": + version "7.18.2" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.2.tgz#8a6d2dedb53f6bf248e31b4baf38739ee4a637bd" + integrity sha512-14GQKWkX9oJzPiQQ7/J36FTXcD4kSp8egKjO9nINlSKiHITRA9q/R74qu8S9xlc/b/yjsJItQUeeh3xnGN0voQ== + +"@babel/helper-function-name@^7.17.9": + version "7.17.9" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz#136fcd54bc1da82fcb47565cf16fd8e444b1ff12" + integrity sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg== + dependencies: + "@babel/template" "^7.16.7" + "@babel/types" "^7.17.0" + +"@babel/helper-hoist-variables@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246" + integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-module-imports@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" + integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-module-transforms@^7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.18.0.tgz#baf05dec7a5875fb9235bd34ca18bad4e21221cd" + integrity sha512-kclUYSUBIjlvnzN2++K9f2qzYKFgjmnmjwL4zlmU5f8ZtzgWe8s0rUPSTGy2HmK4P8T52MQsS+HTQAgZd3dMEA== + dependencies: + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-simple-access" "^7.17.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/helper-validator-identifier" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.18.0" + "@babel/types" "^7.18.0" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.17.12", "@babel/helper-plugin-utils@^7.8.0": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.17.12.tgz#86c2347da5acbf5583ba0a10aed4c9bf9da9cf96" + integrity sha512-JDkf04mqtN3y4iAbO1hv9U2ARpPyPL1zqyWs/2WG1pgSq9llHFjStX5jdxb84himgJm+8Ng+x0oiWF/nw/XQKA== + +"@babel/helper-plugin-utils@^7.20.2": + version "7.21.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.21.5.tgz#345f2377d05a720a4e5ecfa39cbf4474a4daed56" + integrity sha512-0WDaIlXKOX/3KfBK/dwP1oQGiPh6rjMkT7HIRv7i5RR2VUMwrx5ZL0dwBkKx7+SW1zwNdgjHd34IMk5ZjTeHVg== + +"@babel/helper-simple-access@^7.17.7": + version "7.18.2" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.18.2.tgz#4dc473c2169ac3a1c9f4a51cfcd091d1c36fcff9" + integrity sha512-7LIrjYzndorDY88MycupkpQLKS1AFfsVRm2k/9PtKScSy5tZq0McZTj+DiMRynboZfIqOKvo03pmhTaUgiD6fQ== + dependencies: + "@babel/types" "^7.18.2" + +"@babel/helper-split-export-declaration@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b" + integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-validator-identifier@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" + integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== + +"@babel/helper-validator-option@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23" + integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ== + +"@babel/helpers@^7.18.2": + version "7.18.2" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.18.2.tgz#970d74f0deadc3f5a938bfa250738eb4ac889384" + integrity sha512-j+d+u5xT5utcQSzrh9p+PaJX94h++KN+ng9b9WEJq7pkUPAd61FGqhjuUEdfknb3E/uDBb7ruwEeKkIxNJPIrg== + dependencies: + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.18.2" + "@babel/types" "^7.18.2" + +"@babel/highlight@^7.16.7": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.17.12.tgz#257de56ee5afbd20451ac0a75686b6b404257351" + integrity sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.7", "@babel/parser@^7.18.5": + version "7.18.5" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.5.tgz#337062363436a893a2d22faa60be5bb37091c83c" + integrity sha512-YZWVaglMiplo7v8f1oMQ5ZPQr0vn7HPeZXxXWsxXJRjGVrzUFn9OxFQl1sb5wzfootjA/yChhW84BV+383FSOw== + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.8.3": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.7.2": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.21.4.tgz#f264ed7bf40ffc9ec239edabc17a50c4f5b6fea2" + integrity sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + +"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.7.2": + version "7.17.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.17.12.tgz#b54fc3be6de734a56b87508f99d6428b5b605a7b" + integrity sha512-TYY0SXFiO31YXtNg3HtFwNJHjLsAyIIhAhNWkQ5whPPS7HWUFlg9z0Ta4qAQNjQbP1wsSt/oKkmZ/4/WWdMUpw== + dependencies: + "@babel/helper-plugin-utils" "^7.17.12" + +"@babel/template@^7.16.7", "@babel/template@^7.3.3": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" + integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/parser" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/traverse@^7.18.0", "@babel/traverse@^7.18.2", "@babel/traverse@^7.18.5", "@babel/traverse@^7.7.2": + version "7.18.5" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.5.tgz#94a8195ad9642801837988ab77f36e992d9a20cd" + integrity sha512-aKXj1KT66sBj0vVzk6rEeAO6Z9aiiQ68wfDgge3nHhA/my6xMM/7HGQUNumKZaoa2qUPQ5whJG9aAifsxUKfLA== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.18.2" + "@babel/helper-environment-visitor" "^7.18.2" + "@babel/helper-function-name" "^7.17.9" + "@babel/helper-hoist-variables" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/parser" "^7.18.5" + "@babel/types" "^7.18.4" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.16.7", "@babel/types@^7.17.0", "@babel/types@^7.18.0", "@babel/types@^7.18.2", "@babel/types@^7.18.4", "@babel/types@^7.3.0", "@babel/types@^7.3.3": + version "7.18.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.4.tgz#27eae9b9fd18e9dccc3f9d6ad051336f307be354" + integrity sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + to-fast-properties "^2.0.0" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@ensdomains/eth-ens-namehash@^2.0.15": + version "2.0.15" + resolved "https://registry.yarnpkg.com/@ensdomains/eth-ens-namehash/-/eth-ens-namehash-2.0.15.tgz#5e5f2f24ba802aff8bc19edd822c9a11200cdf4a" + integrity sha512-JRDFP6+Hczb1E0/HhIg0PONgBYasfGfDheujmfxaZaAv/NAH4jE6Kf48WbqfRZdxt4IZI3jl3Ri7sZ1nP09lgw== + +"@eslint/eslintrc@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.0.tgz#29f92c30bb3e771e4a2048c95fa6855392dfac4f" + integrity sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.3.2" + globals "^13.15.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@ethersproject/abi@^5.0.12": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.5.0.tgz#fb52820e22e50b854ff15ce1647cc508d6660613" + integrity sha512-loW7I4AohP5KycATvc0MgujU6JyCHPqHdeoo9z3Nr9xEiNioxa65ccdm1+fsoJhkuhdRtfcL8cfyGamz2AxZ5w== + dependencies: + "@ethersproject/address" "^5.5.0" + "@ethersproject/bignumber" "^5.5.0" + "@ethersproject/bytes" "^5.5.0" + "@ethersproject/constants" "^5.5.0" + "@ethersproject/hash" "^5.5.0" + "@ethersproject/keccak256" "^5.5.0" + "@ethersproject/logger" "^5.5.0" + "@ethersproject/properties" "^5.5.0" + "@ethersproject/strings" "^5.5.0" + +"@ethersproject/abi@^5.6.3", "@ethersproject/abi@^5.6.4": + version "5.6.4" + resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.6.4.tgz#f6e01b6ed391a505932698ecc0d9e7a99ee60362" + integrity sha512-TTeZUlCeIHG6527/2goZA6gW5F8Emoc7MrZDC7hhP84aRGvW3TEdTnZR08Ls88YXM1m2SuK42Osw/jSi3uO8gg== + dependencies: + "@ethersproject/address" "^5.6.1" + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/constants" "^5.6.1" + "@ethersproject/hash" "^5.6.1" + "@ethersproject/keccak256" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/strings" "^5.6.1" + +"@ethersproject/abstract-provider@^5.5.0": + version "5.5.1" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.5.1.tgz#2f1f6e8a3ab7d378d8ad0b5718460f85649710c5" + integrity sha512-m+MA/ful6eKbxpr99xUYeRvLkfnlqzrF8SZ46d/xFB1A7ZVknYc/sXJG0RcufF52Qn2jeFj1hhcoQ7IXjNKUqg== + dependencies: + "@ethersproject/bignumber" "^5.5.0" + "@ethersproject/bytes" "^5.5.0" + "@ethersproject/logger" "^5.5.0" + "@ethersproject/networks" "^5.5.0" + "@ethersproject/properties" "^5.5.0" + "@ethersproject/transactions" "^5.5.0" + "@ethersproject/web" "^5.5.0" + +"@ethersproject/abstract-provider@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.6.1.tgz#02ddce150785caf0c77fe036a0ebfcee61878c59" + integrity sha512-BxlIgogYJtp1FS8Muvj8YfdClk3unZH0vRMVX791Z9INBNT/kuACZ9GzaY1Y4yFq+YSy6/w4gzj3HCRKrK9hsQ== + dependencies: + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/networks" "^5.6.3" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/transactions" "^5.6.2" + "@ethersproject/web" "^5.6.1" + +"@ethersproject/abstract-signer@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.5.0.tgz#590ff6693370c60ae376bf1c7ada59eb2a8dd08d" + integrity sha512-lj//7r250MXVLKI7sVarXAbZXbv9P50lgmJQGr2/is82EwEb8r7HrxsmMqAjTsztMYy7ohrIhGMIml+Gx4D3mA== + dependencies: + "@ethersproject/abstract-provider" "^5.5.0" + "@ethersproject/bignumber" "^5.5.0" + "@ethersproject/bytes" "^5.5.0" + "@ethersproject/logger" "^5.5.0" + "@ethersproject/properties" "^5.5.0" + +"@ethersproject/abstract-signer@^5.6.2": + version "5.6.2" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.6.2.tgz#491f07fc2cbd5da258f46ec539664713950b0b33" + integrity sha512-n1r6lttFBG0t2vNiI3HoWaS/KdOt8xyDjzlP2cuevlWLG6EX0OwcKLyG/Kp/cuwNxdy/ous+R/DEMdTUwWQIjQ== + dependencies: + "@ethersproject/abstract-provider" "^5.6.1" + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/properties" "^5.6.0" + +"@ethersproject/address@^5.0.2", "@ethersproject/address@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.5.0.tgz#bcc6f576a553f21f3dd7ba17248f81b473c9c78f" + integrity sha512-l4Nj0eWlTUh6ro5IbPTgbpT4wRbdH5l8CQf7icF7sb/SI3Nhd9Y9HzhonTSTi6CefI0necIw7LJqQPopPLZyWw== + dependencies: + "@ethersproject/bignumber" "^5.5.0" + "@ethersproject/bytes" "^5.5.0" + "@ethersproject/keccak256" "^5.5.0" + "@ethersproject/logger" "^5.5.0" + "@ethersproject/rlp" "^5.5.0" + +"@ethersproject/address@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.6.1.tgz#ab57818d9aefee919c5721d28cd31fd95eff413d" + integrity sha512-uOgF0kS5MJv9ZvCz7x6T2EXJSzotiybApn4XlOgoTX0xdtyVIJ7pF+6cGPxiEq/dpBiTfMiw7Yc81JcwhSYA0Q== + dependencies: + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/keccak256" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/rlp" "^5.6.1" + +"@ethersproject/base64@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.5.0.tgz#881e8544e47ed976930836986e5eb8fab259c090" + integrity sha512-tdayUKhU1ljrlHzEWbStXazDpsx4eg1dBXUSI6+mHlYklOXoXF6lZvw8tnD6oVaWfnMxAgRSKROg3cVKtCcppA== + dependencies: + "@ethersproject/bytes" "^5.5.0" + +"@ethersproject/base64@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.6.1.tgz#2c40d8a0310c9d1606c2c37ae3092634b41d87cb" + integrity sha512-qB76rjop6a0RIYYMiB4Eh/8n+Hxu2NIZm8S/Q7kNo5pmZfXhHGHmS4MinUainiBC54SCyRnwzL+KZjj8zbsSsw== + dependencies: + "@ethersproject/bytes" "^5.6.1" + +"@ethersproject/basex@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.6.1.tgz#badbb2f1d4a6f52ce41c9064f01eab19cc4c5305" + integrity sha512-a52MkVz4vuBXR06nvflPMotld1FJWSj2QT0985v7P/emPZO00PucFAkbcmq2vpVU7Ts7umKiSI6SppiLykVWsA== + dependencies: + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/properties" "^5.6.0" + +"@ethersproject/bignumber@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.5.0.tgz#875b143f04a216f4f8b96245bde942d42d279527" + integrity sha512-6Xytlwvy6Rn3U3gKEc1vP7nR92frHkv6wtVr95LFR3jREXiCPzdWxKQ1cx4JGQBXxcguAwjA8murlYN2TSiEbg== + dependencies: + "@ethersproject/bytes" "^5.5.0" + "@ethersproject/logger" "^5.5.0" + bn.js "^4.11.9" + +"@ethersproject/bignumber@^5.6.2": + version "5.6.2" + resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.6.2.tgz#72a0717d6163fab44c47bcc82e0c550ac0315d66" + integrity sha512-v7+EEUbhGqT3XJ9LMPsKvXYHFc8eHxTowFCG/HgJErmq4XHJ2WR7aeyICg3uTOAQ7Icn0GFHAohXEhxQHq4Ubw== + dependencies: + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + bn.js "^5.2.1" + +"@ethersproject/bignumber@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz#e2f03837f268ba655ffba03a57853e18a18dc9c2" + integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + bn.js "^5.2.1" + +"@ethersproject/bytes@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.5.0.tgz#cb11c526de657e7b45d2e0f0246fb3b9d29a601c" + integrity sha512-ABvc7BHWhZU9PNM/tANm/Qx4ostPGadAuQzWTr3doklZOhDlmcBqclrQe/ZXUIj3K8wC28oYeuRa+A37tX9kog== + dependencies: + "@ethersproject/logger" "^5.5.0" + +"@ethersproject/bytes@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.6.1.tgz#24f916e411f82a8a60412344bf4a813b917eefe7" + integrity sha512-NwQt7cKn5+ZE4uDn+X5RAXLp46E1chXoaMmrxAyA0rblpxz8t58lVkrHXoRIn0lz1joQElQ8410GqhTqMOwc6g== + dependencies: + "@ethersproject/logger" "^5.6.0" + +"@ethersproject/bytes@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.7.0.tgz#a00f6ea8d7e7534d6d87f47188af1148d71f155d" + integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/constants@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.5.0.tgz#d2a2cd7d94bd1d58377d1d66c4f53c9be4d0a45e" + integrity sha512-2MsRRVChkvMWR+GyMGY4N1sAX9Mt3J9KykCsgUFd/1mwS0UH1qw+Bv9k1UJb3X3YJYFco9H20pjSlOIfCG5HYQ== + dependencies: + "@ethersproject/bignumber" "^5.5.0" + +"@ethersproject/constants@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.6.1.tgz#e2e974cac160dd101cf79fdf879d7d18e8cb1370" + integrity sha512-QSq9WVnZbxXYFftrjSjZDUshp6/eKp6qrtdBtUCm0QxCV5z1fG/w3kdlcsjMCQuQHUnAclKoK7XpXMezhRDOLg== + dependencies: + "@ethersproject/bignumber" "^5.6.2" + +"@ethersproject/constants@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.7.0.tgz#df80a9705a7e08984161f09014ea012d1c75295e" + integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + +"@ethersproject/contracts@^5.6.2": + version "5.6.2" + resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.6.2.tgz#20b52e69ebc1b74274ff8e3d4e508de971c287bc" + integrity sha512-hguUA57BIKi6WY0kHvZp6PwPlWF87MCeB4B7Z7AbUpTxfFXFdn/3b0GmjZPagIHS+3yhcBJDnuEfU4Xz+Ks/8g== + dependencies: + "@ethersproject/abi" "^5.6.3" + "@ethersproject/abstract-provider" "^5.6.1" + "@ethersproject/abstract-signer" "^5.6.2" + "@ethersproject/address" "^5.6.1" + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/constants" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/transactions" "^5.6.2" + +"@ethersproject/hash@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.5.0.tgz#7cee76d08f88d1873574c849e0207dcb32380cc9" + integrity sha512-dnGVpK1WtBjmnp3mUT0PlU2MpapnwWI0PibldQEq1408tQBAbZpPidkWoVVuNMOl/lISO3+4hXZWCL3YV7qzfg== + dependencies: + "@ethersproject/abstract-signer" "^5.5.0" + "@ethersproject/address" "^5.5.0" + "@ethersproject/bignumber" "^5.5.0" + "@ethersproject/bytes" "^5.5.0" + "@ethersproject/keccak256" "^5.5.0" + "@ethersproject/logger" "^5.5.0" + "@ethersproject/properties" "^5.5.0" + "@ethersproject/strings" "^5.5.0" + +"@ethersproject/hash@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.6.1.tgz#224572ea4de257f05b4abf8ae58b03a67e99b0f4" + integrity sha512-L1xAHurbaxG8VVul4ankNX5HgQ8PNCTrnVXEiFnE9xoRnaUcgfD12tZINtDinSllxPLCtGwguQxJ5E6keE84pA== + dependencies: + "@ethersproject/abstract-signer" "^5.6.2" + "@ethersproject/address" "^5.6.1" + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/keccak256" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/strings" "^5.6.1" + +"@ethersproject/hdnode@^5.6.2": + version "5.6.2" + resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.6.2.tgz#26f3c83a3e8f1b7985c15d1db50dc2903418b2d2" + integrity sha512-tERxW8Ccf9CxW2db3WsN01Qao3wFeRsfYY9TCuhmG0xNpl2IO8wgXU3HtWIZ49gUWPggRy4Yg5axU0ACaEKf1Q== + dependencies: + "@ethersproject/abstract-signer" "^5.6.2" + "@ethersproject/basex" "^5.6.1" + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/pbkdf2" "^5.6.1" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/sha2" "^5.6.1" + "@ethersproject/signing-key" "^5.6.2" + "@ethersproject/strings" "^5.6.1" + "@ethersproject/transactions" "^5.6.2" + "@ethersproject/wordlists" "^5.6.1" + +"@ethersproject/json-wallets@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.6.1.tgz#3f06ba555c9c0d7da46756a12ac53483fe18dd91" + integrity sha512-KfyJ6Zwz3kGeX25nLihPwZYlDqamO6pfGKNnVMWWfEVVp42lTfCZVXXy5Ie8IZTN0HKwAngpIPi7gk4IJzgmqQ== + dependencies: + "@ethersproject/abstract-signer" "^5.6.2" + "@ethersproject/address" "^5.6.1" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/hdnode" "^5.6.2" + "@ethersproject/keccak256" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/pbkdf2" "^5.6.1" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/random" "^5.6.1" + "@ethersproject/strings" "^5.6.1" + "@ethersproject/transactions" "^5.6.2" + aes-js "3.0.0" + scrypt-js "3.0.1" + +"@ethersproject/keccak256@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.5.0.tgz#e4b1f9d7701da87c564ffe336f86dcee82983492" + integrity sha512-5VoFCTjo2rYbBe1l2f4mccaRFN/4VQEYFwwn04aJV2h7qf4ZvI2wFxUE1XOX+snbwCLRzIeikOqtAoPwMza9kg== + dependencies: + "@ethersproject/bytes" "^5.5.0" + js-sha3 "0.8.0" + +"@ethersproject/keccak256@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.6.1.tgz#b867167c9b50ba1b1a92bccdd4f2d6bd168a91cc" + integrity sha512-bB7DQHCTRDooZZdL3lk9wpL0+XuG3XLGHLh3cePnybsO3V0rdCAOQGpn/0R3aODmnTOOkCATJiD2hnL+5bwthA== + dependencies: + "@ethersproject/bytes" "^5.6.1" + js-sha3 "0.8.0" + +"@ethersproject/logger@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.5.0.tgz#0c2caebeff98e10aefa5aef27d7441c7fd18cf5d" + integrity sha512-rIY/6WPm7T8n3qS2vuHTUBPdXHl+rGxWxW5okDfo9J4Z0+gRRZT0msvUdIJkE4/HS29GUMziwGaaKO2bWONBrg== + +"@ethersproject/logger@^5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.6.0.tgz#d7db1bfcc22fd2e4ab574cba0bb6ad779a9a3e7a" + integrity sha512-BiBWllUROH9w+P21RzoxJKzqoqpkyM1pRnEKG69bulE9TSQD8SAIvTQqIMZmmCO8pUNkgLP1wndX1gKghSpBmg== + +"@ethersproject/logger@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892" + integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== + +"@ethersproject/networks@^5.5.0": + version "5.5.2" + resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.5.2.tgz#784c8b1283cd2a931114ab428dae1bd00c07630b" + integrity sha512-NEqPxbGBfy6O3x4ZTISb90SjEDkWYDUbEeIFhJly0F7sZjoQMnj5KYzMSkMkLKZ+1fGpx00EDpHQCy6PrDupkQ== + dependencies: + "@ethersproject/logger" "^5.5.0" + +"@ethersproject/networks@^5.6.3": + version "5.6.4" + resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.6.4.tgz#51296d8fec59e9627554f5a8a9c7791248c8dc07" + integrity sha512-KShHeHPahHI2UlWdtDMn2lJETcbtaJge4k7XSjDR9h79QTd6yQJmv6Cp2ZA4JdqWnhszAOLSuJEd9C0PRw7hSQ== + dependencies: + "@ethersproject/logger" "^5.6.0" + +"@ethersproject/pbkdf2@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.6.1.tgz#f462fe320b22c0d6b1d72a9920a3963b09eb82d1" + integrity sha512-k4gRQ+D93zDRPNUfmduNKq065uadC2YjMP/CqwwX5qG6R05f47boq6pLZtV/RnC4NZAYOPH1Cyo54q0c9sshRQ== + dependencies: + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/sha2" "^5.6.1" + +"@ethersproject/properties@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.5.0.tgz#61f00f2bb83376d2071baab02245f92070c59995" + integrity sha512-l3zRQg3JkD8EL3CPjNK5g7kMx4qSwiR60/uk5IVjd3oq1MZR5qUg40CNOoEJoX5wc3DyY5bt9EbMk86C7x0DNA== + dependencies: + "@ethersproject/logger" "^5.5.0" + +"@ethersproject/properties@^5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.6.0.tgz#38904651713bc6bdd5bdd1b0a4287ecda920fa04" + integrity sha512-szoOkHskajKePTJSZ46uHUWWkbv7TzP2ypdEK6jGMqJaEt2sb0jCgfBo0gH0m2HBpRixMuJ6TBRaQCF7a9DoCg== + dependencies: + "@ethersproject/logger" "^5.6.0" + +"@ethersproject/providers@^5.6.8": + version "5.6.8" + resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.6.8.tgz#22e6c57be215ba5545d3a46cf759d265bb4e879d" + integrity sha512-Wf+CseT/iOJjrGtAOf3ck9zS7AgPmr2fZ3N97r4+YXN3mBePTG2/bJ8DApl9mVwYL+RpYbNxMEkEp4mPGdwG/w== + dependencies: + "@ethersproject/abstract-provider" "^5.6.1" + "@ethersproject/abstract-signer" "^5.6.2" + "@ethersproject/address" "^5.6.1" + "@ethersproject/base64" "^5.6.1" + "@ethersproject/basex" "^5.6.1" + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/constants" "^5.6.1" + "@ethersproject/hash" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/networks" "^5.6.3" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/random" "^5.6.1" + "@ethersproject/rlp" "^5.6.1" + "@ethersproject/sha2" "^5.6.1" + "@ethersproject/strings" "^5.6.1" + "@ethersproject/transactions" "^5.6.2" + "@ethersproject/web" "^5.6.1" + bech32 "1.1.4" + ws "7.4.6" + +"@ethersproject/random@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.6.1.tgz#66915943981bcd3e11bbd43733f5c3ba5a790255" + integrity sha512-/wtPNHwbmng+5yi3fkipA8YBT59DdkGRoC2vWk09Dci/q5DlgnMkhIycjHlavrvrjJBkFjO/ueLyT+aUDfc4lA== + dependencies: + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + +"@ethersproject/rlp@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.5.0.tgz#530f4f608f9ca9d4f89c24ab95db58ab56ab99a0" + integrity sha512-hLv8XaQ8PTI9g2RHoQGf/WSxBfTB/NudRacbzdxmst5VHAqd1sMibWG7SENzT5Dj3yZ3kJYx+WiRYEcQTAkcYA== + dependencies: + "@ethersproject/bytes" "^5.5.0" + "@ethersproject/logger" "^5.5.0" + +"@ethersproject/rlp@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.6.1.tgz#df8311e6f9f24dcb03d59a2bac457a28a4fe2bd8" + integrity sha512-uYjmcZx+DKlFUk7a5/W9aQVaoEC7+1MOBgNtvNg13+RnuUwT4F0zTovC0tmay5SmRslb29V1B7Y5KCri46WhuQ== + dependencies: + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + +"@ethersproject/sha2@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.5.0.tgz#a40a054c61f98fd9eee99af2c3cc6ff57ec24db7" + integrity sha512-B5UBoglbCiHamRVPLA110J+2uqsifpZaTmid2/7W5rbtYVz6gus6/hSDieIU/6gaKIDcOj12WnOdiymEUHIAOA== + dependencies: + "@ethersproject/bytes" "^5.5.0" + "@ethersproject/logger" "^5.5.0" + hash.js "1.1.7" + +"@ethersproject/sha2@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.6.1.tgz#211f14d3f5da5301c8972a8827770b6fd3e51656" + integrity sha512-5K2GyqcW7G4Yo3uenHegbXRPDgARpWUiXc6RiF7b6i/HXUoWlb7uCARh7BAHg7/qT/Q5ydofNwiZcim9qpjB6g== + dependencies: + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + hash.js "1.1.7" + +"@ethersproject/signing-key@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.5.0.tgz#2aa37169ce7e01e3e80f2c14325f624c29cedbe0" + integrity sha512-5VmseH7qjtNmDdZBswavhotYbWB0bOwKIlOTSlX14rKn5c11QmJwGt4GHeo7NrL/Ycl7uo9AHvEqs5xZgFBTng== + dependencies: + "@ethersproject/bytes" "^5.5.0" + "@ethersproject/logger" "^5.5.0" + "@ethersproject/properties" "^5.5.0" + bn.js "^4.11.9" + elliptic "6.5.4" + hash.js "1.1.7" + +"@ethersproject/signing-key@^5.6.2": + version "5.6.2" + resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.6.2.tgz#8a51b111e4d62e5a62aee1da1e088d12de0614a3" + integrity sha512-jVbu0RuP7EFpw82vHcL+GP35+KaNruVAZM90GxgQnGqB6crhBqW/ozBfFvdeImtmb4qPko0uxXjn8l9jpn0cwQ== + dependencies: + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/properties" "^5.6.0" + bn.js "^5.2.1" + elliptic "6.5.4" + hash.js "1.1.7" + +"@ethersproject/solidity@^5.0.9": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.5.0.tgz#2662eb3e5da471b85a20531e420054278362f93f" + integrity sha512-9NgZs9LhGMj6aCtHXhtmFQ4AN4sth5HuFXVvAQtzmm0jpSCNOTGtrHZJAeYTh7MBjRR8brylWZxBZR9zDStXbw== + dependencies: + "@ethersproject/bignumber" "^5.5.0" + "@ethersproject/bytes" "^5.5.0" + "@ethersproject/keccak256" "^5.5.0" + "@ethersproject/logger" "^5.5.0" + "@ethersproject/sha2" "^5.5.0" + "@ethersproject/strings" "^5.5.0" + +"@ethersproject/solidity@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.6.1.tgz#5845e71182c66d32e6ec5eefd041fca091a473e2" + integrity sha512-KWqVLkUUoLBfL1iwdzUVlkNqAUIFMpbbeH0rgCfKmJp0vFtY4AsaN91gHKo9ZZLkC4UOm3cI3BmMV4N53BOq4g== + dependencies: + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/keccak256" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/sha2" "^5.6.1" + "@ethersproject/strings" "^5.6.1" + +"@ethersproject/strings@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.5.0.tgz#e6784d00ec6c57710755699003bc747e98c5d549" + integrity sha512-9fy3TtF5LrX/wTrBaT8FGE6TDJyVjOvXynXJz5MT5azq+E6D92zuKNx7i29sWW2FjVOaWjAsiZ1ZWznuduTIIQ== + dependencies: + "@ethersproject/bytes" "^5.5.0" + "@ethersproject/constants" "^5.5.0" + "@ethersproject/logger" "^5.5.0" + +"@ethersproject/strings@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.6.1.tgz#dbc1b7f901db822b5cafd4ebf01ca93c373f8952" + integrity sha512-2X1Lgk6Jyfg26MUnsHiT456U9ijxKUybz8IM1Vih+NJxYtXhmvKBcHOmvGqpFSVJ0nQ4ZCoIViR8XlRw1v/+Cw== + dependencies: + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/constants" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + +"@ethersproject/transactions@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.5.0.tgz#7e9bf72e97bcdf69db34fe0d59e2f4203c7a2908" + integrity sha512-9RZYSKX26KfzEd/1eqvv8pLauCKzDTub0Ko4LfIgaERvRuwyaNV78mJs7cpIgZaDl6RJui4o49lHwwCM0526zA== + dependencies: + "@ethersproject/address" "^5.5.0" + "@ethersproject/bignumber" "^5.5.0" + "@ethersproject/bytes" "^5.5.0" + "@ethersproject/constants" "^5.5.0" + "@ethersproject/keccak256" "^5.5.0" + "@ethersproject/logger" "^5.5.0" + "@ethersproject/properties" "^5.5.0" + "@ethersproject/rlp" "^5.5.0" + "@ethersproject/signing-key" "^5.5.0" + +"@ethersproject/transactions@^5.6.2": + version "5.6.2" + resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.6.2.tgz#793a774c01ced9fe7073985bb95a4b4e57a6370b" + integrity sha512-BuV63IRPHmJvthNkkt9G70Ullx6AcM+SDc+a8Aw/8Yew6YwT51TcBKEp1P4oOQ/bP25I18JJr7rcFRgFtU9B2Q== + dependencies: + "@ethersproject/address" "^5.6.1" + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/constants" "^5.6.1" + "@ethersproject/keccak256" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/rlp" "^5.6.1" + "@ethersproject/signing-key" "^5.6.2" + +"@ethersproject/units@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.6.1.tgz#ecc590d16d37c8f9ef4e89e2005bda7ddc6a4e6f" + integrity sha512-rEfSEvMQ7obcx3KWD5EWWx77gqv54K6BKiZzKxkQJqtpriVsICrktIQmKl8ReNToPeIYPnFHpXvKpi068YFZXw== + dependencies: + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/constants" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + +"@ethersproject/units@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.7.0.tgz#637b563d7e14f42deeee39245275d477aae1d8b1" + integrity sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/wallet@^5.6.2": + version "5.6.2" + resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.6.2.tgz#cd61429d1e934681e413f4bc847a5f2f87e3a03c" + integrity sha512-lrgh0FDQPuOnHcF80Q3gHYsSUODp6aJLAdDmDV0xKCN/T7D99ta1jGVhulg3PY8wiXEngD0DfM0I2XKXlrqJfg== + dependencies: + "@ethersproject/abstract-provider" "^5.6.1" + "@ethersproject/abstract-signer" "^5.6.2" + "@ethersproject/address" "^5.6.1" + "@ethersproject/bignumber" "^5.6.2" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/hash" "^5.6.1" + "@ethersproject/hdnode" "^5.6.2" + "@ethersproject/json-wallets" "^5.6.1" + "@ethersproject/keccak256" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/random" "^5.6.1" + "@ethersproject/signing-key" "^5.6.2" + "@ethersproject/transactions" "^5.6.2" + "@ethersproject/wordlists" "^5.6.1" + +"@ethersproject/web@^5.5.0": + version "5.5.1" + resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.5.1.tgz#cfcc4a074a6936c657878ac58917a61341681316" + integrity sha512-olvLvc1CB12sREc1ROPSHTdFCdvMh0J5GSJYiQg2D0hdD4QmJDy8QYDb1CvoqD/bF1c++aeKv2sR5uduuG9dQg== + dependencies: + "@ethersproject/base64" "^5.5.0" + "@ethersproject/bytes" "^5.5.0" + "@ethersproject/logger" "^5.5.0" + "@ethersproject/properties" "^5.5.0" + "@ethersproject/strings" "^5.5.0" + +"@ethersproject/web@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.6.1.tgz#6e2bd3ebadd033e6fe57d072db2b69ad2c9bdf5d" + integrity sha512-/vSyzaQlNXkO1WV+RneYKqCJwualcUdx/Z3gseVovZP0wIlOFcCE1hkRhKBH8ImKbGQbMl9EAAyJFrJu7V0aqA== + dependencies: + "@ethersproject/base64" "^5.6.1" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/strings" "^5.6.1" + +"@ethersproject/wordlists@^5.6.1": + version "5.6.1" + resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.6.1.tgz#1e78e2740a8a21e9e99947e47979d72e130aeda1" + integrity sha512-wiPRgBpNbNwCQFoCr8bcWO8o5I810cqO6mkdtKfLKFlLxeCWcnzDi4Alu8iyNzlhYuS9npCwivMbRWF19dyblw== + dependencies: + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/hash" "^5.6.1" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/strings" "^5.6.1" + +"@humanwhocodes/config-array@^0.9.2": + version "0.9.5" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.5.tgz#2cbaf9a89460da24b5ca6531b8bbfc23e1df50c7" + integrity sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.4" + +"@humanwhocodes/object-schema@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.5.0.tgz#593a6c5c0d3f75689835f1b3b4688c4f8544cb57" + integrity sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ== + dependencies: + "@jest/types" "^29.5.0" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^29.5.0" + jest-util "^29.5.0" + slash "^3.0.0" + +"@jest/core@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.5.0.tgz#76674b96904484e8214614d17261cc491e5f1f03" + integrity sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ== + dependencies: + "@jest/console" "^29.5.0" + "@jest/reporters" "^29.5.0" + "@jest/test-result" "^29.5.0" + "@jest/transform" "^29.5.0" + "@jest/types" "^29.5.0" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + ci-info "^3.2.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^29.5.0" + jest-config "^29.5.0" + jest-haste-map "^29.5.0" + jest-message-util "^29.5.0" + jest-regex-util "^29.4.3" + jest-resolve "^29.5.0" + jest-resolve-dependencies "^29.5.0" + jest-runner "^29.5.0" + jest-runtime "^29.5.0" + jest-snapshot "^29.5.0" + jest-util "^29.5.0" + jest-validate "^29.5.0" + jest-watcher "^29.5.0" + micromatch "^4.0.4" + pretty-format "^29.5.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.5.0.tgz#9152d56317c1fdb1af389c46640ba74ef0bb4c65" + integrity sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ== + dependencies: + "@jest/fake-timers" "^29.5.0" + "@jest/types" "^29.5.0" + "@types/node" "*" + jest-mock "^29.5.0" + +"@jest/expect-utils@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.5.0.tgz#f74fad6b6e20f924582dc8ecbf2cb800fe43a036" + integrity sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg== + dependencies: + jest-get-type "^29.4.3" + +"@jest/expect@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.5.0.tgz#80952f5316b23c483fbca4363ce822af79c38fba" + integrity sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g== + dependencies: + expect "^29.5.0" + jest-snapshot "^29.5.0" + +"@jest/fake-timers@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.5.0.tgz#d4d09ec3286b3d90c60bdcd66ed28d35f1b4dc2c" + integrity sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg== + dependencies: + "@jest/types" "^29.5.0" + "@sinonjs/fake-timers" "^10.0.2" + "@types/node" "*" + jest-message-util "^29.5.0" + jest-mock "^29.5.0" + jest-util "^29.5.0" + +"@jest/globals@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.5.0.tgz#6166c0bfc374c58268677539d0c181f9c1833298" + integrity sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ== + dependencies: + "@jest/environment" "^29.5.0" + "@jest/expect" "^29.5.0" + "@jest/types" "^29.5.0" + jest-mock "^29.5.0" + +"@jest/reporters@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.5.0.tgz#985dfd91290cd78ddae4914ba7921bcbabe8ac9b" + integrity sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^29.5.0" + "@jest/test-result" "^29.5.0" + "@jest/transform" "^29.5.0" + "@jest/types" "^29.5.0" + "@jridgewell/trace-mapping" "^0.3.15" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^5.1.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-message-util "^29.5.0" + jest-util "^29.5.0" + jest-worker "^29.5.0" + slash "^3.0.0" + string-length "^4.0.1" + strip-ansi "^6.0.0" + v8-to-istanbul "^9.0.1" + +"@jest/schemas@^29.4.3": + version "29.4.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.4.3.tgz#39cf1b8469afc40b6f5a2baaa146e332c4151788" + integrity sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg== + dependencies: + "@sinclair/typebox" "^0.25.16" + +"@jest/source-map@^29.4.3": + version "29.4.3" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.4.3.tgz#ff8d05cbfff875d4a791ab679b4333df47951d20" + integrity sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w== + dependencies: + "@jridgewell/trace-mapping" "^0.3.15" + callsites "^3.0.0" + graceful-fs "^4.2.9" + +"@jest/test-result@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.5.0.tgz#7c856a6ca84f45cc36926a4e9c6b57f1973f1408" + integrity sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ== + dependencies: + "@jest/console" "^29.5.0" + "@jest/types" "^29.5.0" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz#34d7d82d3081abd523dbddc038a3ddcb9f6d3cc4" + integrity sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ== + dependencies: + "@jest/test-result" "^29.5.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.5.0" + slash "^3.0.0" + +"@jest/transform@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.5.0.tgz#cf9c872d0965f0cbd32f1458aa44a2b1988b00f9" + integrity sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^29.5.0" + "@jridgewell/trace-mapping" "^0.3.15" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.5.0" + jest-regex-util "^29.4.3" + jest-util "^29.5.0" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.2" + +"@jest/types@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.5.0.tgz#f59ef9b031ced83047c67032700d8c807d6e1593" + integrity sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog== + dependencies: + "@jest/schemas" "^29.4.3" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + +"@jridgewell/gen-mapping@^0.1.0": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" + integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== + dependencies: + "@jridgewell/set-array" "^1.0.0" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@jridgewell/gen-mapping@^0.3.0": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz#cf92a983c83466b8c0ce9124fadeaf09f7c66ea9" + integrity sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg== + dependencies: + "@jridgewell/set-array" "^1.0.0" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + +"@jridgewell/resolve-uri@^3.0.3": + version "3.0.7" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz#30cd49820a962aff48c8fffc5cd760151fca61fe" + integrity sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA== + +"@jridgewell/set-array@^1.0.0": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.1.tgz#36a6acc93987adcf0ba50c66908bd0b70de8afea" + integrity sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ== + +"@jridgewell/sourcemap-codec@1.4.14": + version "1.4.14" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.13" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz#b6461fb0c2964356c469e115f504c95ad97ab88c" + integrity sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w== + +"@jridgewell/trace-mapping@^0.3.12": + version "0.3.14" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed" + integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@jridgewell/trace-mapping@^0.3.15": + version "0.3.18" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6" + integrity sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA== + dependencies: + "@jridgewell/resolve-uri" "3.1.0" + "@jridgewell/sourcemap-codec" "1.4.14" + +"@jridgewell/trace-mapping@^0.3.9": + version "0.3.13" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz#dcfe3e95f224c8fe97a87a5235defec999aa92ea" + integrity sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@openzeppelin/contracts@3.4.1-solc-0.7-2": + version "3.4.1-solc-0.7-2" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.4.1-solc-0.7-2.tgz#371c67ebffe50f551c3146a9eec5fe6ffe862e92" + integrity sha512-tAG9LWg8+M2CMu7hIsqHPaTyG4uDzjr6mhvH96LvOpLZZj6tgzTluBt+LsCf1/QaYrlis6pITvpIaIhE+iZB+Q== + +"@openzeppelin/contracts@3.4.2-solc-0.7": + version "3.4.2-solc-0.7" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.4.2-solc-0.7.tgz#38f4dbab672631034076ccdf2f3201fab1726635" + integrity sha512-W6QmqgkADuFcTLzHL8vVoNBtkwjvQRpYIAom7KiUNoLKghyx3FgH0GBjt8NRvigV1ZmMOBllvE1By1C+bi8WpA== + +"@sinclair/typebox@^0.25.16": + version "0.25.24" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.24.tgz#8c7688559979f7079aacaf31aa881c3aa410b718" + integrity sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ== + +"@sinonjs/commons@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-2.0.0.tgz#fd4ca5b063554307e8327b4564bd56d3b73924a3" + integrity sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^10.0.2": + version "10.0.2" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz#d10549ed1f423d80639c528b6c7f5a1017747d0c" + integrity sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw== + dependencies: + "@sinonjs/commons" "^2.0.0" + +"@snapshot-labs/snapshot.js@^0.4.106": + version "0.4.106" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.106.tgz#1861b0346a93f1caf35e89c0dcff95945407dc31" + integrity sha512-sWQzBmEYl9d5LE1p7ZZRx5+0M/DylcLuh1RLlpbNLYmGM01LFi+bThjB4lsnj/BvyAYFHKNIZam9OHPV2fA+uw== + dependencies: + "@ensdomains/eth-ens-namehash" "^2.0.15" + "@ethersproject/abi" "^5.6.4" + "@ethersproject/address" "^5.6.1" + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/contracts" "^5.6.2" + "@ethersproject/hash" "^5.6.1" + "@ethersproject/providers" "^5.6.8" + "@ethersproject/units" "^5.7.0" + "@ethersproject/wallet" "^5.6.2" + ajv "^8.11.0" + ajv-formats "^2.1.1" + cross-fetch "^3.1.6" + json-to-graphql-query "^2.2.4" + lodash.set "^4.3.2" + +"@spruceid/didkit-wasm-node@^0.2.1": + version "0.2.1" + resolved "https://registry.yarnpkg.com/@spruceid/didkit-wasm-node/-/didkit-wasm-node-0.2.1.tgz#85f7023979b4ef84bd6de16c79c67b6e9a08e1db" + integrity sha512-c8e3u5FIRS/2Gf6UHnRPnfRozgKgby4avZzlvIiaJRDVLl1LaX1SE13vEvKV2rAq6NMfZrV4YG908M4uVlT90Q== + +"@types/babel__core@^7.1.14": + version "7.1.19" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.19.tgz#7b497495b7d1b4812bdb9d02804d0576f43ee460" + integrity sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.4.tgz#1f20ce4c5b1990b37900b63f050182d28c2439b7" + integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.1" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" + integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": + version "7.17.1" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.17.1.tgz#1a0e73e8c28c7e832656db372b779bfd2ef37314" + integrity sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA== + dependencies: + "@babel/types" "^7.3.0" + +"@types/graceful-fs@^4.1.3": + version "4.1.5" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" + integrity sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw== + dependencies: + "@types/node" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" + integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== + +"@types/istanbul-lib-report@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" + integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" + integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@^29.5.1": + version "29.5.1" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.1.tgz#83c818aa9a87da27d6da85d3378e5a34d2f31a47" + integrity sha512-tEuVcHrpaixS36w7hpsfLBLpjtMRJUE09/MHXn923LOVojDwyC14cWcfc0rDs0VEfUyYmt/+iX1kxxp+gZMcaQ== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + +"@types/json-schema@^7.0.9": + version "7.0.11" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" + integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== + +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= + +"@types/node@*": + version "18.0.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.0.0.tgz#67c7b724e1bcdd7a8821ce0d5ee184d3b4dd525a" + integrity sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA== + +"@types/node@^18.0.3": + version "18.0.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.0.3.tgz#463fc47f13ec0688a33aec75d078a0541a447199" + integrity sha512-HzNRZtp4eepNitP+BD6k2L6DROIDG4Q0fm4x+dwfsr6LGmROENnok75VGw40628xf+iR24WeMFcHuuBDUAzzsQ== + +"@types/prettier@^2.1.5": + version "2.6.3" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.6.3.tgz#68ada76827b0010d0db071f739314fa429943d0a" + integrity sha512-ymZk3LEC/fsut+/Q5qejp6R9O1rMxz3XaRHDV6kX8MrGAhOSPqVARbDi+EZvInBpw+BnCX3TD240byVkOfQsHg== + +"@types/stack-utils@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" + integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== + +"@types/yargs-parser@*": + version "21.0.0" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" + integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== + +"@types/yargs@^17.0.8": + version "17.0.10" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.10.tgz#591522fce85d8739bca7b8bb90d048e4478d186a" + integrity sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA== + dependencies: + "@types/yargs-parser" "*" + +"@typescript-eslint/eslint-plugin@^5.30.5": + version "5.30.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.5.tgz#e9a0afd6eb3b1d663db91cf1e7bc7584d394503d" + integrity sha512-lftkqRoBvc28VFXEoRgyZuztyVUQ04JvUnATSPtIRFAccbXTWL6DEtXGYMcbg998kXw1NLUJm7rTQ9eUt+q6Ig== + dependencies: + "@typescript-eslint/scope-manager" "5.30.5" + "@typescript-eslint/type-utils" "5.30.5" + "@typescript-eslint/utils" "5.30.5" + debug "^4.3.4" + functional-red-black-tree "^1.0.1" + ignore "^5.2.0" + regexpp "^3.2.0" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/parser@^5.30.5": + version "5.30.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.30.5.tgz#f667c34e4e4c299d98281246c9b1e68c03a92522" + integrity sha512-zj251pcPXI8GO9NDKWWmygP6+UjwWmrdf9qMW/L/uQJBM/0XbU2inxe5io/234y/RCvwpKEYjZ6c1YrXERkK4Q== + dependencies: + "@typescript-eslint/scope-manager" "5.30.5" + "@typescript-eslint/types" "5.30.5" + "@typescript-eslint/typescript-estree" "5.30.5" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@5.30.5": + version "5.30.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.30.5.tgz#7f90b9d6800552c856a5f3644f5e55dd1469d964" + integrity sha512-NJ6F+YHHFT/30isRe2UTmIGGAiXKckCyMnIV58cE3JkHmaD6e5zyEYm5hBDv0Wbin+IC0T1FWJpD3YqHUG/Ydg== + dependencies: + "@typescript-eslint/types" "5.30.5" + "@typescript-eslint/visitor-keys" "5.30.5" + +"@typescript-eslint/type-utils@5.30.5": + version "5.30.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.30.5.tgz#7a9656f360b4b1daea635c4621dab053d08bf8a9" + integrity sha512-k9+ejlv1GgwN1nN7XjVtyCgE0BTzhzT1YsQF0rv4Vfj2U9xnslBgMYYvcEYAFVdvhuEscELJsB7lDkN7WusErw== + dependencies: + "@typescript-eslint/utils" "5.30.5" + debug "^4.3.4" + tsutils "^3.21.0" + +"@typescript-eslint/types@5.30.5": + version "5.30.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.30.5.tgz#36a0c05a72af3623cdf9ee8b81ea743b7de75a98" + integrity sha512-kZ80w/M2AvsbRvOr3PjaNh6qEW1LFqs2pLdo2s5R38B2HYXG8Z0PP48/4+j1QHJFL3ssHIbJ4odPRS8PlHrFfw== + +"@typescript-eslint/typescript-estree@5.30.5": + version "5.30.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.5.tgz#c520e4eba20551c4ec76af8d344a42eb6c9767bb" + integrity sha512-qGTc7QZC801kbYjAr4AgdOfnokpwStqyhSbiQvqGBLixniAKyH+ib2qXIVo4P9NgGzwyfD9I0nlJN7D91E1VpQ== + dependencies: + "@typescript-eslint/types" "5.30.5" + "@typescript-eslint/visitor-keys" "5.30.5" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/utils@5.30.5": + version "5.30.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.30.5.tgz#3999cbd06baad31b9e60d084f20714d1b2776765" + integrity sha512-o4SSUH9IkuA7AYIfAvatldovurqTAHrfzPApOZvdUq01hHojZojCFXx06D/aFpKCgWbMPRdJBWAC3sWp3itwTA== + dependencies: + "@types/json-schema" "^7.0.9" + "@typescript-eslint/scope-manager" "5.30.5" + "@typescript-eslint/types" "5.30.5" + "@typescript-eslint/typescript-estree" "5.30.5" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + +"@typescript-eslint/visitor-keys@5.30.5": + version "5.30.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.5.tgz#d4bb969202019d5d5d849a0aaedc7370cc044b14" + integrity sha512-D+xtGo9HUMELzWIUqcQc0p2PO4NyvTrgIOK/VnSH083+8sq0tiLozNRKuLarwHYGRuA6TVBQSuuLwJUDWd3aaA== + dependencies: + "@typescript-eslint/types" "5.30.5" + eslint-visitor-keys "^3.3.0" + +"@uniswap/lib@^4.0.1-alpha": + version "4.0.1-alpha" + resolved "https://registry.yarnpkg.com/@uniswap/lib/-/lib-4.0.1-alpha.tgz#2881008e55f075344675b3bca93f020b028fbd02" + integrity sha512-f6UIliwBbRsgVLxIaBANF6w09tYqc6Y/qXdsrbEmXHyFA7ILiKrIwRFXe1yOg8M3cksgVsO9N7yuL2DdCGQKBA== + +"@uniswap/sdk-core@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@uniswap/sdk-core/-/sdk-core-3.0.1.tgz#d08dd68257983af64b9a5f4d6b9cf26124b4138f" + integrity sha512-WbeDkhZ9myVR0VnHOdTrb8nHKKkqTFa5uE9RvUbG3eyDt2NWWDwhhqGHwAWJEHG405l30Fa1u3PogHDFsIOQlA== + dependencies: + "@ethersproject/address" "^5.0.2" + big.js "^5.2.2" + decimal.js-light "^2.5.0" + jsbi "^3.1.4" + tiny-invariant "^1.1.0" + toformat "^2.0.0" + +"@uniswap/swap-router-contracts@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@uniswap/swap-router-contracts/-/swap-router-contracts-1.2.1.tgz#223c8b6672b7754080d95ca917763d98feb5e696" + integrity sha512-aRNiZYIOpJ0uYxujPxvQsUEuNJWLC4bvnmU40TlNej1rGWHPyDL1PmnVzebu8UpW9EGeKlvDjsNGTyo53dih9Q== + dependencies: + "@openzeppelin/contracts" "3.4.2-solc-0.7" + "@uniswap/v2-core" "1.0.1" + "@uniswap/v3-core" "1.0.0" + "@uniswap/v3-periphery" "1.4.1" + dotenv "^14.2.0" + hardhat-watcher "^2.1.1" + +"@uniswap/v2-core@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@uniswap/v2-core/-/v2-core-1.0.1.tgz#af8f508bf183204779938969e2e54043e147d425" + integrity sha512-MtybtkUPSyysqLY2U210NBDeCHX+ltHt3oADGdjqoThZaFRDKwM6k1Nb3F0A3hk5hwuQvytFWhrWHOEq6nVJ8Q== + +"@uniswap/v3-core@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@uniswap/v3-core/-/v3-core-1.0.0.tgz#6c24adacc4c25dceee0ba3ca142b35adbd7e359d" + integrity sha512-kSC4djMGKMHj7sLMYVnn61k9nu+lHjMIxgg9CDQT+s2QYLoA56GbSK9Oxr+qJXzzygbkrmuY6cwgP6cW2JXPFA== + +"@uniswap/v3-periphery@1.4.1", "@uniswap/v3-periphery@^1.0.1", "@uniswap/v3-periphery@^1.1.1": + version "1.4.1" + resolved "https://registry.yarnpkg.com/@uniswap/v3-periphery/-/v3-periphery-1.4.1.tgz#b90f08b7386163c0abfd7258831caef6339c7862" + integrity sha512-Ab0ZCKOQrQMKIcpBTezTsEhWfQjItd0TtkCG8mPhoQu+wC67nPaf4hYUhM6wGHeFUmDiYY5MpEQuokB0ENvoTg== + dependencies: + "@openzeppelin/contracts" "3.4.2-solc-0.7" + "@uniswap/lib" "^4.0.1-alpha" + "@uniswap/v2-core" "1.0.1" + "@uniswap/v3-core" "1.0.0" + base64-sol "1.0.1" + hardhat-watcher "^2.1.1" + +"@uniswap/v3-sdk@^3.9.0": + version "3.9.0" + resolved "https://registry.yarnpkg.com/@uniswap/v3-sdk/-/v3-sdk-3.9.0.tgz#de93fa19f89c29d460996aa4d0b4bb6531641105" + integrity sha512-LuoF3UcY1DxSAQKJ3E4/1Eq4HaNp+x+7q9mvbpiu+/PBj+O1DjLforAMrKxu+RsA0aarmZtz7yBnAPy+akgfgQ== + dependencies: + "@ethersproject/abi" "^5.0.12" + "@ethersproject/solidity" "^5.0.9" + "@uniswap/sdk-core" "^3.0.1" + "@uniswap/swap-router-contracts" "^1.2.1" + "@uniswap/v3-periphery" "^1.1.1" + "@uniswap/v3-staker" "1.0.0" + tiny-invariant "^1.1.0" + tiny-warning "^1.0.3" + +"@uniswap/v3-staker@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@uniswap/v3-staker/-/v3-staker-1.0.0.tgz#9a6915ec980852479dfc903f50baf822ff8fa66e" + integrity sha512-JV0Qc46Px5alvg6YWd+UIaGH9lDuYG/Js7ngxPit1SPaIP30AlVer1UYB7BRYeUVVxE+byUyIeN5jeQ7LLDjIw== + dependencies: + "@openzeppelin/contracts" "3.4.1-solc-0.7-2" + "@uniswap/v3-core" "1.0.0" + "@uniswap/v3-periphery" "^1.0.1" + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^8.7.1: + version "8.7.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" + integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== + +aes-js@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" + integrity sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0= + +ajv-formats@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" + integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== + dependencies: + ajv "^8.0.0" + +ajv@^6.10.0, ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^8.0.0: + version "8.9.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.9.0.tgz#738019146638824dea25edcf299dcba1b0e7eb18" + integrity sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + +ajv@^8.11.0: + version "8.11.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" + integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +anymatch@^3.0.3, anymatch@~3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +array-includes@^3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.4.tgz#f5b493162c760f3539631f005ba2bb46acb45ba9" + integrity sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + get-intrinsic "^1.1.1" + is-string "^1.0.7" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +array.prototype.flat@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz#07e0975d84bbc7c48cd1879d609e682598d33e13" + integrity sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.0" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +axios@^0.27.2: + version "0.27.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972" + integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ== + dependencies: + follow-redirects "^1.14.9" + form-data "^4.0.0" + +babel-jest@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.5.0.tgz#3fe3ddb109198e78b1c88f9ebdecd5e4fc2f50a5" + integrity sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q== + dependencies: + "@jest/transform" "^29.5.0" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^29.5.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz#a97db437936f441ec196990c9738d4b88538618a" + integrity sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" + "@types/babel__traverse" "^7.0.6" + +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + +babel-preset-jest@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz#57bc8cc88097af7ff6a5ab59d1cd29d52a5916e2" + integrity sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg== + dependencies: + babel-plugin-jest-hoist "^29.5.0" + babel-preset-current-node-syntax "^1.0.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base64-sol@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/base64-sol/-/base64-sol-1.0.1.tgz#91317aa341f0bc763811783c5729f1c2574600f6" + integrity sha512-ld3cCNMeXt4uJXmLZBHFGMvVpK9KsLVEhPpFRXnvSVAqABKbuNZg/+dsq3NuM+wxFLb/UrVkz7m1ciWmkMfTbg== + +bech32@1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" + integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +blakejs@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.2.1.tgz#5057e4206eadb4a97f7c0b6e197a505042fc3814" + integrity sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ== + +bn.js@^4.11.9: + version "4.12.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== + +bn.js@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^3.0.1, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= + +browserslist@^4.20.2: + version "4.20.4" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.4.tgz#98096c9042af689ee1e0271333dbc564b8ce4477" + integrity sha512-ok1d+1WpnU24XYN7oC3QWgTyMhY/avPJ/r9T00xxvUOIparA/gc+UPUMaod3i+G6s+nI2nUb9xZ5k794uIwShw== + dependencies: + caniuse-lite "^1.0.30001349" + electron-to-chromium "^1.4.147" + escalade "^3.1.1" + node-releases "^2.0.5" + picocolors "^1.0.0" + +bs-logger@0.x: + version "0.2.6" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001349: + version "1.0.30001357" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001357.tgz#dec7fc4158ef6ad24690d0eec7b91f32b8cb1b5d" + integrity sha512-b+KbWHdHePp+ZpNj+RDHFChZmuN+J5EvuQUlee9jOQIUAdhv9uvAZeEtUeLAknXbkiu1uxjQ9NLp1ie894CuWg== + +chalk@^2.0.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +chokidar@^3.4.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +ci-info@^3.2.0: + version "3.3.2" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.2.tgz#6d2967ffa407466481c6c90b6e16b3098f080128" + integrity sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg== + +cjs-module-lexer@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" + integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== + +collect-v8-coverage@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" + integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +confusing-browser-globals@^1.0.10: + version "1.0.11" + resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz#ae40e9b57cdd3915408a2805ebd3a5585608dc81" + integrity sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA== + +convert-source-map@^1.6.0, convert-source-map@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== + dependencies: + safe-buffer "~5.1.1" + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +copyfiles@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/copyfiles/-/copyfiles-2.4.1.tgz#d2dcff60aaad1015f09d0b66e7f0f1c5cd3c5da5" + integrity sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg== + dependencies: + glob "^7.0.5" + minimatch "^3.0.3" + mkdirp "^1.0.4" + noms "0.0.0" + through2 "^2.0.1" + untildify "^4.0.0" + yargs "^16.1.0" + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +cross-fetch@^3.1.6: + version "3.1.6" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.6.tgz#bae05aa31a4da760969756318feeee6e70f15d6c" + integrity sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g== + dependencies: + node-fetch "^2.6.11" + +cross-spawn@^7.0.2, cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +debug@^2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^3.2.7: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +decimal.js-light@^2.5.0: + version "2.5.1" + resolved "https://registry.yarnpkg.com/decimal.js-light/-/decimal.js-light-2.5.1.tgz#134fd32508f19e208f4fb2f8dac0d2626a867934" + integrity sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg== + +dedent@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" + integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +deepmerge@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" + integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== + +define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +diff-sequences@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.3.tgz#9314bc1fabe09267ffeca9cbafc457d8499a13f2" + integrity sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA== + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +dotenv@^14.2.0: + version "14.3.2" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-14.3.2.tgz#7c30b3a5f777c79a3429cb2db358eef6751e8369" + integrity sha512-vwEppIphpFdvaMCaHfCEv9IgwcxMljMw2TnAQBB4VWPvzXQLTb82jwmdOKzlEVUL3gNFT4l4TPKO+Bn+sqcrVQ== + +dotenv@^16.0.3: + version "16.0.3" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.3.tgz#115aec42bac5053db3c456db30cc243a5a836a07" + integrity sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ== + +electron-to-chromium@^1.4.147: + version "1.4.161" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.161.tgz#49cb5b35385bfee6cc439d0a04fbba7a7a7f08a1" + integrity sha512-sTjBRhqh6wFodzZtc5Iu8/R95OkwaPNn7tj/TaDU5nu/5EFiQDtADGAXdR4tJcTEHlYfJpHqigzJqHvPgehP8A== + +elliptic@6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" + integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + +emittery@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" + integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.19.0, es-abstract@^1.19.1: + version "1.19.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" + integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w== + dependencies: + call-bind "^1.0.2" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + get-intrinsic "^1.1.1" + get-symbol-description "^1.0.0" + has "^1.0.3" + has-symbols "^1.0.2" + internal-slot "^1.0.3" + is-callable "^1.2.4" + is-negative-zero "^2.0.1" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.1" + is-string "^1.0.7" + is-weakref "^1.0.1" + object-inspect "^1.11.0" + object-keys "^1.1.1" + object.assign "^4.1.2" + string.prototype.trimend "^1.0.4" + string.prototype.trimstart "^1.0.4" + unbox-primitive "^1.0.1" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-config-airbnb-base@^15.0.0: + version "15.0.0" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz#6b09add90ac79c2f8d723a2580e07f3925afd236" + integrity sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig== + dependencies: + confusing-browser-globals "^1.0.10" + object.assign "^4.1.2" + object.entries "^1.1.5" + semver "^6.3.0" + +eslint-import-resolver-node@^0.3.6: + version "0.3.6" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd" + integrity sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw== + dependencies: + debug "^3.2.7" + resolve "^1.20.0" + +eslint-module-utils@^2.7.3: + version "2.7.3" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz#ad7e3a10552fdd0642e1e55292781bd6e34876ee" + integrity sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ== + dependencies: + debug "^3.2.7" + find-up "^2.1.0" + +eslint-plugin-import@^2.26.0: + version "2.26.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz#f812dc47be4f2b72b478a021605a59fc6fe8b88b" + integrity sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA== + dependencies: + array-includes "^3.1.4" + array.prototype.flat "^1.2.5" + debug "^2.6.9" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.6" + eslint-module-utils "^2.7.3" + has "^1.0.3" + is-core-module "^2.8.1" + is-glob "^4.0.3" + minimatch "^3.1.2" + object.values "^1.1.5" + resolve "^1.22.0" + tsconfig-paths "^3.14.1" + +eslint-plugin-prettier@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz#651cbb88b1dab98bfd42f017a12fa6b2d993f94b" + integrity sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ== + dependencies: + prettier-linter-helpers "^1.0.0" + +eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-scope@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" + integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + +eslint-visitor-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== + +eslint-visitor-keys@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" + integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== + +eslint@^8.19.0: + version "8.19.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.19.0.tgz#7342a3cbc4fbc5c106a1eefe0fd0b50b6b1a7d28" + integrity sha512-SXOPj3x9VKvPe81TjjUJCYlV4oJjQw68Uek+AM0X4p+33dj2HY5bpTZOgnQHcG2eAm1mtCU9uNMnJi7exU/kYw== + dependencies: + "@eslint/eslintrc" "^1.3.0" + "@humanwhocodes/config-array" "^0.9.2" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.1.1" + eslint-utils "^3.0.0" + eslint-visitor-keys "^3.3.0" + espree "^9.3.2" + esquery "^1.4.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^6.0.1" + globals "^13.15.0" + ignore "^5.2.0" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.1" + regexpp "^3.2.0" + strip-ansi "^6.0.1" + strip-json-comments "^3.1.0" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^9.3.2: + version "9.3.2" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.2.tgz#f58f77bd334731182801ced3380a8cc859091596" + integrity sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA== + dependencies: + acorn "^8.7.1" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.3.0" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" + integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +eth-ens-namehash@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz#229ac46eca86d52e0c991e7cb2aef83ff0f68bcf" + integrity sha1-IprEbsqG1S4MmR58sq74P/D2i88= + dependencies: + idna-uts46-hx "^2.3.1" + js-sha3 "^0.5.7" + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== + +expect@^29.0.0, expect@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.5.0.tgz#68c0509156cb2a0adb8865d413b137eeaae682f7" + integrity sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg== + dependencies: + "@jest/expect-utils" "^29.5.0" + jest-get-type "^29.4.3" + jest-matcher-utils "^29.5.0" + jest-message-util "^29.5.0" + jest-util "^29.5.0" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-diff@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" + integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== + +fast-glob@^3.2.9: + version "3.2.11" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" + integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastq@^1.6.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" + integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== + dependencies: + reusify "^1.0.4" + +fb-watchman@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" + integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== + dependencies: + bser "2.1.1" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= + dependencies: + locate-path "^2.0.0" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + +flatted@^3.1.0: + version "3.2.6" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.6.tgz#022e9218c637f9f3fc9c35ab9c9193f05add60b2" + integrity sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ== + +follow-redirects@^1.14.9: + version "1.15.2" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" + integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== + +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@^2.3.2, fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" + integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob@^7.0.5: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.1.3, glob@^7.1.4: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^13.15.0: + version "13.16.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.16.0.tgz#9be4aca28f311aaeb974ea54978ebbb5e35ce46a" + integrity sha512-A1lrQfpNF+McdPOnnFqY3kSN0AFTy485bTi1bkLk4mVPODIUEcSfhHgRqA+QdXPksrSTTztYXx37NFV+GpGk3Q== + dependencies: + type-fest "^0.20.2" + +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +graceful-fs@^4.2.9: + version "4.2.10" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" + integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + +hardhat-watcher@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/hardhat-watcher/-/hardhat-watcher-2.1.1.tgz#8b05fec429ed45da11808bbf6054a90f3e34c51a" + integrity sha512-zilmvxAYD34IofBrwOliQn4z92UiDmt2c949DW4Gokf0vS0qk4YTfVCi/LmUBICThGygNANE3WfnRTpjCJGtDA== + dependencies: + chokidar "^3.4.3" + +has-bigints@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" + integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-symbols@^1.0.1, has-symbols@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" + integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +idna-uts46-hx@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz#a1dc5c4df37eee522bf66d969cc980e00e8711f9" + integrity sha512-PWoF9Keq6laYdIRwwCdhTPl60xRqAloYNMQLiyUnG42VjT53oW07BXIRM+NK7eQjzXjAk2gUvX9caRxlnF9TAA== + dependencies: + punycode "2.1.0" + +ignore@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" + integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== + +import-fresh@^3.0.0, import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-local@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +internal-slot@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" + integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== + dependencies: + get-intrinsic "^1.1.0" + has "^1.0.3" + side-channel "^1.0.4" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-callable@^1.1.4, is-callable@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" + integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== + +is-core-module@^2.8.0, is-core-module@^2.8.1, is-core-module@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69" + integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A== + dependencies: + has "^1.0.3" + +is-date-object@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-negative-zero@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + +is-number-object@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" + integrity sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g== + dependencies: + has-tostringtag "^1.0.0" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-shared-array-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" + integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-weakref@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== + +istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz#31d18bdd127f825dd02ea7bfdfd906f8ab840e9f" + integrity sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + +istanbul-lib-report@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" + integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^3.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.1.3: + version "3.1.4" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.4.tgz#1b6f068ecbc6c331040aab5741991273e609e40c" + integrity sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jest-changed-files@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.5.0.tgz#e88786dca8bf2aa899ec4af7644e16d9dcf9b23e" + integrity sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag== + dependencies: + execa "^5.0.0" + p-limit "^3.1.0" + +jest-circus@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.5.0.tgz#b5926989449e75bff0d59944bae083c9d7fb7317" + integrity sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA== + dependencies: + "@jest/environment" "^29.5.0" + "@jest/expect" "^29.5.0" + "@jest/test-result" "^29.5.0" + "@jest/types" "^29.5.0" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^0.7.0" + is-generator-fn "^2.0.0" + jest-each "^29.5.0" + jest-matcher-utils "^29.5.0" + jest-message-util "^29.5.0" + jest-runtime "^29.5.0" + jest-snapshot "^29.5.0" + jest-util "^29.5.0" + p-limit "^3.1.0" + pretty-format "^29.5.0" + pure-rand "^6.0.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-cli@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.5.0.tgz#b34c20a6d35968f3ee47a7437ff8e53e086b4a67" + integrity sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw== + dependencies: + "@jest/core" "^29.5.0" + "@jest/test-result" "^29.5.0" + "@jest/types" "^29.5.0" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + import-local "^3.0.2" + jest-config "^29.5.0" + jest-util "^29.5.0" + jest-validate "^29.5.0" + prompts "^2.0.1" + yargs "^17.3.1" + +jest-config@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.5.0.tgz#3cc972faec8c8aaea9ae158c694541b79f3748da" + integrity sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA== + dependencies: + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^29.5.0" + "@jest/types" "^29.5.0" + babel-jest "^29.5.0" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^29.5.0" + jest-environment-node "^29.5.0" + jest-get-type "^29.4.3" + jest-regex-util "^29.4.3" + jest-resolve "^29.5.0" + jest-runner "^29.5.0" + jest-util "^29.5.0" + jest-validate "^29.5.0" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^29.5.0" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-diff@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.5.0.tgz#e0d83a58eb5451dcc1fa61b1c3ee4e8f5a290d63" + integrity sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.4.3" + jest-get-type "^29.4.3" + pretty-format "^29.5.0" + +jest-docblock@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.4.3.tgz#90505aa89514a1c7dceeac1123df79e414636ea8" + integrity sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg== + dependencies: + detect-newline "^3.0.0" + +jest-each@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.5.0.tgz#fc6e7014f83eac68e22b7195598de8554c2e5c06" + integrity sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA== + dependencies: + "@jest/types" "^29.5.0" + chalk "^4.0.0" + jest-get-type "^29.4.3" + jest-util "^29.5.0" + pretty-format "^29.5.0" + +jest-environment-node@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.5.0.tgz#f17219d0f0cc0e68e0727c58b792c040e332c967" + integrity sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw== + dependencies: + "@jest/environment" "^29.5.0" + "@jest/fake-timers" "^29.5.0" + "@jest/types" "^29.5.0" + "@types/node" "*" + jest-mock "^29.5.0" + jest-util "^29.5.0" + +jest-get-type@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.4.3.tgz#1ab7a5207c995161100b5187159ca82dd48b3dd5" + integrity sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg== + +jest-haste-map@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.5.0.tgz#69bd67dc9012d6e2723f20a945099e972b2e94de" + integrity sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA== + dependencies: + "@jest/types" "^29.5.0" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^29.4.3" + jest-util "^29.5.0" + jest-worker "^29.5.0" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" + +jest-leak-detector@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz#cf4bdea9615c72bac4a3a7ba7e7930f9c0610c8c" + integrity sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow== + dependencies: + jest-get-type "^29.4.3" + pretty-format "^29.5.0" + +jest-matcher-utils@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz#d957af7f8c0692c5453666705621ad4abc2c59c5" + integrity sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw== + dependencies: + chalk "^4.0.0" + jest-diff "^29.5.0" + jest-get-type "^29.4.3" + pretty-format "^29.5.0" + +jest-message-util@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.5.0.tgz#1f776cac3aca332ab8dd2e3b41625435085c900e" + integrity sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.5.0" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.5.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.5.0.tgz#26e2172bcc71d8b0195081ff1f146ac7e1518aed" + integrity sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw== + dependencies: + "@jest/types" "^29.5.0" + "@types/node" "*" + jest-util "^29.5.0" + +jest-pnp-resolver@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" + integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== + +jest-regex-util@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.4.3.tgz#a42616141e0cae052cfa32c169945d00c0aa0bb8" + integrity sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg== + +jest-resolve-dependencies@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz#f0ea29955996f49788bf70996052aa98e7befee4" + integrity sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg== + dependencies: + jest-regex-util "^29.4.3" + jest-snapshot "^29.5.0" + +jest-resolve@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.5.0.tgz#b053cc95ad1d5f6327f0ac8aae9f98795475ecdc" + integrity sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w== + dependencies: + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.5.0" + jest-pnp-resolver "^1.2.2" + jest-util "^29.5.0" + jest-validate "^29.5.0" + resolve "^1.20.0" + resolve.exports "^2.0.0" + slash "^3.0.0" + +jest-runner@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.5.0.tgz#6a57c282eb0ef749778d444c1d758c6a7693b6f8" + integrity sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ== + dependencies: + "@jest/console" "^29.5.0" + "@jest/environment" "^29.5.0" + "@jest/test-result" "^29.5.0" + "@jest/transform" "^29.5.0" + "@jest/types" "^29.5.0" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.13.1" + graceful-fs "^4.2.9" + jest-docblock "^29.4.3" + jest-environment-node "^29.5.0" + jest-haste-map "^29.5.0" + jest-leak-detector "^29.5.0" + jest-message-util "^29.5.0" + jest-resolve "^29.5.0" + jest-runtime "^29.5.0" + jest-util "^29.5.0" + jest-watcher "^29.5.0" + jest-worker "^29.5.0" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runtime@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.5.0.tgz#c83f943ee0c1da7eb91fa181b0811ebd59b03420" + integrity sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw== + dependencies: + "@jest/environment" "^29.5.0" + "@jest/fake-timers" "^29.5.0" + "@jest/globals" "^29.5.0" + "@jest/source-map" "^29.4.3" + "@jest/test-result" "^29.5.0" + "@jest/transform" "^29.5.0" + "@jest/types" "^29.5.0" + "@types/node" "*" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^29.5.0" + jest-message-util "^29.5.0" + jest-mock "^29.5.0" + jest-regex-util "^29.4.3" + jest-resolve "^29.5.0" + jest-snapshot "^29.5.0" + jest-util "^29.5.0" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-snapshot@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.5.0.tgz#c9c1ce0331e5b63cd444e2f95a55a73b84b1e8ce" + integrity sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g== + dependencies: + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-jsx" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/traverse" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^29.5.0" + "@jest/transform" "^29.5.0" + "@jest/types" "^29.5.0" + "@types/babel__traverse" "^7.0.6" + "@types/prettier" "^2.1.5" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^29.5.0" + graceful-fs "^4.2.9" + jest-diff "^29.5.0" + jest-get-type "^29.4.3" + jest-matcher-utils "^29.5.0" + jest-message-util "^29.5.0" + jest-util "^29.5.0" + natural-compare "^1.4.0" + pretty-format "^29.5.0" + semver "^7.3.5" + +jest-util@^29.0.0, jest-util@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.5.0.tgz#24a4d3d92fc39ce90425311b23c27a6e0ef16b8f" + integrity sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ== + dependencies: + "@jest/types" "^29.5.0" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-validate@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.5.0.tgz#8e5a8f36178d40e47138dc00866a5f3bd9916ffc" + integrity sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ== + dependencies: + "@jest/types" "^29.5.0" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^29.4.3" + leven "^3.1.0" + pretty-format "^29.5.0" + +jest-watcher@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.5.0.tgz#cf7f0f949828ba65ddbbb45c743a382a4d911363" + integrity sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA== + dependencies: + "@jest/test-result" "^29.5.0" + "@jest/types" "^29.5.0" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.13.1" + jest-util "^29.5.0" + string-length "^4.0.1" + +jest-worker@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.5.0.tgz#bdaefb06811bd3384d93f009755014d8acb4615d" + integrity sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA== + dependencies: + "@types/node" "*" + jest-util "^29.5.0" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-29.5.0.tgz#f75157622f5ce7ad53028f2f8888ab53e1f1f24e" + integrity sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ== + dependencies: + "@jest/core" "^29.5.0" + "@jest/types" "^29.5.0" + import-local "^3.0.2" + jest-cli "^29.5.0" + +js-sha3@0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" + integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== + +js-sha3@^0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" + integrity sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc= + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +jsbi@^3.1.4: + version "3.2.5" + resolved "https://registry.yarnpkg.com/jsbi/-/jsbi-3.2.5.tgz#b37bb90e0e5c2814c1c2a1bcd8c729888a2e37d6" + integrity sha512-aBE4n43IPvjaddScbvWRA2YlTzKEynHzu7MqOyTipdHucf/VxS63ViCjxYRg86M8Rxwbt/GfzHl1kKERkt45fQ== + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + +json-to-graphql-query@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/json-to-graphql-query/-/json-to-graphql-query-2.2.4.tgz#ada9cfdbb9bf38589fd2661e1588d1edd0a882cc" + integrity sha512-vNvsOKDSlEqYCzejI1xHS9Hm738dSnG4Upy09LUGqyybZXSIIb7NydDphB/6WxW2EEVpPU4JeU/Yo63Nw9dEJg== + +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + dependencies: + minimist "^1.2.0" + +json5@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" + integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== + +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +lodash.memoize@4.x: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.set@^4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23" + integrity sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM= + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +make-dir@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +make-error@1.x: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" + integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== + dependencies: + braces "^3.0.1" + picomatch "^2.2.3" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= + +minimatch@^3.0.3: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.0, minimist@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== + +mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +node-fetch@^2.6.11: + version "2.6.11" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.11.tgz#cde7fc71deef3131ef80a738919f999e6edfff25" + integrity sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w== + dependencies: + whatwg-url "^5.0.0" + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== + +node-releases@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.5.tgz#280ed5bc3eba0d96ce44897d8aee478bfb3d9666" + integrity sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q== + +noms@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/noms/-/noms-0.0.0.tgz#da8ebd9f3af9d6760919b27d9cdc8092a7332859" + integrity sha1-2o69nzr51nYJGbJ9nNyAkqczKFk= + dependencies: + inherits "^2.0.1" + readable-stream "~1.0.31" + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +object-inspect@^1.11.0, object-inspect@^1.9.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" + integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== + +object-keys@^1.0.12, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" + integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + has-symbols "^1.0.1" + object-keys "^1.1.1" + +object.entries@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.5.tgz#e1acdd17c4de2cd96d5a08487cfb9db84d881861" + integrity sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + +object.values@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac" + integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= + dependencies: + p-limit "^1.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pirates@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" + integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== + dependencies: + fast-diff "^1.1.2" + +prettier@^2.7.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" + integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== + +pretty-format@^29.0.0, pretty-format@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.5.0.tgz#283134e74f70e2e3e7229336de0e4fce94ccde5a" + integrity sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw== + dependencies: + "@jest/schemas" "^29.4.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +prompts@^2.0.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +punycode@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" + integrity sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0= + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +pure-rand@^6.0.0: + version "6.0.2" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.0.2.tgz#a9c2ddcae9b68d736a8163036f088a2781c8b306" + integrity sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +react-is@^18.0.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" + integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + +readable-stream@~1.0.31: + version "1.0.34" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + integrity sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw= + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@~2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +regexpp@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve.exports@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" + integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== + +resolve@^1.20.0: + version "1.21.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.21.0.tgz#b51adc97f3472e6a5cf4444d34bc9d6b9037591f" + integrity sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA== + dependencies: + is-core-module "^2.8.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +resolve@^1.22.0: + version "1.22.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" + integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== + dependencies: + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +scrypt-js@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" + integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== + +semver@7.x, semver@^7.3.7: + version "7.3.7" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" + integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== + dependencies: + lru-cache "^6.0.0" + +semver@^6.0.0, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +semver@^7.3.5: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +signal-exit@^3.0.3, signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +stack-utils@^2.0.3: + version "2.0.5" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" + integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA== + dependencies: + escape-string-regexp "^2.0.0" + +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string.prototype.trimend@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" + integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +string.prototype.trimstart@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" + integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + +through2@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + +tiny-invariant@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.2.0.tgz#a1141f86b672a9148c72e978a19a73b9b94a15a9" + integrity sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg== + +tiny-warning@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" + integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== + +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toformat@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/toformat/-/toformat-2.0.0.tgz#7a043fd2dfbe9021a4e36e508835ba32056739d8" + integrity sha512-03SWBVop6nU8bpyZCx7SodpYznbZF5R4ljwNLBcTQzKOD9xuihRo/psX58llS1BMFhhAI08H3luot5GoXJz2pQ== + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + +ts-jest@^29.1.0: + version "29.1.0" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.1.0.tgz#4a9db4104a49b76d2b368ea775b6c9535c603891" + integrity sha512-ZhNr7Z4PcYa+JjMl62ir+zPiNJfXJN6E8hSLnaUKhOgqcn8vb3e537cpkd0FuAfRK3sR1LSqM1MOhliXNgOFPA== + dependencies: + bs-logger "0.x" + fast-json-stable-stringify "2.x" + jest-util "^29.0.0" + json5 "^2.2.3" + lodash.memoize "4.x" + make-error "1.x" + semver "7.x" + yargs-parser "^21.0.1" + +tsconfig-paths@^3.14.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" + integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.1" + minimist "^1.2.6" + strip-bom "^3.0.0" + +tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + +tulons@^0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/tulons/-/tulons-0.0.7.tgz#31677402ab51dc51478d375f90df76ea2ca8cbb9" + integrity sha512-JyL9Vn4PPG2TTEJS35yqQgAMLd3IX9pFIlbiLmv47HuHTo2F3ihYg2yfMqde4hqGY1nGk77iJ/lvsTbAURJ8rg== + dependencies: + axios "^0.27.2" + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +typescript@^4.7.4: + version "4.7.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235" + integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== + +unbox-primitive@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" + integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== + dependencies: + function-bind "^1.1.1" + has-bigints "^1.0.1" + has-symbols "^1.0.2" + which-boxed-primitive "^1.0.2" + +untildify@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" + integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +v8-compile-cache@^2.0.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== + +v8-to-istanbul@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz#b6f994b0b5d4ef255e17a0d17dc444a9f5132fa4" + integrity sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^1.6.0" + +walker@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +word-wrap@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +write-file-atomic@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" + integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^3.0.7" + +ws@7.4.6: + version "7.4.6" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" + integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== + +xtend@~4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs-parser@^21.0.0, yargs-parser@^21.0.1: + version "21.0.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.1.tgz#0267f286c877a4f0f728fceb6f8a3e4cb95c6e35" + integrity sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg== + +yargs@^16.1.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yargs@^17.3.1: + version "17.5.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.5.1.tgz#e109900cab6fcb7fd44b1d8249166feb0b36e58e" + integrity sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.0.0" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== From c2f6bd98705960d77c0a818a120da70b56be5fa0 Mon Sep 17 00:00:00 2001 From: Jacob Homanics <32080359+Hotmanics@users.noreply.github.com> Date: Fri, 28 Jul 2023 01:07:46 -0500 Subject: [PATCH 454/815] [hats-protocol-single-vote-per-org] bugfix #1 (#1232) * added in hats protocol strategy * updted readme * Revert "updted readme" This reverts commit 8746d5d68b67105013af51fb9a685b51194c5a1c. * added in simulated project, updated README, added documentation * functional implementation before eligibility * functional but dirty * fully functional - still dirty * added support for different chains * updated readme and removed unnecessary files * removed console messages and fixed strategies/index.ts * Revert "removed console messages and fixed strategies/index.ts" This reverts commit e92e3df90f5b802b4c933bd9d73144f15be4f4c0. * Revert "Merge branch 'master' into master" This reverts commit c48ccff95e4643d4244f91ffcc0ea7f8aa0c9326, reversing changes made to 612687e5e5d97e310d09b787749be83be2b3e6c2. * Revert "Revert "Merge branch 'master' into master"" This reverts commit f15c406c549ac92f0f5d808aec497fb6145e63e4. * Revert "Revert "removed console messages and fixed strategies/index.ts"" This reverts commit 74cf341c373d385c327f8d9405f4035fab548675. * reverted yarn lock back to original commit and removed package-lock.json * Update yarn.lock * Update src/strategies/hats-protocol-single-vote-per-org/index.ts * Update src/strategies/hats-protocol-single-vote-per-org/index.ts * Update src/strategies/hats-protocol-single-vote-per-org/index.ts * added snapshot to subgraph requests * fixed ethers error and updated yarn lock to match snapshot-strategies main * updated yarn.lock * Update yarn.lock * Update src/strategies/hats-protocol-single-vote-per-org/index.ts * fixed a bug where needed to convert to hex before making subgraph call * updated versioning --------- Co-authored-by: Chaitanya --- .../hats-protocol-single-vote-per-org/README.md | 2 +- .../hats-protocol-single-vote-per-org/examples.json | 8 ++++---- src/strategies/hats-protocol-single-vote-per-org/index.ts | 7 ++++--- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/strategies/hats-protocol-single-vote-per-org/README.md b/src/strategies/hats-protocol-single-vote-per-org/README.md index 399061d96..f5f252946 100644 --- a/src/strategies/hats-protocol-single-vote-per-org/README.md +++ b/src/strategies/hats-protocol-single-vote-per-org/README.md @@ -7,6 +7,6 @@ Here is an example of parameters: ```json { "address": "0x3bc1A0Ad72417f2d411118085256fC53CBdDd137", - "humanReadableTreeId": 2 + "humanReadableTreeId": 44 } ``` diff --git a/src/strategies/hats-protocol-single-vote-per-org/examples.json b/src/strategies/hats-protocol-single-vote-per-org/examples.json index 45c0e1bd5..42f990f79 100644 --- a/src/strategies/hats-protocol-single-vote-per-org/examples.json +++ b/src/strategies/hats-protocol-single-vote-per-org/examples.json @@ -5,16 +5,16 @@ "name": "hats-protocol-single-vote-per-org", "params": { "address": "0x3bc1A0Ad72417f2d411118085256fC53CBdDd137", - "humanReadableTreeId" : 2 + "humanReadableTreeId" : 44 } }, - "network": "10", + "network": "5", "addresses": [ - "0xbeC26FFa12c90217943D1b2958f60A821aE6E549", + "0xc4f6578c24c599F195c0758aD3D4861758d703A3", "0xa6aF0566EF4eF7E8f38913f69d4e55c06F00A5aC", "0x00e7332F9Cd4C05a0645AC959Fb1Be60ec24F94f", "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ], - "snapshot": 107031024 + "snapshot": 9418504 } ] diff --git a/src/strategies/hats-protocol-single-vote-per-org/index.ts b/src/strategies/hats-protocol-single-vote-per-org/index.ts index 1d5cba91e..80c2f2eeb 100644 --- a/src/strategies/hats-protocol-single-vote-per-org/index.ts +++ b/src/strategies/hats-protocol-single-vote-per-org/index.ts @@ -4,7 +4,7 @@ import { StaticJsonRpcProvider } from '@ethersproject/providers'; import { multicall } from '../../utils'; export const author = 'hotmanics'; -export const version = '0.1.1'; +export const version = '0.1.2'; const abi = [ 'function isWearerOfHat(address _user, uint256 _hatId) external view returns (bool isWearer)' @@ -12,9 +12,10 @@ const abi = [ async function subgraphRequestHats(url, snapshot, humanReadableTreeId) { const str1 = '0x'; - const length = humanReadableTreeId.toString().length; + const hex = humanReadableTreeId.toString(16); + const length = hex.toString().length; let resultString = str1.padEnd(10 - length, '0'); - resultString = resultString + humanReadableTreeId.toString(); + resultString = resultString + hex.toString(); const params = { tree: { From 1599a2530ded9ce1e8605fd38de5b438a20af9ac Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Sun, 30 Jul 2023 02:29:20 +0530 Subject: [PATCH 455/815] [reliquary] Fix multicaller limit (#1234) --- src/strategies/reliquary/index.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/strategies/reliquary/index.ts b/src/strategies/reliquary/index.ts index d288fb55a..c05471b6c 100644 --- a/src/strategies/reliquary/index.ts +++ b/src/strategies/reliquary/index.ts @@ -30,7 +30,10 @@ export async function strategy( ) { const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - const multi = new Multicaller(network, provider, abi, { blockTag }); + const multi = new Multicaller(network, provider, abi, { + blockTag, + limit: 475 + }); for (const address of addresses) { multi.call(address, options.reliquaryAddress, 'relicPositionsOfOwner', [ @@ -95,7 +98,7 @@ export async function strategy( const userVotingPower: Record = {}; - /* + /* if we use the level strategy, we just add the level as a multiplier in relation to the max level. So the formula used is: relicAmount * level / maxLevel */ From 234aba79554516846df846c664ca5ba71bf85192 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 30 Jul 2023 18:11:16 +0530 Subject: [PATCH 456/815] Automated lint (#1236) Co-authored-by: ChaituVR --- .../examples.json | 2 +- src/strategies/index.ts | 4 ++-- .../index.ts | 5 +++-- .../rocketpool-node-operator-v2/index.ts | 20 +++++++++---------- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/strategies/hats-protocol-single-vote-per-org/examples.json b/src/strategies/hats-protocol-single-vote-per-org/examples.json index 42f990f79..5518f2edc 100644 --- a/src/strategies/hats-protocol-single-vote-per-org/examples.json +++ b/src/strategies/hats-protocol-single-vote-per-org/examples.json @@ -5,7 +5,7 @@ "name": "hats-protocol-single-vote-per-org", "params": { "address": "0x3bc1A0Ad72417f2d411118085256fC53CBdDd137", - "humanReadableTreeId" : 44 + "humanReadableTreeId": 44 } }, "network": "5", diff --git a/src/strategies/index.ts b/src/strategies/index.ts index a3c394835..66dcc0a6b 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -401,7 +401,7 @@ import * as syntheticNounsClaimerOwner from './synthetic-nouns-with-claimer'; import * as depositInSablierStream from './deposit-in-sablier-stream'; import * as echelonWalletPrimeAndCachedKey from './echelon-wallet-prime-and-cached-key'; import * as nation3VotesWIthDelegations from './nation3-votes-with-delegations'; -import * as nation3CoopPassportWithDelegations from './nation3-passport-coop-with-delegations' +import * as nation3CoopPassportWithDelegations from './nation3-passport-coop-with-delegations'; import * as aavegotchiAgip37WapGhst from './aavegotchi-agip-37-wap-ghst'; import * as aavegotchiAgip37GltrStakedLp from './aavegotchi-agip-37-gltr-staked-lp'; import * as posichainStaking from './posichain-staking'; @@ -863,7 +863,7 @@ const strategies = { 'deposit-in-sablier-stream': depositInSablierStream, 'echelon-wallet-prime-and-cached-key': echelonWalletPrimeAndCachedKey, 'nation3-votes-with-delegations': nation3VotesWIthDelegations, - 'nation3-passport-coop-with-delegations':nation3CoopPassportWithDelegations, + 'nation3-passport-coop-with-delegations': nation3CoopPassportWithDelegations, 'aavegotchi-agip-37-wap-ghst': aavegotchiAgip37WapGhst, 'aavegotchi-agip-37-gltr-staked-lp': aavegotchiAgip37GltrStakedLp, 'erc20-tokens-per-uni': erc20TokensPerUni, diff --git a/src/strategies/nation3-passport-coop-with-delegations/index.ts b/src/strategies/nation3-passport-coop-with-delegations/index.ts index cf49b910a..833a030cb 100644 --- a/src/strategies/nation3-passport-coop-with-delegations/index.ts +++ b/src/strategies/nation3-passport-coop-with-delegations/index.ts @@ -39,7 +39,8 @@ export async function strategy( erc721SignerCaller.call(i, options.erc721, 'signerOf', [i]); } - const erc721Signers : Record = await erc721SignerCaller.execute(); + const erc721Signers: Record = + await erc721SignerCaller.execute(); const erc721SignersArr = Object.entries(erc721Signers); @@ -47,5 +48,5 @@ export async function strategy( .map(([, address]) => address) .filter((address) => addresses.includes(address)); - return Object.fromEntries(eligibleAddresses.map(value => [value, 1])); + return Object.fromEntries(eligibleAddresses.map((value) => [value, 1])); } diff --git a/src/strategies/rocketpool-node-operator-v2/index.ts b/src/strategies/rocketpool-node-operator-v2/index.ts index 576be693c..362581f8f 100644 --- a/src/strategies/rocketpool-node-operator-v2/index.ts +++ b/src/strategies/rocketpool-node-operator-v2/index.ts @@ -1,13 +1,13 @@ -import { BigNumberish } from "@ethersproject/bignumber"; -import { formatUnits } from "@ethersproject/units"; -import { Multicaller } from "../../utils"; +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; -export const author = "rocket-pool"; -export const version = "0.1.2"; +export const author = 'rocket-pool'; +export const version = '0.1.2'; -const rocketNodeStakingAddress = "0x0d8D8f8541B12A0e1194B7CC4b6D954b90AB82ec"; +const rocketNodeStakingAddress = '0x0d8D8f8541B12A0e1194B7CC4b6D954b90AB82ec'; const rocketNodeStakingContractAbi = [ - "function getNodeEffectiveRPLStake(address _nodeAddress) external view returns (uint256)", + 'function getNodeEffectiveRPLStake(address _nodeAddress) external view returns (uint256)' ]; export async function strategy( @@ -18,7 +18,7 @@ export async function strategy( options, snapshot ): Promise> { - const blockTag = typeof snapshot === "number" ? snapshot : "latest"; + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; const effectiveStake = new Multicaller( network, @@ -31,7 +31,7 @@ export async function strategy( effectiveStake.call( address, rocketNodeStakingAddress, - "getNodeEffectiveRPLStake", + 'getNodeEffectiveRPLStake', [address] ); }); @@ -42,7 +42,7 @@ export async function strategy( return Object.fromEntries( Object.entries(effectiveStakeResponse).map(([address, balance]) => [ address, - Math.sqrt(parseFloat(formatUnits(balance, options.decimals))) / 2, + Math.sqrt(parseFloat(formatUnits(balance, options.decimals))) / 2 ]) ); } From 56c8f6ef232cabf6adbe13f2ab8351af029e0ede Mon Sep 17 00:00:00 2001 From: Razvan Gabriel Apostu Date: Mon, 31 Jul 2023 08:31:48 +0200 Subject: [PATCH 457/815] [sablier-v2] add strategy for Sablier V2 streams (#1235) * feat: sablier v2 total amounts strategy * feat: add sablier strategies for withdraw, streamed and deposited assets * fix: use addresses box for recipient or sender list, disallow global search * fix: withdrawable amount, aggregate senders when using proxy --- src/strategies/index.ts | 4 +- src/strategies/sablier-v2/README.md | 86 ++++++ src/strategies/sablier-v2/configuration.ts | 230 +++++++++++++++ src/strategies/sablier-v2/examples.json | 78 +++++ src/strategies/sablier-v2/index.ts | 94 ++++++ src/strategies/sablier-v2/queries.ts | 314 +++++++++++++++++++++ src/strategies/sablier-v2/schema.json | 40 +++ 7 files changed, 845 insertions(+), 1 deletion(-) create mode 100644 src/strategies/sablier-v2/README.md create mode 100644 src/strategies/sablier-v2/configuration.ts create mode 100644 src/strategies/sablier-v2/examples.json create mode 100644 src/strategies/sablier-v2/index.ts create mode 100644 src/strategies/sablier-v2/queries.ts create mode 100644 src/strategies/sablier-v2/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 66dcc0a6b..218faa3fc 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -452,6 +452,7 @@ import * as hatsProtocolSingleVotePerOrg from './hats-protocol-single-vote-per-o import * as karmaDiscordRoles from './karma-discord-roles'; import * as seedifyHoldStakingFarming from './seedify-cumulative-voting-power-hodl-staking-farming'; import * as stakedMoreKudasai from './staked-morekudasai'; +import * as sablierV2 from './sablier-v2'; const strategies = { 'cap-voting-power': capVotingPower, @@ -911,7 +912,8 @@ const strategies = { 'karma-discord-roles': karmaDiscordRoles, 'seedify-cumulative-voting-power-hodl-staking-farming': seedifyHoldStakingFarming, - 'staked-morekudasai': stakedMoreKudasai + 'staked-morekudasai': stakedMoreKudasai, + 'sablier-v2': sablierV2 }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/sablier-v2/README.md b/src/strategies/sablier-v2/README.md new file mode 100644 index 000000000..ee5681b5b --- /dev/null +++ b/src/strategies/sablier-v2/README.md @@ -0,0 +1,86 @@ +# sablier-v2 + +This set of strategies returns various amounts related to Sablier V2 streams for any given asset. + +### Setup + +```json +{ + "address": "0x97cb342cf2f6ecf48c1285fb8668f5a4237bf862", + "symbol": "DAI", + "decimals": 18, + "policy": "withdrawable-recipient" // recommended, +} +``` + +#### Other parameters + +Aside from this example setup, we use Snapshot's base parameters such as `Network`, `Snapshot`(block) or `Addresses`. +Based on the chosen strategy, the values filled in the `Addresses` field will represent a list (>= 1) of senders or recipients. + +### Policies + +| Policy | Methodology | +| ---------------------- | --------------------------------------------------------------------------------------------- | +| withdrawable-recipient | Tokens available for withdrawal from the stream. | +| streamed-recipient | Tokens that have been streamed until the snapshot. | +| deposited-recipient | Tokens that have been deposited in streams the recipient owns at snapshot. | +| deposited-sender | Tokens that have been deposited in streams started by the sender by the time of the snapshot. | + +### Example + +``` +Sablier V2 Stream #000001 +--- +Deposited: TKN 1000 for 30 days +Withdrawn: TKN 450 before snapshot +Snapshot: Day 15 (Half) with a streamed amount of TKN 500 + ++------------------------+----------+ +| POLICY | POWER | ++------------------------+----------+ +| withdrawable-recipient | TKN 50 | ++------------------------+----------+ +| streamed-recipient | TKN 500 | ++------------------------+----------+ +| deposited-recipient | TKN 1000 | ++------------------------+----------+ +| deposited-sender | TKN 1000 | ++------------------------+----------+ +| erc20-balance-of | TKN 450 | ++------------------------+----------+ +``` + +### Details and Caveats + +#### `withdrawable-recipient` + +The withdrawable amount represents assets that have been streamed but not withdrawn yet by the recipient. + +It relies on the `withdrawableAmountOf` contract [method](https://docs.sablier.com/contracts/v2/reference/core/abstracts/abstract.SablierV2Lockup#withdrawableamountof). + +We recommend using the `withdrawable-recipient` strategy alongside `erc20-balance-of` for the best results. It counts assets is the user's wallet, as well as assets streamed but not withdrawn yet. + +#### `streamed-recipient` + +It aggregates historical amounts that have already been streamed to the recipient. This will also include already withdrawn assets. + +It relies on the `streamedAmountOf` contract methods ([linear](https://docs.sablier.com/contracts/v2/reference/core/contract.SablierV2LockupLinear#streamedamountof), [dynamic](https://docs.sablier.com/contracts/v2/reference/core/contract.SablierV2LockupDynamic#streamedamountof)). + +_Caveat #1:_ Careful when using alongside `erc20-balance-of` as it may double count assets. In the [example](#example): `TNK 500` streamed from which `TKN 450` withdrawn equals a voting power or `TKN 950`. + +_Caveat #2:_ If funds are recycled (streamed, withdrawn and streamed again) the voting power may be increased artificially. + +#### `deposited-recipient` + +It aggregates historical deposits up to the moment of the snapshot. Counts streams owned by the recipient. + +_Caveat #1:_ Streaming, canceling and streaming again will cause assets to be counted multiple times. + +#### `deposited-sender` + +It aggregates historical deposits up to the moment of the snapshot. Counts streams started by the sender. + +_Caveat #1:_ Streaming, canceling and streaming again will cause assets to be counted multiple times. + +_Caveat #2:_ This also takes into account streams created through PRB-Proxy instances configured through the frontend app. Read more about it in the [docs](https://docs.sablier.com/contracts/v2/reference/overview#periphery). diff --git a/src/strategies/sablier-v2/configuration.ts b/src/strategies/sablier-v2/configuration.ts new file mode 100644 index 000000000..5f8c46559 --- /dev/null +++ b/src/strategies/sablier-v2/configuration.ts @@ -0,0 +1,230 @@ +/** + * ------------------------------------------------------ + * SABLIER V2 CONSTANTS + * ------------------------------------------------------ + */ + +const chains = { + arbitrum: '42161', + avalanche: '43114', + bsc: '56', + ethereum: '1', + goerli: '5', + gnosis: '100', + optimism: '10', + polygon: '137' +}; + +const deployments = { + [chains.arbitrum]: { + contracts: [ + '0x197d655f3be03903fd25e7828c3534504bfe525e', // SablierV2LockupLinear + '0xa9efbef1a35ff80041f567391bdc9813b2d50197' // SablierV2LockupDynamic + ], + subgraph: + 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2-arbitrum' + }, + [chains.avalanche]: { + contracts: [ + '0x610346e9088afa70d6b03e96a800b3267e75ca19', // SablierV2LockupLinear + '0x665d1c8337f1035cfbe13dd94bb669110b975f5f' // SablierV2LockupDynamic + ], + subgraph: + 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2-avalanche' + }, + [chains.bsc]: { + contracts: [ + '0x3fe4333f62a75c2a85c8211c6aefd1b9bfde6e51', // SablierV2LockupLinear + '0xf2f3fef2454dca59eca929d2d8cd2a8669cc6214' // SablierV2LockupDynamic + ], + subgraph: + 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2-bsc' + }, + + [chains.ethereum]: { + contracts: [ + '0xb10daee1fcf62243ae27776d7a92d39dc8740f95', // SablierV2LockupLinear + '0x39efdc3dbb57b2388ccc4bb40ac4cb1226bc9e44' // SablierV2LockupDynamic + ], + subgraph: 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2' + }, + [chains.optimism]: { + contracts: [ + '0xb923abdca17aed90eb5ec5e407bd37164f632bfd', // SablierV2LockupLinear + '0x6f68516c21e248cddfaf4898e66b2b0adee0e0d6' // SablierV2LockupDynamic + ], + subgraph: + 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2-optimism' + }, + [chains.polygon]: { + contracts: [ + '0x67422c3e36a908d5c3237e9cffeb40bde7060f6e', // SablierV2LockupLinear + '0x7313addb53f96a4f710d3b91645c62b434190725' // SablierV2LockupDynamic + ], + subgraph: + 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2-polygon' + }, + [chains.goerli]: { + contracts: [ + '0x6e3678c005815ab34986d8d66a353cd3699103de', // SablierV2LockupLinear + '0x4be70ede968e9dba12db42b9869bec66bedc17d7' // SablierV2LockupDynamic + ], + subgraph: + 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2-goerli' + }, + [chains.gnosis]: { + contracts: [ + '0x685e92c9ca2bb23f1b596d0a7d749c0603e88585', // SablierV2LockupLinear + '0xeb148e4ec13aaa65328c0ba089a278138e9e53f9' // SablierV2LockupDynamic + ], + subgraph: + 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2-gnosis' + } +}; + +const abi = { + getDepositedAmount: + 'function getDepositedAmount(uint256 streamId) external view returns (uint128 depositedAmount)', + streamedAmountOf: + 'function streamedAmountOf(uint256 streamId) external view returns (uint128 streamedAmount)', + withdrawableAmountOf: + 'function withdrawableAmountOf(uint256 streamId) external view returns (uint128 withdrawableAmount)' +}; + +const page = 1000; + +const policies = { + 'withdrawable-recipient': 'withdrawable-recipient', + 'streamed-recipient': 'streamed-recipient', + 'deposited-recipient': 'deposited-recipient', + 'deposited-sender': 'deposited-sender' +}; + +type IPolicy = typeof policies[keyof typeof policies]; + +interface IOptions { + address: string; + decimals: number; + symbol?: string; + policy: IPolicy; +} + +/** + * ------------------------------------------------------ + * SABLIER V2 SUBGRAPH QUERIES + * ------------------------------------------------------ + */ + +interface IStreamsByAssetParams { + accounts: string[]; + asset: string; + block: number; + first?: number; + skip?: number; +} + +type IAccountMap = Map< + string, + { id: string; contract: string; deposited: string; withdrawn: string }[] +>; + +interface IStreamsByAssetResult { + streams: { + id: string; + contract: { + id: string; + }; + proxied: boolean; + proxender: string; + recipient: string; + sender: string; + tokenId: string; + depositAmount: string; + withdrawnAmount: string; + }[]; +} + +/** @returns Streams by recipient and asset/token at the given block */ + +const RecipientStreamsByAsset = ({ + asset, + block, + first = page, + accounts, + skip = 0 +}: IStreamsByAssetParams) => ({ + streams: { + __args: { + block: { number: block }, + first, + orderBy: 'timestamp', + orderDirection: 'desc', + skip, + where: { + asset, + recipient_in: accounts + } + }, + id: true, + contract: { + id: true + }, + recipient: true, + sender: true, + tokenId: true, + depositAmount: true, + withdrawnAmount: true + } +}); + +/** @returns Streams by recipient and asset/token at the given block */ + +const SenderStreamsByAsset = ({ + asset, + block, + first = page, + accounts, + skip = 0 +}: IStreamsByAssetParams) => ({ + streams: { + __args: { + block: { number: block }, + first, + orderBy: 'timestamp', + orderDirection: 'desc', + skip, + where: { + or: [ + { + and: [{ asset: asset }, { sender_in: accounts }] + }, + { + and: [{ asset: asset }, { proxender_in: accounts }] + } + ] + } + }, + id: true, + contract: { + id: true + }, + proxied: true, + proxender: true, + recipient: true, + sender: true, + tokenId: true, + depositAmount: true, + withdrawnAmount: true + } +}); + +const queries = { RecipientStreamsByAsset, SenderStreamsByAsset }; + +export type { + IAccountMap, + IOptions, + IPolicy, + IStreamsByAssetParams, + IStreamsByAssetResult +}; +export { abi, chains, deployments, page, policies, queries }; diff --git a/src/strategies/sablier-v2/examples.json b/src/strategies/sablier-v2/examples.json new file mode 100644 index 000000000..3ac7908cb --- /dev/null +++ b/src/strategies/sablier-v2/examples.json @@ -0,0 +1,78 @@ +[ + { + "name": "Example query with policy: withdrawable-recipient (recommended)", + "strategy": { + "name": "sablier-v2", + "params": { + "address": "0x97cb342cf2f6ecf48c1285fb8668f5a4237bf862", + "decimals": 18, + "symbol": "DAI", + "policy": "withdrawable-recipient" + } + }, + "network": "5", + "addresses": [ + "0x9ad7cad4f10d0c3f875b8a2fd292590490c9f491", + "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", + "0x506C56B2541eFeCf7A510E9A0c0382cB2FC69051" + ], + "snapshot": 9432707 + }, + { + "name": "Example query with policy: streamed-recipient", + "strategy": { + "name": "sablier-v2", + "params": { + "address": "0x97cb342cf2f6ecf48c1285fb8668f5a4237bf862", + "decimals": 18, + "symbol": "DAI", + "policy": "streamed-recipient" + } + }, + "network": "5", + "addresses": [ + "0x9ad7cad4f10d0c3f875b8a2fd292590490c9f491", + "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", + "0x506C56B2541eFeCf7A510E9A0c0382cB2FC69051" + ], + "snapshot": 9432707 + }, + { + "name": "Example query with policy: deposited-recipient", + "strategy": { + "name": "sablier-v2", + "params": { + "address": "0x97cb342cf2f6ecf48c1285fb8668f5a4237bf862", + "decimals": 18, + "symbol": "DAI", + "policy": "deposited-recipient" + } + }, + "network": "5", + "addresses": [ + "0x9ad7cad4f10d0c3f875b8a2fd292590490c9f491", + "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", + "0x506C56B2541eFeCf7A510E9A0c0382cB2FC69051" + ], + "snapshot": 9432707 + }, + { + "name": "Example query with policy: deposited-sender", + "strategy": { + "name": "sablier-v2", + "params": { + "address": "0x97cb342cf2f6ecf48c1285fb8668f5a4237bf862", + "decimals": 18, + "symbol": "DAI", + "policy": "deposited-sender" + } + }, + "network": "5", + "addresses": [ + "0x9ad7cad4f10d0c3f875b8a2fd292590490c9f491", + "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", + "0x506C56B2541eFeCf7A510E9A0c0382cB2FC69051" + ], + "snapshot": 9432707 + } +] diff --git a/src/strategies/sablier-v2/index.ts b/src/strategies/sablier-v2/index.ts new file mode 100644 index 000000000..9bc5b5f84 --- /dev/null +++ b/src/strategies/sablier-v2/index.ts @@ -0,0 +1,94 @@ +import { formatUnits } from '@ethersproject/units'; +import { getAddress } from '@ethersproject/address'; +import type { StaticJsonRpcProvider } from '@ethersproject/providers'; + +import { deployments, policies } from './configuration'; +import { + getRecipientStreams, + getRecipientStreamedAmounts, + getRecipientDepositedAmounts, + getRecipientWithdrawableAmounts, + getSenderStreams, + getSenderDepositedAmounts +} from './queries'; +import type { IOptions } from './configuration'; + +export const author = 'razgraf'; +export const version = '0.0.1'; + +function validate(network: string, addresses: string[], options: IOptions) { + if (!Object.hasOwn(deployments, network)) { + throw new Error( + 'Invalid parameter. The chosen network has to be supported by Sablier V2.' + ); + } + + if (!addresses || addresses?.length === 0) { + throw new Error( + 'Invalid parameter. The addresses field must specify at least one account.' + ); + } + + if (!options || !Object.values(policies).includes(options.policy)) { + throw new Error( + `Invalid parameter. The policy is not supported. Chose: ${ + options.policy + }. Try: ${Object.values(policies).join(', ')}.` + ); + } +} + +export async function strategy( + _space, + network: string, + provider: StaticJsonRpcProvider, + addresses: string[], + options: IOptions, + snapshot: number +): Promise> { + const snap = typeof snapshot === 'number' ? snapshot : undefined; + const block = snap || (await provider.getBlockNumber()) - 1; + const setup = { block, network, provider }; + + await validate(network, addresses, options); + + const balances = await (async () => { + switch (options.policy) { + case 'deposited-recipient': { + const streams = await getRecipientStreams(addresses, options, setup); + const balances = await getRecipientDepositedAmounts(streams); + return balances; + } + case 'deposited-sender': { + const streams = await getSenderStreams(addresses, options, setup); + const balances = await getSenderDepositedAmounts(streams); + return balances; + } + case 'streamed-recipient': { + const streams = await getRecipientStreams(addresses, options, setup); + const balances = await getRecipientStreamedAmounts(streams, setup); + return balances; + } + case 'withdrawable-recipient': + default: { + const streams = await getRecipientStreams(addresses, options, setup); + const balances = await getRecipientWithdrawableAmounts(streams, setup); + return balances; + } + } + })(); + + /** Prepare the final object (checksum address, format amounts) */ + + const prepared = {}; + balances.forEach((balance, recipient) => { + prepared[getAddress(recipient)] = parseFloat( + formatUnits(balance, options.decimals) + ); + }); + + console.log('=== SABLIER V2 ==='); + console.log(options.policy, prepared); + + return prepared; +} diff --git a/src/strategies/sablier-v2/queries.ts b/src/strategies/sablier-v2/queries.ts new file mode 100644 index 000000000..485a43d33 --- /dev/null +++ b/src/strategies/sablier-v2/queries.ts @@ -0,0 +1,314 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import type { StaticJsonRpcProvider } from '@ethersproject/providers'; +import type { + IOptions, + IAccountMap, + IStreamsByAssetParams, + IStreamsByAssetResult +} from './configuration'; + +import { abi, deployments, queries, page } from './configuration'; +import { multicall, subgraphRequest } from '../../utils'; + +/** + * Query the subgraph for all the streams owned by all (or a given set of) recipients. + * + * @returns A mapping from each recipient to their list of owned streams. + */ +async function getRecipientStreams( + recipients: string[], + options: IOptions, + setup: { + block: number; + network: string; + } +) { + const { block, network } = setup; + const endpoint = deployments[network].subgraph; + + /** Mapping recipients to the streams they own */ + const streams: IAccountMap = new Map(); + if (recipients) { + recipients.forEach((address) => { + streams.set(address.toLowerCase(), []); + }); + } + + let skip = 0; + while (true) { + const params: IStreamsByAssetParams = { + accounts: recipients.map((item) => item.toLowerCase()), + block, + asset: options.address.toLowerCase(), + first: page, + skip: skip * page + }; + + const results = (await subgraphRequest( + endpoint, + queries.RecipientStreamsByAsset(params) + )) as IStreamsByAssetResult; + + const list = results?.streams; + + if (list && list.length) { + list.forEach((item) => { + const recipient = item.recipient.toLowerCase(); + const entry = { + id: item.tokenId, + contract: item.contract.id, + deposited: item.depositAmount, + withdrawn: item.withdrawnAmount + }; + + if (!streams.has(recipient)) { + streams.set(recipient, [entry]); + } else { + streams.set(recipient, [...(streams.get(recipient) || []), entry]); + } + }); + } + + skip += 1; + if (list.length < page) { + break; + } + } + + return streams; +} + +/** + * Query the subgraph for all the streams started by all (or a given set of) senders. + * + * @returns A mapping from each sender to their list of started streams. + */ +async function getSenderStreams( + senders: string[], + options: IOptions, + setup: { + block: number; + network: string; + } +) { + const { block, network } = setup; + const endpoint = deployments[network].subgraph; + + /** Mapping senders to the streams they own */ + const streams: IAccountMap = new Map(); + if (senders) { + senders.forEach((address) => { + streams.set(address.toLowerCase(), []); + }); + } + + let skip = 0; + while (true) { + const params: IStreamsByAssetParams = { + accounts: senders.map((item) => item.toLowerCase()), + block, + asset: options.address.toLowerCase(), + first: page, + skip: skip * page + }; + + const results = (await subgraphRequest( + endpoint, + queries.SenderStreamsByAsset(params) + )) as IStreamsByAssetResult; + + const list = results?.streams; + + if (list && list.length) { + list.forEach((item) => { + const sender = item.proxied + ? item.proxender.toLowerCase() + : item.sender.toLowerCase(); + const entry = { + id: item.tokenId, + contract: item.contract.id, + deposited: item.depositAmount, + withdrawn: item.withdrawnAmount + }; + + if (!streams.has(sender)) { + streams.set(sender, [entry]); + } else { + streams.set(sender, [...(streams.get(sender) || []), entry]); + } + }); + } + + skip += 1; + if (list.length < page) { + break; + } + } + + return streams; +} + +/** + * Query the blockchain for streamed amounts for streams of every chosen recipient. + * + * @returns Full amounts made up of streamed assets for each recipient (from all owned streams). + */ +async function getRecipientStreamedAmounts( + mapping: IAccountMap, + setup: { + block: number; + network: string; + provider: StaticJsonRpcProvider; + } +) { + const { block, network, provider } = setup; + + const requests: { recipient: string; call: any }[] = []; + mapping.forEach((streams, recipient) => { + streams.forEach((stream) => { + const method: keyof typeof abi = 'streamedAmountOf'; + const call = [stream.contract.toLowerCase(), method, [stream.id]]; + requests.push({ recipient, call }); + }); + }); + + const results = await multicall( + network, + provider, + Object.values(abi), + requests.map((item) => item.call), + { blockTag: block } + ); + + /** Aggregate results from streams with the same recipient into individual amounts */ + + const amounts: Map = new Map(); + mapping.forEach((_, recipient) => { + amounts.set(recipient, BigNumber.from(0)); + }); + + requests.forEach(({ recipient }, index) => { + const amount = amounts.get(recipient); + const additional = results[index].toString(); + + const total = amount + ? amount?.add(BigNumber.from(additional)) + : BigNumber.from(0); + + amounts.set(recipient, total); + }); + + return amounts; +} + +/** + * Query the blockchain for withdrawable amounts for streams of every chosen recipient. + * + * @returns Full amounts made up of withdrawable assets for each recipient (from all owned streams). + */ +async function getRecipientWithdrawableAmounts( + mapping: IAccountMap, + setup: { + block: number; + network: string; + provider: StaticJsonRpcProvider; + } +) { + const { block, network, provider } = setup; + + const requests: { recipient: string; call: any }[] = []; + mapping.forEach((streams, recipient) => { + streams.forEach((stream) => { + const method: keyof typeof abi = 'withdrawableAmountOf'; + const call = [stream.contract.toLowerCase(), method, [stream.id]]; + requests.push({ recipient, call }); + }); + }); + + const results = await multicall( + network, + provider, + Object.values(abi), + requests.map((item) => item.call), + { blockTag: block } + ); + + /** Aggregate results from streams with the same recipient into individual amounts */ + + const amounts: Map = new Map(); + mapping.forEach((_, recipient) => { + amounts.set(recipient, BigNumber.from(0)); + }); + + requests.forEach(({ recipient }, index) => { + const amount = amounts.get(recipient); + const additional = results[index].toString(); + + const total = amount + ? amount?.add(BigNumber.from(additional)) + : BigNumber.from(0); + + amounts.set(recipient, total); + }); + + return amounts; +} + +/** + * Use the deposited amount from the subgraph query (getRecipientStreams). + * + * @returns Full amounts of initially deposited funds (by senders) for each recipient (from all owned streams) + */ + +async function getRecipientDepositedAmounts(mapping: IAccountMap) { + const amounts: Map = new Map(); + mapping.forEach((_, recipient) => { + amounts.set(recipient, BigNumber.from(0)); + }); + + mapping.forEach((streams, recipient) => { + streams.forEach((stream) => { + const deposited = BigNumber.from(stream.deposited); + if (amounts.has(recipient)) { + const total = amounts.get(recipient) || BigNumber.from(0); + amounts.set(recipient, total.add(deposited)); + } + }); + }); + + return amounts; +} + +/** + * Use the deposited amount from the subgraph query (getSenderStreams). + * + * @returns Full amounts of initially deposited funds (by senders) for each recipient (from all owned streams) + */ + +async function getSenderDepositedAmounts(mapping: IAccountMap) { + const amounts: Map = new Map(); + mapping.forEach((_, sender) => { + amounts.set(sender, BigNumber.from(0)); + }); + + mapping.forEach((streams, sender) => { + streams.forEach((stream) => { + const deposited = BigNumber.from(stream.deposited); + if (amounts.has(sender)) { + const total = amounts.get(sender) || BigNumber.from(0); + amounts.set(sender, total.add(deposited)); + } + }); + }); + + return amounts; +} + +export { + getRecipientStreams, + getRecipientStreamedAmounts, + getRecipientDepositedAmounts, + getRecipientWithdrawableAmounts, + getSenderStreams, + getSenderDepositedAmounts +}; diff --git a/src/strategies/sablier-v2/schema.json b/src/strategies/sablier-v2/schema.json new file mode 100644 index 000000000..a29456485 --- /dev/null +++ b/src/strategies/sablier-v2/schema.json @@ -0,0 +1,40 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Asset Symbol", + "examples": ["e.g. DAI"], + "maxLength": 16 + }, + "address": { + "type": "string", + "title": "Asset Address", + "examples": ["e.g. 0x97cb342cf2f6ecf48c1285fb8668f5a4237bf862"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42 + }, + "decimals": { + "type": "number", + "title": "Asset Decimals", + "examples": ["e.g. 18"] + }, + "policy": { + "type": "string", + "title": "Policy", + "examples": [ + "e.g. withdrawable-recipient / streamed-recipient / deposited-recipient / deposited-sender" + ], + "pattern": "^((withdrawable-recipient)|(streamed-recipient)|(deposited-recipient)|(deposited-sender))$" + } + }, + "required": ["address", "decimals", "policy"], + "additionalProperties": false + } + } +} From 81ea80f05c91564cc01a3d8073cbefb26c54dca5 Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Mon, 31 Jul 2023 17:49:20 +0300 Subject: [PATCH 458/815] docs: polish wording in Sablier V2 README (#1237) refactor: put "streamed-amount-of" policy at the end refactor: reorder Sablier V2 policies --- src/strategies/sablier-v2/README.md | 70 ++++++++++++---------- src/strategies/sablier-v2/configuration.ts | 45 +++++++------- src/strategies/sablier-v2/examples.json | 12 ++-- src/strategies/sablier-v2/index.ts | 16 ++--- src/strategies/sablier-v2/queries.ts | 4 +- src/strategies/sablier-v2/schema.json | 4 +- 6 files changed, 81 insertions(+), 70 deletions(-) diff --git a/src/strategies/sablier-v2/README.md b/src/strategies/sablier-v2/README.md index ee5681b5b..47a2f7db9 100644 --- a/src/strategies/sablier-v2/README.md +++ b/src/strategies/sablier-v2/README.md @@ -1,8 +1,11 @@ -# sablier-v2 +# Sablier V2 Strategies -This set of strategies returns various amounts related to Sablier V2 streams for any given asset. +In Sablier V2, a stream creator locks up an amount of ERC-20 tokens in a contract that progressively allocates the funds to the designated +recipient. The tokens are released by the second, and the recipient can withdraw them at any time. -### Setup +The strategies in this folder read the various amounts that can be found in Sablier V2 streams. + +### Example Setup ```json { @@ -15,72 +18,77 @@ This set of strategies returns various amounts related to Sablier V2 streams for #### Other parameters -Aside from this example setup, we use Snapshot's base parameters such as `Network`, `Snapshot`(block) or `Addresses`. +Aside from this example setup, we use Snapshot's base parameters `Network`, `Snapshot` (block), and `Addresses`. + Based on the chosen strategy, the values filled in the `Addresses` field will represent a list (>= 1) of senders or recipients. ### Policies -| Policy | Methodology | -| ---------------------- | --------------------------------------------------------------------------------------------- | -| withdrawable-recipient | Tokens available for withdrawal from the stream. | -| streamed-recipient | Tokens that have been streamed until the snapshot. | -| deposited-recipient | Tokens that have been deposited in streams the recipient owns at snapshot. | -| deposited-sender | Tokens that have been deposited in streams started by the sender by the time of the snapshot. | +| Policy | Methodology | +| :--------------------- | :------------------------------------------------------------------------------------ | +| withdrawable-recipient | Tokens available to be withdrawn by the stream's recipient. | +| deposited-recipient | Tokens that have been deposited in streams the recipient owned at snapshot time. | +| deposited-sender | Tokens that have been deposited in streams started by the sender before the snapshot. | +| streamed-recipient | Tokens that have been streamed to the recipient until the snapshot. | ### Example -``` +```text Sablier V2 Stream #000001 --- Deposited: TKN 1000 for 30 days Withdrawn: TKN 450 before snapshot -Snapshot: Day 15 (Half) with a streamed amount of TKN 500 +Snapshot: Day 15 (midway) with a streamed amount of TKN 500 +------------------------+----------+ | POLICY | POWER | +------------------------+----------+ -| withdrawable-recipient | TKN 50 | +| erc20-balance-of | TKN 450 | +------------------------+----------+ -| streamed-recipient | TKN 500 | +| withdrawable-recipient | TKN 50 | +------------------------+----------+ | deposited-recipient | TKN 1000 | +------------------------+----------+ | deposited-sender | TKN 1000 | +------------------------+----------+ -| erc20-balance-of | TKN 450 | +| streamed-recipient | TKN 500 | +------------------------+----------+ ``` +### Recommendation + +For the best results, we recommend using the `withdrawable-recipient` policy alongside `erc20-balance-of`. Doing so will count tokens both in the user's wallet, as well as tokens streamed but not withdrawn yet. + ### Details and Caveats #### `withdrawable-recipient` -The withdrawable amount represents assets that have been streamed but not withdrawn yet by the recipient. - -It relies on the `withdrawableAmountOf` contract [method](https://docs.sablier.com/contracts/v2/reference/core/abstracts/abstract.SablierV2Lockup#withdrawableamountof). +The withdrawable amount represents tokens that have been streamed but not withdrawn yet by the recipient. -We recommend using the `withdrawable-recipient` strategy alongside `erc20-balance-of` for the best results. It counts assets is the user's wallet, as well as assets streamed but not withdrawn yet. +This is provided by the [`withdrawableAmountOf`](https://docs.sablier.com/contracts/v2/reference/core/abstracts/abstract.SablierV2Lockup#withdrawableamountof) contract method. -#### `streamed-recipient` +#### `deposited-recipient` -It aggregates historical amounts that have already been streamed to the recipient. This will also include already withdrawn assets. +It aggregates historical deposits up to the snapshot time, counting only the streams owned by the recipient. -It relies on the `streamedAmountOf` contract methods ([linear](https://docs.sablier.com/contracts/v2/reference/core/contract.SablierV2LockupLinear#streamedamountof), [dynamic](https://docs.sablier.com/contracts/v2/reference/core/contract.SablierV2LockupDynamic#streamedamountof)). +:warning: Caveat: streaming, canceling and streaming again will cause tokens to be counted multiple times. -_Caveat #1:_ Careful when using alongside `erc20-balance-of` as it may double count assets. In the [example](#example): `TNK 500` streamed from which `TKN 450` withdrawn equals a voting power or `TKN 950`. +#### `deposited-sender` -_Caveat #2:_ If funds are recycled (streamed, withdrawn and streamed again) the voting power may be increased artificially. +It aggregates historical deposits up to the snapshot time, counting only the streams started by the sender. -#### `deposited-recipient` +:warning: Caveats: -It aggregates historical deposits up to the moment of the snapshot. Counts streams owned by the recipient. +- Streaming, canceling and streaming again will cause tokens to be counted multiple times. +- It takes into account streams created through [PRBProxy](https://docs.sablier.com/contracts/v2/reference/overview#periphery) instances configured through the official [Sablier Interface](https://app.sablier.com/). -_Caveat #1:_ Streaming, canceling and streaming again will cause assets to be counted multiple times. +#### `streamed-recipient` -#### `deposited-sender` +It aggregates historical amounts that have already been streamed to the recipient. Crucially, it includes already withdrawn tokens. -It aggregates historical deposits up to the moment of the snapshot. Counts streams started by the sender. +It relies on the `streamedAmountOf` methods in the [LockupLinear](https://docs.sablier.com/contracts/v2/reference/core/contract.SablierV2LockupLinear#streamedamountof) and [LockupDynamic](https://docs.sablier.com/contracts/v2/reference/core/contract.SablierV2LockupDynamic#streamedamountof) contracts. -_Caveat #1:_ Streaming, canceling and streaming again will cause assets to be counted multiple times. +:warning: Caveats: -_Caveat #2:_ This also takes into account streams created through PRB-Proxy instances configured through the frontend app. Read more about it in the [docs](https://docs.sablier.com/contracts/v2/reference/overview#periphery). +- Using this policy alongside `erc20-balance-of` may double count tokens. In the example above, `TNK 500` was streamed, but the recipient withdrew `TKN 450`, so the total voting power would be `TKN 950`. +- If funds are recycled (streamed, withdrawn and streamed again) the voting power may be increased artificially. diff --git a/src/strategies/sablier-v2/configuration.ts b/src/strategies/sablier-v2/configuration.ts index 5f8c46559..12e7bda15 100644 --- a/src/strategies/sablier-v2/configuration.ts +++ b/src/strategies/sablier-v2/configuration.ts @@ -48,22 +48,6 @@ const deployments = { ], subgraph: 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2' }, - [chains.optimism]: { - contracts: [ - '0xb923abdca17aed90eb5ec5e407bd37164f632bfd', // SablierV2LockupLinear - '0x6f68516c21e248cddfaf4898e66b2b0adee0e0d6' // SablierV2LockupDynamic - ], - subgraph: - 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2-optimism' - }, - [chains.polygon]: { - contracts: [ - '0x67422c3e36a908d5c3237e9cffeb40bde7060f6e', // SablierV2LockupLinear - '0x7313addb53f96a4f710d3b91645c62b434190725' // SablierV2LockupDynamic - ], - subgraph: - 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2-polygon' - }, [chains.goerli]: { contracts: [ '0x6e3678c005815ab34986d8d66a353cd3699103de', // SablierV2LockupLinear @@ -79,12 +63,28 @@ const deployments = { ], subgraph: 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2-gnosis' + }, + [chains.optimism]: { + contracts: [ + '0xb923abdca17aed90eb5ec5e407bd37164f632bfd', // SablierV2LockupLinear + '0x6f68516c21e248cddfaf4898e66b2b0adee0e0d6' // SablierV2LockupDynamic + ], + subgraph: + 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2-optimism' + }, + [chains.polygon]: { + contracts: [ + '0x67422c3e36a908d5c3237e9cffeb40bde7060f6e', // SablierV2LockupLinear + '0x7313addb53f96a4f710d3b91645c62b434190725' // SablierV2LockupDynamic + ], + subgraph: + 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2-polygon' } }; const abi = { getDepositedAmount: - 'function getDepositedAmount(uint256 streamId) external view returns (uint128 depositedAmount)', + 'function getDepositedAmount(uint256 streamId) external view returns (uint128 depositAmount)', streamedAmountOf: 'function streamedAmountOf(uint256 streamId) external view returns (uint128 streamedAmount)', withdrawableAmountOf: @@ -95,9 +95,9 @@ const page = 1000; const policies = { 'withdrawable-recipient': 'withdrawable-recipient', - 'streamed-recipient': 'streamed-recipient', 'deposited-recipient': 'deposited-recipient', - 'deposited-sender': 'deposited-sender' + 'deposited-sender': 'deposited-sender', + 'streamed-recipient': 'streamed-recipient' }; type IPolicy = typeof policies[keyof typeof policies]; @@ -115,6 +115,11 @@ interface IOptions { * ------------------------------------------------------ */ +/* + * See the docs for more example queries: + * https://docs.sablier.com/api/subgraphs/queries + */ + interface IStreamsByAssetParams { accounts: string[]; asset: string; @@ -145,7 +150,6 @@ interface IStreamsByAssetResult { } /** @returns Streams by recipient and asset/token at the given block */ - const RecipientStreamsByAsset = ({ asset, block, @@ -178,7 +182,6 @@ const RecipientStreamsByAsset = ({ }); /** @returns Streams by recipient and asset/token at the given block */ - const SenderStreamsByAsset = ({ asset, block, diff --git a/src/strategies/sablier-v2/examples.json b/src/strategies/sablier-v2/examples.json index 3ac7908cb..88a4a1bea 100644 --- a/src/strategies/sablier-v2/examples.json +++ b/src/strategies/sablier-v2/examples.json @@ -19,14 +19,14 @@ "snapshot": 9432707 }, { - "name": "Example query with policy: streamed-recipient", + "name": "Example query with policy: deposited-recipient", "strategy": { "name": "sablier-v2", "params": { "address": "0x97cb342cf2f6ecf48c1285fb8668f5a4237bf862", "decimals": 18, "symbol": "DAI", - "policy": "streamed-recipient" + "policy": "deposited-recipient" } }, "network": "5", @@ -38,14 +38,14 @@ "snapshot": 9432707 }, { - "name": "Example query with policy: deposited-recipient", + "name": "Example query with policy: deposited-sender", "strategy": { "name": "sablier-v2", "params": { "address": "0x97cb342cf2f6ecf48c1285fb8668f5a4237bf862", "decimals": 18, "symbol": "DAI", - "policy": "deposited-recipient" + "policy": "deposited-sender" } }, "network": "5", @@ -57,14 +57,14 @@ "snapshot": 9432707 }, { - "name": "Example query with policy: deposited-sender", + "name": "Example query with policy: streamed-recipient", "strategy": { "name": "sablier-v2", "params": { "address": "0x97cb342cf2f6ecf48c1285fb8668f5a4237bf862", "decimals": 18, "symbol": "DAI", - "policy": "deposited-sender" + "policy": "streamed-recipient" } }, "network": "5", diff --git a/src/strategies/sablier-v2/index.ts b/src/strategies/sablier-v2/index.ts index 9bc5b5f84..a497c747c 100644 --- a/src/strategies/sablier-v2/index.ts +++ b/src/strategies/sablier-v2/index.ts @@ -19,13 +19,13 @@ export const version = '0.0.1'; function validate(network: string, addresses: string[], options: IOptions) { if (!Object.hasOwn(deployments, network)) { throw new Error( - 'Invalid parameter. The chosen network has to be supported by Sablier V2.' + 'Invalid parameter. The provided network is not supported by Sablier V2.' ); } if (!addresses || addresses?.length === 0) { throw new Error( - 'Invalid parameter. The addresses field must specify at least one account.' + 'Invalid parameter. The addresses field must contain at least one address.' ); } @@ -54,6 +54,12 @@ export async function strategy( const balances = await (async () => { switch (options.policy) { + case 'withdrawable-recipient': + default: { + const streams = await getRecipientStreams(addresses, options, setup); + const balances = await getRecipientWithdrawableAmounts(streams, setup); + return balances; + } case 'deposited-recipient': { const streams = await getRecipientStreams(addresses, options, setup); const balances = await getRecipientDepositedAmounts(streams); @@ -69,12 +75,6 @@ export async function strategy( const balances = await getRecipientStreamedAmounts(streams, setup); return balances; } - case 'withdrawable-recipient': - default: { - const streams = await getRecipientStreams(addresses, options, setup); - const balances = await getRecipientWithdrawableAmounts(streams, setup); - return balances; - } } })(); diff --git a/src/strategies/sablier-v2/queries.ts b/src/strategies/sablier-v2/queries.ts index 485a43d33..edd325aca 100644 --- a/src/strategies/sablier-v2/queries.ts +++ b/src/strategies/sablier-v2/queries.ts @@ -149,7 +149,7 @@ async function getSenderStreams( } /** - * Query the blockchain for streamed amounts for streams of every chosen recipient. + * Query the blockchain for streamed amounts found in the streams owned by every provided recipient. * * @returns Full amounts made up of streamed assets for each recipient (from all owned streams). */ @@ -202,7 +202,7 @@ async function getRecipientStreamedAmounts( } /** - * Query the blockchain for withdrawable amounts for streams of every chosen recipient. + * Query the blockchain for withdrawable amounts found in the streams owned by the provided recipients. * * @returns Full amounts made up of withdrawable assets for each recipient (from all owned streams). */ diff --git a/src/strategies/sablier-v2/schema.json b/src/strategies/sablier-v2/schema.json index a29456485..006af0366 100644 --- a/src/strategies/sablier-v2/schema.json +++ b/src/strategies/sablier-v2/schema.json @@ -28,9 +28,9 @@ "type": "string", "title": "Policy", "examples": [ - "e.g. withdrawable-recipient / streamed-recipient / deposited-recipient / deposited-sender" + "withdrawable-recipient, deposited-recipient, deposited-sender, or streamed-recipient" ], - "pattern": "^((withdrawable-recipient)|(streamed-recipient)|(deposited-recipient)|(deposited-sender))$" + "pattern": "^((withdrawable-recipient)|(deposited-recipient)|(deposited-sender)|(streamed-recipient))$" } }, "required": ["address", "decimals", "policy"], From 90ffdc133979365a78d9f90d8fa59072bb967318 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 1 Aug 2023 23:34:10 +0530 Subject: [PATCH 459/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.107 (#1239) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 144 +++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 140 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 1326fdd2e..7ece8c05d 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.106", + "@snapshot-labs/snapshot.js": "^0.4.107", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 915a3d8e0..957e5b96c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -372,6 +372,19 @@ "@ethersproject/transactions" "^5.6.2" "@ethersproject/web" "^5.6.1" +"@ethersproject/abstract-provider@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz#b0a8550f88b6bf9d51f90e4795d48294630cb9ef" + integrity sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/networks" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/web" "^5.7.0" + "@ethersproject/abstract-signer@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.5.0.tgz#590ff6693370c60ae376bf1c7ada59eb2a8dd08d" @@ -394,6 +407,17 @@ "@ethersproject/logger" "^5.6.0" "@ethersproject/properties" "^5.6.0" +"@ethersproject/abstract-signer@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz#13f4f32117868452191a4649723cb086d2b596b2" + integrity sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/address@^5.0.2", "@ethersproject/address@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.5.0.tgz#bcc6f576a553f21f3dd7ba17248f81b473c9c78f" @@ -416,6 +440,17 @@ "@ethersproject/logger" "^5.6.0" "@ethersproject/rlp" "^5.6.1" +"@ethersproject/address@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.7.0.tgz#19b56c4d74a3b0a46bfdbb6cfcc0a153fc697f37" + integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/base64@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.5.0.tgz#881e8544e47ed976930836986e5eb8fab259c090" @@ -430,6 +465,13 @@ dependencies: "@ethersproject/bytes" "^5.6.1" +"@ethersproject/base64@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.7.0.tgz#ac4ee92aa36c1628173e221d0d01f53692059e1c" + integrity sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/basex@^5.6.1": version "5.6.1" resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.6.1.tgz#badbb2f1d4a6f52ce41c9064f01eab19cc4c5305" @@ -551,6 +593,21 @@ "@ethersproject/properties" "^5.6.0" "@ethersproject/strings" "^5.6.1" +"@ethersproject/hash@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.7.0.tgz#eb7aca84a588508369562e16e514b539ba5240a7" + integrity sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/hdnode@^5.6.2": version "5.6.2" resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.6.2.tgz#26f3c83a3e8f1b7985c15d1db50dc2903418b2d2" @@ -604,6 +661,14 @@ "@ethersproject/bytes" "^5.6.1" js-sha3 "0.8.0" +"@ethersproject/keccak256@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.7.0.tgz#3186350c6e1cd6aba7940384ec7d6d9db01f335a" + integrity sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg== + dependencies: + "@ethersproject/bytes" "^5.7.0" + js-sha3 "0.8.0" + "@ethersproject/logger@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.5.0.tgz#0c2caebeff98e10aefa5aef27d7441c7fd18cf5d" @@ -633,6 +698,13 @@ dependencies: "@ethersproject/logger" "^5.6.0" +"@ethersproject/networks@^5.7.0": + version "5.7.1" + resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.7.1.tgz#118e1a981d757d45ccea6bb58d9fd3d9db14ead6" + integrity sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ== + dependencies: + "@ethersproject/logger" "^5.7.0" + "@ethersproject/pbkdf2@^5.6.1": version "5.6.1" resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.6.1.tgz#f462fe320b22c0d6b1d72a9920a3963b09eb82d1" @@ -655,6 +727,13 @@ dependencies: "@ethersproject/logger" "^5.6.0" +"@ethersproject/properties@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.7.0.tgz#a6e12cb0439b878aaf470f1902a176033067ed30" + integrity sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw== + dependencies: + "@ethersproject/logger" "^5.7.0" + "@ethersproject/providers@^5.6.8": version "5.6.8" resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.6.8.tgz#22e6c57be215ba5545d3a46cf759d265bb4e879d" @@ -705,6 +784,14 @@ "@ethersproject/bytes" "^5.6.1" "@ethersproject/logger" "^5.6.0" +"@ethersproject/rlp@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.7.0.tgz#de39e4d5918b9d74d46de93af80b7685a9c21304" + integrity sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/sha2@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.5.0.tgz#a40a054c61f98fd9eee99af2c3cc6ff57ec24db7" @@ -747,6 +834,18 @@ elliptic "6.5.4" hash.js "1.1.7" +"@ethersproject/signing-key@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.7.0.tgz#06b2df39411b00bc57c7c09b01d1e41cf1b16ab3" + integrity sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + bn.js "^5.2.1" + elliptic "6.5.4" + hash.js "1.1.7" + "@ethersproject/solidity@^5.0.9": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.5.0.tgz#2662eb3e5da471b85a20531e420054278362f93f" @@ -789,6 +888,15 @@ "@ethersproject/constants" "^5.6.1" "@ethersproject/logger" "^5.6.0" +"@ethersproject/strings@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.7.0.tgz#54c9d2a7c57ae8f1205c88a9d3a56471e14d5ed2" + integrity sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/transactions@^5.5.0": version "5.5.0" resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.5.0.tgz#7e9bf72e97bcdf69db34fe0d59e2f4203c7a2908" @@ -819,6 +927,21 @@ "@ethersproject/rlp" "^5.6.1" "@ethersproject/signing-key" "^5.6.2" +"@ethersproject/transactions@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.7.0.tgz#91318fc24063e057885a6af13fdb703e1f993d3b" + integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ== + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + "@ethersproject/units@^5.6.1": version "5.6.1" resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.6.1.tgz#ecc590d16d37c8f9ef4e89e2005bda7ddc6a4e6f" @@ -880,6 +1003,17 @@ "@ethersproject/properties" "^5.6.0" "@ethersproject/strings" "^5.6.1" +"@ethersproject/web@^5.7.0": + version "5.7.1" + resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.7.1.tgz#de1f285b373149bee5928f4eb7bcb87ee5fbb4ae" + integrity sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w== + dependencies: + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/wordlists@^5.6.1": version "5.6.1" resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.6.1.tgz#1e78e2740a8a21e9e99947e47979d72e130aeda1" @@ -1229,17 +1363,17 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.4.106": - version "0.4.106" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.106.tgz#1861b0346a93f1caf35e89c0dcff95945407dc31" - integrity sha512-sWQzBmEYl9d5LE1p7ZZRx5+0M/DylcLuh1RLlpbNLYmGM01LFi+bThjB4lsnj/BvyAYFHKNIZam9OHPV2fA+uw== +"@snapshot-labs/snapshot.js@^0.4.107": + version "0.4.107" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.107.tgz#147879ed6e4903d4651747863118e8ca59c45c80" + integrity sha512-2LjjDZyVaWdAa2U5vbKLYA+NjDANd6Te7iRVTw5LdrFCtdhngvy+Whe0+qFOWR1SbjorrOO6nl4caljSwUOC3A== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" "@ethersproject/address" "^5.6.1" "@ethersproject/bytes" "^5.6.1" "@ethersproject/contracts" "^5.6.2" - "@ethersproject/hash" "^5.6.1" + "@ethersproject/hash" "^5.7.0" "@ethersproject/providers" "^5.6.8" "@ethersproject/units" "^5.7.0" "@ethersproject/wallet" "^5.6.2" From 5c11d52b811ff14c1361567edc30b39a31393e94 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Wed, 2 Aug 2023 17:15:02 +0530 Subject: [PATCH 460/815] [eth-balance] Add readme and schema for eth-balance strategy (#1241) --- src/strategies/eth-balance/README.md | 13 +++++++++++++ src/strategies/eth-balance/schema.json | 20 ++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 src/strategies/eth-balance/README.md create mode 100644 src/strategies/eth-balance/schema.json diff --git a/src/strategies/eth-balance/README.md b/src/strategies/eth-balance/README.md new file mode 100644 index 000000000..ab04c9e52 --- /dev/null +++ b/src/strategies/eth-balance/README.md @@ -0,0 +1,13 @@ +# eth-balance + +This strategy is used for use ETH balance as voting power. + +The balance displayed may vary depending on the network, and represents the balance of the main currency used on that network (e.g. ETH on Ethereum mainnet, BNB on Binance Smart Chain, etc.). + +## Params + +This strategy does need any parameters. + +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| `symbol`(optional) | `string` | `` | The symbol of the currency to used for the balance. | diff --git a/src/strategies/eth-balance/schema.json b/src/strategies/eth-balance/schema.json new file mode 100644 index 000000000..f1310fb3a --- /dev/null +++ b/src/strategies/eth-balance/schema.json @@ -0,0 +1,20 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. ETH"], + "maxLength": 16 + } + }, + "required": [], + "additionalProperties": false + } + } +} From 11940aa86a8a204bdfa9d7b7fc2bed1bc45ed695 Mon Sep 17 00:00:00 2001 From: 0x-logic <140852514+0x-logic@users.noreply.github.com> Date: Wed, 2 Aug 2023 12:28:51 -0700 Subject: [PATCH 461/815] add erc4626-assets-of strategy (#1243) --- src/strategies/erc4626-assets-of/README.md | 17 +++++++ .../erc4626-assets-of/examples.json | 22 +++++++++ src/strategies/erc4626-assets-of/index.ts | 47 +++++++++++++++++++ src/strategies/erc4626-assets-of/schema.json | 33 +++++++++++++ src/strategies/index.ts | 4 +- 5 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 src/strategies/erc4626-assets-of/README.md create mode 100644 src/strategies/erc4626-assets-of/examples.json create mode 100644 src/strategies/erc4626-assets-of/index.ts create mode 100644 src/strategies/erc4626-assets-of/schema.json diff --git a/src/strategies/erc4626-assets-of/README.md b/src/strategies/erc4626-assets-of/README.md new file mode 100644 index 000000000..4dd9298cc --- /dev/null +++ b/src/strategies/erc4626-assets-of/README.md @@ -0,0 +1,17 @@ +# erc4626-assets-of + +Returns the quantity of assets held within a ERC4626 vault by a specific address. + +ERC4626 has a `balanceOf` function that returns the number of "shares" owned by an address. This strategy converts the number of shares to the number of assets by using the vault's `convertToAssets` function. + +For instance, each share might represent ~1.2 underlying asset tokens. We use the ERC4626's internal `convertToAssets` function to convert the number of shares to the number of assets, which represent protocol governance votes. + +Here is an example of parameters: + +```json +{ + "address": "0x44e4c3668552033419520be229cd9df0c35c4417", + "symbol": "stMGN", + "decimals": 18 +} +``` diff --git a/src/strategies/erc4626-assets-of/examples.json b/src/strategies/erc4626-assets-of/examples.json new file mode 100644 index 000000000..81f7cdf36 --- /dev/null +++ b/src/strategies/erc4626-assets-of/examples.json @@ -0,0 +1,22 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "erc4626-assets-of", + "params": { + "address": "0x44e4c3668552033419520be229cd9df0c35c4417", + "symbol": "MGN", + "decimals": 18 + } + }, + "network": "42161", + "addresses": [ + "0x65877BE34c0c3C3A317d97028FD91bd261410026", + "0x86341e73d9Deb4696B1Ae50DBCe8F2D62FA06023", + "0xb738Ce8df54A6d1035d651D77816ae20AFff3bE6", + "0x0c9a74a6Fe43341e90Ab436439C361452eEb9c6b", + "0x72C861B1C98994d54Cc0c6E98B4379203a1905dA" + ], + "snapshot": 117490161 + } +] diff --git a/src/strategies/erc4626-assets-of/index.ts b/src/strategies/erc4626-assets-of/index.ts new file mode 100644 index 000000000..2b04add57 --- /dev/null +++ b/src/strategies/erc4626-assets-of/index.ts @@ -0,0 +1,47 @@ +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; + +import { Multicaller } from '../../utils'; + +export const author = '0x-logic'; +export const version = '0.0.1'; + +const abi: string[] = [ + 'function balanceOf(address account) external view returns (uint256)', + 'function convertToAssets(uint256 shares) public view returns (uint256 assets)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + // 0. Initialize our Multicaller + const multi = new Multicaller(network, provider, abi, { blockTag }); + + // 1. Get the ERC4626 token balance of each address + addresses.forEach((address: string) => + multi.call(address, options.address, 'balanceOf', [address]) + ); + const tokenBalanceResults: Record = + await multi.execute(); + + // 2. Convert the ERC4626 token balances to asset balances + Object.entries(tokenBalanceResults).forEach(([address, balance]) => + multi.call(address, options.address, 'convertToAssets', [balance]) + ); + const assetBalanceResults: Record = + await multi.execute(); + + return Object.fromEntries( + Object.entries(assetBalanceResults).map(([address, assetBalance]) => [ + address, + parseFloat(formatUnits(assetBalance, options.decimals)) + ]) + ); +} diff --git a/src/strategies/erc4626-assets-of/schema.json b/src/strategies/erc4626-assets-of/schema.json new file mode 100644 index 000000000..fde067c18 --- /dev/null +++ b/src/strategies/erc4626-assets-of/schema.json @@ -0,0 +1,33 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. MGN"], + "maxLength": 16 + }, + "address": { + "type": "string", + "title": "ERC4626 contract address", + "examples": ["e.g. 0x44e4c3668552033419520be229cd9df0c35c4417"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 18"] + } + }, + "required": ["address", "decimals"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 218faa3fc..9d8a3a86b 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -453,6 +453,7 @@ import * as karmaDiscordRoles from './karma-discord-roles'; import * as seedifyHoldStakingFarming from './seedify-cumulative-voting-power-hodl-staking-farming'; import * as stakedMoreKudasai from './staked-morekudasai'; import * as sablierV2 from './sablier-v2'; +import * as erc4626AssetsOf from './erc4626-assets-of'; const strategies = { 'cap-voting-power': capVotingPower, @@ -913,7 +914,8 @@ const strategies = { 'seedify-cumulative-voting-power-hodl-staking-farming': seedifyHoldStakingFarming, 'staked-morekudasai': stakedMoreKudasai, - 'sablier-v2': sablierV2 + 'sablier-v2': sablierV2, + 'erc4626-assets-of': erc4626AssetsOf }; Object.keys(strategies).forEach(function (strategyName) { From 6090f963c6e2043dda3324322031a934bdb94a24 Mon Sep 17 00:00:00 2001 From: Alex <33397242+alxdca@users.noreply.github.com> Date: Wed, 2 Aug 2023 21:52:55 +0200 Subject: [PATCH 462/815] [gelato-staking] add gelato-staking strategy (#1242) * feat: add gelato-staking strategy * Update src/strategies/gelato-staking/index.ts * Update src/strategies/gelato-staking/index.ts --------- Co-authored-by: Chaitanya --- src/strategies/gelato-staking/README.md | 12 ++++++ src/strategies/gelato-staking/examples.json | 22 +++++++++++ src/strategies/gelato-staking/index.ts | 43 +++++++++++++++++++++ src/strategies/gelato-staking/schema.json | 33 ++++++++++++++++ src/strategies/index.ts | 2 + 5 files changed, 112 insertions(+) create mode 100644 src/strategies/gelato-staking/README.md create mode 100644 src/strategies/gelato-staking/examples.json create mode 100644 src/strategies/gelato-staking/index.ts create mode 100644 src/strategies/gelato-staking/schema.json diff --git a/src/strategies/gelato-staking/README.md b/src/strategies/gelato-staking/README.md new file mode 100644 index 000000000..bea899eb3 --- /dev/null +++ b/src/strategies/gelato-staking/README.md @@ -0,0 +1,12 @@ +# Gelato-Staking + +Strategy that returns voting power based on GEL stake. + +Here is an example of parameters: + +```json +{ + "address": "0xc2a813699bF2353380c625e3D6b544dC42963941", + "decimals": 18 +} +``` diff --git a/src/strategies/gelato-staking/examples.json b/src/strategies/gelato-staking/examples.json new file mode 100644 index 000000000..7e72d28d9 --- /dev/null +++ b/src/strategies/gelato-staking/examples.json @@ -0,0 +1,22 @@ +[ + { + "name": "Gelato Staking", + "strategy": { + "name": "gelato-staking", + "params": { + "address": "0xc2a813699bF2353380c625e3D6b544dC42963941", + "decimals": 18 + } + }, + "network": "1", + "addresses": [ + "0x417B4Adc279743FC49F047C323FC668db9E600D8", + "0x3D529c760F3EC4c89Bdd6549DDabE9097C1da6e9", + "0x59eD948390F079F2534C052acc3419d34975E026", + "0xda81a723E748C782284Bbb06AB74e3D0A9dBBC77", + "0x2CAd75e380Ddb12329231DF6793A0343917BE8B3", + "0xeD5cF41b0fD6A3C564c17eE34d9D26Eafc30619b" + ], + "snapshot": 17821000 + } +] diff --git a/src/strategies/gelato-staking/index.ts b/src/strategies/gelato-staking/index.ts new file mode 100644 index 000000000..02b118ded --- /dev/null +++ b/src/strategies/gelato-staking/index.ts @@ -0,0 +1,43 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import { Multicaller } from '../../utils'; +import { formatUnits } from '@ethersproject/units'; + +export const author = 'alxdca'; +export const version = '0.1.0'; + +const abi = [ + 'function stakers() external view returns (address[])', + 'function getStake(address) public view returns (uint256)', + 'function manager(address) public view returns (address)' +]; + +const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multi = new Multicaller(network, provider, abi, { blockTag }); + multi.call('stakers', options.address, 'stakers', []); + const stakersResults: Record = await multi.execute(); + + const stakers = stakersResults.stakers; + stakers.forEach((staker) => { + multi.call(`${staker}.stake`, options.address, 'getStake', [staker]); + multi.call(`${staker}.manager`, options.address, 'manager', [staker]); + }); + const results: Record = + await multi.execute(); + + return Object.entries(results).reduce((prev, [staker, result]) => { + prev[result.manager !== ZERO_ADDRESS ? result.manager : staker] = + parseFloat(formatUnits(result.stake, options.decimals)); + return prev; + }, {}); +} diff --git a/src/strategies/gelato-staking/schema.json b/src/strategies/gelato-staking/schema.json new file mode 100644 index 000000000..2113da8b8 --- /dev/null +++ b/src/strategies/gelato-staking/schema.json @@ -0,0 +1,33 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. UNI"], + "maxLength": 16 + }, + "address": { + "type": "string", + "title": "Contract address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 18"] + } + }, + "required": ["address", "decimals"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 9d8a3a86b..59c6c4406 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -453,6 +453,7 @@ import * as karmaDiscordRoles from './karma-discord-roles'; import * as seedifyHoldStakingFarming from './seedify-cumulative-voting-power-hodl-staking-farming'; import * as stakedMoreKudasai from './staked-morekudasai'; import * as sablierV2 from './sablier-v2'; +import * as gelatoStaking from './gelato-staking'; import * as erc4626AssetsOf from './erc4626-assets-of'; const strategies = { @@ -915,6 +916,7 @@ const strategies = { seedifyHoldStakingFarming, 'staked-morekudasai': stakedMoreKudasai, 'sablier-v2': sablierV2, + 'gelato-staking': gelatoStaking, 'erc4626-assets-of': erc4626AssetsOf }; From cb874f24aa20a8024169e33439c2da3e12979452 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 3 Aug 2023 16:07:06 +0530 Subject: [PATCH 463/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.108 (#1245) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 7ece8c05d..af2aee218 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.107", + "@snapshot-labs/snapshot.js": "^0.4.108", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 957e5b96c..200a9e76c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.4.107": - version "0.4.107" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.107.tgz#147879ed6e4903d4651747863118e8ca59c45c80" - integrity sha512-2LjjDZyVaWdAa2U5vbKLYA+NjDANd6Te7iRVTw5LdrFCtdhngvy+Whe0+qFOWR1SbjorrOO6nl4caljSwUOC3A== +"@snapshot-labs/snapshot.js@^0.4.108": + version "0.4.108" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.108.tgz#f8c8699d13c087effa89ad1b4fef44bd7e72975c" + integrity sha512-2Az0SlwSlaihoTKpqxq1OmtsaMdFV/0qbe6zgINVP6O9hEKW59n2nPVyRHZWcpuL3Sf5ths37SLYOs0mzTeA7g== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 5001115c9e412cca567139b78b9df5deed9b306c Mon Sep 17 00:00:00 2001 From: Razvan Gabriel Apostu Date: Thu, 3 Aug 2023 18:37:37 +0200 Subject: [PATCH 464/815] feat: add new policies to the sablier-v2 strategy (#1246) --- src/strategies/sablier-v2/README.md | 52 ++++-- src/strategies/sablier-v2/configuration.ts | 15 +- src/strategies/sablier-v2/examples.json | 46 ++++- src/strategies/sablier-v2/index.ts | 37 ++-- src/strategies/sablier-v2/queries.ts | 186 ++++++++++++++++++--- src/strategies/sablier-v2/schema.json | 4 +- 6 files changed, 286 insertions(+), 54 deletions(-) diff --git a/src/strategies/sablier-v2/README.md b/src/strategies/sablier-v2/README.md index 47a2f7db9..addf64417 100644 --- a/src/strategies/sablier-v2/README.md +++ b/src/strategies/sablier-v2/README.md @@ -24,12 +24,23 @@ Based on the chosen strategy, the values filled in the `Addresses` field will re ### Policies -| Policy | Methodology | -| :--------------------- | :------------------------------------------------------------------------------------ | -| withdrawable-recipient | Tokens available to be withdrawn by the stream's recipient. | -| deposited-recipient | Tokens that have been deposited in streams the recipient owned at snapshot time. | -| deposited-sender | Tokens that have been deposited in streams started by the sender before the snapshot. | -| streamed-recipient | Tokens that have been streamed to the recipient until the snapshot. | +#### Primary policies + +| Policy ⭐️ | Methodology | +| :--------------------- | :------------------------------------------------------------------------ | +| withdrawable-recipient | Tokens available/withdrawable by the stream's recipient. | +| reserved-recipient | Tokens available/withdrawable aggregated with unstreamed tokens (future). | + +#### Secondary policies + +These computation methods are here to aid with special use cases. We still recommend using the primary policies to avoid most caveats. + +| Policy | Methodology | +| :------------------- | :------------------------------------------------------------------------------------ | +| deposited-recipient | Tokens that have been deposited in streams the recipient owned at snapshot time. | +| deposited-sender | Tokens that have been deposited in streams started by the sender before the snapshot. | +| streamed-recipient | Tokens that have been streamed to the recipient until the snapshot. | +| unstreamed-recipient | Tokens that have not yet been streamed to the recipient at the time of snapshot. | ### Example @@ -47,25 +58,42 @@ Snapshot: Day 15 (midway) with a streamed amount of TKN 500 +------------------------+----------+ | withdrawable-recipient | TKN 50 | +------------------------+----------+ +| reserved-recipient | TKN 550 | ++------------------------+----------+ | deposited-recipient | TKN 1000 | +------------------------+----------+ | deposited-sender | TKN 1000 | +------------------------+----------+ | streamed-recipient | TKN 500 | +------------------------+----------+ +| unstreamed-recipient | TKN 500 | ++------------------------+----------+ ``` ### Recommendation -For the best results, we recommend using the `withdrawable-recipient` policy alongside `erc20-balance-of`. Doing so will count tokens both in the user's wallet, as well as tokens streamed but not withdrawn yet. +For the best results, we recommend using the primary policies. + +1. The first option is to use the `withdrawable-recipient` policy alongside `erc20-balance-of`. Doing so will aggregate tokens streamed but not withdrawn yet, as well as tokens in the user's wallet. +2. The second best option is using `reserved-recipient` with `erc20-balance-of`. It will aggregate: tokens streamed but not withdrawn yet, unstreamed funds (accessible in the future) and finally, tokens in the user's wallet. ### Details and Caveats -#### `withdrawable-recipient` +#### `withdrawable-recipient` ⭐️ + +The withdrawable amount counts tokens that have been streamed but not withdrawn yet by the recipient. -The withdrawable amount represents tokens that have been streamed but not withdrawn yet by the recipient. +This is provided using the [`withdrawableAmountOf`](https://docs.sablier.com/contracts/v2/reference/core/abstracts/abstract.SablierV2Lockup#withdrawableamountof) contract method. -This is provided by the [`withdrawableAmountOf`](https://docs.sablier.com/contracts/v2/reference/core/abstracts/abstract.SablierV2Lockup#withdrawableamountof) contract method. +Voting power: realized (present). + +#### `reserved-recipient` ⭐️ + +The reserved amount combines tokens that have been streamed but not withdrawn yet (similar to `withdrawable-recipient`) with tokens that haven't been streamed (still locked yet accessible in the future). It can be computed as `reserved = withdrawable + unstreamed === deposited - withdrawn`. Canceled streams will only count the final withdrawable amount, if any. + +Voting power: realized (present) + expected (future). + +--- #### `deposited-recipient` @@ -92,3 +120,7 @@ It relies on the `streamedAmountOf` methods in the [LockupLinear](https://docs.s - Using this policy alongside `erc20-balance-of` may double count tokens. In the example above, `TNK 500` was streamed, but the recipient withdrew `TKN 450`, so the total voting power would be `TKN 950`. - If funds are recycled (streamed, withdrawn and streamed again) the voting power may be increased artificially. + +#### `unstreamed-recipient` + +The opposite of `streamed-recipient`, counting amounts that have not been streamed yet (locked, but will become available in the future). It subtracts the `streamed` amount from the initial `deposit`. For canceled streams, the unstreamed amount will be `0`. diff --git a/src/strategies/sablier-v2/configuration.ts b/src/strategies/sablier-v2/configuration.ts index 12e7bda15..f29a36689 100644 --- a/src/strategies/sablier-v2/configuration.ts +++ b/src/strategies/sablier-v2/configuration.ts @@ -95,9 +95,11 @@ const page = 1000; const policies = { 'withdrawable-recipient': 'withdrawable-recipient', + 'reserved-recipient': 'reserved-recipient', 'deposited-recipient': 'deposited-recipient', 'deposited-sender': 'deposited-sender', - 'streamed-recipient': 'streamed-recipient' + 'streamed-recipient': 'streamed-recipient', + 'unstreamed-recipient': 'unstreamed-recipient' }; type IPolicy = typeof policies[keyof typeof policies]; @@ -130,7 +132,13 @@ interface IStreamsByAssetParams { type IAccountMap = Map< string, - { id: string; contract: string; deposited: string; withdrawn: string }[] + { + id: string; + canceled: boolean; + contract: string; + deposited: string; + withdrawn: string; + }[] >; interface IStreamsByAssetResult { @@ -139,6 +147,7 @@ interface IStreamsByAssetResult { contract: { id: string; }; + canceled: boolean; proxied: boolean; proxender: string; recipient: string; @@ -173,6 +182,7 @@ const RecipientStreamsByAsset = ({ contract: { id: true }, + canceled: true, recipient: true, sender: true, tokenId: true, @@ -211,6 +221,7 @@ const SenderStreamsByAsset = ({ contract: { id: true }, + canceled: true, proxied: true, proxender: true, recipient: true, diff --git a/src/strategies/sablier-v2/examples.json b/src/strategies/sablier-v2/examples.json index 88a4a1bea..eec00ad9c 100644 --- a/src/strategies/sablier-v2/examples.json +++ b/src/strategies/sablier-v2/examples.json @@ -16,7 +16,7 @@ "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "0x506C56B2541eFeCf7A510E9A0c0382cB2FC69051" ], - "snapshot": 9432707 + "snapshot": 9455671 }, { "name": "Example query with policy: deposited-recipient", @@ -35,7 +35,7 @@ "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "0x506C56B2541eFeCf7A510E9A0c0382cB2FC69051" ], - "snapshot": 9432707 + "snapshot": 9455671 }, { "name": "Example query with policy: deposited-sender", @@ -54,7 +54,7 @@ "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "0x506C56B2541eFeCf7A510E9A0c0382cB2FC69051" ], - "snapshot": 9432707 + "snapshot": 9455671 }, { "name": "Example query with policy: streamed-recipient", @@ -73,6 +73,44 @@ "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "0x506C56B2541eFeCf7A510E9A0c0382cB2FC69051" ], - "snapshot": 9432707 + "snapshot": 9455671 + }, + { + "name": "Example query with policy: unstreamed-recipient", + "strategy": { + "name": "sablier-v2", + "params": { + "address": "0x97cb342cf2f6ecf48c1285fb8668f5a4237bf862", + "decimals": 18, + "symbol": "DAI", + "policy": "unstreamed-recipient" + } + }, + "network": "5", + "addresses": [ + "0x9ad7cad4f10d0c3f875b8a2fd292590490c9f491", + "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", + "0x506C56B2541eFeCf7A510E9A0c0382cB2FC69051" + ], + "snapshot": 9455671 + }, + { + "name": "Example query with policy: reserved-recipient", + "strategy": { + "name": "sablier-v2", + "params": { + "address": "0x97cb342cf2f6ecf48c1285fb8668f5a4237bf862", + "decimals": 18, + "symbol": "DAI", + "policy": "reserved-recipient" + } + }, + "network": "5", + "addresses": [ + "0x9ad7cad4f10d0c3f875b8a2fd292590490c9f491", + "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", + "0x506C56B2541eFeCf7A510E9A0c0382cB2FC69051" + ], + "snapshot": 9455671 } ] diff --git a/src/strategies/sablier-v2/index.ts b/src/strategies/sablier-v2/index.ts index a497c747c..3967349e8 100644 --- a/src/strategies/sablier-v2/index.ts +++ b/src/strategies/sablier-v2/index.ts @@ -4,12 +4,14 @@ import type { StaticJsonRpcProvider } from '@ethersproject/providers'; import { deployments, policies } from './configuration'; import { + getRecipientDepositedAmounts, + getRecipientReservedAmounts, getRecipientStreams, getRecipientStreamedAmounts, - getRecipientDepositedAmounts, + getRecipientUnstreamedAmounts, getRecipientWithdrawableAmounts, - getSenderStreams, - getSenderDepositedAmounts + getSenderDepositedAmounts, + getSenderStreams } from './queries'; import type { IOptions } from './configuration'; @@ -57,23 +59,36 @@ export async function strategy( case 'withdrawable-recipient': default: { const streams = await getRecipientStreams(addresses, options, setup); - const balances = await getRecipientWithdrawableAmounts(streams, setup); - return balances; + const { amounts } = await getRecipientWithdrawableAmounts( + streams, + setup + ); + return amounts; + } + case 'reserved-recipient': { + const streams = await getRecipientStreams(addresses, options, setup); + const { amounts } = await getRecipientReservedAmounts(streams, setup); + return amounts; } case 'deposited-recipient': { const streams = await getRecipientStreams(addresses, options, setup); - const balances = await getRecipientDepositedAmounts(streams); - return balances; + const { amounts } = await getRecipientDepositedAmounts(streams); + return amounts; } case 'deposited-sender': { const streams = await getSenderStreams(addresses, options, setup); - const balances = await getSenderDepositedAmounts(streams); - return balances; + const { amounts } = await getSenderDepositedAmounts(streams); + return amounts; } case 'streamed-recipient': { const streams = await getRecipientStreams(addresses, options, setup); - const balances = await getRecipientStreamedAmounts(streams, setup); - return balances; + const { amounts } = await getRecipientStreamedAmounts(streams, setup); + return amounts; + } + case 'unstreamed-recipient': { + const streams = await getRecipientStreams(addresses, options, setup); + const { amounts } = await getRecipientUnstreamedAmounts(streams, setup); + return amounts; } } })(); diff --git a/src/strategies/sablier-v2/queries.ts b/src/strategies/sablier-v2/queries.ts index edd325aca..e344f0434 100644 --- a/src/strategies/sablier-v2/queries.ts +++ b/src/strategies/sablier-v2/queries.ts @@ -11,7 +11,7 @@ import { abi, deployments, queries, page } from './configuration'; import { multicall, subgraphRequest } from '../../utils'; /** - * Query the subgraph for all the streams owned by all (or a given set of) recipients. + * Query the subgraph for all the streams owned by all recipients. * * @returns A mapping from each recipient to their list of owned streams. */ @@ -56,6 +56,7 @@ async function getRecipientStreams( const recipient = item.recipient.toLowerCase(); const entry = { id: item.tokenId, + canceled: item.canceled, contract: item.contract.id, deposited: item.depositAmount, withdrawn: item.withdrawnAmount @@ -79,7 +80,7 @@ async function getRecipientStreams( } /** - * Query the subgraph for all the streams started by all (or a given set of) senders. + * Query the subgraph for all the streams started by senders. * * @returns A mapping from each sender to their list of started streams. */ @@ -126,6 +127,7 @@ async function getSenderStreams( : item.sender.toLowerCase(); const entry = { id: item.tokenId, + canceled: item.canceled, contract: item.contract.id, deposited: item.depositAmount, withdrawn: item.withdrawnAmount @@ -149,9 +151,9 @@ async function getSenderStreams( } /** - * Query the blockchain for streamed amounts found in the streams owned by every provided recipient. + * Query the blockchain for streamed amounts found in the recipients' streams. * - * @returns Full amounts made up of streamed assets for each recipient (from all owned streams). + * @returns Full amounts made up of streamed assets for each recipient and every stream. */ async function getRecipientStreamedAmounts( mapping: IAccountMap, @@ -180,7 +182,7 @@ async function getRecipientStreamedAmounts( { blockTag: block } ); - /** Aggregate results from streams with the same recipient into individual amounts */ + /** Aggregate results from streams with the same recipient into individual streamed amounts */ const amounts: Map = new Map(); mapping.forEach((_, recipient) => { @@ -191,20 +193,17 @@ async function getRecipientStreamedAmounts( const amount = amounts.get(recipient); const additional = results[index].toString(); - const total = amount - ? amount?.add(BigNumber.from(additional)) - : BigNumber.from(0); - + const total = (amount || BigNumber.from(0)).add(BigNumber.from(additional)); amounts.set(recipient, total); }); - return amounts; + return { amounts }; } /** - * Query the blockchain for withdrawable amounts found in the streams owned by the provided recipients. + * Query the blockchain for withdrawable amounts found in recipients' streams. * - * @returns Full amounts made up of withdrawable assets for each recipient (from all owned streams). + * @returns Full amounts made up of withdrawable assets for each recipient and every stream. */ async function getRecipientWithdrawableAmounts( mapping: IAccountMap, @@ -233,7 +232,7 @@ async function getRecipientWithdrawableAmounts( { blockTag: block } ); - /** Aggregate results from streams with the same recipient into individual amounts */ + /** Aggregate results from streams with the same recipient into individual withdrawable amounts */ const amounts: Map = new Map(); mapping.forEach((_, recipient) => { @@ -244,20 +243,17 @@ async function getRecipientWithdrawableAmounts( const amount = amounts.get(recipient); const additional = results[index].toString(); - const total = amount - ? amount?.add(BigNumber.from(additional)) - : BigNumber.from(0); - + const total = (amount || BigNumber.from(0)).add(BigNumber.from(additional)); amounts.set(recipient, total); }); - return amounts; + return { amounts }; } /** * Use the deposited amount from the subgraph query (getRecipientStreams). * - * @returns Full amounts of initially deposited funds (by senders) for each recipient (from all owned streams) + * @returns Full amounts of initially deposited funds (by senders) for each recipient and every stream. */ async function getRecipientDepositedAmounts(mapping: IAccountMap) { @@ -276,13 +272,13 @@ async function getRecipientDepositedAmounts(mapping: IAccountMap) { }); }); - return amounts; + return { amounts }; } /** * Use the deposited amount from the subgraph query (getSenderStreams). * - * @returns Full amounts of initially deposited funds (by senders) for each recipient (from all owned streams) + * @returns Full amounts of initially deposited funds (by senders) for each sender and every stream. */ async function getSenderDepositedAmounts(mapping: IAccountMap) { @@ -301,14 +297,154 @@ async function getSenderDepositedAmounts(mapping: IAccountMap) { }); }); - return amounts; + return { amounts }; +} + +/** + * Query the blockchain for streamed amounts found in the uncanceled streams. + * Use the deposited amount from the subgraph query (getRecipientStreams). + * + * @returns Full amounts made up of unstreamed assets (deposited - streamed) for each recipient and every stream. + */ +async function getRecipientUnstreamedAmounts( + mapping: IAccountMap, + setup: { + block: number; + network: string; + provider: StaticJsonRpcProvider; + } +) { + const { block, network, provider } = setup; + + const requests: { recipient: string; deposited: string; call: any }[] = []; + mapping.forEach((streams, recipient) => { + streams.forEach((stream) => { + /** Canceled streams will not count here, so skip them */ + if (!stream.canceled) { + const method: keyof typeof abi = 'streamedAmountOf'; + const call = [stream.contract.toLowerCase(), method, [stream.id]]; + requests.push({ recipient, deposited: stream.deposited, call }); + } + }); + }); + + const results = await multicall( + network, + provider, + Object.values(abi), + requests.map((item) => item.call), + { blockTag: block } + ); + + /** Aggregate results from streams with the same recipient into individual unstreamed amounts */ + + const amounts: Map = new Map(); + mapping.forEach((_, recipient) => { + amounts.set(recipient, BigNumber.from(0)); + }); + + requests.forEach(({ recipient }, index) => { + const amount = amounts.get(recipient); + + const streamed = results[index].toString(); + const deposited = requests[index].deposited; + + const additional = BigNumber.from(deposited).sub(BigNumber.from(streamed)); + const total = (amount || BigNumber.from(0)).add(additional); + + amounts.set(recipient, total); + }); + + return { amounts }; +} + +/** + * Query the blockchain for withdrawable amounts found in the canceled streams. + * Use the deposited and withdrawn amounts from the subgraph query (getRecipientStreams). + * + * Tip: in active streams, reserved = unstreamed + withdrawable === deposited - withdrawn. In canceled, reserved = withdrawable. + * + * @returns Full amounts made up of reserved (unstreamed + withdrawable) assets for each recipient and every stream. + */ +async function getRecipientReservedAmounts( + mapping: IAccountMap, + setup: { + block: number; + network: string; + provider: StaticJsonRpcProvider; + } +) { + /** + * Break results into canceled streams and active ones. + * For canceled streams look for withdrawable amounts (the final recipient withdraw). + * For active streams, look for reserved amounts as `deposited - withdrawn`. + */ + + const mapping_active: IAccountMap = new Map(); + const mapping_canceled: IAccountMap = new Map(); + + mapping.forEach((streams, recipient) => { + mapping_active.set(recipient, []); + mapping_canceled.set(recipient, []); + + streams.forEach((stream) => { + if (stream.canceled) { + mapping_canceled.set(recipient, [ + ...(mapping_canceled.get(recipient) || []), + stream + ]); + } else { + mapping_active.set(recipient, [ + ...(mapping_active.get(recipient) || []), + stream + ]); + } + }); + }); + + /** Get withdrawable amounts for canceled streams */ + + const { amounts: withdrawable } = await getRecipientWithdrawableAmounts( + mapping_canceled, + setup + ); + + /** Get reserved amounts for active streams (`deposited - withdrawn`) */ + + const amounts: Map = new Map(); + mapping.forEach((_, recipient) => { + amounts.set(recipient, BigNumber.from(0)); + }); + + mapping_active.forEach((streams, recipient) => { + streams.forEach((stream) => { + const deposited = BigNumber.from(stream.deposited); + const withdrawn = BigNumber.from(stream.withdrawn); + + if (amounts.has(recipient)) { + const total = amounts.get(recipient) || BigNumber.from(0); + amounts.set(recipient, total.add(deposited.sub(withdrawn))); + } + }); + }); + + /** Aggregate */ + + withdrawable.forEach((withdrawable, recipient) => { + const active = amounts.get(recipient) || BigNumber.from(0); + amounts.set(recipient, active.add(withdrawable)); + }); + + return { amounts }; } export { + getRecipientDepositedAmounts, + getRecipientReservedAmounts, getRecipientStreams, getRecipientStreamedAmounts, - getRecipientDepositedAmounts, + getRecipientUnstreamedAmounts, getRecipientWithdrawableAmounts, - getSenderStreams, - getSenderDepositedAmounts + getSenderDepositedAmounts, + getSenderStreams }; diff --git a/src/strategies/sablier-v2/schema.json b/src/strategies/sablier-v2/schema.json index 006af0366..1efe7a26d 100644 --- a/src/strategies/sablier-v2/schema.json +++ b/src/strategies/sablier-v2/schema.json @@ -28,9 +28,9 @@ "type": "string", "title": "Policy", "examples": [ - "withdrawable-recipient, deposited-recipient, deposited-sender, or streamed-recipient" + "withdrawable-recipient, reserved-recipient, deposited-recipient, deposited-sender, streamed-recipient or unstreamed-recipient" ], - "pattern": "^((withdrawable-recipient)|(deposited-recipient)|(deposited-sender)|(streamed-recipient))$" + "pattern": "^((withdrawable-recipient)|(reserved-recipient)|(deposited-recipient)|(deposited-sender)|(streamed-recipient)|(unstreamed-recipient))$" } }, "required": ["address", "decimals", "policy"], From bef5d70eca0540b15620057e0e603662999feb78 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 3 Aug 2023 22:27:06 +0530 Subject: [PATCH 465/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.109 (#1247) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index af2aee218..e8c1e883e 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.108", + "@snapshot-labs/snapshot.js": "^0.4.109", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 200a9e76c..a6a5abe8a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.4.108": - version "0.4.108" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.108.tgz#f8c8699d13c087effa89ad1b4fef44bd7e72975c" - integrity sha512-2Az0SlwSlaihoTKpqxq1OmtsaMdFV/0qbe6zgINVP6O9hEKW59n2nPVyRHZWcpuL3Sf5ths37SLYOs0mzTeA7g== +"@snapshot-labs/snapshot.js@^0.4.109": + version "0.4.109" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.109.tgz#2946dd6a87b03c44a1c2e5ba187add5e0ea2a34a" + integrity sha512-urV42YwiGWpxnrVMSg9QI4iJdCyYNfyOVZ4r6xYrFT+5Wz3YKUWmAgVm5C1v0HAFPDchGxzwcISHhnX3oMky/Q== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 64fee995a1c59d2572035f5d08b6141f935f3f4e Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Thu, 3 Aug 2023 22:38:10 +0530 Subject: [PATCH 466/815] [api-v2-override] New strategy to call api-v2 strategy with all addresses (#1248) --- src/strategies/api-v2-override/README.md | 9 ++++++++ src/strategies/api-v2-override/examples.json | 23 ++++++++++++++++++++ src/strategies/index.ts | 1 + 3 files changed, 33 insertions(+) create mode 100644 src/strategies/api-v2-override/README.md create mode 100644 src/strategies/api-v2-override/examples.json diff --git a/src/strategies/api-v2-override/README.md b/src/strategies/api-v2-override/README.md new file mode 100644 index 000000000..2ac495496 --- /dev/null +++ b/src/strategies/api-v2-override/README.md @@ -0,0 +1,9 @@ +# API V2 Override strategy + +Same as the `api-v2` strategy, but passes all voter addresses in the query string / body payload of the API endpoint. +Prefer `api-post` method for better scalability. + +## Params + +All params are same as the `api-v2` strategy. +Refer to the `api-v2` strategy's documentation for more details. diff --git a/src/strategies/api-v2-override/examples.json b/src/strategies/api-v2-override/examples.json new file mode 100644 index 000000000..b0c0cce2d --- /dev/null +++ b/src/strategies/api-v2-override/examples.json @@ -0,0 +1,23 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "api-v2-override", + "params": { + "url": "ipfs://QmbmhTivxYuLE5uhNEALoBmvP7Yg9acA2Lkw9V9PqaEmw6", + "type": "ipfs" + } + }, + "network": "1", + "addresses": [ + "0xeD2bcC3104Da5F5f8fA988D6e9fAFd74Ae62f319", + "0x3c4B8C52Ed4c29eE402D9c91FfAe1Db2BAdd228D", + "0xd649bACfF66f1C85618c5376ee4F38e43eE53b63", + "0x726022a9fe1322fA9590FB244b8164936bB00489", + "0xc6665eb39d2106fb1DBE54bf19190F82FD535c19", + "0x6ef2376fa6e12dabb3a3ed0fb44e4ff29847af68", + "0x89446aF03652c5257dB5C8E4E85495EB754196c5" + ], + "snapshot": 11437846 + } +] diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 59c6c4406..bfcc9a035 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -618,6 +618,7 @@ const strategies = { api, 'api-post': apiPost, 'api-v2': apiV2, + 'api-v2-override': apiV2, xseen, 'moloch-all': molochAll, 'moloch-loot': molochLoot, From 82cb55d90931e19d95fd45a53f00de7fc758d936 Mon Sep 17 00:00:00 2001 From: Arthur <32548365+Arthh@users.noreply.github.com> Date: Sun, 6 Aug 2023 16:59:51 -0300 Subject: [PATCH 467/815] [karma-discord-roles] update karma-discord-roles strategy (#1244) * feat: use snapshot and filter by address * fix: strategy version * fix: remove logs * fix: remove logs --- .../karma-discord-roles/examples.json | 4 +- src/strategies/karma-discord-roles/index.ts | 41 ++++++++++++++----- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/strategies/karma-discord-roles/examples.json b/src/strategies/karma-discord-roles/examples.json index a08521164..71bf3b607 100644 --- a/src/strategies/karma-discord-roles/examples.json +++ b/src/strategies/karma-discord-roles/examples.json @@ -11,10 +11,10 @@ "network": "1", "addresses": [ "0x10cCD4136471c7c266a9Fc4569622989Fb4caB99", - "0x95e1eeb014eeB6c8709f2Ce4F19B847138fd5685", + "0x1aD7C3d3AC2118335D5437e46BBdCcf69D1f1a4f", "0x7B124228eC8e9C9C9ddC3278bb0ee4a6dAa5dDee" ], - "snapshot": 11437846 + "snapshot": 17829912 } ] diff --git a/src/strategies/karma-discord-roles/index.ts b/src/strategies/karma-discord-roles/index.ts index bf8adee0a..5a645a47c 100644 --- a/src/strategies/karma-discord-roles/index.ts +++ b/src/strategies/karma-discord-roles/index.ts @@ -2,9 +2,20 @@ import fetch from 'cross-fetch'; import { getAddress } from '@ethersproject/address'; export const author = 'show-karma'; -export const version = '1.0.0'; +export const version = '1.0.1'; -const KARMA_API = 'https://api.karmahq.xyz/api/dao/discordUsers'; +const KARMA_API = 'https://api.karmahq.xyz/api/dao/discord-users'; + +async function getBlockTimestamp(provider, snapshot) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + let block; + try { + block = await provider.getBlock(blockTag); + } catch (error) { + throw new Error('Failed to get block information'); + } + return ((block?.timestamp || 0) * 1000).toString(); +} export async function strategy( space, @@ -20,26 +31,36 @@ export async function strategy( if (!name || !roles) return {}; - const response = await fetch(`${KARMA_API}/${name}/${roles.join(',')}`, { + const timestamp = await getBlockTimestamp(provider, snapshot); + + const queryParams = new URLSearchParams({ + name, + roles: roles.join(','), + timestamp, + addresses: addresses.join(', ') + }); + + const requestOptions = { method: 'GET', headers: { Accept: 'application/json', 'Content-Type': 'application/json' } - }); + }; + + const response = await fetch(`${KARMA_API}?${queryParams}`, requestOptions); const parsedResponse = !response.ok ? [] : await response.json(); const delegates = parsedResponse.data?.delegates || []; const votingPower = {}; - const userAddresses = delegates.map((user) => user.publicAddress); - const paramAddresses = addresses.length ? addresses : []; - const allAddresses = [...userAddresses, ...paramAddresses]; - - allAddresses.forEach((address) => { + addresses.forEach((address: string) => { + const userExists = delegates.find( + (delegate) => delegate.publicAddress === address.toLowerCase() + ); const checksumAddress = getAddress(address); - votingPower[checksumAddress] = 1; + votingPower[checksumAddress] = !!userExists ? 1 : 0; }); return votingPower; From ed9f722319f7b36f639949b67f6352afd14cb52b Mon Sep 17 00:00:00 2001 From: ChaituVR Date: Mon, 7 Aug 2023 01:32:57 +0530 Subject: [PATCH 468/815] Fix lint --- src/strategies/staked-morekudasai/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategies/staked-morekudasai/index.ts b/src/strategies/staked-morekudasai/index.ts index f1b465f11..91c4c9737 100644 --- a/src/strategies/staked-morekudasai/index.ts +++ b/src/strategies/staked-morekudasai/index.ts @@ -63,7 +63,7 @@ export async function strategy( // aggregate const ret = addressWithIndexes - .map(([address, _], index) => { + .map(([address], index) => { return { address: address, vp: stakingDurations[index][0] From 4e5efa0677e1e8ccbb08903ec15b2b1f40837080 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment?= <55331875+clement-ux@users.noreply.github.com> Date: Wed, 9 Aug 2023 06:37:48 +0200 Subject: [PATCH 469/815] [sd-vote-boost-twavp-v2] add: sd-vote-boost-twavp-v2 (#1249) * add: sd-vote-boost-twavp-v2 * fix(sd-vote-boost-twavp-v2): throw error when whiteListedAddress is more than 20 --------- Co-authored-by: Chaitanya --- src/strategies/index.ts | 4 +- .../sd-vote-boost-twavp-v2/README.md | 24 +++ .../sd-vote-boost-twavp-v2/examples.json | 28 ++++ .../sd-vote-boost-twavp-v2/index.ts | 139 ++++++++++++++++++ 4 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 src/strategies/sd-vote-boost-twavp-v2/README.md create mode 100644 src/strategies/sd-vote-boost-twavp-v2/examples.json create mode 100644 src/strategies/sd-vote-boost-twavp-v2/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index bfcc9a035..629582442 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -455,6 +455,7 @@ import * as stakedMoreKudasai from './staked-morekudasai'; import * as sablierV2 from './sablier-v2'; import * as gelatoStaking from './gelato-staking'; import * as erc4626AssetsOf from './erc4626-assets-of'; +import * as sdVoteBoostTWAVPV2 from './sd-vote-boost-twavp-v2'; const strategies = { 'cap-voting-power': capVotingPower, @@ -918,7 +919,8 @@ const strategies = { 'staked-morekudasai': stakedMoreKudasai, 'sablier-v2': sablierV2, 'gelato-staking': gelatoStaking, - 'erc4626-assets-of': erc4626AssetsOf + 'erc4626-assets-of': erc4626AssetsOf, + 'sd-vote-boost-twavp-v2': sdVoteBoostTWAVPV2 }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/sd-vote-boost-twavp-v2/README.md b/src/strategies/sd-vote-boost-twavp-v2/README.md new file mode 100644 index 000000000..6dee8304a --- /dev/null +++ b/src/strategies/sd-vote-boost-twavp-v2/README.md @@ -0,0 +1,24 @@ +# sd-vote-boost-twavp-v2 + +This strategy is used by Stake DAO to vote with sdToken using Time Weigthed Averaged Voting Power (TWAVP) system and adapted for veSDT boost delegation with possibility to whiteliste address to by pass TWAVP. + +``` +VotingPower(user) = veToken.balanceOf(liquidLocker) * (average.sdTokenGauge.working_balances(user) / sdTokenGauge.working_supply) +``` + +>_sampleSize: in days_ +>_sampleStep: the number of block for `average` calculation (max 5)_ + +Here is an example of parameters: + +```json +{ + "veToken": "0x5f3b5DfEb7B28CDbD7FAba78963EE202a494e2A2", + "liquidLocker": "0x52f541764E6e90eeBc5c21Ff570De0e2D63766B6", + "sdTokenGauge": "0x7f50786A0b15723D741727882ee99a0BF34e3466", + "symbol": "sdToken", + "decimals": 18, + "sampleSize": 10, + "sampleStep": 5, +} +``` \ No newline at end of file diff --git a/src/strategies/sd-vote-boost-twavp-v2/examples.json b/src/strategies/sd-vote-boost-twavp-v2/examples.json new file mode 100644 index 000000000..dea07fe5a --- /dev/null +++ b/src/strategies/sd-vote-boost-twavp-v2/examples.json @@ -0,0 +1,28 @@ +[ + { + "name": "Stake DAO vote boost using TWAVP V2", + "strategy": { + "name": "sd-vote-boost-twavp-v2", + "params": { + "veToken": "0x5f3b5DfEb7B28CDbD7FAba78963EE202a494e2A2", + "liquidLocker": "0x52f541764E6e90eeBc5c21Ff570De0e2D63766B6", + "sdTokenGauge": "0x7f50786A0b15723D741727882ee99a0BF34e3466", + "symbol": "sdToken", + "decimals": 18, + "sampleSize": 10, + "sampleStep": 5, + "whiteListedAddress": [ + "0x1c0D72a330F2768dAF718DEf8A19BAb019EEAd09" + ] + } + }, + "network": "1", + "addresses": [ + "0x26a5994176d34D128C5e6ab80Fa0882A7df4fF00", + "0xDdB50FfDbA4D89354E1088e4EA402de895562173", + "0xE1F7eaD40d33eeF30dCf15eB5efC45409001aAB8", + "0x1c0D72a330F2768dAF718DEf8A19BAb019EEAd09" + ], + "snapshot": 17835000 + } +] \ No newline at end of file diff --git a/src/strategies/sd-vote-boost-twavp-v2/index.ts b/src/strategies/sd-vote-boost-twavp-v2/index.ts new file mode 100644 index 000000000..d432cfb4d --- /dev/null +++ b/src/strategies/sd-vote-boost-twavp-v2/index.ts @@ -0,0 +1,139 @@ +import { multicall } from '../../utils'; +import { BigNumber } from '@ethersproject/bignumber'; + +export const author = 'clement-ux'; +export const version = '0.0.1'; + +// Used ABI +const abi = [ + 'function balanceOf(address account) external view returns (uint256)', + 'function working_supply() external view returns (uint256)', + 'function working_balances(address account) external view returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + // Maximum of 5 multicall! + if (options.sampleStep > 5) { + throw new Error('maximum of 5 call'); + } + + // Maximum of 20 whitelisted address + if (options.whiteListedAddress.length > 20) { + throw new Error('maximum of 20 whitelisted address'); + } + + // --- Create block number list for twavp + // Obtain last block number + let lastBlock = await provider.getBlockNumber(); + // Create block tag + let blockTag = typeof snapshot === 'number' ? snapshot : lastBlock; + // Create block list + let blockList = getPreviousBlocks(blockTag, options.sampleStep, options.sampleSize); + + // Query working balance of users + const workingBalanceQuery = addresses.map((address: any) => [ + options.sdTokenGauge, + 'working_balances', + [address] + ]); + + // Execute multicall `sampleStep` times + let response: number[] = []; + for (let i = 0; i < options.sampleStep; i++) { + // Use good block number + blockTag = blockList[i]; + + // Add mutlicall response to array + response.push( + await multicall( + network, + provider, + abi, + [ + [options.sdTokenGauge, 'working_supply'], + [options.veToken, 'balanceOf', [options.liquidLocker]], + ...workingBalanceQuery + ], + { blockTag } + ) + ) + }; + + // Get working supply + const workingSupply = response[response.length - 1][0][0]; // Last response, latest block + // Get voting power of liquid locker + const votingPowerLiquidLocker = response[response.length - 1][1][0]; // Last response, latest block + + return Object.fromEntries( + Array(addresses.length) + .fill('x') + .map((_, i) => { + // Init array of working balances for user + let userWorkingBalances: BigNumber[] = []; + + for (let j = 0; j < options.sampleStep; j++) { + // Add working balance to array. + userWorkingBalances.push(response[j][i + 2][0]); + } + + // Get average working balance. + let averageWorkingBalance = average(userWorkingBalances, addresses[i], options.whiteListedAddress); + + // Calculate voting power. + let votingPower = + workingSupply != 0 + ? (averageWorkingBalance).mul(votingPowerLiquidLocker).div(workingSupply.mul(BigNumber.from(10).pow(options.decimals))) + : 0; + + // Return address and voting power + return [addresses[i], Number(votingPower)]; + }) + ); +} + +function getPreviousBlocks(currentBlockNumber: number, numberOfBlocks: number, daysInterval: number): number[] { + // Estimate number of blocks per day + const blocksPerDay = 86400 / 12; + // Calculate total blocks interval + const totalBlocksInterval = blocksPerDay * daysInterval; + // Calculate block interval + const blockInterval = totalBlocksInterval / (numberOfBlocks - 1); + + // Init array of block numbers + const blockNumbers: number[] = []; + + for (let i = 0; i < numberOfBlocks; i++) { + // Calculate block number + let blockNumber = currentBlockNumber - totalBlocksInterval + (blockInterval * i); + // Add block number to array + blockNumbers.push(Math.round(blockNumber)); + } + + // Return array of block numbers + return blockNumbers; +} + +function average(numbers: BigNumber[], address: string, whiteListedAddress: string[]): BigNumber { + // If no numbers, return 0 to avoid division by 0. + if (numbers.length === 0) return BigNumber.from(0); + + // If address is whitelisted, return most recent working balance. i.e. no twavp applied. + if (whiteListedAddress.includes(address)) return numbers[numbers.length - 1]; + + // Init sum + let sum = BigNumber.from(0); + // Loop through all elements and add them to sum + for (let i = 0; i < numbers.length; i++) { + sum = sum.add(numbers[i]); + } + + // Return sum divided by array length to get mean + return sum.div(numbers.length); +} \ No newline at end of file From 3202d7571d54100f8c6547b36f5e03c6b3c54e77 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 9 Aug 2023 21:38:26 +0530 Subject: [PATCH 470/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.4.110 (#1251) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index e8c1e883e..d5dae683f 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.109", + "@snapshot-labs/snapshot.js": "^0.4.110", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index a6a5abe8a..96cadc2c8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.4.109": - version "0.4.109" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.109.tgz#2946dd6a87b03c44a1c2e5ba187add5e0ea2a34a" - integrity sha512-urV42YwiGWpxnrVMSg9QI4iJdCyYNfyOVZ4r6xYrFT+5Wz3YKUWmAgVm5C1v0HAFPDchGxzwcISHhnX3oMky/Q== +"@snapshot-labs/snapshot.js@^0.4.110": + version "0.4.110" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.110.tgz#a7b2eda4deff333c75741fbb7490eb96a923fe5a" + integrity sha512-Cie6CsVVSUh5vbuo8ZU/YuPD+iF8mKuVGsCDbm2PLyvXX2EPJVVmBYrvuQizpP79Q8NWtQucqb/fFVnDBRogxA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From b4d4e5fe78227f0e734e92fdcc7f5daa7453b38b Mon Sep 17 00:00:00 2001 From: Andre Mury <109355036+andremury@users.noreply.github.com> Date: Fri, 11 Aug 2023 01:12:41 -0300 Subject: [PATCH 471/815] [karma-eas-attestation] EAS Attestation Proposal Validation (#1238) * feat: proposal creation validation with EAS * feat: added support for chainId 10 and 42161 * Update src/validations/eas-attestation/index.ts Set as proposal validity only Co-authored-by: Chaitanya * Update src/validations/eas-attestation/index.ts fix github name Co-authored-by: Chaitanya * Update src/validations/eas-attestation/index.ts removed author and version Co-authored-by: Chaitanya * feat: add schema to validation * validation name * Update src/validations/karma-eas-attestation/index.ts Co-authored-by: Chaitanya * Update src/validations/karma-eas-attestation/index.ts Co-authored-by: Chaitanya --------- Co-authored-by: Chaitanya --- src/validations/index.ts | 4 +- .../karma-eas-attestation/README.md | 8 ++ .../karma-eas-attestation/examples.json | 12 +++ .../karma-eas-attestation/index.ts | 82 +++++++++++++++++++ .../karma-eas-attestation/schema.json | 19 +++++ 5 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 src/validations/karma-eas-attestation/README.md create mode 100644 src/validations/karma-eas-attestation/examples.json create mode 100644 src/validations/karma-eas-attestation/index.ts create mode 100644 src/validations/karma-eas-attestation/schema.json diff --git a/src/validations/index.ts b/src/validations/index.ts index ee47e2564..ec757114c 100644 --- a/src/validations/index.ts +++ b/src/validations/index.ts @@ -4,12 +4,14 @@ import basic from './basic'; import passportGated from './passport-gated'; import passportWeighted from './passport-weighted'; import arbitrum from './arbitrum'; +import karmaEasAttestation from './karma-eas-attestation'; const validationClasses = { basic, 'passport-gated': passportGated, 'passport-weighted': passportWeighted, - arbitrum: arbitrum + arbitrum: arbitrum, + 'karma-eas-attestation': karmaEasAttestation }; const validations = {}; diff --git a/src/validations/karma-eas-attestation/README.md b/src/validations/karma-eas-attestation/README.md new file mode 100644 index 000000000..02749373e --- /dev/null +++ b/src/validations/karma-eas-attestation/README.md @@ -0,0 +1,8 @@ +# eas-attestation +Karma's solution to validate proposal creators using EAS Attest.sh. +> This should only be used to validate proposal creation. + +Parameters: +`schemaId`: EAS's schema UID given when the schema is created. Example: [`0xc0f979976278d9e1d4fa97b7270c0cc07835aa5f27dd897a871b3332ec6cff22`](https://sepolia.easscan.org/schema/view/0xc0f979976278d9e1d4fa97b7270c0cc07835aa5f27dd897a871b3332ec6cff22) +`address`: The proposer's address +`network`: The chain ID. Currently supports only Mainnet (1) diff --git a/src/validations/karma-eas-attestation/examples.json b/src/validations/karma-eas-attestation/examples.json new file mode 100644 index 000000000..bb5a38647 --- /dev/null +++ b/src/validations/karma-eas-attestation/examples.json @@ -0,0 +1,12 @@ +[ + { + "name": "Example of a Karma's EAS Attestation", + "author": "0xd7d1DB401EA825b0325141Cd5e6cd7C2d01825f2", + "space": "0xmury.eth", + "network": "11155111", + "snapshot": "latest", + "params": { + "schemaId": "0xc0f979976278d9e1d4fa97b7270c0cc07835aa5f27dd897a871b3332ec6cff22" + } + } +] diff --git a/src/validations/karma-eas-attestation/index.ts b/src/validations/karma-eas-attestation/index.ts new file mode 100644 index 000000000..adb7ba365 --- /dev/null +++ b/src/validations/karma-eas-attestation/index.ts @@ -0,0 +1,82 @@ +import Validation from '../validation'; +import fetch from 'cross-fetch'; + +interface Attestation { + attester: string; + data: string; + recipient: string; + revoked: boolean; +} +interface AttestationSchema { + schema: { + attestations: Attestation[]; + }; +} +interface SubgraphResponse { + data: AttestationSchema; +} + +const EASNetworks = { + 1: 'https://easscan.org/graphql', + 10: 'https://optimism.easscan.org/graphql', + 42161: 'https://arbitrum.easscan.org/graphql', + 11155111: 'https://sepolia.easscan.org/graphql' +}; + +const easScanQuery = ` +query Attestations($schemaId: String!) { + schema(where: {id: $schemaId}) { + attestations { + attester + data + recipient + revoked + } + } +} +`; + +/** + * Query EAS subgraph to determine if user is attested + * @param schemaId Schema UID + * @param address Targer user address + * @param network Network ID (1 = mainnet, 11155111 = sepolia) + * @returns + */ +async function isAttested(schemaId: string, address: string, network = 1) { + const easUrl = EASNetworks[network]; + if (!easUrl) throw new Error(`EAS network ${network} not supported`); + + const response: SubgraphResponse = await fetch(easUrl, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + query: easScanQuery, + variables: { schemaId } + }) + }).then((res) => res.json()); + const index = response.data.schema.attestations.findIndex( + (a) => a.recipient.toLowerCase() === address.toLowerCase() && !a.revoked + ); + + return index >= 0; +} + +export default class extends Validation { + public id = 'karma-eas-attestation'; + public github = 'karmahq'; + public version = '0.1.0'; + public title = 'Karma EAS Attestation'; + public description = + 'Use EAS attest.sh to determine if user can create a proposal.'; + public proposalValidationOnly = true; + async validate(): Promise { + const schemaId = this.params.schemaId; + if (!schemaId) throw new Error(`Attestation schema not provided`); + + if (!Number.isSafeInteger(+this.network)) + throw new Error(`Network ID ${this.network} not supported`); + + return isAttested(schemaId, this.author, +this.network); + } +} diff --git a/src/validations/karma-eas-attestation/schema.json b/src/validations/karma-eas-attestation/schema.json new file mode 100644 index 000000000..ac02af8bd --- /dev/null +++ b/src/validations/karma-eas-attestation/schema.json @@ -0,0 +1,19 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Validation", + "definitions": { + "Validation": { + "title": "Eas attestation", + "type": "object", + "properties": { + "schemaId": { + "type": "string", + "title": "Schema Id", + "examples": ["e.g. 0xc0f979976278d9e1d4fa97b7270c0cc07835aa5f27dd897a871b3332ec6cff22"] + } + }, + "required": [], + "additionalProperties": false + } + } +} \ No newline at end of file From def02a86d700f1e2a6a6a08797eff627c1fde3d3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 11 Aug 2023 09:48:58 +0530 Subject: [PATCH 472/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.5.3 (#1252) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index d5dae683f..c44e70d96 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.4.110", + "@snapshot-labs/snapshot.js": "^0.5.3", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 96cadc2c8..b252c14b9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.4.110": - version "0.4.110" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.4.110.tgz#a7b2eda4deff333c75741fbb7490eb96a923fe5a" - integrity sha512-Cie6CsVVSUh5vbuo8ZU/YuPD+iF8mKuVGsCDbm2PLyvXX2EPJVVmBYrvuQizpP79Q8NWtQucqb/fFVnDBRogxA== +"@snapshot-labs/snapshot.js@^0.5.3": + version "0.5.3" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.5.3.tgz#1bc43227a91316180a5f9808950110de4c0433aa" + integrity sha512-ZAP8nG5Oie+IdNrGiv353J8OnspDDoJE4VRNLifAF5VDGIMxA5GDk+1DSHUR6ffAqUHjP6TMlaT0zE5PDFUezQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 7063bba8cb1ca08eb2856c1e278709074655056d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 13 Aug 2023 19:50:39 +0530 Subject: [PATCH 473/815] Automated lint (#1253) Co-authored-by: ChaituVR --- .../sd-vote-boost-twavp-v2/examples.json | 6 +- .../sd-vote-boost-twavp-v2/index.ts | 265 ++++++++++-------- .../karma-eas-attestation/schema.json | 40 +-- 3 files changed, 166 insertions(+), 145 deletions(-) diff --git a/src/strategies/sd-vote-boost-twavp-v2/examples.json b/src/strategies/sd-vote-boost-twavp-v2/examples.json index dea07fe5a..27e792d10 100644 --- a/src/strategies/sd-vote-boost-twavp-v2/examples.json +++ b/src/strategies/sd-vote-boost-twavp-v2/examples.json @@ -11,9 +11,7 @@ "decimals": 18, "sampleSize": 10, "sampleStep": 5, - "whiteListedAddress": [ - "0x1c0D72a330F2768dAF718DEf8A19BAb019EEAd09" - ] + "whiteListedAddress": ["0x1c0D72a330F2768dAF718DEf8A19BAb019EEAd09"] } }, "network": "1", @@ -25,4 +23,4 @@ ], "snapshot": 17835000 } -] \ No newline at end of file +] diff --git a/src/strategies/sd-vote-boost-twavp-v2/index.ts b/src/strategies/sd-vote-boost-twavp-v2/index.ts index d432cfb4d..085144226 100644 --- a/src/strategies/sd-vote-boost-twavp-v2/index.ts +++ b/src/strategies/sd-vote-boost-twavp-v2/index.ts @@ -6,134 +6,155 @@ export const version = '0.0.1'; // Used ABI const abi = [ - 'function balanceOf(address account) external view returns (uint256)', - 'function working_supply() external view returns (uint256)', - 'function working_balances(address account) external view returns (uint256)' + 'function balanceOf(address account) external view returns (uint256)', + 'function working_supply() external view returns (uint256)', + 'function working_balances(address account) external view returns (uint256)' ]; export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot + space, + network, + provider, + addresses, + options, + snapshot ): Promise> { - // Maximum of 5 multicall! - if (options.sampleStep > 5) { - throw new Error('maximum of 5 call'); - } - - // Maximum of 20 whitelisted address - if (options.whiteListedAddress.length > 20) { - throw new Error('maximum of 20 whitelisted address'); - } - - // --- Create block number list for twavp - // Obtain last block number - let lastBlock = await provider.getBlockNumber(); - // Create block tag - let blockTag = typeof snapshot === 'number' ? snapshot : lastBlock; - // Create block list - let blockList = getPreviousBlocks(blockTag, options.sampleStep, options.sampleSize); - - // Query working balance of users - const workingBalanceQuery = addresses.map((address: any) => [ - options.sdTokenGauge, - 'working_balances', - [address] - ]); - - // Execute multicall `sampleStep` times - let response: number[] = []; - for (let i = 0; i < options.sampleStep; i++) { - // Use good block number - blockTag = blockList[i]; - - // Add mutlicall response to array - response.push( - await multicall( - network, - provider, - abi, - [ - [options.sdTokenGauge, 'working_supply'], - [options.veToken, 'balanceOf', [options.liquidLocker]], - ...workingBalanceQuery - ], - { blockTag } - ) - ) - }; - - // Get working supply - const workingSupply = response[response.length - 1][0][0]; // Last response, latest block - // Get voting power of liquid locker - const votingPowerLiquidLocker = response[response.length - 1][1][0]; // Last response, latest block - - return Object.fromEntries( - Array(addresses.length) - .fill('x') - .map((_, i) => { - // Init array of working balances for user - let userWorkingBalances: BigNumber[] = []; - - for (let j = 0; j < options.sampleStep; j++) { - // Add working balance to array. - userWorkingBalances.push(response[j][i + 2][0]); - } - - // Get average working balance. - let averageWorkingBalance = average(userWorkingBalances, addresses[i], options.whiteListedAddress); - - // Calculate voting power. - let votingPower = - workingSupply != 0 - ? (averageWorkingBalance).mul(votingPowerLiquidLocker).div(workingSupply.mul(BigNumber.from(10).pow(options.decimals))) - : 0; - - // Return address and voting power - return [addresses[i], Number(votingPower)]; - }) + // Maximum of 5 multicall! + if (options.sampleStep > 5) { + throw new Error('maximum of 5 call'); + } + + // Maximum of 20 whitelisted address + if (options.whiteListedAddress.length > 20) { + throw new Error('maximum of 20 whitelisted address'); + } + + // --- Create block number list for twavp + // Obtain last block number + const lastBlock = await provider.getBlockNumber(); + // Create block tag + let blockTag = typeof snapshot === 'number' ? snapshot : lastBlock; + // Create block list + const blockList = getPreviousBlocks( + blockTag, + options.sampleStep, + options.sampleSize + ); + + // Query working balance of users + const workingBalanceQuery = addresses.map((address: any) => [ + options.sdTokenGauge, + 'working_balances', + [address] + ]); + + // Execute multicall `sampleStep` times + const response: number[] = []; + for (let i = 0; i < options.sampleStep; i++) { + // Use good block number + blockTag = blockList[i]; + + // Add mutlicall response to array + response.push( + await multicall( + network, + provider, + abi, + [ + [options.sdTokenGauge, 'working_supply'], + [options.veToken, 'balanceOf', [options.liquidLocker]], + ...workingBalanceQuery + ], + { blockTag } + ) ); + } + + // Get working supply + const workingSupply = response[response.length - 1][0][0]; // Last response, latest block + // Get voting power of liquid locker + const votingPowerLiquidLocker = response[response.length - 1][1][0]; // Last response, latest block + + return Object.fromEntries( + Array(addresses.length) + .fill('x') + .map((_, i) => { + // Init array of working balances for user + const userWorkingBalances: BigNumber[] = []; + + for (let j = 0; j < options.sampleStep; j++) { + // Add working balance to array. + userWorkingBalances.push(response[j][i + 2][0]); + } + + // Get average working balance. + const averageWorkingBalance = average( + userWorkingBalances, + addresses[i], + options.whiteListedAddress + ); + + // Calculate voting power. + const votingPower = + workingSupply != 0 + ? averageWorkingBalance + .mul(votingPowerLiquidLocker) + .div( + workingSupply.mul(BigNumber.from(10).pow(options.decimals)) + ) + : 0; + + // Return address and voting power + return [addresses[i], Number(votingPower)]; + }) + ); } -function getPreviousBlocks(currentBlockNumber: number, numberOfBlocks: number, daysInterval: number): number[] { - // Estimate number of blocks per day - const blocksPerDay = 86400 / 12; - // Calculate total blocks interval - const totalBlocksInterval = blocksPerDay * daysInterval; - // Calculate block interval - const blockInterval = totalBlocksInterval / (numberOfBlocks - 1); - - // Init array of block numbers - const blockNumbers: number[] = []; - - for (let i = 0; i < numberOfBlocks; i++) { - // Calculate block number - let blockNumber = currentBlockNumber - totalBlocksInterval + (blockInterval * i); - // Add block number to array - blockNumbers.push(Math.round(blockNumber)); - } - - // Return array of block numbers - return blockNumbers; +function getPreviousBlocks( + currentBlockNumber: number, + numberOfBlocks: number, + daysInterval: number +): number[] { + // Estimate number of blocks per day + const blocksPerDay = 86400 / 12; + // Calculate total blocks interval + const totalBlocksInterval = blocksPerDay * daysInterval; + // Calculate block interval + const blockInterval = totalBlocksInterval / (numberOfBlocks - 1); + + // Init array of block numbers + const blockNumbers: number[] = []; + + for (let i = 0; i < numberOfBlocks; i++) { + // Calculate block number + const blockNumber = + currentBlockNumber - totalBlocksInterval + blockInterval * i; + // Add block number to array + blockNumbers.push(Math.round(blockNumber)); + } + + // Return array of block numbers + return blockNumbers; } -function average(numbers: BigNumber[], address: string, whiteListedAddress: string[]): BigNumber { - // If no numbers, return 0 to avoid division by 0. - if (numbers.length === 0) return BigNumber.from(0); - - // If address is whitelisted, return most recent working balance. i.e. no twavp applied. - if (whiteListedAddress.includes(address)) return numbers[numbers.length - 1]; - - // Init sum - let sum = BigNumber.from(0); - // Loop through all elements and add them to sum - for (let i = 0; i < numbers.length; i++) { - sum = sum.add(numbers[i]); - } - - // Return sum divided by array length to get mean - return sum.div(numbers.length); -} \ No newline at end of file +function average( + numbers: BigNumber[], + address: string, + whiteListedAddress: string[] +): BigNumber { + // If no numbers, return 0 to avoid division by 0. + if (numbers.length === 0) return BigNumber.from(0); + + // If address is whitelisted, return most recent working balance. i.e. no twavp applied. + if (whiteListedAddress.includes(address)) return numbers[numbers.length - 1]; + + // Init sum + let sum = BigNumber.from(0); + // Loop through all elements and add them to sum + for (let i = 0; i < numbers.length; i++) { + sum = sum.add(numbers[i]); + } + + // Return sum divided by array length to get mean + return sum.div(numbers.length); +} diff --git a/src/validations/karma-eas-attestation/schema.json b/src/validations/karma-eas-attestation/schema.json index ac02af8bd..987929438 100644 --- a/src/validations/karma-eas-attestation/schema.json +++ b/src/validations/karma-eas-attestation/schema.json @@ -1,19 +1,21 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$ref": "#/definitions/Validation", - "definitions": { - "Validation": { - "title": "Eas attestation", - "type": "object", - "properties": { - "schemaId": { - "type": "string", - "title": "Schema Id", - "examples": ["e.g. 0xc0f979976278d9e1d4fa97b7270c0cc07835aa5f27dd897a871b3332ec6cff22"] - } - }, - "required": [], - "additionalProperties": false - } - } -} \ No newline at end of file +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Validation", + "definitions": { + "Validation": { + "title": "Eas attestation", + "type": "object", + "properties": { + "schemaId": { + "type": "string", + "title": "Schema Id", + "examples": [ + "e.g. 0xc0f979976278d9e1d4fa97b7270c0cc07835aa5f27dd897a871b3332ec6cff22" + ] + } + }, + "required": [], + "additionalProperties": false + } + } +} From 85bae41cb1ed508c30ead708d92cc09d0447d0fc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 14 Aug 2023 16:44:51 +0530 Subject: [PATCH 474/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.5.4 (#1254) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index c44e70d96..09d0f3445 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.5.3", + "@snapshot-labs/snapshot.js": "^0.5.4", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index b252c14b9..f0e3c6022 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.5.3": - version "0.5.3" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.5.3.tgz#1bc43227a91316180a5f9808950110de4c0433aa" - integrity sha512-ZAP8nG5Oie+IdNrGiv353J8OnspDDoJE4VRNLifAF5VDGIMxA5GDk+1DSHUR6ffAqUHjP6TMlaT0zE5PDFUezQ== +"@snapshot-labs/snapshot.js@^0.5.4": + version "0.5.4" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.5.4.tgz#193a489530d9753c441bbec56297fc011a547e58" + integrity sha512-vgJx5MkyndcXMKRpdZDbICycl0EF3gGc2Tb52TCbVCS8C2keajWlZW6aPQivLEP5B18EmD+h+l8U9kn0zj9NiQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 5251228e9a1b537e2ad68dda5820a65c1149b523 Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Thu, 17 Aug 2023 22:20:20 +0300 Subject: [PATCH 475/815] [sablier-v1-deposit] refactor: rename Sablier V1 strategy (#1240) * refactor: rename Sablier V1 strategy fix: fix subgraph URLs * Update src/strategies/sablier-v1-deposit/index.ts Co-authored-by: Chaitanya * refactor: remove optional subGraphURL * refactor: update sablier v1 example addresses * fix: fix sablier v1 example addresses --------- Co-authored-by: Chaitanya --- .../deposit-in-sablier-stream/examples.json | 35 ------------------ src/strategies/index.ts | 4 +-- .../README.md | 7 ++-- .../sablier-v1-deposit/examples.json | 36 +++++++++++++++++++ .../index.ts | 29 ++++++++------- .../schema.json | 5 --- 6 files changed, 57 insertions(+), 59 deletions(-) delete mode 100644 src/strategies/deposit-in-sablier-stream/examples.json rename src/strategies/{deposit-in-sablier-stream => sablier-v1-deposit}/README.md (55%) create mode 100644 src/strategies/sablier-v1-deposit/examples.json rename src/strategies/{deposit-in-sablier-stream => sablier-v1-deposit}/index.ts (55%) rename src/strategies/{deposit-in-sablier-stream => sablier-v1-deposit}/schema.json (82%) diff --git a/src/strategies/deposit-in-sablier-stream/examples.json b/src/strategies/deposit-in-sablier-stream/examples.json deleted file mode 100644 index e0eea6f0d..000000000 --- a/src/strategies/deposit-in-sablier-stream/examples.json +++ /dev/null @@ -1,35 +0,0 @@ -[ - { - "name": "Example query 0", - "strategy": { - "name": "deposit-in-sablier-stream", - "params": { - "sender": "0xC9F2D9adfa6C24ce0D5a999F2BA3c6b06E36F75E", - "token": "0x7f8F6E42C169B294A384F5667c303fd8Eedb3CF3" - } - }, - "network": "5", - "addresses": [ - "0x3f9b2fea60325d733e61bc76598725c5430cd751", - "0x7f8F6E42C169B294A384F5667c303fd8Eedb3CF3" - ], - "snapshot": 7572600 - }, - { - "name": "Example query 1", - "strategy": { - "name": "deposit-in-sablier-stream", - "params": { - "sender": "0xC9F2D9adfa6C24ce0D5a999F2BA3c6b06E36F75E", - "token": "0x7f8F6E42C169B294A384F5667c303fd8Eedb3CF3", - "subGraphURL": "https://api.thegraph.com/subgraphs/name/sablierhq/sablier-goerli" - } - }, - "network": "5", - "addresses": [ - "0x1206b51217271FC3ffCa57d0678121983ce0390E", - "0x7f8F6E42C169B294A384F5667c303fd8Eedb3CF3" - ], - "snapshot": 7572688 - } -] diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 629582442..1d534d48f 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -398,7 +398,6 @@ import * as safeVested from './safe-vested'; import * as riskharborUnderwriter from './riskharbor-underwriter'; import * as otterspaceBadges from './otterspace-badges'; import * as syntheticNounsClaimerOwner from './synthetic-nouns-with-claimer'; -import * as depositInSablierStream from './deposit-in-sablier-stream'; import * as echelonWalletPrimeAndCachedKey from './echelon-wallet-prime-and-cached-key'; import * as nation3VotesWIthDelegations from './nation3-votes-with-delegations'; import * as nation3CoopPassportWithDelegations from './nation3-passport-coop-with-delegations'; @@ -452,6 +451,7 @@ import * as hatsProtocolSingleVotePerOrg from './hats-protocol-single-vote-per-o import * as karmaDiscordRoles from './karma-discord-roles'; import * as seedifyHoldStakingFarming from './seedify-cumulative-voting-power-hodl-staking-farming'; import * as stakedMoreKudasai from './staked-morekudasai'; +import * as sablierV1Deposit from './sablier-v1-deposit'; import * as sablierV2 from './sablier-v2'; import * as gelatoStaking from './gelato-staking'; import * as erc4626AssetsOf from './erc4626-assets-of'; @@ -865,7 +865,6 @@ const strategies = { 'riskharbor-underwriter': riskharborUnderwriter, 'otterspace-badges': otterspaceBadges, 'synthetic-nouns-with-claimer': syntheticNounsClaimerOwner, - 'deposit-in-sablier-stream': depositInSablierStream, 'echelon-wallet-prime-and-cached-key': echelonWalletPrimeAndCachedKey, 'nation3-votes-with-delegations': nation3VotesWIthDelegations, 'nation3-passport-coop-with-delegations': nation3CoopPassportWithDelegations, @@ -917,6 +916,7 @@ const strategies = { 'seedify-cumulative-voting-power-hodl-staking-farming': seedifyHoldStakingFarming, 'staked-morekudasai': stakedMoreKudasai, + 'sablier-v1-deposit': sablierV1Deposit, 'sablier-v2': sablierV2, 'gelato-staking': gelatoStaking, 'erc4626-assets-of': erc4626AssetsOf, diff --git a/src/strategies/deposit-in-sablier-stream/README.md b/src/strategies/sablier-v1-deposit/README.md similarity index 55% rename from src/strategies/deposit-in-sablier-stream/README.md rename to src/strategies/sablier-v1-deposit/README.md index 9c60aac49..d8e03ed6a 100644 --- a/src/strategies/deposit-in-sablier-stream/README.md +++ b/src/strategies/sablier-v1-deposit/README.md @@ -1,10 +1,13 @@ # Deposit in Sablier Stream -This strategy returns the score for any voter as the sum of all deposits made by a sender towards the voters for a specific ERC20 token; +In Sablier V1, a stream creator locks up an amount of ERC-20 tokens in a contract that progressively allocates the funds to the designated +recipient. The tokens are released by the second, and the recipient can withdraw them at any time. + +This strategy returns the score for any voter as the sum of all deposits made by a sender towards the voters for a specific ERC20 token. Here is an example of parameters: -```JSON +```json { "sender": "0xC9F2D9adfa6C24ce0D5a999F2BA3c6b06E36F75E", "token": "0x7f8F6E42C169B294A384F5667c303fd8Eedb3CF3" diff --git a/src/strategies/sablier-v1-deposit/examples.json b/src/strategies/sablier-v1-deposit/examples.json new file mode 100644 index 000000000..c52b59ad3 --- /dev/null +++ b/src/strategies/sablier-v1-deposit/examples.json @@ -0,0 +1,36 @@ +[ + { + "name": "Example query 0", + "strategy": { + "name": "sablier-v1-deposit", + "params": { + "sender": "0xcCe2CbDcD0eee72984c58A84678F0D49a95257ae", + "token": "0x97cb342Cf2F6EcF48c1285Fb8668f5a4237BF862" + } + }, + "network": "5", + "addresses": [ + "0x06255FA39EBD18796eCCCc17DB8153Ef58DBA0a8", + "0xf976aF93B0A5A9F55A7f285a3B5355B8575Eb5bc", + "0x5bCAc9fC8827231839c5861b719e0cAE57da3CfB" + ], + "snapshot": 9515850 + }, + { + "name": "Example query 1", + "strategy": { + "name": "sablier-v1-deposit", + "params": { + "sender": "0xcCe2CbDcD0eee72984c58A84678F0D49a95257ae", + "token": "0x97cb342Cf2F6EcF48c1285Fb8668f5a4237BF862" + } + }, + "network": "5", + "addresses": [ + "0x06255FA39EBD18796eCCCc17DB8153Ef58DBA0a8", + "0xf976aF93B0A5A9F55A7f285a3B5355B8575Eb5bc", + "0x5bCAc9fC8827231839c5861b719e0cAE57da3CfB" + ], + "snapshot": 9515900 + } +] diff --git a/src/strategies/deposit-in-sablier-stream/index.ts b/src/strategies/sablier-v1-deposit/index.ts similarity index 55% rename from src/strategies/deposit-in-sablier-stream/index.ts rename to src/strategies/sablier-v1-deposit/index.ts index afad5ab87..e83febe47 100644 --- a/src/strategies/deposit-in-sablier-stream/index.ts +++ b/src/strategies/sablier-v1-deposit/index.ts @@ -3,19 +3,21 @@ import { formatUnits } from '@ethersproject/units'; import { subgraphRequest } from '../../utils'; const SUBGRAPH_URL = { - '1': 'https://api.thegraph.com/subgraphs/name/sablierhq/sablier', // mainnet - '3': 'https://api.thegraph.com/subgraphs/name/sablierhq/sablier-ropsten', // ropsten - '4': 'https://api.thegraph.com/subgraphs/name/sablierhq/sablier-rinkeby', // rinkeby - '5': 'https://api.thegraph.com/subgraphs/name/sablierhq/sablier-goerli', // goerli - '10': 'https://api.thegraph.com/subgraphs/name/sablierhq/sablier-optimism', // optimism - '42': 'https://api.thegraph.com/subgraphs/name/sablierhq/sablier-kovan', // kovan - '56': 'https://api.thegraph.com/subgraphs/name/sablierhq/sablier-bsc', // bsc - '137': 'https://api.thegraph.com/subgraphs/name/sablierhq/sablier-matic', // polygon - '42161': 'https://api.thegraph.com/subgraphs/name/sablierhq/sablier-arbitrum', // arbitrum - '43114': 'https://api.thegraph.com/subgraphs/name/sablierhq/sablier-avalanche' // avalanche + '1': 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier', // mainnet + '3': 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-ropsten', // ropsten + '4': 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-rinkeby', // rinkeby + '5': 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-goerli', // goerli + '10': 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-optimism', // optimism + '42': 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-kovan', // kovan + '56': 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-bsc', // bsc + '137': 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-matic', // polygon + '42161': + 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-arbitrum', // arbitrum + '43114': + 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-avalanche' // avalanche }; -export const author = 'dan13ram'; +export const author = 'sablier-labs'; export const version = '0.1.0'; export async function strategy( @@ -48,10 +50,7 @@ export async function strategy( // @ts-ignore params.streams.__args.block = { number: snapshot }; } - const result = await subgraphRequest( - options.subGraphURL ? options.subGraphURL : SUBGRAPH_URL[network], - params - ); + const result = await subgraphRequest(SUBGRAPH_URL[network], params); const score = Object.fromEntries( addresses.map((address) => [getAddress(address), 0]) ); diff --git a/src/strategies/deposit-in-sablier-stream/schema.json b/src/strategies/sablier-v1-deposit/schema.json similarity index 82% rename from src/strategies/deposit-in-sablier-stream/schema.json rename to src/strategies/sablier-v1-deposit/schema.json index 583a6148d..2e364e335 100644 --- a/src/strategies/deposit-in-sablier-stream/schema.json +++ b/src/strategies/sablier-v1-deposit/schema.json @@ -21,11 +21,6 @@ "pattern": "^0x[a-fA-F0-9]{40}$", "minLength": 42, "maxLength": 42 - }, - "subGraphURL": { - "type": "string", - "title": "Optional subgraph url", - "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"] } }, "required": ["sender", "token"], From a185f2246f5f62584c7c6b3d5c0f89d64121a5ea Mon Sep 17 00:00:00 2001 From: less Date: Tue, 22 Aug 2023 05:59:09 +0700 Subject: [PATCH 476/815] feat: add friend-tech strategy --- src/strategies/friend-tech/README.md | 12 +++++++++ src/strategies/friend-tech/examples.json | 19 ++++++++++++++ src/strategies/friend-tech/index.ts | 33 ++++++++++++++++++++++++ src/strategies/friend-tech/schema.json | 28 ++++++++++++++++++++ src/strategies/index.ts | 2 ++ 5 files changed, 94 insertions(+) create mode 100644 src/strategies/friend-tech/README.md create mode 100644 src/strategies/friend-tech/examples.json create mode 100644 src/strategies/friend-tech/index.ts create mode 100644 src/strategies/friend-tech/schema.json diff --git a/src/strategies/friend-tech/README.md b/src/strategies/friend-tech/README.md new file mode 100644 index 000000000..34377b453 --- /dev/null +++ b/src/strategies/friend-tech/README.md @@ -0,0 +1,12 @@ +# friend-tech + +This strategy allocates voting power according to the number of keys (or shares) a voter possesses on friend.tech for a particular user. + +Here is an example of parameters: + +```json +{ + "address": "0xe12a2f60b400e6c6971d5602df454e5da63edd78", + "symbol": "KEYS" +} +``` diff --git a/src/strategies/friend-tech/examples.json b/src/strategies/friend-tech/examples.json new file mode 100644 index 000000000..38a2fcfbd --- /dev/null +++ b/src/strategies/friend-tech/examples.json @@ -0,0 +1,19 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "friend-tech", + "params": { + "address": "0xe12A2f60B400E6c6971D5602DF454E5dA63eDD78", + "symbol": "KEYS" + } + }, + "network": "8453", + "addresses": [ + "0x81a9a7979f5EB27588b5AB9448398ad321Dba90C", + "0x3B7576DF0Ef2d6c1656245aE15Ad52DCf34FD04a", + "0x7C2FDC7de9F536560E47105257a57C8C8dF79372" + ], + "snapshot": 2933820 + } +] diff --git a/src/strategies/friend-tech/index.ts b/src/strategies/friend-tech/index.ts new file mode 100644 index 000000000..cf5ebc6b3 --- /dev/null +++ b/src/strategies/friend-tech/index.ts @@ -0,0 +1,33 @@ +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'bonustrack'; +export const version = '0.1.0'; + +const abi = ['function sharesBalance(address,address) view returns (uint256)']; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const contract = '0xcf205808ed36593aa40a44f10c7f7c2f67d4a4d4'; + + const multi = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => + multi.call(address, contract, 'sharesBalance', [options.address, address]) + ); + const result: Record = await multi.execute(); + + return Object.fromEntries( + Object.entries(result).map(([address, balance]) => [ + address, + parseFloat(formatUnits(balance, 0)) + ]) + ); +} diff --git a/src/strategies/friend-tech/schema.json b/src/strategies/friend-tech/schema.json new file mode 100644 index 000000000..8213636da --- /dev/null +++ b/src/strategies/friend-tech/schema.json @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "address": { + "type": "string", + "title": "User address", + "examples": ["e.g. 0xe12a2f60b400e6c6971d5602df454e5da63edd78"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. KEYS"], + "maxLength": 16 + } + }, + "required": ["address"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 1d534d48f..4f83fdc90 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -456,6 +456,7 @@ import * as sablierV2 from './sablier-v2'; import * as gelatoStaking from './gelato-staking'; import * as erc4626AssetsOf from './erc4626-assets-of'; import * as sdVoteBoostTWAVPV2 from './sd-vote-boost-twavp-v2'; +import * as friendTech from './friend-tech'; const strategies = { 'cap-voting-power': capVotingPower, @@ -920,6 +921,7 @@ const strategies = { 'sablier-v2': sablierV2, 'gelato-staking': gelatoStaking, 'erc4626-assets-of': erc4626AssetsOf, + 'friend-tech': friendTech, 'sd-vote-boost-twavp-v2': sdVoteBoostTWAVPV2 }; From 5d34048711bd5cbf879b1cfa9805747226aa8e07 Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Wed, 23 Aug 2023 09:04:45 +0300 Subject: [PATCH 477/815] docs: polish wording in sablier v2 (#1257) --- src/strategies/sablier-v2/README.md | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/strategies/sablier-v2/README.md b/src/strategies/sablier-v2/README.md index addf64417..fd1a2ffd8 100644 --- a/src/strategies/sablier-v2/README.md +++ b/src/strategies/sablier-v2/README.md @@ -26,14 +26,14 @@ Based on the chosen strategy, the values filled in the `Addresses` field will re #### Primary policies -| Policy ⭐️ | Methodology | -| :--------------------- | :------------------------------------------------------------------------ | -| withdrawable-recipient | Tokens available/withdrawable by the stream's recipient. | -| reserved-recipient | Tokens available/withdrawable aggregated with unstreamed tokens (future). | +| Policy | Methodology | +| :--------------------- | :---------------------------------------------------------------- | +| withdrawable-recipient | Tokens that are available for the stream's recipient to withdraw. | +| reserved-recipient | Tokens available for withdraw aggregated with unstreamed tokens. | #### Secondary policies -These computation methods are here to aid with special use cases. We still recommend using the primary policies to avoid most caveats. +These policies are designed to address specific edge cases. We strongly recommend using the primary policies. | Policy | Methodology | | :------------------- | :------------------------------------------------------------------------------------ | @@ -74,8 +74,11 @@ Snapshot: Day 15 (midway) with a streamed amount of TKN 500 For the best results, we recommend using the primary policies. -1. The first option is to use the `withdrawable-recipient` policy alongside `erc20-balance-of`. Doing so will aggregate tokens streamed but not withdrawn yet, as well as tokens in the user's wallet. -2. The second best option is using `reserved-recipient` with `erc20-balance-of`. It will aggregate: tokens streamed but not withdrawn yet, unstreamed funds (accessible in the future) and finally, tokens in the user's wallet. +1. The best option is to combine the `withdrawable-recipient` policy with `erc20-balance-of`. Doing so will aggregate + tokens streamed but not withdrawn yet, as well as tokens in the user's wallet. +2. The second best option is to combine `reserved-recipient` with `erc20-balance-of`. They will aggregate (i) tokens + streamed but not withdrawn yet, (ii) unstreamed funds (which will become available in the future), and (iii) the + tokens in the user's wallet. ### Details and Caveats @@ -83,13 +86,18 @@ For the best results, we recommend using the primary policies. The withdrawable amount counts tokens that have been streamed but not withdrawn yet by the recipient. -This is provided using the [`withdrawableAmountOf`](https://docs.sablier.com/contracts/v2/reference/core/abstracts/abstract.SablierV2Lockup#withdrawableamountof) contract method. +This is provided using the +[`withdrawableAmountOf`](/contracts/v2/reference/core/abstracts/abstract.SablierV2Lockup#withdrawableamountof) contract +method. Voting power: realized (present). #### `reserved-recipient` ⭐️ -The reserved amount combines tokens that have been streamed but not withdrawn yet (similar to `withdrawable-recipient`) with tokens that haven't been streamed (still locked yet accessible in the future). It can be computed as `reserved = withdrawable + unstreamed === deposited - withdrawn`. Canceled streams will only count the final withdrawable amount, if any. +The reserved amount combines tokens that have been streamed but not withdrawn yet (similar to `withdrawable-recipient`) +with tokens that haven't been streamed (which will become available in the future). Can be computed as +`reserved = withdrawable + unstreamed === deposited - withdrawn`. Canceled streams will only count the final +withdrawable amount, if any. Voting power: realized (present) + expected (future). From a13cff707aa9f76899f632a88f7fdf7e48f897bf Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Thu, 24 Aug 2023 00:01:48 +0530 Subject: [PATCH 478/815] Enable dependabot for snapshot.js (#1258) --- .github/dependabot.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..4f1006822 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,14 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "daily" + allow: + # Allow updates for snapshot.js only + - dependency-name: "@snapshot-labs/snapshot.js" From a66ded9d8accf1d2de2f684703bad2871c433d48 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 23 Aug 2023 20:43:07 +0200 Subject: [PATCH 479/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.5.5 (#1259) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 09d0f3445..9fd9c31ea 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.5.4", + "@snapshot-labs/snapshot.js": "^0.5.5", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index f0e3c6022..37826f872 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.5.4": - version "0.5.4" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.5.4.tgz#193a489530d9753c441bbec56297fc011a547e58" - integrity sha512-vgJx5MkyndcXMKRpdZDbICycl0EF3gGc2Tb52TCbVCS8C2keajWlZW6aPQivLEP5B18EmD+h+l8U9kn0zj9NiQ== +"@snapshot-labs/snapshot.js@^0.5.5": + version "0.5.5" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.5.5.tgz#1ad759ae1c6504ad2d506ddb6f71756151847622" + integrity sha512-JNBGdqim9+IriPRv0R8vhLe3ojVv7i2R1qrx6PxQCbdHwiBr7d7Npei+h8VpnzOKYcVzPAkttOedxDvxxR2wnA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From e31e59be8d09c7c83aa6e77fa60372b9a388b653 Mon Sep 17 00:00:00 2001 From: halledilirya <95592377+halledilirya@users.noreply.github.com> Date: Fri, 25 Aug 2023 07:08:20 +0300 Subject: [PATCH 480/815] [pancake-profile] add pancake-profile strategy (#1261) --- src/strategies/index.ts | 2 + src/strategies/pancake-profile/README.md | 13 ++++ src/strategies/pancake-profile/examples.json | 37 +++++++++++ src/strategies/pancake-profile/index.ts | 67 ++++++++++++++++++++ src/strategies/pancake-profile/schema.json | 33 ++++++++++ 5 files changed, 152 insertions(+) create mode 100644 src/strategies/pancake-profile/README.md create mode 100644 src/strategies/pancake-profile/examples.json create mode 100644 src/strategies/pancake-profile/index.ts create mode 100644 src/strategies/pancake-profile/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 4f83fdc90..be2b104d7 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -57,6 +57,7 @@ import * as uniswap from './uniswap'; import * as faralandStaking from './faraland-staking'; import * as flashstake from './flashstake'; import * as pancake from './pancake'; +import * as pancakeProfile from './pancake-profile'; import * as synthetix from './synthetix'; import * as aelinCouncil from './aelin-council'; import * as synthetixQuadratic from './synthetix-quadratic'; @@ -546,6 +547,7 @@ const strategies = { 'faraland-staking': faralandStaking, flashstake, pancake, + 'pancake-profile': pancakeProfile, synthetix, 'aelin-council': aelinCouncil, 'synthetix-quadratic': synthetixQuadratic, diff --git a/src/strategies/pancake-profile/README.md b/src/strategies/pancake-profile/README.md new file mode 100644 index 000000000..18a0ab900 --- /dev/null +++ b/src/strategies/pancake-profile/README.md @@ -0,0 +1,13 @@ +# pancake-profile + +## Description + +This strategy calculates the voting power of users who have locked their NFTs from a specific collection within the Pancake Profile contract. + +```json +{ + "address": "0x0a8901b0E25DEb55A87524f0cC164E9644020EBA", + "symbol": "PCS", + "decimals": 18 +} +``` diff --git a/src/strategies/pancake-profile/examples.json b/src/strategies/pancake-profile/examples.json new file mode 100644 index 000000000..d979ad404 --- /dev/null +++ b/src/strategies/pancake-profile/examples.json @@ -0,0 +1,37 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "pancake-profile", + "params": { + "address": "0x0a8901b0E25DEb55A87524f0cC164E9644020EBA", + "symbol": "PCS", + "decimals": 18 + } + }, + "network": "56", + "addresses": [ + "0x89eBA09BbFf0CD6f750bCDB423A3cD1f09d876fD", + "0x56d0b5ed3d525332f00c9bc938f93598ab16aaa7", + "0x49e4dbff86a2e5da27c540c9a9e8d2c3726e278f", + "0x4757ce43dc5429b8f1a132dc29ef970e55ae722b", + "0xB4E597e34E3eC254e9e4795ECF1A31b9Fa1e40F4", + "0xd7539FCdC0aB79a7B688b04387cb128E75cb77Dc", + "0x6E33e22f7aC5A4b58A93C7f6D8Da8b46c50A3E20", + "0xC9dA7343583fA8Bb380A6F04A208C612F86C7701", + "0x5315A1C257FD6266F9608f31AC9b6501C98c5750", + "0x2AC89522CB415AC333E64F52a1a5693218cEBD58", + "0xd90c6f6D37716b1Cc4dd2B116be42e8683550F45", + "0x69ABF813a683391C0ec888351912E14590B56e88", + "0x5bFE87274C671b4Cf6A1AF554916819F6141EaA1", + "0x85924aA0B2cb5a0BbeC583Dd090bF7CEdBa5D2Ea", + "0x9149B2b87159c4CC9e2f10C2711357720Da4DA08", + "0xa0710d3b4BA0f848f7edf9CC827aF70A183EAd26", + "0xAE1220f6bFEb414Ed0A95fbb5A6Ecc303b10aa46", + "0x776b913480d4326430F52F58b16DdF67eEB08DEb", + "0xebe986802F7858E1919451C6Ff893e294F31CE54", + "0x2d7cAA8462023af022A5004dA7b781b8ccF81Da7" + ], + "snapshot": 31132896 + } +] diff --git a/src/strategies/pancake-profile/index.ts b/src/strategies/pancake-profile/index.ts new file mode 100644 index 000000000..3fe488ee9 --- /dev/null +++ b/src/strategies/pancake-profile/index.ts @@ -0,0 +1,67 @@ +import { getAddress } from '@ethersproject/address'; +import { multicall } from '../../utils'; + +export const author = 'yusnu'; +export const version = '0.0.1'; + +const hasRegisteredAbi = [ + 'function hasRegistered(address _userAddress) view returns (bool)' +]; + +const getUserProfileAbi = [ + 'function getUserProfile(address _userAddress) view returns (uint256, uint256, uint256, address, uint256, bool)' +]; + +const pancakeProfileAddress = '0xdf4dbf6536201370f95e06a0f8a7a70fe40e388a'; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const { address: checkAddress } = options; + + const users = Object.fromEntries( + addresses.map((address: any) => [getAddress(address), 0]) + ); + + const hasRegistered = await multicall( + network, + provider, + hasRegisteredAbi, + addresses.map((address: any) => [ + pancakeProfileAddress, + 'hasRegistered', + [address] + ]), + { blockTag } + ); + + const usersWithProfile = addresses.filter( + (address: any, i: number) => hasRegistered[i][0] + ); + + if (usersWithProfile.length) { + const profiles = await multicall( + network, + provider, + getUserProfileAbi, + usersWithProfile.map((user: any) => [ + pancakeProfileAddress, + 'getUserProfile', + [user] + ]), + { blockTag } + ); + + usersWithProfile.forEach((user: any, i: number) => { + users[user] = profiles[i][3] === checkAddress ? 1 : 0; + }); + } + + return users; +} diff --git a/src/strategies/pancake-profile/schema.json b/src/strategies/pancake-profile/schema.json new file mode 100644 index 000000000..2d6e68b84 --- /dev/null +++ b/src/strategies/pancake-profile/schema.json @@ -0,0 +1,33 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "address": { + "type": "string", + "title": "Contract Address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. UNI"], + "maxLength": 16 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 18"] + } + }, + "required": ["address"], + "additionalProperties": false + } + } +} From 14209f9ba17d91f4052c82a12b486e5706764d22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?El=C5=91d=20Varga?= <100562086+VargaElod23@users.noreply.github.com> Date: Fri, 25 Aug 2023 07:17:36 +0200 Subject: [PATCH 481/815] [taraxa-delegation] Implements and adds Taraxa delegation strategy (#1190) * implements and adds taraxa delegation strategy * fixes dependency and lints * Update src/strategies/taraxa-delegation/index.ts Co-authored-by: Chaitanya * simplifies implementation * implements balance + delegation voting strat --------- Co-authored-by: VargaElod23 Co-authored-by: Chaitanya --- src/strategies/index.ts | 2 + src/strategies/taraxa-delegation/README.md | 15 +++++ .../taraxa-delegation/examples.json | 25 ++++++++ src/strategies/taraxa-delegation/index.ts | 57 +++++++++++++++++++ src/strategies/taraxa-delegation/schema.json | 33 +++++++++++ 5 files changed, 132 insertions(+) create mode 100644 src/strategies/taraxa-delegation/README.md create mode 100644 src/strategies/taraxa-delegation/examples.json create mode 100644 src/strategies/taraxa-delegation/index.ts create mode 100644 src/strategies/taraxa-delegation/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index be2b104d7..3d426fa88 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -193,6 +193,7 @@ import * as trancheStakingSLICE from './tranche-staking-slice'; import * as unipoolSameToken from './unipool-same-token'; import * as unipoolUniv2Lp from './unipool-univ2-lp'; import * as unipoolXSushi from './unipool-xsushi'; +import * as taraxaDelegation from './taraxa-delegation'; import * as poap from './poap'; import * as poapWithWeight from './poap-with-weight'; import * as poapWithWeightV2 from './poap-with-weight-v2'; @@ -665,6 +666,7 @@ const strategies = { 'unipool-same-token': unipoolSameToken, 'unipool-univ2-lp': unipoolUniv2Lp, 'unipool-xsushi': unipoolXSushi, + 'taraxa-delegation': taraxaDelegation, poap: poap, 'poap-with-weight': poapWithWeight, 'poap-with-weight-v2': poapWithWeightV2, diff --git a/src/strategies/taraxa-delegation/README.md b/src/strategies/taraxa-delegation/README.md new file mode 100644 index 000000000..c3f25122d --- /dev/null +++ b/src/strategies/taraxa-delegation/README.md @@ -0,0 +1,15 @@ +# Simple Taraxa Delegation Strategy + +Calculates the stakes of voters, based on their DPOS stakes in the previous specified snapshot. + +## Examples + +Used as the base vote strategy for Taraxa Governance, the space config will look like this: + +```JSON +{ + "strategies": [ + ["taraxa-delegation"] + ] +} +``` diff --git a/src/strategies/taraxa-delegation/examples.json b/src/strategies/taraxa-delegation/examples.json new file mode 100644 index 000000000..aea6a3538 --- /dev/null +++ b/src/strategies/taraxa-delegation/examples.json @@ -0,0 +1,25 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "taraxa-delegation", + "params": { + "address": "0x00000000000000000000000000000000000000fe", + "symbol": "TARA", + "decimals": 18 + } + }, + "network": "841", + "addresses": [ + "0xc6a808A6EC3103548f0b38d32DCb6a705B734c89", + "0xf3F6dBBE59AA219eAcE04955Bd6c3045ab4fF615", + "0x0dc0d841f962759da25547c686fa440cf6c28c61", + "0x4a179a005dcbe770c6970ee390a43d2284f67527", + "0x931d0b36e648906a27a67bc6057579984765e198", + "0xfc43217e71ec0a1cc480f3d210cd07cbde7374ec", + "0x21db400dcb1ef3bc3aee4f3d028ec1939b7fadd6", + "0x1daaa59a8d4a5c08080cadb65204d2d275838a99" + ], + "snapshot": 3112430 + } +] diff --git a/src/strategies/taraxa-delegation/index.ts b/src/strategies/taraxa-delegation/index.ts new file mode 100644 index 000000000..bc0385277 --- /dev/null +++ b/src/strategies/taraxa-delegation/index.ts @@ -0,0 +1,57 @@ +import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { getAddress } from '@ethersproject/address'; +import networks from '@snapshot-labs/snapshot.js/src/networks.json'; +import { Multicaller } from '../../utils'; + +export const author = 'Taraxa-project'; +export const version = '0.1.0'; + +const MIN_SCORE_AMOUNT = BigNumber.from(10).mul(BigNumber.from(10).pow(18)); + +const abi = [ + 'function getTotalDelegation(address delegator) external view returns (uint256 total_delegation)', + 'function getEthBalance(address account) public view returns (uint256 balance)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multi = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address: string) => { + multi.call(address, options.address, 'getTotalDelegation', [address]); + }); + const resultDelegations: Record = await multi.execute(); + + addresses.forEach((address: string) => { + multi.call(address, networks[network].multicall, 'getEthBalance', [ + address + ]); + }); + const resultBalances: Record = await multi.execute(); + + const scores = {}; + + for (const address of addresses) { + const score = BigNumber.from(resultBalances[address] || 0).add( + BigNumber.from(resultDelegations[address] || 0) + ); + + if (score.lt(MIN_SCORE_AMOUNT)) { + scores[getAddress(address)] = 0; + } else { + scores[getAddress(address)] = parseFloat( + formatUnits(score, options.decimals) + ); + } + } + + return scores; +} diff --git a/src/strategies/taraxa-delegation/schema.json b/src/strategies/taraxa-delegation/schema.json new file mode 100644 index 000000000..6a71ae4f5 --- /dev/null +++ b/src/strategies/taraxa-delegation/schema.json @@ -0,0 +1,33 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. TARA"], + "maxLength": 16 + }, + "address": { + "type": "string", + "title": "Contract address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 18"] + } + }, + "required": ["address", "decimals"], + "additionalProperties": false + } + } +} From 4365d688c383c499ec73c911e05191df1b612f0f Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Sun, 27 Aug 2023 23:47:35 +0530 Subject: [PATCH 482/815] [karma-discord-roles] Add items type to schema.json (#1265) --- src/strategies/karma-discord-roles/schema.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/strategies/karma-discord-roles/schema.json b/src/strategies/karma-discord-roles/schema.json index 74e0b97fc..a7530d877 100644 --- a/src/strategies/karma-discord-roles/schema.json +++ b/src/strategies/karma-discord-roles/schema.json @@ -14,7 +14,8 @@ "roles": { "type": "array", "title": "Discord Roles", - "examples": ["e.g. Assembly, Trader, Moderator"] + "examples": ["e.g. Assembly, Trader, Moderator"], + "items": {"type": "string"} } }, "required": ["name", "roles"], From 72001705679b4bb2e06608e71d28e1b929dcca8d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 28 Aug 2023 10:43:33 +0530 Subject: [PATCH 483/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.5.6 (#1264) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 9fd9c31ea..97d90045d 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.5.5", + "@snapshot-labs/snapshot.js": "^0.5.6", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 37826f872..5ddb3ce52 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.5.5": - version "0.5.5" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.5.5.tgz#1ad759ae1c6504ad2d506ddb6f71756151847622" - integrity sha512-JNBGdqim9+IriPRv0R8vhLe3ojVv7i2R1qrx6PxQCbdHwiBr7d7Npei+h8VpnzOKYcVzPAkttOedxDvxxR2wnA== +"@snapshot-labs/snapshot.js@^0.5.6": + version "0.5.6" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.5.6.tgz#e8fa4786bfc1fd69c5093d31e65b60ad2f0c5f65" + integrity sha512-5YVgM2V2uhJi3PZfTwSNihcrPa66Wz697IfC8v57enXdYaVYryZnwZfB0A0eahgwdtjBHWlyPOvfRI4Rr7aoTw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 3ff51eed1542895199798557e7da958c9fddea7b Mon Sep 17 00:00:00 2001 From: halledilirya <95592377+halledilirya@users.noreply.github.com> Date: Mon, 28 Aug 2023 21:38:22 +0300 Subject: [PATCH 484/815] [pancake-profile] update strategy (#1267) * [pancake-profile] check if profile is active * Update author Co-authored-by: Chaitanya --------- Co-authored-by: Chaitanya --- src/strategies/pancake-profile/index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/strategies/pancake-profile/index.ts b/src/strategies/pancake-profile/index.ts index 3fe488ee9..3d2840a46 100644 --- a/src/strategies/pancake-profile/index.ts +++ b/src/strategies/pancake-profile/index.ts @@ -1,8 +1,8 @@ import { getAddress } from '@ethersproject/address'; import { multicall } from '../../utils'; -export const author = 'yusnu'; -export const version = '0.0.1'; +export const author = 'skyrocktech'; +export const version = '0.0.2'; const hasRegisteredAbi = [ 'function hasRegistered(address _userAddress) view returns (bool)' @@ -59,7 +59,7 @@ export async function strategy( ); usersWithProfile.forEach((user: any, i: number) => { - users[user] = profiles[i][3] === checkAddress ? 1 : 0; + users[user] = profiles[i][3] === checkAddress && profiles[i][5] ? 1 : 0; }); } From 48a7b6a2693147d339c7fcc2a596168d7ee98e3f Mon Sep 17 00:00:00 2001 From: Wan <495709+wa0x6e@users.noreply.github.com> Date: Tue, 29 Aug 2023 14:27:55 +0900 Subject: [PATCH 485/815] fix: catch and throw meaningful error on non-existing startegy (#1268) --- src/utils.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/utils.ts b/src/utils.ts index 2764b5552..ed4d1372c 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -11,6 +11,11 @@ async function callStrategy(space, network, addresses, strategy, snapshot) { (snapshot === 'latest' || snapshot > strategy.params?.end)) ) return {}; + + if (!_strategies.hasOwnProperty(strategy.name)) { + throw new Error(`Invalid strategy: ${strategy.name}`); + } + const score: any = await _strategies[strategy.name].strategy( space, network, From 9eb3dccb40c3f683c8a616ec3e7e8f96ee251a6c Mon Sep 17 00:00:00 2001 From: Raj Kharvar Date: Tue, 29 Aug 2023 17:38:15 +0530 Subject: [PATCH 486/815] [razor-network-voting] update strategy (#1266) * updated strategy * Update examples.json * Update subgraph endpoint and addresses in examples.json * Update address in examples.json * Add snapshot block number check * Update examples.json for Razor SKALE chain * Update strategy to support paginated data --------- Co-authored-by: Aditya Dhir <31381639+adi44@users.noreply.github.com> Co-authored-by: Skanda Bhat --- .../razor-network-voting/examples.json | 20 ++-- src/strategies/razor-network-voting/index.ts | 100 ++++++++++++------ 2 files changed, 76 insertions(+), 44 deletions(-) diff --git a/src/strategies/razor-network-voting/examples.json b/src/strategies/razor-network-voting/examples.json index e3adcd773..3d3454a50 100644 --- a/src/strategies/razor-network-voting/examples.json +++ b/src/strategies/razor-network-voting/examples.json @@ -7,16 +7,18 @@ "symbol": "RAZOR" } }, - "network": "80001", - "snapshot": 665995, + "network": "278611351", + "snapshot": 434071, "addresses": [ - "0xE79772bC4798fE17dABD3f033af63cc9f887B50F", - "0x6ee26af75a47e15ab040af73cbdc077740f4825c", - "0xfbf427e3c5456b8f3b2e0b98145fa13c16747369", - "0xe0add3053b836e1e1006540b4de959f2b4472a24", - "0xfBf3140A02C1E8fe08a39b86b97c50175B698111", - "0x26A98513240401567733253C6CdD16F006fcd9b1", - "0xA74b60E368c7C870EeB581dc899cFA8158058bb8" + "0xf5ad93418e727607bfea3adf5c056e056d0236a7", + "0x7ee4e7a1403db07c6908ef29c00f20270a28fd2d", + "0x5faf079b1CD8e3Cd526FDbbf3d4e4179ddE476AC", + "0x24566839d381e2f5a5d8f5bf880354f0851cbb76", + "0x7af34d14524104ec65b882b7e31b022eebc88936", + "0x66851befbec4f6acf4bfd2371dab3dfe45f2b920", + "0x35ed54562ddaddd7dd699cdf92128c1d9c1a1529", + "0x13E5f89515B0C781B7118b5dAEEde7Da4BCf9d7b", + "0x13E5f89515B0C781B7118b5dAEEde7Da4BCf9d7b" ] } ] diff --git a/src/strategies/razor-network-voting/index.ts b/src/strategies/razor-network-voting/index.ts index f83d3671a..ea8e101a9 100644 --- a/src/strategies/razor-network-voting/index.ts +++ b/src/strategies/razor-network-voting/index.ts @@ -4,6 +4,7 @@ import { BigNumber } from '@ethersproject/bignumber'; export const author = 'razor-network'; export const version = '0.1.0'; +const PAGE_SIZE = 1000; const RAZOR_NETWORK_SUBGRAPH_URL = 'https://graph-indexer.razorscan.io/subgraphs/name/razor/razor'; @@ -25,6 +26,68 @@ function wei_to_ether(amount: number) { return amount / 10 ** 18; } +export async function getAllData(snapshot) { + let skip = 0; + let allDelegators = []; + let allStakers = []; + + while (true) { + const params = { + delegators: { + __args: { + first: PAGE_SIZE, + skip + }, + staker: { + totalSupply: true, + stake: true, + staker: true + }, + delegatorAddress: true, + sAmount: true + }, + stakers: { + __args: { + first: PAGE_SIZE, + skip + }, + stake: true, + totalSupply: true, + staker: true, + sAmount: true + } + }; + + if (snapshot !== 'latest') { + // @ts-ignore + params.delegators.__args.block = { number: snapshot }; + // @ts-ignore + params.stakers.__args.block = { number: snapshot }; + } + + const response = await subgraphRequest(RAZOR_NETWORK_SUBGRAPH_URL, params); + + if (response.delegators && response.delegators.length) { + allDelegators = allDelegators.concat(response.delegators); + } + + if (response.stakers && response.stakers.length) { + allStakers = allStakers.concat(response.stakers); + } + + if ( + response.stakers.length === PAGE_SIZE || + response.delegators.length === PAGE_SIZE + ) { + skip += PAGE_SIZE; + } else { + break; + } + } + + return { stakers: allStakers, delegators: allDelegators }; +} + export async function strategy( space: any, network: any, @@ -34,43 +97,10 @@ export async function strategy( //symbol: string, snapshot: string ) { - const params = { - delegators: { - __args: { - where: { - delegatorAddress_in: addresses - } // delegatorAddress - }, // Amount_Delegated - staker: { - totalSupply: true, - stake: true, - staker: true - }, - delegatorAddress: true, - sAmount: true - }, - stakers: { - __args: { - where: { - staker_in: addresses // stakerAddress - } - }, - stake: true, - totalSupply: true, - staker: true, - sAmount: true - } - }; - - if (snapshot !== 'latest') { - // @ts-ignore - params.delegators.__args.block = { number: snapshot }; - } - const score = {}; - // subgraph request 1 : it fetches all the details of the stakers and delegators. - const result = await subgraphRequest(RAZOR_NETWORK_SUBGRAPH_URL, params); + // subgraph request : it fetches all the details of the stakers and delegators. + const result = await getAllData(snapshot); if (result.delegators || result.stakers) { result.delegators.forEach( async (delegator: { From 852ebd631cd4bc899a890f02a98be59e26bbb71d Mon Sep 17 00:00:00 2001 From: kostyamospan <37243242+kostyamospan@users.noreply.github.com> Date: Wed, 30 Aug 2023 19:53:27 +0300 Subject: [PATCH 487/815] [erc20-balance-of-top-holders] Adding erc20-balance-of-top-holders (#1269) * wip: strategy for erc20 top holders balances * chore: strategy changed to work with subgraph history * chore: readme example updated * fix: lint --- .../erc20-balance-of-top-holders/README.md | 17 +++++ .../examples.json | 30 ++++++++ .../erc20-balance-of-top-holders/index.ts | 73 +++++++++++++++++++ src/strategies/index.ts | 2 + 4 files changed, 122 insertions(+) create mode 100644 src/strategies/erc20-balance-of-top-holders/README.md create mode 100644 src/strategies/erc20-balance-of-top-holders/examples.json create mode 100644 src/strategies/erc20-balance-of-top-holders/index.ts diff --git a/src/strategies/erc20-balance-of-top-holders/README.md b/src/strategies/erc20-balance-of-top-holders/README.md new file mode 100644 index 000000000..211310382 --- /dev/null +++ b/src/strategies/erc20-balance-of-top-holders/README.md @@ -0,0 +1,17 @@ +# erc20-balance-of-top-holders + +Strategy, that accept votes only from top N token holders + +Subgraph should be compatible with [OpenZeppelin ERC20 Subgraph](https://github.com/OpenZeppelin/openzeppelin-subgraphs) + +Here is an example of parameters: + +```json +{ + "address": "0x8494Aee22e0DB34daA1e8D6829d85710357be9F7", + "symbol": "HANDZ", + "decimals": 18, + "subgraphUrl": "https://api.thegraph.com/subgraphs/name/kostyamospan/handz-token", + "topHolders": 5 +} +``` diff --git a/src/strategies/erc20-balance-of-top-holders/examples.json b/src/strategies/erc20-balance-of-top-holders/examples.json new file mode 100644 index 000000000..fda35a613 --- /dev/null +++ b/src/strategies/erc20-balance-of-top-holders/examples.json @@ -0,0 +1,30 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "erc20-balance-of-top-holders", + "params": { + "address": "0x8494Aee22e0DB34daA1e8D6829d85710357be9F7", + "symbol": "HANDZ", + "decimals": 18, + "subgraphUrl": "https://api.thegraph.com/subgraphs/name/kostyamospan/handz-token", + "topHolders": 5 + } + }, + "network": "1", + "addresses": [ + "0xD87dec8eE5d941234d85a9d2636D077fE03B0660", + "0x54B9ca09248C49e9ed0968bfD0AA0bd13E85992A", + "0x254c8A6225CE32903D2657D0945701ACD6e42188", + "0xF59Dd6525529F77cF90Ec9A8205d52874af7a425", + "0x0a0A1669A7E3f16b3010dD78F53D3E22Dcf4b739", + "0x5b941eA7387190Ba6a0bF4B766c1F3eB0Ab30A25", + "0xc0D57b31F33Ce4f6627d353Ac51461fB7cDC1519", + "0xF5De2507726A312aD6f806A9972Ed438344022b2", + "0x33b5752C03495014A130f8f4A235f6280C58f266", + "0x6323b71f37a07642F8055E9847B58Ffc9FA44243", + "0xf5F730146D177Cf7Dd28AA39F81359DaE51D4379" + ], + "snapshot": 18020926 + } +] diff --git a/src/strategies/erc20-balance-of-top-holders/index.ts b/src/strategies/erc20-balance-of-top-holders/index.ts new file mode 100644 index 000000000..353f5e1e1 --- /dev/null +++ b/src/strategies/erc20-balance-of-top-holders/index.ts @@ -0,0 +1,73 @@ +import { subgraphRequest } from '../../utils'; +import { getAddress } from '@ethersproject/address'; + +export const author = 'RedDuck-Software'; +export const version = '0.0.1'; + +async function getTopHoldersBalance( + url, + options, + snapshot +): Promise> { + const topHoldersAmount = +options.topHolders || 0; + + const query = { + erc20Balances: { + __args: { + where: { + account_not: null, + contract: options.address + }, + orderBy: 'valueExact', + orderDirection: 'desc', + first: topHoldersAmount + }, + value: true, + contract: true, + account: { + id: true + } + } + }; + + if (snapshot !== 'latest') { + // @ts-ignore + query.erc20Balances.__args.block = { number: snapshot }; + } + + const topHolders: Record = {}; + + const result = await subgraphRequest(url, query); + + if (result && result.erc20Balances) { + result.erc20Balances.forEach((tokenBalance) => { + const address = getAddress(tokenBalance.account.id); + const balance = parseFloat(tokenBalance.value); + topHolders[address] = balance; + }); + } + + return topHolders; +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const topHoldersBalancesScores = await getTopHoldersBalance( + options.subgraphUrl, + options, + snapshot + ); + + return Object.fromEntries( + addresses.map((address) => [ + address, + topHoldersBalancesScores[address] ? topHoldersBalancesScores[address] : 0 + ]) + ); +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 3d426fa88..10b551850 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -31,6 +31,7 @@ import * as erc20WithBalance from './erc20-with-balance'; import * as erc20BalanceOfDelegation from './erc20-balance-of-delegation'; import * as erc20BalanceOfWithDelegation from './erc20-balance-of-with-delegation'; import * as erc20BalanceOfQuadraticDelegation from './erc20-balance-of-quadratic-delegation'; +import * as erc20BalanceOfTopHolders from './erc20-balance-of-top-holders'; import * as erc20BalanceOfWeighted from './erc20-balance-of-weighted'; import * as ethalendBalanceOf from './ethalend-balance-of'; import * as prepoVesting from './prepo-vesting'; @@ -509,6 +510,7 @@ const strategies = { 'erc20-balance-of-delegation': erc20BalanceOfDelegation, 'erc20-balance-of-with-delegation': erc20BalanceOfWithDelegation, 'erc20-balance-of-quadratic-delegation': erc20BalanceOfQuadraticDelegation, + 'erc20-balance-of-top-holders': erc20BalanceOfTopHolders, 'erc20-balance-of-weighted': erc20BalanceOfWeighted, 'minto-balance-of-all': mintoBalanceAll, 'erc20-balance-of-indexed': erc20BalanceOfIndexed, From 35e094c5bf477e0fa4fe99201bebb43ee84131a6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 31 Aug 2023 00:58:50 +0530 Subject: [PATCH 488/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.5.8 (#1273) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 97d90045d..4157d65b5 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.5.6", + "@snapshot-labs/snapshot.js": "^0.5.8", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 5ddb3ce52..c4850455c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.5.6": - version "0.5.6" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.5.6.tgz#e8fa4786bfc1fd69c5093d31e65b60ad2f0c5f65" - integrity sha512-5YVgM2V2uhJi3PZfTwSNihcrPa66Wz697IfC8v57enXdYaVYryZnwZfB0A0eahgwdtjBHWlyPOvfRI4Rr7aoTw== +"@snapshot-labs/snapshot.js@^0.5.8": + version "0.5.8" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.5.8.tgz#16bf19b27e487e937be8472e53f0ed71f25e47af" + integrity sha512-bFe4VBUOD2LbKKesD52G7hqBCrmx7BS/4n8JfnzR+GZddL4UWmjRhfnxx/6YLeJvaHOWSPs7LHkr16fpJXD7pQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 337eee36470b11b83ae1eae40d3ead01002c304b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 4 Sep 2023 11:25:31 +0530 Subject: [PATCH 489/815] Automated lint (#1275) Co-authored-by: ChaituVR --- src/strategies/karma-discord-roles/schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategies/karma-discord-roles/schema.json b/src/strategies/karma-discord-roles/schema.json index a7530d877..ada8692b0 100644 --- a/src/strategies/karma-discord-roles/schema.json +++ b/src/strategies/karma-discord-roles/schema.json @@ -15,7 +15,7 @@ "type": "array", "title": "Discord Roles", "examples": ["e.g. Assembly, Trader, Moderator"], - "items": {"type": "string"} + "items": { "type": "string" } } }, "required": ["name", "roles"], From 81550710fedbc917a4dbc41b26836ccf9f7d4b9c Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Mon, 4 Sep 2023 23:25:17 +0530 Subject: [PATCH 490/815] Update aave-governance-power strategy Readme (#1276) --- src/strategies/aave-governance-power/README.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/strategies/aave-governance-power/README.md b/src/strategies/aave-governance-power/README.md index f091e23ba..6ab02a140 100644 --- a/src/strategies/aave-governance-power/README.md +++ b/src/strategies/aave-governance-power/README.md @@ -1,11 +1,10 @@ -# Contract call strategy +# aave-governance-power strategy Allows to get Voting power or Proposition power from an Aave GovernanceStrategy contract. -## Strategy Parameters +## Params -| Param | Type | Description | | | -| ------------------ | ------ | -------------------------------------------------------------------------------------------------------------------------- | --- | --- | -| governanceStrategy | string | The Ethereum address of the GovernanceStrategy contract to measure voting or proposition power from an address at a block. | | | -| powerType | string | Use `vote` for Voting Power or `proposition` for Proposition Power | | | -| | | | | | +| Param | Type | Description | +| --- | --- | --- | +| governanceStrategy | string | The Ethereum address of the GovernanceStrategy contract to measure voting or proposition power from an address at a block. | +| powerType | string | Use `vote` for Voting Power or `proposition` for Proposition Power | From 48fe81ad253f868e77f32a18e3cad69a066915f2 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Tue, 5 Sep 2023 00:00:13 +0530 Subject: [PATCH 491/815] [aave-governance-power] Add aave gov power strategy schema (#1277) * Update aave-governance-power strategy Readme * Add schema --- .../aave-governance-power/examples.json | 10 ++--- src/strategies/aave-governance-power/index.ts | 22 +--------- .../aave-governance-power/schema.json | 40 +++++++++++++++++++ 3 files changed, 47 insertions(+), 25 deletions(-) create mode 100644 src/strategies/aave-governance-power/schema.json diff --git a/src/strategies/aave-governance-power/examples.json b/src/strategies/aave-governance-power/examples.json index 76b6e2b5f..e297a3380 100644 --- a/src/strategies/aave-governance-power/examples.json +++ b/src/strategies/aave-governance-power/examples.json @@ -4,14 +4,14 @@ "strategy": { "name": "aave-governance-power", "params": { - "governanceStrategy": "0xb7e383ef9b1e9189fc0f71fb30af8aa14377429e", + "symbol": "AAVE+stkAAVE", + "decimals": 18, "powerType": "vote", - "symbol": "Voting Power", - "decimals": 18 + "governanceStrategy": "0xb7e383ef9b1e9189fc0f71fb30af8aa14377429e" } }, "network": "1", - "addresses": ["0x5BC928BF0DAb1e4A2ddd9e347b0F22e88026D76c"], - "snapshot": 12657715 + "addresses": ["0x329c54289Ff5D6B7b7daE13592C6B1EDA1543eD4", "0x57ab7ee15cE5ECacB1aB84EE42D5A9d0d8112922", "0x0ab97008cad303a8C90ea630c282760284c19e93"], + "snapshot": 18054498 } ] diff --git a/src/strategies/aave-governance-power/index.ts b/src/strategies/aave-governance-power/index.ts index 0e0542f97..a7157abf3 100644 --- a/src/strategies/aave-governance-power/index.ts +++ b/src/strategies/aave-governance-power/index.ts @@ -10,26 +10,8 @@ export const version = '0.1.0'; */ const abi = [ - { - inputs: [ - { internalType: 'address', name: 'user', type: 'address' }, - { internalType: 'uint256', name: 'blockNumber', type: 'uint256' } - ], - name: 'getPropositionPowerAt', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - stateMutability: 'view', - type: 'function' - }, - { - inputs: [ - { internalType: 'address', name: 'user', type: 'address' }, - { internalType: 'uint256', name: 'blockNumber', type: 'uint256' } - ], - name: 'getVotingPowerAt', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - stateMutability: 'view', - type: 'function' - } + 'function getPropositionPowerAt(address user, uint256 blockNumber) view returns (uint256)', + 'function getVotingPowerAt(address user, uint256 blockNumber) view returns (uint256)' ]; const powerTypesToMethod = { diff --git a/src/strategies/aave-governance-power/schema.json b/src/strategies/aave-governance-power/schema.json new file mode 100644 index 000000000..25cedec86 --- /dev/null +++ b/src/strategies/aave-governance-power/schema.json @@ -0,0 +1,40 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. DOODLE"], + "maxLength": 16 + }, + "governanceStrategy": { + "type": "string", + "title": "Contract address", + "examples": ["e.g. 0x1f9840a85d5af5bf1d1762f925bdaddc4201f984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "powerType": { + "type": "string", + "title": "Power type", + "enum": ["vote", "proposition"] + }, + "decimals": { + "type": "integer", + "title": "Decimals", + "examples": ["e.g. 18"], + "minimum": 0, + "maximum": 18 + } + }, + "required": ["governanceStrategy", "powerType", "decimals"], + "additionalProperties": false + } + } +} From e978c32bf128969db9af78c681b4d06fecf31149 Mon Sep 17 00:00:00 2001 From: Vesper <120714950+RealWorldVesper@users.noreply.github.com> Date: Thu, 7 Sep 2023 21:52:03 +0400 Subject: [PATCH 492/815] [moonbase] Moonbase Strategy (#1278) * init commit for snapshot analysis * Update yarn.lock * Update package.json * resolve final issues * Update src/strategies/moonbase/index.ts Co-authored-by: Chaitanya --------- Co-authored-by: Chaitanya --- src/strategies/index.ts | 4 +- src/strategies/moonbase/README.md | 37 +++++++++++ src/strategies/moonbase/examples.json | 27 ++++++++ src/strategies/moonbase/index.ts | 89 +++++++++++++++++++++++++++ 4 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 src/strategies/moonbase/README.md create mode 100644 src/strategies/moonbase/examples.json create mode 100644 src/strategies/moonbase/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 10b551850..c9068b0c2 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -460,6 +460,7 @@ import * as gelatoStaking from './gelato-staking'; import * as erc4626AssetsOf from './erc4626-assets-of'; import * as sdVoteBoostTWAVPV2 from './sd-vote-boost-twavp-v2'; import * as friendTech from './friend-tech'; +import * as moonbase from './moonbase'; const strategies = { 'cap-voting-power': capVotingPower, @@ -928,7 +929,8 @@ const strategies = { 'gelato-staking': gelatoStaking, 'erc4626-assets-of': erc4626AssetsOf, 'friend-tech': friendTech, - 'sd-vote-boost-twavp-v2': sdVoteBoostTWAVPV2 + 'sd-vote-boost-twavp-v2': sdVoteBoostTWAVPV2, + 'moonbase': moonbase }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/moonbase/README.md b/src/strategies/moonbase/README.md new file mode 100644 index 000000000..aa7bc5d1b --- /dev/null +++ b/src/strategies/moonbase/README.md @@ -0,0 +1,37 @@ +# Moonbase + +This is the strategy, it returns the balances of the voters for MBG token balances +in Moonbase project(pools, farms, vaults, token). + +Here is an example of parameters: + +```json +[ + { + "name": "Example query Moonbase", + "strategy": { + "name": "moonbase", + "params": { + "address": "0xc97c478Fc35d75b51549C39974053a679A5C67E1", + "masterChef": "0x830304d6C669d33738c7E4c1F2310CC1E530Df63", + "moonbaseLPs": [ + { + "address": "0x230C64C42886A1F6b91eD8C11B59a2D45865d38F", + "pid": 7 + } + ], + "symbol": "MBG", + "decimals": 18 + } + }, + "network": "84531", + "addresses": [ + "0xe32C26Be24232ba92cd89d116985F81f94Dd26a8", + "0x7DC90A11489C384dc72234120B0f84C3932d94Ce", + "0xf704872349a62ceBb40F841B635de268b2F7B9Fb" + ], + "snapshot": 9182354 + } +] +``` +Note: A maximum of 1,000,000,000 moonbaseLPs are allowed in the strategy to avoid memory issues. \ No newline at end of file diff --git a/src/strategies/moonbase/examples.json b/src/strategies/moonbase/examples.json new file mode 100644 index 000000000..1668c37e4 --- /dev/null +++ b/src/strategies/moonbase/examples.json @@ -0,0 +1,27 @@ +[ + { + "name": "Example query Moonbase", + "strategy": { + "name": "moonbase", + "params": { + "address": "0xc97c478Fc35d75b51549C39974053a679A5C67E1", + "masterChef": "0x830304d6C669d33738c7E4c1F2310CC1E530Df63", + "moonbaseLPs": [ + { + "address": "0x230C64C42886A1F6b91eD8C11B59a2D45865d38F", + "pid": 7 + } + ], + "symbol": "MBG", + "decimals": 18 + } + }, + "network": "84531", + "addresses": [ + "0xe32C26Be24232ba92cd89d116985F81f94Dd26a8", + "0x7DC90A11489C384dc72234120B0f84C3932d94Ce", + "0xf704872349a62ceBb40F841B635de268b2F7B9Fb" + ], + "snapshot": 9182354 + } + ] \ No newline at end of file diff --git a/src/strategies/moonbase/index.ts b/src/strategies/moonbase/index.ts new file mode 100644 index 000000000..a48a17357 --- /dev/null +++ b/src/strategies/moonbase/index.ts @@ -0,0 +1,89 @@ +import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; +import examplesFile from './examples.json'; + +export const author = 'MoonbaseMarkets'; +export const version = '0.0.1'; +export const examples = examplesFile; + +const abi = [ + 'function totalSupply() view returns (uint256)', + 'function balanceOf(address _owner) view returns (uint256 balance)', + 'function userInfo(uint256, address) view returns (uint256 amount, uint256 rewardDebt)' +]; + +const bn = (num: any): BigNumber => { + return BigNumber.from(num.toString()); +}; + +const addUserBalance = (userBalances, user: string, balance) => { + if (userBalances[user]) { + return (userBalances[user] = userBalances[user].add(balance)); + } else { + return (userBalances[user] = balance); + } +}; + +const MAX_MOONBASE_LPS = 1000000000; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + + if (options.moonbaseLPs.length > MAX_MOONBASE_LPS) { + throw new Error(`Too many moonbaseLPs. Maximum allowed is ${MAX_MOONBASE_LPS}.`); + } + + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multicall = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address: any) => { + multicall.call(`token.${address}`, options.address, 'balanceOf', [address]); + }); + options.moonbaseLPs.forEach((lp: { address: string; pid: number }) => { + multicall.call(`lp.${lp.pid}.totalSupply`, lp.address, 'totalSupply'); + multicall.call(`lp.${lp.pid}.balanceOf`, options.address, 'balanceOf', [ + lp.address + ]); + addresses.forEach((address: any) => { + multicall.call( + `lpUsers.${address}.${lp.pid}`, + options.masterChef, + 'userInfo', + [lp.pid, address] + ); + }); + }); + const result = await multicall.execute(); + + const userBalances: any = []; + for (let i = 0; i < addresses.length - 1; i++) { + userBalances[addresses[i]] = bn(0); + } + + addresses.forEach((address: any) => { + addUserBalance(userBalances, address, result.token[address]); + options.moonbaseLPs.forEach((lp: { address: string; pid: number }) => { + addUserBalance( + userBalances, + address, + result.lpUsers[address][lp.pid][0] + .mul(result.lp[lp.pid].balanceOf) + .div(result.lp[lp.pid].totalSupply) + ); + }); + }); + + return Object.fromEntries( + Object.entries(userBalances).map(([address, balance]) => [ + address, + parseFloat(formatUnits(balance, options.decimals)) + ]) + ); +} \ No newline at end of file From 1ad64e1deca31edaf90ba01dcd019f88becc3be1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 10 Sep 2023 19:57:46 +0530 Subject: [PATCH 493/815] Automated lint (#1279) Co-authored-by: ChaituVR --- .../aave-governance-power/examples.json | 6 ++- src/strategies/index.ts | 2 +- src/strategies/moonbase/examples.json | 52 +++++++++---------- src/strategies/moonbase/index.ts | 7 +-- 4 files changed, 36 insertions(+), 31 deletions(-) diff --git a/src/strategies/aave-governance-power/examples.json b/src/strategies/aave-governance-power/examples.json index e297a3380..03c23fc1a 100644 --- a/src/strategies/aave-governance-power/examples.json +++ b/src/strategies/aave-governance-power/examples.json @@ -11,7 +11,11 @@ } }, "network": "1", - "addresses": ["0x329c54289Ff5D6B7b7daE13592C6B1EDA1543eD4", "0x57ab7ee15cE5ECacB1aB84EE42D5A9d0d8112922", "0x0ab97008cad303a8C90ea630c282760284c19e93"], + "addresses": [ + "0x329c54289Ff5D6B7b7daE13592C6B1EDA1543eD4", + "0x57ab7ee15cE5ECacB1aB84EE42D5A9d0d8112922", + "0x0ab97008cad303a8C90ea630c282760284c19e93" + ], "snapshot": 18054498 } ] diff --git a/src/strategies/index.ts b/src/strategies/index.ts index c9068b0c2..dd115e385 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -930,7 +930,7 @@ const strategies = { 'erc4626-assets-of': erc4626AssetsOf, 'friend-tech': friendTech, 'sd-vote-boost-twavp-v2': sdVoteBoostTWAVPV2, - 'moonbase': moonbase + moonbase: moonbase }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/moonbase/examples.json b/src/strategies/moonbase/examples.json index 1668c37e4..f875696bf 100644 --- a/src/strategies/moonbase/examples.json +++ b/src/strategies/moonbase/examples.json @@ -1,27 +1,27 @@ [ - { - "name": "Example query Moonbase", - "strategy": { - "name": "moonbase", - "params": { - "address": "0xc97c478Fc35d75b51549C39974053a679A5C67E1", - "masterChef": "0x830304d6C669d33738c7E4c1F2310CC1E530Df63", - "moonbaseLPs": [ - { - "address": "0x230C64C42886A1F6b91eD8C11B59a2D45865d38F", - "pid": 7 - } - ], - "symbol": "MBG", - "decimals": 18 - } - }, - "network": "84531", - "addresses": [ - "0xe32C26Be24232ba92cd89d116985F81f94Dd26a8", - "0x7DC90A11489C384dc72234120B0f84C3932d94Ce", - "0xf704872349a62ceBb40F841B635de268b2F7B9Fb" - ], - "snapshot": 9182354 - } - ] \ No newline at end of file + { + "name": "Example query Moonbase", + "strategy": { + "name": "moonbase", + "params": { + "address": "0xc97c478Fc35d75b51549C39974053a679A5C67E1", + "masterChef": "0x830304d6C669d33738c7E4c1F2310CC1E530Df63", + "moonbaseLPs": [ + { + "address": "0x230C64C42886A1F6b91eD8C11B59a2D45865d38F", + "pid": 7 + } + ], + "symbol": "MBG", + "decimals": 18 + } + }, + "network": "84531", + "addresses": [ + "0xe32C26Be24232ba92cd89d116985F81f94Dd26a8", + "0x7DC90A11489C384dc72234120B0f84C3932d94Ce", + "0xf704872349a62ceBb40F841B635de268b2F7B9Fb" + ], + "snapshot": 9182354 + } +] diff --git a/src/strategies/moonbase/index.ts b/src/strategies/moonbase/index.ts index a48a17357..98ab3d4d0 100644 --- a/src/strategies/moonbase/index.ts +++ b/src/strategies/moonbase/index.ts @@ -35,9 +35,10 @@ export async function strategy( options, snapshot ): Promise> { - if (options.moonbaseLPs.length > MAX_MOONBASE_LPS) { - throw new Error(`Too many moonbaseLPs. Maximum allowed is ${MAX_MOONBASE_LPS}.`); + throw new Error( + `Too many moonbaseLPs. Maximum allowed is ${MAX_MOONBASE_LPS}.` + ); } const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; @@ -86,4 +87,4 @@ export async function strategy( parseFloat(formatUnits(balance, options.decimals)) ]) ); -} \ No newline at end of file +} From b11ca2d4fa951d077bf96794c7d41e354a8fa179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?El=C5=91d=20Varga?= <100562086+VargaElod23@users.noreply.github.com> Date: Wed, 13 Sep 2023 02:46:26 -0400 Subject: [PATCH 494/815] Remove min check from taraxa-delegation strat [taraxa-delegation] (#1280) * implements and adds taraxa delegation strategy * fixes dependency and lints * Update src/strategies/taraxa-delegation/index.ts Co-authored-by: Chaitanya * simplifies implementation * implements balance + delegation voting strat * removes min score check --------- Co-authored-by: VargaElod23 Co-authored-by: Chaitanya --- src/strategies/taraxa-delegation/index.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/strategies/taraxa-delegation/index.ts b/src/strategies/taraxa-delegation/index.ts index bc0385277..be50ca99f 100644 --- a/src/strategies/taraxa-delegation/index.ts +++ b/src/strategies/taraxa-delegation/index.ts @@ -7,8 +7,6 @@ import { Multicaller } from '../../utils'; export const author = 'Taraxa-project'; export const version = '0.1.0'; -const MIN_SCORE_AMOUNT = BigNumber.from(10).mul(BigNumber.from(10).pow(18)); - const abi = [ 'function getTotalDelegation(address delegator) external view returns (uint256 total_delegation)', 'function getEthBalance(address account) public view returns (uint256 balance)' @@ -44,13 +42,9 @@ export async function strategy( BigNumber.from(resultDelegations[address] || 0) ); - if (score.lt(MIN_SCORE_AMOUNT)) { - scores[getAddress(address)] = 0; - } else { - scores[getAddress(address)] = parseFloat( - formatUnits(score, options.decimals) - ); - } + scores[getAddress(address)] = parseFloat( + formatUnits(score, options.decimals) + ); } return scores; From 9c4428f3286cf22777c28f3bbebad9a2d0d6bc7f Mon Sep 17 00:00:00 2001 From: Nick Doherty Date: Wed, 20 Sep 2023 13:07:19 +0800 Subject: [PATCH 495/815] add rocketpool node operator v3 strategy (#1284) --- src/strategies/index.ts | 2 + .../rocketpool-node-operator-v3/README.md | 13 ++ .../rocketpool-node-operator-v3/examples.json | 34 ++++++ .../rocketpool-node-operator-v3/index.ts | 112 ++++++++++++++++++ 4 files changed, 161 insertions(+) create mode 100644 src/strategies/rocketpool-node-operator-v3/README.md create mode 100644 src/strategies/rocketpool-node-operator-v3/examples.json create mode 100644 src/strategies/rocketpool-node-operator-v3/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index dd115e385..6b8faea37 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -363,6 +363,7 @@ import * as auraBalanceOfVlauraVebal from './aura-balance-of-vlaura-vebal'; import * as auraBalanceOfSingleAsset from './aura-vault-balance-of-single-asset'; import * as rocketpoolNodeOperator from './rocketpool-node-operator'; import * as rocketpoolNodeOperatorv2 from './rocketpool-node-operator-v2'; +import * as rocketpoolNodeOperatorv3 from './rocketpool-node-operator-v3'; import * as earthfundChildDaoStakingBalance from './earthfund-child-dao-staking-balance'; import * as unipilotVaultPilotBalance from './unipilot-vault-pilot-balance'; import * as sdBoostTWAVP from './sd-boost-twavp'; @@ -832,6 +833,7 @@ const strategies = { 'aura-vault-balance-of-single-asset': auraBalanceOfSingleAsset, 'rocketpool-node-operator': rocketpoolNodeOperator, 'rocketpool-node-operator-v2': rocketpoolNodeOperatorv2, + 'rocketpool-node-operator-v3': rocketpoolNodeOperatorv3, 'earthfund-child-dao-staking-balance': earthfundChildDaoStakingBalance, 'sd-boost-twavp': sdBoostTWAVP, 'unipilot-vault-pilot-balance': unipilotVaultPilotBalance, diff --git a/src/strategies/rocketpool-node-operator-v3/README.md b/src/strategies/rocketpool-node-operator-v3/README.md new file mode 100644 index 000000000..04193da89 --- /dev/null +++ b/src/strategies/rocketpool-node-operator-v3/README.md @@ -0,0 +1,13 @@ +# rocketpool-node-operator-v3 + +This is a strategy for staking node operators, it returns the half square rooted node effective stake balance given a node address. + +Here is an example of parameters: + +```json +{ + "address": "0xD33526068D116cE69F19A9ee46F0bd304F21A51f", + "symbol": "RPL", + "decimals": 18 +} +``` diff --git a/src/strategies/rocketpool-node-operator-v3/examples.json b/src/strategies/rocketpool-node-operator-v3/examples.json new file mode 100644 index 000000000..c45f377ed --- /dev/null +++ b/src/strategies/rocketpool-node-operator-v3/examples.json @@ -0,0 +1,34 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "rocketpool-node-operator-v3", + "params": { + "address": "0xD33526068D116cE69F19A9ee46F0bd304F21A51f", + "symbol": "RPL", + "decimals": 18 + } + }, + "network": "1", + "addresses": [ + "0x17Fa597cEc16Ab63A7ca00Fb351eb4B29Ffa6f46", + "0xca317A4ecCbe0Dd5832dE2A7407e3c03F88b2CdD", + "0x327260c50634136551bfE4e4eB082281555AAfAE", + "0x5d8172792a9e649053c07366E3a7C24a37F0C534", + "0x701F4dcEAD1049FA01F321d49F6dca525cF4A5A5", + "0xb8ed9ea221bf33d37360A76DDD52bA7b1E66AA5C", + "0xbfaf9BFa09F26EF8104A6d5FF09afdCC9300E5bc", + "0x174E0b45C03318B0C9bc03573028605B26764931", + "0x5f4cB66c9B1Ed8A4758A059FDB10E0F72C307D8A", + "0x24609303B67051eF77735E34D671e2A13E3Da35d", + "0xE35854CdE18A3cC4706134b4850Dd861a55B9A30", + "0x53938f795AB6c57070AAd32905a70A2E5961A887", + "0xD6527Bd3d62f1Da520E6f74B89EBD8F8cD04564f", + "0xf8bFf17a1C9dfC632F6C905d12C404AfE451B16c", + "0x689C6853f3deBac91b72f32BafA83200eeC9613C", + "0xaEbb400542598E6ee58b2FDF2E7425c07E8Ba68D", + "0xa016344b2D4dfBf370766F24d196171DeC86544A" + ], + "snapshot": 17761214 + } +] diff --git a/src/strategies/rocketpool-node-operator-v3/index.ts b/src/strategies/rocketpool-node-operator-v3/index.ts new file mode 100644 index 000000000..effdabfcf --- /dev/null +++ b/src/strategies/rocketpool-node-operator-v3/index.ts @@ -0,0 +1,112 @@ +import { BigNumberish, BigNumber } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'rocket-pool'; +export const version = '0.1.3'; + +const rocketNetworkPricesAddress = '0xd3f500F550F46e504A4D2153127B47e007e11166'; +const rocketNetworkPricesContractAbi = [ + 'function getRPLPrice() external view returns (uint256)' +]; +const rocketNodeStakingAddress = '0x0d8D8f8541B12A0e1194B7CC4b6D954b90AB82ec'; +const rocketNodeStakingContractAbi = [ + 'function getNodeEffectiveRPLStake(address _nodeAddress) external view returns (uint256)', + 'function getNodeRPLStake(address _nodeAddress) external view returns (uint256)', + 'function getNodeETHProvided(address _nodeAddress) external view returns (uint256)' +]; + +function minBN(a, b) { + return a.lt(b) ? a : b; +} +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const nodeRPLStake = new Multicaller( + network, + provider, + rocketNodeStakingContractAbi, + { blockTag } + ); + + const nodeETHProvided = new Multicaller( + network, + provider, + rocketNodeStakingContractAbi, + { blockTag } + ); + + const RPLPrice = new Multicaller( + network, + provider, + rocketNetworkPricesContractAbi, + { blockTag } + ); + + addresses.forEach((address) => { + nodeRPLStake.call(address, rocketNodeStakingAddress, 'getNodeRPLStake', [ + address + ]); + nodeETHProvided.call( + address, + rocketNodeStakingAddress, + 'getNodeETHProvided', + [address] + ); + RPLPrice.call(address, rocketNetworkPricesAddress, 'getRPLPrice'); + }); + + const nodeRPLStakeResponse: Record = + await nodeRPLStake.execute(); + + const nodeETHProvidedResponse: Record = + await nodeETHProvided.execute(); + + const RPLPriceResponse: Record = + await RPLPrice.execute(); + + const merged = addresses.map((address) => { + const nodeRPLStake = nodeRPLStakeResponse[address]; + const nodeETHProvided = nodeETHProvidedResponse[address]; + const RPLPrice = RPLPriceResponse[address]; + + return { + address: address, + nodeRPLStake: nodeRPLStake, + nodeETHProvided: nodeETHProvided, + RPLPrice: RPLPrice + }; + }); + + const data = merged.map((item) => { + const multiplier = BigNumber.from('15').mul(BigNumber.from('10').pow(17)); + const numerator = item.nodeETHProvided.mul(multiplier); + const denominator = item.RPLPrice; + const maxEffectiveStake = numerator.div(denominator); + const effectiveStake = minBN(item.nodeRPLStake, maxEffectiveStake); + + return { + address: item.address, + effectiveStake: effectiveStake + }; + }); + + const reduced: Record = data.reduce((acc, obj) => { + acc[obj.address] = obj.effectiveStake; + return acc; + }, {}); + + return Object.fromEntries( + Object.entries(reduced).map(([address, balance]) => [ + address, + Math.sqrt(parseFloat(formatUnits(balance, options.decimals))) / 2 + ]) + ); +} From 579c0f7ad381b99eda8c4548ab2caa92daf70a12 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 20 Sep 2023 10:37:37 +0530 Subject: [PATCH 496/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.6.0 (#1281) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 4157d65b5..f7b8a4b99 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.5.8", + "@snapshot-labs/snapshot.js": "^0.6.0", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index c4850455c..b75574be5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.5.8": - version "0.5.8" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.5.8.tgz#16bf19b27e487e937be8472e53f0ed71f25e47af" - integrity sha512-bFe4VBUOD2LbKKesD52G7hqBCrmx7BS/4n8JfnzR+GZddL4UWmjRhfnxx/6YLeJvaHOWSPs7LHkr16fpJXD7pQ== +"@snapshot-labs/snapshot.js@^0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.6.0.tgz#e954056108871fd57bb74fd8cc404c6a5771f81f" + integrity sha512-vMHIiQYCIQLiPg0IO5RPy+nUOhvNE6nVLPiupOFD/7p1LiDwdqn5qdegdbYTPzEbvBp3rccQfFgj9uyjUM0dhw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From dc99e798be908be5c31b18e8c8670dfe7b6b0ef7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 21 Sep 2023 18:41:41 +0530 Subject: [PATCH 497/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.6.1 (#1285) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f7b8a4b99..7c0d67e43 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.6.0", + "@snapshot-labs/snapshot.js": "^0.6.1", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index b75574be5..f0d91ca6d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.6.0": - version "0.6.0" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.6.0.tgz#e954056108871fd57bb74fd8cc404c6a5771f81f" - integrity sha512-vMHIiQYCIQLiPg0IO5RPy+nUOhvNE6nVLPiupOFD/7p1LiDwdqn5qdegdbYTPzEbvBp3rccQfFgj9uyjUM0dhw== +"@snapshot-labs/snapshot.js@^0.6.1": + version "0.6.1" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.6.1.tgz#95625b36fa8f4d8c120c14a5bfcd343d353daffb" + integrity sha512-kIJJPE7N7izOxZM5FvrHrAdH3DWVa3p1d2w3P1TqrBDI6129pq4YyHXaFVFu3shWSAm4z243aVRDHwYgQbkkbQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 52f9bcdda8a4a0e89697ceb7d01bf650984e7450 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 22 Sep 2023 23:34:52 +0530 Subject: [PATCH 498/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.6.2 (#1287) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 7c0d67e43..c02fff4be 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.6.1", + "@snapshot-labs/snapshot.js": "^0.6.2", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index f0d91ca6d..8c050a765 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.6.1": - version "0.6.1" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.6.1.tgz#95625b36fa8f4d8c120c14a5bfcd343d353daffb" - integrity sha512-kIJJPE7N7izOxZM5FvrHrAdH3DWVa3p1d2w3P1TqrBDI6129pq4YyHXaFVFu3shWSAm4z243aVRDHwYgQbkkbQ== +"@snapshot-labs/snapshot.js@^0.6.2": + version "0.6.2" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.6.2.tgz#0f9ddf591ec50912aeed545c807b5295365d4e2f" + integrity sha512-hQjZ0I9uLu2sUpuR05maYCq9KLi6yNJnCCkjIutDQjFFEzmeMqJ0Lru1tOdcRMsPW3g5ktdo5xi265ESEBDPdA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 0b44b4ea3c1f11910ce449204cb6763ea59cc59a Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Mon, 25 Sep 2023 14:02:33 +0530 Subject: [PATCH 499/815] fix: [api-v2] Fix reference issue with api-v2-override strategy (#1288) * [api-v2] Fix reference issue with api-v2-override strategy * Revert test file --- src/strategies/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 6b8faea37..7eb9fd0c3 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -627,7 +627,7 @@ const strategies = { api, 'api-post': apiPost, 'api-v2': apiV2, - 'api-v2-override': apiV2, + 'api-v2-override': { ...apiV2 }, xseen, 'moloch-all': molochAll, 'moloch-loot': molochLoot, From abf8810109c20db491b93116d6a93eabc823caab Mon Sep 17 00:00:00 2001 From: Santiago Gonzalez Toral Date: Mon, 25 Sep 2023 08:27:51 -0500 Subject: [PATCH 500/815] [passport-gated]: Update implementation to include Passport scoring mechanism (#1270) * [passport-gated]: validate address using passport stamps + score * fix: allow valiidation.test to eval multiple examples per strategy * [passport-weighted]: deprecate strategy * [passport-gated]: update README * [passport-gated]: set scoreThreshold as optional param * [passport-gated]: handle missing scorer_id env variable * [passport-gated]: include required env vars on Github action * [passport-gated]: update README * [passport-gated]: add minor fixes * [passport-gated]: fixed based on feedback review * [passport-gated]: add api fixes based on feedback review * [passport-gated]: minor fixes --- .github/workflows/validation.yml | 7 + src/validations/index.ts | 2 - src/validations/passport-gated/README.md | 59 +- src/validations/passport-gated/examples.json | 18 +- src/validations/passport-gated/index.ts | 177 +++- src/validations/passport-gated/schema.json | 236 ++--- .../passport-gated/stampsMetadata.json | 830 ++++++++++++++++++ src/validations/passport-weighted/README.md | 31 - .../passport-weighted/examples.json | 20 - src/validations/passport-weighted/index.ts | 52 -- src/validations/passport-weighted/schema.json | 278 ------ test/validation.test.ts | 39 +- 12 files changed, 1142 insertions(+), 607 deletions(-) create mode 100644 src/validations/passport-gated/stampsMetadata.json delete mode 100644 src/validations/passport-weighted/README.md delete mode 100644 src/validations/passport-weighted/examples.json delete mode 100644 src/validations/passport-weighted/index.ts delete mode 100644 src/validations/passport-weighted/schema.json diff --git a/.github/workflows/validation.yml b/.github/workflows/validation.yml index eb38d8490..70e8a58f4 100644 --- a/.github/workflows/validation.yml +++ b/.github/workflows/validation.yml @@ -18,6 +18,13 @@ jobs: steps: - uses: actions/checkout@v2.3.4 + + - name: Create env file + run: | + touch .env + echo PASSPORT_API_KEY=${{ secrets.PASSPORT_API_KEY }} >> .env + echo PASSPORT_SCORER_ID=${{ secrets.PASSPORT_SCORER_ID }} >> .env + - name: yarn install and test validation run: | yarn install --frozen-lockfile diff --git a/src/validations/index.ts b/src/validations/index.ts index ec757114c..3cdc99c23 100644 --- a/src/validations/index.ts +++ b/src/validations/index.ts @@ -2,14 +2,12 @@ import { readFileSync } from 'fs'; import path from 'path'; import basic from './basic'; import passportGated from './passport-gated'; -import passportWeighted from './passport-weighted'; import arbitrum from './arbitrum'; import karmaEasAttestation from './karma-eas-attestation'; const validationClasses = { basic, 'passport-gated': passportGated, - 'passport-weighted': passportWeighted, arbitrum: arbitrum, 'karma-eas-attestation': karmaEasAttestation }; diff --git a/src/validations/passport-gated/README.md b/src/validations/passport-gated/README.md index 7cd6d0a05..9e41bc9ca 100644 --- a/src/validations/passport-gated/README.md +++ b/src/validations/passport-gated/README.md @@ -1,29 +1,74 @@ # Gitcoin Passport Gated Validation -This repository provides a passport-gated validation strategy for Snapshot. The implementation integrates with the Gitcoin API to validate whether a user is authorized to vote on a proposal. +This repository provides a passport-gated validation strategy for Snapshot. It integrates with Gitcoin Passport to validate whether a user is authorized to create/vote on a proposal. -## Prerequisites +## Overview + +This implementation uses the Gitcoin Passport API to check whether a user has a valid passport by looking for their [Stamps](https://docs.passport.gitcoin.co/building-with-passport/major-concepts#stamps) and [score](https://docs.passport.gitcoin.co/building-with-passport/major-concepts#scorer). A passport is set to be valid if it meets the minimum criteria in terms of valid (non-expired) stamp collection it should own and minimum score threshold. Both criteria are set as parameters during setup. + +* A passport is set to own a particular Stamp if it has at least one [verifiable credential](https://docs.passport.gitcoin.co/building-with-passport/major-concepts#verifiable-credentials-vcs). +* The current implementation is best suited to use the `Unique Humanity` scoring mechanism. To learn more about the available scorers check this [link](https://docs.passport.gitcoin.co/building-with-passport/major-concepts#scoring-mechanisms). -Before using this code, ensure that you have the following information stored in a `.env` file at the project root: +## Pre-requisites + +Before using this code, you need to create an API Key and Scorer ID to interact with the Passport API. You can get them at the [Passport Scorer](https://scorer.gitcoin.co/) dashboard. Then, ensure that you have the following information stored in a `.env` file at the project root: - `PASSPORT_API_KEY=` +- `PASSPORT_SCORER_ID=` -## Overview +**NOTICE**: make sure to create a Scorer using the `Unique Humanity` mechanism. + +## Stamps Metadata -This implementation uses the Gitcoin Passport API to check whether a user has a valid passport by looking for their stamps. +The Stamps currently supported by Gitcoin Passport are stored in [stampsMetadata.json](./stampsMetadata.json). The Passport API has an [endpoint](https://docs.passport.gitcoin.co/building-with-passport/scorer-api/endpoint-definition#get-stamps-metadata-beta) where you can fetch all this information, but we don't do this programmatically in order to minimize the number of requests made by the validation strategy and meet the requirements listed in the main [README](../../../README.md). + +**NOTICE**: this file might need to be updated from time to time when Passport updates their supported Stamps and VCs. + +## Strategy Schema + +Strategy schema & parameters are defined under [schema.json](./schema.json). In case Passport creates new and/or deprecate stamps, it is required to update the `stamps` property to reflect those changes in the Snapshot UI. See the section above to know how to get the latest supported stamps. ## Code Explanation -The main function in this codebase checks stamps for a user and returns a boolean value indicating whether the user has a valid passport. +The main function (validate()) first fetches the following paramaters: + +* `stamps` (required): a list of Stamps that a passport should own. +* `operator` (required): (and/or) whether a Passport should own all or at least one of the required stamps. +* `scoreThreshold` ([0-100]): the threshold a Passport score should surpass in order to be eligible for creating/voting on a proposal. If not set, default value is set to zero to preserve backward compatibility. + +Then, it calls the following validation methods: + +* `validateStamps`: it uses the API to fetch the current user's Passport stamps and verifies that each has valid issuance and isn't expired. Then, depending on the `operator`, it will iterate through the requred `stamps` and check that the user holds at least one verifiable credential that makes the passport eligible for that stamp. Finally, a Passport will be set as valid if it meets the criteria. +* `validatePassportScore`: if `scoreThreshold` is set to zero this function will be ommited. Otherwise when called, it uses the Scorer API to submit the passport for scoring and get the latest score. If the API response returns a payload with `status === 'DONE'` it will return the result of evaluating the scoring threshold criteria, otherwise the implementation will make periodic requests (up to `PASSPORT_SCORER_MAX_ATTEMPTS`) to the Scorer API until getting a `DONE` status. + +Finally, it checks the results of both eval functions and returns a boolean value indicating whether the user has a valid Passport. + +### Notes on Scorer API + +Currently, the [Submit Passport endpoint](https://docs.passport.gitcoin.co/building-with-passport/scorer-api/endpoint-definition#submit-for-scoring) (used to submit a Passport **the fist time** to the `Scorer` for evaluation) has `signature` and `nonce` as optional parameters, so it isn't required to get an authorization from the Passport owner (via authentication) in order to request the `Scorer` to calculate the Passport score. In case this changes in the future, it will be required to either: a) use the same `PASSPORT_SCORER_ID` used by the frontend interface where the user signed the authentication message requesting the Passport stamps + score (e.g. `https://passport.gitcoin.co/`) so the validation strategy can fetch the latest Passport score without any issues, or b) implement the logic for requesting and verifying the signed message within the custom validation strategy. + +### Unit tests + +A few validation examples are provided in [examples.json](./examples.json). However, Passport stamps expire after some predetermined time which might end up breaking unit tests, so it is important to have in mind that a few example passports/stamp will require to be updated regurlarly before running tests. The `valid` property is used to set an example as valid/invalid passport during testing. ## Modifications +### June 1, 2023 + The original code utilized the Passport SDK to check if the user has a valid passport and stamps. [Coming Soon] However, with the introduction of the Passport API, we can now simplify the process by checking for a score. +--- + +### September 21, 2023 + +Code is fully integrated with Passport API. In order to evaluate if an address is eligible for creating/voting on a proposa, It checks for passport stamp collection and minimum score using the `Unique Humanity` scoring mechanism, however it could be upgraded in the future to support other scoring algorithms. + +Unit tests now support multiple example Passports to evaluate different validation scenarios. + ## Last Modified -This code was last modified on June 1, 2023. +This code was last modified on September 21, 2023. Feel free to customize and extend this implementation to suit your specific needs. diff --git a/src/validations/passport-gated/examples.json b/src/validations/passport-gated/examples.json index ba7428ae1..d5347bd99 100644 --- a/src/validations/passport-gated/examples.json +++ b/src/validations/passport-gated/examples.json @@ -6,8 +6,22 @@ "network": "1", "snapshot": "latest", "params": { - "stamps": ["Ens", "Github", "POAP", "SnapshotVotesProvider"], + "stamps": ["Ens", "Github", "Snapshot"], "operator": "OR" - } + }, + "valid": true + }, + { + "name": "Example of a passport gated validation", + "author": "0x1F069c5B3D2dD6716020959d2c7dEfb01EEaD296", + "space": "fabien.eth", + "network": "1", + "snapshot": "latest", + "params": { + "stamps": ["Ens", "Github", "Snapshot"], + "operator": "OR", + "scoreThreshold": 20 + }, + "valid": false } ] diff --git a/src/validations/passport-gated/index.ts b/src/validations/passport-gated/index.ts index 1344aaf51..a920582cf 100644 --- a/src/validations/passport-gated/index.ts +++ b/src/validations/passport-gated/index.ts @@ -1,9 +1,12 @@ import fetch from 'cross-fetch'; -import Validation from '../validation'; import snapshot from '@snapshot-labs/snapshot.js'; +import STAMPS from './stampsMetadata.json'; +import Validation from '../validation'; + // Create one from https://scorer.gitcoin.co/#/dashboard/api-keys const API_KEY = process.env.PASSPORT_API_KEY || ''; +const SCORER_ID = process.env.PASSPORT_SCORER_ID || ''; const headers = API_KEY ? { @@ -12,9 +15,28 @@ const headers = API_KEY } : undefined; +// const GET_STAMPS_METADATA_URI = `https://api.scorer.gitcoin.co/registry/stamp-metadata`; const GET_PASSPORT_STAMPS_URI = `https://api.scorer.gitcoin.co/registry/stamps/`; +const GET_PASSPORT_SCORE_URI = `https://api.scorer.gitcoin.co/registry/score/${SCORER_ID}/`; +const POST_SUBMIT_PASSPORT_URI = `https://api.scorer.gitcoin.co/registry/submit-passport`; + +const PASSPORT_SCORER_MAX_ATTEMPTS = 2; + +const stampCredentials = STAMPS.map((stamp) => { + return { + id: stamp.id, + name: stamp.name, + description: stamp.description, + credentials: stamp.groups + .flatMap((group) => group.stamps) + .map((credential) => credential.name) + }; +}); + +// Useful to get stamp metadata and update `stampsMetata.json` +// console.log('stampCredentials', JSON.stringify(stampCredentials.map((s) => ({"const": s.id, title: s.name})))); -function hasValidIssuanceAndExpiration(credential, proposalTs) { +function hasValidIssuanceAndExpiration(credential: any, proposalTs: string) { const issuanceDate = Number( new Date(credential.issuanceDate).getTime() / 1000 ).toFixed(0); @@ -27,46 +49,145 @@ function hasValidIssuanceAndExpiration(credential, proposalTs) { return false; } +function hasStampCredential(stampId: string, credentials: Array) { + const stamp = stampCredentials.find((stamp) => stamp.id === stampId); + if (!stamp) { + console.log('[passport] Stamp not supported', stampId); + throw new Error('Stamp not supported'); + } + return credentials.some((credential) => + stamp.credentials.includes(credential) + ); +} + +async function validateStamps( + currentAddress: string, + operator: string, + proposalTs: string, + requiredStamps: Array = [] +): Promise { + if (requiredStamps.length === 0) return true; + + const stampsResponse = await fetch(GET_PASSPORT_STAMPS_URI + currentAddress, { + headers + }); + const stampsData = await stampsResponse.json(); + + if (!stampsData?.items) { + console.log('[passport] Stamps Unknown error', stampsData); + throw new Error('Unknown error'); + } + if (stampsData.items.length === 0) return false; + + // check expiration for all stamps + const validStamps = stampsData.items + .filter((stamp: any) => + hasValidIssuanceAndExpiration(stamp.credential, proposalTs) + ) + .map((stamp: any) => stamp.credential.credentialSubject.provider); + + if (operator === 'AND') { + return requiredStamps.every((stampId) => + hasStampCredential(stampId, validStamps) + ); + } else if (operator === 'OR') { + return requiredStamps.some((stampId) => + hasStampCredential(stampId, validStamps) + ); + } + return false; +} + +function evalPassportScore(scoreData: any, minimumThreshold = 0): boolean { + // scoreData.evidence?.type === 'ThresholdScoreCheck' -> Returned if using Boolean Unique Humanity Scorer (should not be used) + if (scoreData.evidence?.type === 'ThresholdScoreCheck') { + return ( + Number(scoreData.evidence.rawScore) > Number(scoreData.evidence.threshold) + ); + } + // scoreData.score -> Returned if using Unique Humanity Score + return Number(scoreData.score) >= minimumThreshold; +} + +async function validatePassportScore( + currentAddress: string, + scoreThreshold: number +): Promise { + // always hit the /submit-passport endpoint to get the latest passport score + const submittedPassport = await fetch(POST_SUBMIT_PASSPORT_URI, { + headers, + method: 'POST', + body: JSON.stringify({ address: currentAddress, scorer_id: SCORER_ID }) + }); + const submissionData = + submittedPassport.ok && (await submittedPassport.json()); + + if (!submittedPassport.ok) { + const reason = !SCORER_ID + ? 'SCORER_ID missing' + : submittedPassport.statusText; + console.log('[passport] Scorer error', reason); + throw new Error(`Scorer error: ${reason}`); + } + + // Scorer done calculating passport score during submission + if (submittedPassport.ok && submissionData.status === 'DONE') { + return evalPassportScore(submissionData, scoreThreshold); + } + + // Try to fetch Passport Score if still processing (submittedPassport.status === 'PROCESSING') + for (let i = 0; i < PASSPORT_SCORER_MAX_ATTEMPTS; i++) { + const scoreResponse = await fetch(GET_PASSPORT_SCORE_URI + currentAddress, { + headers + }); + const scoreData = await scoreResponse.json(); + + if (scoreResponse.ok && scoreData.status === 'DONE') { + return evalPassportScore(scoreData, scoreThreshold); + } + console.log( + `[passport] Waiting for scorer... (${i}/${PASSPORT_SCORER_MAX_ATTEMPTS})` + ); + await snapshot.utils.sleep(3e3); + } + const reason = + 'Failed to fetch Passport Score. Reached PASSPORT_SCORER_MAX_ATTEMPTS'; + console.log('[passport] Scorer error', reason); + throw new Error(`Scorer error: ${reason}`); +} + export default class extends Validation { public id = 'passport-gated'; public github = 'snapshot-labs'; - public version = '0.1.0'; + public version = '1.0.0'; public title = 'Gitcoin Passport Gated'; public description = - 'Protect your proposals from spam and vote manipulation by requiring users to have a Gitcoin Passport.'; + 'Protect your proposals from spam and vote manipulation by requiring users to have a valid Gitcoin Passport.'; async validate(currentAddress = this.author): Promise { const requiredStamps = this.params.stamps || []; const operator = this.params.operator; + const scoreThreshold = this.params.scoreThreshold || 0; if (!operator) throw new Error('Operator is required'); - const stampsResponse = await fetch( - GET_PASSPORT_STAMPS_URI + currentAddress, - { headers } + const provider = snapshot.utils.getProvider(this.network); + const proposalTs = (await provider.getBlock(this.snapshot)).timestamp; + const validStamps = await validateStamps( + currentAddress, + operator, + proposalTs, + requiredStamps ); - const stampsData = await stampsResponse.json(); - - if (!stampsData?.items) { - console.log('[passport] Unknown error', stampsData); - throw new Error('Unknown error'); + if (scoreThreshold === 0) { + return validStamps; } - if (stampsData.items.length === 0) return false; - const provider = snapshot.utils.getProvider(this.network); - const proposalTs = (await provider.getBlock(this.snapshot)).timestamp; - // check expiration for all stamps - const validStamps = stampsData.items - .filter((stamp) => - hasValidIssuanceAndExpiration(stamp.credential, proposalTs) - ) - .map((stamp) => stamp.credential.credentialSubject.provider); - - if (operator === 'AND') { - return requiredStamps.every((stamp) => validStamps.includes(stamp)); - } else if (operator === 'OR') { - return requiredStamps.some((stamp) => validStamps.includes(stamp)); - } - return false; + const validScore = await validatePassportScore( + currentAddress, + scoreThreshold + ); + + return validStamps && validScore; } } diff --git a/src/validations/passport-gated/schema.json b/src/validations/passport-gated/schema.json index 76ada86d9..effaa435a 100644 --- a/src/validations/passport-gated/schema.json +++ b/src/validations/passport-gated/schema.json @@ -11,239 +11,117 @@ "title": "Stamps", "uniqueItems": true, "minItems": 1, - "maxItems": 32, + "maxItems": 27, "items": { "type": "string", "anyOf": [ { - "const": "Google", - "title": "Google account" - }, - { - "const": "Ens", - "title": "ENS owner" + "const": "GtcStaking", + "title": "GTC Staking" }, { - "const": "Poh", - "title": "Proof of humanity" + "const": "Gitcoin", + "title": "Gitcoin" }, { "const": "Twitter", - "title": "Twitter account" - }, - { - "const": "TwitterTweetGT10", - "title": "Twitter followers > 10" - }, - { - "const": "TwitterFollowerGT100", - "title": "Twitter followers > 100" - }, - { - "const": "TwitterFollowerGT500", - "title": "Twitter followers > 500" + "title": "Twitter" }, { - "const": "TwitterFollowerGTE1000", - "title": "Twitter followers > 1000" - }, - { - "const": "TwitterFollowerGT5000", - "title": "Twitter followers > 5000" - }, - { - "const": "POAP", - "title": "POAP owner" - }, - { - "const": "Facebook", - "title": "Facebook account" - }, - { - "const": "FacebookFriends", - "title": "Facebook friends > 100" - }, - { - "const": "FacebookProfilePicture", - "title": "Facebook profile picture" + "const": "Discord", + "title": "Discord" }, { - "const": "Brightid", - "title": "Brightid" + "const": "Google", + "title": "Google" }, { "const": "Github", - "title": "Github account" - }, - { - "const": "FiveOrMoreGithubRepos", - "title": "Github repos at least 5" - }, - { - "const": "ForkedGithubRepoProvider", - "title": "Github repo forked" - }, - { - "const": "StarredGithubRepoProvider", - "title": "Github repo starred" - }, - { - "const": "TenOrMoreGithubFollowers", - "title": "Github followers at least 10" - }, - { - "const": "FiftyOrMoreGithubFollowers", - "title": "Github followers at least 50" - }, - { - "const": "GitcoinContributorStatistics#numGrantsContributeToGte#1", - "title": "Grants contributed to at least 1" - }, - - { - "const": "GitcoinContributorStatistics#numGrantsContributeToGte#10", - "title": "Grants contributed to at least 10" - }, - { - "const": "GitcoinContributorStatistics#numGrantsContributeToGte#25", - "title": "Grants contributed to at least 25" + "title": "Github" }, { - "const": "GitcoinContributorStatistics#numGrantsContributeToGte#100", - "title": "Grants contributed to at least 100" - }, - { - "const": "GitcoinContributorStatistics#totalContributionAmountGte#10", - "title": "Grant contributions at least $10" - }, - { - "const": "GitcoinContributorStatistics#totalContributionAmountGte#100", - "title": "Grant contributions at least $100" - }, - { - "const": "GitcoinContributorStatistics#totalContributionAmountGte#1000", - "title": "Grant contributions at least $1000" - }, - { - "const": "GitcoinGranteeStatistics#numOwnedGrants#1", - "title": "Grant owner of at least 1 Grant" - }, - { - "const": "GitcoinGranteeStatistics#numGrantContributors#10", - "title": "Grant contributors at least 10" - }, - { - "const": "GitcoinGranteeStatistics#numGrantContributors#25", - "title": "Grant contributors at least 25" - }, - - { - "const": "GitcoinGranteeStatistics#numGrantContributors#100", - "title": "Grant contributors at least 100" - }, - { - "const": "GitcoinGranteeStatistics#totalContributionAmount#100", - "title": "Grant have received at least $100" - }, - { - "const": "GitcoinGranteeStatistics#totalContributionAmount#1000", - "title": "Grant have received at least $1000" - }, - { - "const": "GitcoinGranteeStatistics#totalContributionAmount#10000", - "title": "Grant have received at least $10000" - }, - { - "const": "GitcoinGranteeStatistics#numGrantsInEcoAndCauseRound#1", - "title": "Grant owner at least 1 Eco & Cause" + "const": "Facebook", + "title": "Facebook" }, { "const": "Linkedin", - "title": "Linkedin account" - }, - { - "const": "Discord", - "title": "Discord account" - }, - { - "const": "SnapshotVotesProvider", - "title": "Snapshot voter" + "title": "Linkedin" }, { - "const": "SnapshotProposalsProvider", - "title": "Snapshot proposer" + "const": "Ens", + "title": "ENS" }, { - "const": "ethPossessionsGte#1", - "title": "ETH at least 1" + "const": "Brightid", + "title": "BrightID" }, { - "const": "ethPossessionsGte#10", - "title": "ETH at least 10" + "const": "Poh", + "title": "Proof of Humanity" }, { - "const": "ethPossessionsGte#32", - "title": "ETH at least 32" + "const": "ETH", + "title": "ETH" }, { - "const": "FirstEthTxnProvider", - "title": "First ETH more than 30 days ago" + "const": "Snapshot", + "title": "Snapshot" }, { - "const": "EthGTEOneTxnProvider", - "title": "ETH tx at least 1" + "const": "NFT", + "title": "NFT Holder" }, { - "const": "EthGasProvider", - "title": "ETH gas at least 0.5" + "const": "ZkSync", + "title": "ZkSync" }, { - "const": "gtcPossessionsGte#10", - "title": "Gitcoin GTC at least 10" + "const": "Lens", + "title": "Lens" }, { - "const": "gtcPossessionsGte#100", - "title": "Gitcoin GTC at least 100" + "const": "GnosisSafe", + "title": "Gnosis Safe" }, { - "const": "SelfStakingBronze", - "title": "GTC staked at least 1" + "const": "Coinbase", + "title": "Coinbase" }, { - "const": "SelfStakingSilver", - "title": "GTC staked at least 10" + "const": "GuildXYZ", + "title": "Guild Membership and Roles" }, { - "const": "SelfStakingGold", - "title": "GTC staked at least 100" + "const": "Hypercerts", + "title": "Hypercerts" }, { - "const": "CommunityStakingBronze", - "title": "Comm GTC staked at least 1" + "const": "PHI", + "title": "PHI" }, { - "const": "CommunityStakingSilver", - "title": "Comm GTC staked at least 10" + "const": "Holonym", + "title": "Holonym" }, { - "const": "CommunityStakingGold", - "title": "Comm GTC staked at least 100" + "const": "Idena", + "title": "Idena" }, { - "const": "NFT", - "title": "NFT holder" + "const": "Civic", + "title": "Civic" }, { - "const": "ZkSync", - "title": "ZkSync account" + "const": "CyberConnect", + "title": "CyberConnect" }, { - "const": "Lens", - "title": "Lens account" + "const": "GrantsStack", + "title": "GrantsStack" }, { - "const": "GnosisSafe", - "title": "GnosisSafe singer/owner" + "const": "TrustaLabs", + "title": "Trusta Labs" } ] } @@ -262,9 +140,17 @@ "title": "Require at least one stamp" } ] + }, + "scoreThreshold": { + "type": "number", + "title": "Passport Score Threshold", + "description": "Minimum Passport score threshold (>) to be eligible as a valid Passport", + "minimum": 0, + "maximum": 100, + "default": 0 } }, - "required": ["stamps"], + "required": ["stamps", "operator"], "additionalProperties": false } } diff --git a/src/validations/passport-gated/stampsMetadata.json b/src/validations/passport-gated/stampsMetadata.json new file mode 100644 index 000000000..52faeeb4f --- /dev/null +++ b/src/validations/passport-gated/stampsMetadata.json @@ -0,0 +1,830 @@ +[ + { + "id": "GtcStaking", + "icon": "https://passport.gitcoin.co/assets/gtcStakingLogoIcon.svg", + "name": "GTC Staking", + "description": "Connect to passport to verify your staking amount.", + "connectMessage": "Verify amount", + "groups": [ + { + "name": "Stakes on Yourself.", + "stamps": [ + { + "name": "SelfStakingBronze", + "description": "5 GTC (Bronze)", + "hash": "0x8a1a9419d0ee9371c7c31f74df3eb853d1f876d345c54c680ada09157aa70cd1" + }, + { + "name": "SelfStakingSilver", + "description": "20 GTC (Silver)", + "hash": "0xde1cec0f6691783047022214e07d5a0f2bc245d8abc795a777e4dff41b3dc8e4" + }, + { + "name": "SelfStakingGold", + "description": "125 GTC (Gold)", + "hash": "0x12b38168f416d8b2ed1e465d2f234ab22e7329dc7d2efa13a39f69f3cda1c678" + } + ] + }, + { + "name": "Stakes from Others.", + "stamps": [ + { + "name": "CommunityStakingBronze", + "description": "5 GTC (Bronze)", + "hash": "0x3012fa3fa74589db9854ec645de58cc7235ec424b666ee689bae384e47133cba" + }, + { + "name": "CommunityStakingSilver", + "description": "20 GTC (Silver)", + "hash": "0x42d32cfd78c1968a0e1f67016610eb9aa3c30619f95f93cb8c357d380100cc1d" + }, + { + "name": "CommunityStakingGold", + "description": "125 GTC (Gold)", + "hash": "0xe8fabdda06242bb1035f87927fde0ce9ef188af1fd8c7f5d5e33e496afe9910c" + } + ] + } + ] + }, + { + "id": "Gitcoin", + "icon": "https://passport.gitcoin.co/assets/gtcGrantsLightIcon.svg", + "name": "Gitcoin", + "description": "Connect with Github to verify with your Gitcoin account.", + "connectMessage": "Connect Account", + "groups": [ + { + "name": "Contributed to...", + "stamps": [ + { + "name": "GitcoinContributorStatistics#numGrantsContributeToGte#1", + "description": "at least 1 Grant", + "hash": "0xf00a3ee94de8826a9a3d0737b2d9e26d9af265952a27fb8cef0836c7793af8f1" + }, + { + "name": "GitcoinContributorStatistics#numGrantsContributeToGte#10", + "description": "at least 10 Grants", + "hash": "0x4c283770cdaf51d8007faaa16e0121b7f97c44cd324cb7d494f85c7e85ad4640" + }, + { + "name": "GitcoinContributorStatistics#numGrantsContributeToGte#25", + "description": "at least 25 Grants", + "hash": "0xf783f98b7fda2c3b7994ba1f0da2a2a5cc640b106490ce463bbe0555f54d7a3b" + }, + { + "name": "GitcoinContributorStatistics#numGrantsContributeToGte#100", + "description": "at least 100 Grants", + "hash": "0xddc23222c6de0a80261979370c61ad9118ceeda22cee6000eef363ddd9ed8ad4" + } + ] + }, + { + "name": "Contributed ($)...", + "stamps": [ + { + "name": "GitcoinContributorStatistics#totalContributionAmountGte#10", + "description": "at least $10", + "hash": "0xdf8b29cdd778290585b1e25c4f3ce8a13717aebe37d9b74c5ef911360c374abd" + }, + { + "name": "GitcoinContributorStatistics#totalContributionAmountGte#100", + "description": "at least $100", + "hash": "0x234c0cee45dbfa611911b478ee676e179c059e5599c6c5dec81b26b2e7f4dcd4" + }, + { + "name": "GitcoinContributorStatistics#totalContributionAmountGte#1000", + "description": "at least $1000", + "hash": "0xd4113e909955bd57da077a3ed40b3e56703334c41e514d09f259d1b301048c90" + } + ] + }, + { + "name": "Contributed in...", + "stamps": [ + { + "name": "GitcoinContributorStatistics#numGr14ContributionsGte#1", + "description": "GR14", + "hash": "0x629493e28cc66eb32390cf4fcf4de1c8098b483c80fa21a8d04717d9ae90175e" + }, + { + "name": "GitcoinContributorStatistics#numRoundsContributedToGte#1", + "description": "at least 1 Round", + "hash": "0x91953495f7ce4d377732b5079f92fab047c3e269fbe078f14eaf5e45769cb8f4" + } + ] + } + ] + }, + { + "id": "Twitter", + "icon": "https://passport.gitcoin.co/assets/twitterStampIcon.svg", + "name": "Twitter", + "description": "Connect your existing Twitter account to verify.", + "connectMessage": "Connect Account", + "groups": [ + { + "name": "Account Creation", + "stamps": [ + { + "name": "twitterAccountAgeGte#180", + "description": "Created at least 180 days ago", + "hash": "0x1975f9b5a89f5667d88046de8b662857a3d72d62387d446871c936c213d05b5c" + }, + { + "name": "twitterAccountAgeGte#365", + "description": "Created at least 1 year ago", + "hash": "0x560925afd4119f8c00e591d177695f9ea74cd6768d58ceda25eaf6379267f9a5" + }, + { + "name": "twitterAccountAgeGte#730", + "description": "Created at least 2 years ago", + "hash": "0x75c8ff4b789f8fa039e62c3614c922a28d26bf3d9e8ef091f414a9b27cfc7b2b" + } + ] + } + ] + }, + { + "id": "Discord", + "icon": "https://passport.gitcoin.co/assets/discordStampIcon.svg", + "name": "Discord", + "description": "Connect your existing Discord account to verify.", + "connectMessage": "Connect Account", + "groups": [ + { + "name": "Account Name", + "stamps": [ + { + "name": "Discord", + "description": "Encrypted", + "hash": "0x47024beb35c119cb9ca37d810b63c51b538c48fc98c7b88a52d78b633e5600df" + } + ] + } + ] + }, + { + "id": "Google", + "icon": "https://passport.gitcoin.co/assets/googleStampIcon.svg", + "name": "Google", + "description": "Connect your existing Google Account to verify", + "connectMessage": "Connect Account", + "groups": [ + { + "name": "Account Name", + "stamps": [ + { + "name": "Google", + "description": "Google", + "hash": "0xf610f88085f5955bccb50431e1315a28335522d87be5000ff334274cc9985741" + } + ] + } + ] + }, + { + "id": "Github", + "icon": "https://passport.gitcoin.co/assets/githubWhiteStampIcon.svg", + "name": "Github", + "description": "Connect your existing Github account to verify.", + "connectMessage": "Connect Account", + "groups": [ + { + "name": "Account Creation", + "stamps": [ + { + "name": "githubAccountCreationGte#90", + "description": "Created at least 90 days ago", + "hash": "0x7f57b88d2714b69f0d183595d2c894da2cbf5b8afa7add7f32456f2ec81c7e1b" + }, + { + "name": "githubAccountCreationGte#180", + "description": "Created at least 180 days ago", + "hash": "0x86bca597d35530ad8b40bca7d323972bcd418c0ca1bccf8ba3247cc9ae0a7a83" + }, + { + "name": "githubAccountCreationGte#365", + "description": "Created at least 365 days ago", + "hash": "0xd573ecf208f0924d88ff46d4be73ea915aa9ff0bcf79cc2f54788b6bea4f824e" + } + ] + }, + { + "name": "Contribution Activity", + "stamps": [ + { + "name": "githubContributionActivityGte#30", + "description": "Contributions on at least 30 distinct days", + "hash": "0xaabb0990679413b556c716ad2403eac57b3be530b87732041408894d0f495f9f" + }, + { + "name": "githubContributionActivityGte#60", + "description": "Contributions on at least 60 distinct days", + "hash": "0x272b07a5f3a7496932c5d349c2d5377ae5333fb14d5793736f40043b123f15f7" + }, + { + "name": "githubContributionActivityGte#120", + "description": "Contributions on at least 120 distinct days", + "hash": "0x9ee061bf0fc5c6ee4b1197ea5f2dd9eb5e26a84bab40b579d6f87701ef434bff" + } + ] + } + ] + }, + { + "id": "Facebook", + "icon": "https://passport.gitcoin.co/assets/facebookStampIcon.svg", + "name": "Facebook", + "description": "Connect your existing account to verify with Facebook.", + "connectMessage": "Connect Account", + "groups": [ + { + "name": "Account Name", + "stamps": [ + { + "name": "Facebook", + "description": "Encrypted", + "hash": "0x6f028453ddea055c2bfd6baeffa906ae6954e0bb90083e4b76c86058e9e2c08a" + } + ] + }, + { + "name": "Profile", + "stamps": [ + { + "name": "FacebookProfilePicture", + "description": "Profile Picture attached", + "hash": "0x60bf1e8210955d6145087c9f57f277f16e8637fcd18c4d16bfd883d81ad0c753" + } + ] + } + ] + }, + { + "id": "Linkedin", + "icon": "https://passport.gitcoin.co/assets/linkedinStampIcon.svg", + "name": "Linkedin", + "description": "Connect your existing Linkedin account to verify.", + "connectMessage": "Connect Account", + "groups": [ + { + "name": "Account Name", + "stamps": [ + { + "name": "Linkedin", + "description": "Encrypted", + "hash": "0x837ace622183eccb5f06b05be962fcbeb7a32a8785546c56f13175ee45b7d92b" + } + ] + } + ] + }, + { + "id": "Ens", + "icon": "https://passport.gitcoin.co/assets/ensStampIcon.svg", + "name": "ENS", + "description": "Purchase an .eth name to verify/ connect your existing account.", + "connectMessage": "Connect Account", + "groups": [ + { + "name": "Account Name", + "stamps": [ + { + "name": "Ens", + "description": "Encrypted", + "hash": "0xb4448bd57db012361e41665a60f3906dda48b4ffc1e4b8151cb2b6d431861fae" + } + ] + } + ] + }, + { + "id": "Brightid", + "icon": "https://passport.gitcoin.co/assets/brightidStampIcon.svg", + "name": "BrightID", + "description": "Connect your BrightID", + "connectMessage": "Connect Account", + "groups": [ + { + "name": "Account Name", + "stamps": [ + { + "name": "Brightid", + "description": "Encrypted", + "hash": "0xc2e6ff5c52185cfef9d800302d6bf36ddbb693d3c37b81d268f0154a7819e8c0" + } + ] + } + ] + }, + { + "id": "Poh", + "icon": "https://passport.gitcoin.co/assets/pohStampIcon.svg", + "name": "Proof of Humanity", + "description": "Connect your wallet to start the process of verifying with Proof of Humanity.", + "connectMessage": "Connect Account", + "groups": [ + { + "name": "Account Name", + "stamps": [ + { + "name": "Poh", + "description": "Encrypted", + "hash": "0x4c3831eefbfc1b22e1b8d83bad19bcf4ed1a5f56666c2129c3f52055009fd10b" + } + ] + } + ] + }, + { + "id": "ETH", + "icon": "https://passport.gitcoin.co/assets/ethereumStampIcon.svg", + "name": "ETH", + "description": "ETH possession and transaction verification", + "connectMessage": "Verify Account", + "groups": [ + { + "name": "Possessions", + "stamps": [ + { + "name": "ethPossessionsGte#1", + "description": "At least 1 ETH", + "hash": "0x829a03ea65f255c7d3f444f05a6edb9e9b5a1b1b59c2b7ff329df1e05f68f045" + }, + { + "name": "ethPossessionsGte#10", + "description": "At least 10 ETH", + "hash": "0x372a7f0b2e51cd0ea6a0e6f9491297a6aa97961f09ac7d7455a594f254811280" + }, + { + "name": "ethPossessionsGte#32", + "description": "At least 32 ETH", + "hash": "0x2351f93a7a10097410e3a06ab7e7ae46bb736776c5c40c64de39f091970ff296" + } + ] + }, + { + "name": "Transactions", + "stamps": [ + { + "name": "FirstEthTxnProvider", + "description": "First ETH transaction occurred more than 30 days ago", + "hash": "0xf5d84532cd4145037fb3ccf5895bf01be3151f7b6328e336999f4c474bb2842c" + }, + { + "name": "EthGTEOneTxnProvider", + "description": "At least 1 ETH transaction", + "hash": "0xf83912da72a27a9b4d36beb8e898b766fae3dc174e546d6f737c814b4586ca0d" + } + ] + }, + { + "name": "Gas fees spent", + "stamps": [ + { + "name": "EthGasProvider", + "description": "At least 0.5 ETH in gas fees spent", + "hash": "0xead90b8cb4c9d13e9260d61a08c39d6125c9f2b934dbfcb96ec0e310daf45f38" + } + ] + } + ] + }, + { + "id": "Snapshot", + "icon": "https://passport.gitcoin.co/assets/snapshotStampIcon.svg", + "name": "Snapshot", + "description": "Connect your existing account to verify with Snapshot.", + "connectMessage": "Verify Account", + "groups": [ + { + "name": "Snapshot Voter", + "stamps": [ + { + "name": "SnapshotVotesProvider", + "description": "Voted on 2 or more DAO proposals", + "hash": "0x48c72633aa8e5e893b1d4385f04fdc03b8c1cbb5daac8fd44067f404a20be08e" + } + ] + }, + { + "name": "Snapshot Proposal Creator", + "stamps": [ + { + "name": "SnapshotProposalsProvider", + "description": "Created a DAO proposal that was voted on by at least 1 account", + "hash": "0x49f4974bd25815b5deea86c2158bc9e1a18df0059c81ea14468ea8edaf7b8815" + } + ] + } + ] + }, + { + "id": "NFT", + "icon": "https://passport.gitcoin.co/assets/nftStampIcon.svg", + "name": "NFT Holder", + "description": "Connect a wallet and validate the stamp by retrieving an NFT.", + "connectMessage": "Connect NFT", + "groups": [ + { + "name": "NFT Holder", + "stamps": [ + { + "name": "NFT", + "description": "Holds at least 1 NFT", + "hash": "0x9c4138cd0a1311e4748f70d0fe3dc55f0f5f75e0f20db731225cbc3b8914016a" + } + ] + } + ] + }, + { + "id": "ZkSync", + "icon": "https://passport.gitcoin.co/assets/zksyncStampIcon.svg", + "name": "ZkSync", + "description": "ZkSync Verification", + "connectMessage": "Verify Account", + "groups": [ + { + "name": "zkSync Lite", + "stamps": [ + { + "name": "ZkSync", + "description": "Transacted on zkSync Lite", + "hash": "0x2e760812e6696b561a918e71ad2845639638959ed846b188488dd0d8c0b953ef" + } + ] + }, + { + "name": "zkSync Era", + "stamps": [ + { + "name": "ZkSyncEra", + "description": "Transacted on zkSync Era", + "hash": "0x58350b1934e59355216e23d91bb55f8a4c43adbdeb411fc9dfd6ee6ada375166" + } + ] + } + ] + }, + { + "id": "Lens", + "icon": "https://passport.gitcoin.co/assets/lensWhiteStampIcon.svg", + "name": "Lens", + "description": "Lens Profile Verification", + "connectMessage": "Verify Account", + "groups": [ + { + "name": "Lens Handle", + "stamps": [ + { + "name": "Lens", + "description": "At least 1 Lens Handle", + "hash": "0xc419da342463a3de054e208341b27aaef55e74a1660a45ac10cf1dae4d4964d2" + } + ] + } + ] + }, + { + "id": "GnosisSafe", + "icon": "https://passport.gitcoin.co/assets/gnosisSafeStampIcon.svg", + "name": "Gnosis Safe", + "description": "Gnosis Safe Signer/Owner Verification", + "connectMessage": "Verify Account", + "groups": [ + { + "name": "Account Name", + "stamps": [ + { + "name": "GnosisSafe", + "description": "Encrypted", + "hash": "0x6190ebf51fd5de79822a58c3de8080e9dd8d8465157d8f054218eddd5042f8cc" + } + ] + } + ] + }, + { + "id": "Coinbase", + "icon": "https://passport.gitcoin.co/assets/coinbaseStampIcon.svg", + "name": "Coinbase", + "description": "Connect your existing account to verify with Coinbase.", + "connectMessage": "Connect Account", + "groups": [ + { + "name": "Account Name", + "stamps": [ + { + "name": "Coinbase", + "description": "Encrypted", + "hash": "0x93dc6da870b5c43845c57c5ec7b162b128fd9be0ea503c865e9c1c163df72e4f" + } + ] + } + ] + }, + { + "id": "GuildXYZ", + "icon": "https://passport.gitcoin.co/assets/guildXYZStampIcon.svg", + "name": "Guild Membership and Roles", + "description": "Connect your Guild XYZ account to verify your memberships.", + "connectMessage": "Verify Guilds", + "groups": [ + { + "name": "Guild Member", + "stamps": [ + { + "name": "GuildMember", + "description": "Member of more than 5 guilds and more than 15 roles*", + "hash": "0xabbc040da64c74e20701ef1cc807f2eb893218c1cbf09fe2e0e8d021fc27ac0b" + } + ] + }, + { + "name": "Guild Admin", + "stamps": [ + { + "name": "GuildAdmin", + "description": "Owner or Administrator of one or more guilds*", + "hash": "0xc9c133c0562b97cb13073c80d829afe63678e804b083f7dc5168b454ada25bc1" + } + ] + }, + { + "name": "Guild Passport Member", + "stamps": [ + { + "name": "GuildPassportMember", + "description": "Member with 1 or more roles in Gitcoin Passport Guild", + "hash": "0x9e6e85c3cc8c738ffb999a6e15ddeee80344c28966348d16025c44fb064c6025" + } + ] + } + ] + }, + { + "id": "Hypercerts", + "icon": "https://passport.gitcoin.co/assets/hypercertsStampIcon.svg", + "name": "Hypercerts", + "description": "Connect your wallet to verify that you hold Hypercerts", + "connectMessage": "Connect Wallet", + "groups": [ + { + "name": "Account Name", + "stamps": [ + { + "name": "Hypercerts", + "description": "Held at least two Hypercerts for more than 15 days", + "hash": "0xbd8dfabd37a988e4f6e3bdfc04c105a3863e0fce9e624812bb51bbdab4040748" + } + ] + } + ] + }, + { + "id": "PHI", + "icon": "https://passport.gitcoin.co/assets/phiLogoIcon.svg", + "name": "PHI", + "description": "Connect your wallet to verify your phi activity.", + "connectMessage": "Verify Account", + "groups": [ + { + "name": "PHI Activity", + "stamps": [ + { + "name": "PHIActivitySilver", + "description": "Active Rank Silver I ~ V (Earn 65,000 EXP ~ on Active Score)", + "hash": "0x8df856188c159082e1bee29935f0bed64e5b88b8cf4543496aaf5074e92eb546" + }, + { + "name": "PHIActivityGold", + "description": "Active Rank Gold I ~ V (Earn 150,000 EXP ~ on Active Score)", + "hash": "0x2bc2f17d351619957ff810b3d151105ce92cd0b1b11fcefe535a55ca6ef7f660" + } + ] + } + ] + }, + { + "id": "Holonym", + "icon": "https://passport.gitcoin.co/assets/holonymStampIcon.svg", + "name": "Holonym", + "description": "To verify your Holo, mint your Holo at app.holonym.id and then prove uniqueness at app.holonym.id/prove/uniqueness", + "connectMessage": "Connect Account", + "groups": [ + { + "name": "Government ID", + "stamps": [ + { + "name": "HolonymGovIdProvider", + "description": "Proven uniqueness using Holonym with government ID", + "hash": "0x78c4c1cc586be667bc3ad2d22d33fbca8b584eebc5d516207740e9258b69e5be" + } + ] + } + ] + }, + { + "id": "Idena", + "icon": "https://passport.gitcoin.co/assets/idenaStampIcon.svg", + "name": "Idena", + "description": "Connect your existing Identity to verify.", + "connectMessage": "Verify Identity", + "groups": [ + { + "name": "Identity State", + "stamps": [ + { + "name": "IdenaState#Newbie", + "description": "Newbie", + "hash": "0xffd81d1ffa3ed2e5b44c82b1cd1c5955f22e79507ba4f4c2ab43fa2e3f214406" + }, + { + "name": "IdenaState#Verified", + "description": "Verified", + "hash": "0xe941ad16ad0698e5e731c8dbdcd3345550ef325e0034f729ad590e6581be8c84" + }, + { + "name": "IdenaState#Human", + "description": "Human", + "hash": "0x8679c35b2667db5fc91100ec573ef6f5e069777e2cee5b715a3b41fad6dd09a1" + } + ] + }, + { + "name": "Identity Stake", + "stamps": [ + { + "name": "IdenaStake#1k", + "description": "more than 1k iDna", + "hash": "0x6db7527c79b36cc4bdb774ba5026c2e3aa046ed60996c0140a543ca3d8c77757" + }, + { + "name": "IdenaStake#10k", + "description": "more than 10k iDna", + "hash": "0xcfcaca117245b7a2a5b6c677aed46e999dfefb2b15907a1d414b0bb3976df4eb" + }, + { + "name": "IdenaStake#100k", + "description": "more than 100k iDna", + "hash": "0xcca730a281d3175c9fb9273f06a54bd13a66da9cd7a6e560107a94e24351dde3" + } + ] + }, + { + "name": "Identity Age", + "stamps": [ + { + "name": "IdenaAge#5", + "description": "more than 5 epochs", + "hash": "0x807b95a92837d5695a39b8e86d21c4f6b5023b96e887c62669caed981beeec78" + }, + { + "name": "IdenaAge#10", + "description": "more than 10 epochs", + "hash": "0xbc06b0eade94d62212da4e7d9d1cadb8a2ea22e8848ccf9c3b22865e59dc85a1" + } + ] + } + ] + }, + { + "id": "Civic", + "icon": "https://passport.gitcoin.co/assets/civicStampIcon.svg", + "name": "Civic", + "description": "Civic Profile Verification", + "connectMessage": "Verify Account", + "groups": [ + { + "name": "CAPTCHA Pass", + "stamps": [ + { + "name": "CivicCaptchaPass", + "description": "holds a Civic CAPTCHA Pass", + "hash": "0x2446ef93a12158854f514d7672cec48cd42ef208d47a823e6666a89e33edcb81" + } + ] + }, + { + "name": "Uniqueness Pass", + "stamps": [ + { + "name": "CivicUniquenessPass", + "description": "holds a Civic Uniqueness Pass", + "hash": "0xa4da5d264e77069abed068700e9ded90c5f97cf7c64cd37fdde7d5ee4db1b10c" + } + ] + }, + { + "name": "Liveness Pass", + "stamps": [ + { + "name": "CivicLivenessPass", + "description": "holds a Civic Liveness Pass", + "hash": "0xa9fa0086eddc2ec9570da457a8202186be34c2edc4a7f4786b18e38628d1ec67" + } + ] + } + ] + }, + { + "id": "CyberConnect", + "icon": "https://passport.gitcoin.co/assets/cyberconnectLogoIcon.svg", + "name": "CyberConnect", + "description": "Connect your wallet to verify your CyberProfile Handle.", + "connectMessage": "Verify Account", + "groups": [ + { + "name": "CyberProfile Handle", + "stamps": [ + { + "name": "CyberProfilePremium", + "description": "Premium CyberProfile Handle ( length is between 1 and 6 characters )", + "hash": "0xd8bfe75b5f61ca9908892cf1e959f17f90ae8995f43697f22d9cae9a92d9be04" + }, + { + "name": "CyberProfilePaid", + "description": "Paid CyberProfile Handle ( length is between 7 and 12 characters )", + "hash": "0x8739aafbbc0e3b5c99166a7a3141887aad86dbea103eaf706e2885734c142747" + }, + { + "name": "CyberProfileOrgMember", + "description": "Organization Membership", + "hash": "0x6ac2a6233e1204e1f8cc2ed9a5c75c82649d727cfea28109c07c5bdf36f74f26" + } + ] + } + ] + }, + { + "id": "GrantsStack", + "icon": "https://passport.gitcoin.co/assets/grantsStackLogo.svg", + "name": "GrantsStack", + "description": "Connect your existing GrantsStack Account to verify", + "connectMessage": "Connect Account", + "groups": [ + { + "name": "Projects Contributed To:", + "stamps": [ + { + "name": "GrantsStack3Projects", + "description": "Supported 3+ unique projects", + "hash": "0x3eba85ce74666f77715afeced5cc11d760115a9092f803239c60eefb5cc83de2" + }, + { + "name": "GrantsStack5Projects", + "description": "Supported 5+ unique projects", + "hash": "0x01d058ed7e60dea954aa3f40c989d74947159dff2c345ebf0190a23f06025f5b" + }, + { + "name": "GrantsStack7Projects", + "description": "Supported 7+ unique projects", + "hash": "0x6cdd2d911e02a94b753b6e652734b7e90d92a271e939fe489fa264b7ba7faabb" + } + ] + }, + { + "name": "Matching Fund Programs Participation:", + "stamps": [ + { + "name": "GrantsStack2Programs", + "description": "Contributed to 2+ unique programs.", + "hash": "0x00d12cf35a48e15ed9a7b3313da0039596df8b8ff57a9de5fbb0b4140cba376f" + }, + { + "name": "GrantsStack4Programs", + "description": "Contributed to 4+ unique programs.", + "hash": "0x9a212c88976c807492fe7ed4d86d981bdb16ea78e408cff9ff1d951250f3d6b9" + }, + { + "name": "GrantsStack6Programs", + "description": "Contributed to 6+ unique programs.", + "hash": "0x0e2b38bda57667aa6dda8a3880a385a66d8c5036abf6f5f1fcf10722134bd641" + } + ] + } + ] + }, + { + "id": "TrustaLabs", + "icon": "https://passport.gitcoin.co/assets/trustaLabsStampIcon.svg", + "name": "Trusta Labs", + "description": "Launch Trusta's TrustScan to verify this account has non-Sybil behavior", + "connectMessage": "Connect Account", + "groups": [ + { + "name": "Trusta Labs", + "stamps": [ + { + "name": "TrustaLabs", + "description": "TrustScan Non-Sybil Account", + "hash": "0x84ab19b20f9272264f28c39bea4821bcbe5a6d49a125ea01e4b1668f01320b2e" + } + ] + } + ] + } +] diff --git a/src/validations/passport-weighted/README.md b/src/validations/passport-weighted/README.md deleted file mode 100644 index 48a20f34c..000000000 --- a/src/validations/passport-weighted/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# Gitcoin passport weighted validation - -This repository provides a passport-weighted validation strategy for Snapshot. The implementation integrates with the Gitcoin API to validate whether a user is authorized to vote on a proposal. - -## Prerequisites - -Before using this code, ensure that you have the following information stored in a `.env` file at the project root: - -- `NEXT_PUBLIC_GC_API_KEY=` -- `NEXT_PUBLIC_GC_SCORER_ID=` - -## Overview - -This implementation uses the Gitcoin Passport API to check whether a user has a passport score thats above the minScore threshold value. - -## Code Explanation - -The main function in this codebase returns a threshold score based on the user's passport. - -## Modifications - -The original code utilized the Passport SDK to check if the user meets the passport score threshold. However, with the introduction of the Passport API, we can now simplify the process by checking directly for the score. - -## Last Modified - -This code was last modified on May 11, 2023. - -Feel free to customize and extend this implementation to suit your specific needs. - - - diff --git a/src/validations/passport-weighted/examples.json b/src/validations/passport-weighted/examples.json deleted file mode 100644 index 5e6c883c5..000000000 --- a/src/validations/passport-weighted/examples.json +++ /dev/null @@ -1,20 +0,0 @@ -[ - { - "name": "Example of a passport-weighted validation", - "author": "0x24F15402C6Bb870554489b2fd2049A85d75B982f", - "space": "fabien.eth", - "network": "1", - "snapshot": "latest", - "params": { - "minScore": 10, - "stamps": [ - { "id": "Ens", "weight": 2 }, - { "id": "Twitter", "weight": 0.5 }, - { "id": "Github", "weight": 0.5 }, - { "id": "POAP", "weight": 2 }, - { "id": "SnapshotVotesProvider", "weight": 2 } - ], - "min_weight": 1 - } - } -] diff --git a/src/validations/passport-weighted/index.ts b/src/validations/passport-weighted/index.ts deleted file mode 100644 index d72299e25..000000000 --- a/src/validations/passport-weighted/index.ts +++ /dev/null @@ -1,52 +0,0 @@ -import fetch from 'cross-fetch'; -import Validation from '../validation'; -import dotenv from 'dotenv'; -dotenv.config({ path: '.env' }); - -const API_KEY = process.env.NEXT_PUBLIC_GC_API_KEY; -const SCORER_ID = process.env.NEXT_PUBLIC_GC_SCORER_ID; - -const headers = API_KEY - ? { - 'Content-Type': 'application/json', - 'X-API-Key': API_KEY - } - : undefined; - -export default class extends Validation { - public id = 'passport-weighted'; - public github = 'snapshot-labs'; - public version = '0.1.0'; - public title = 'Gitcoin Passport Weighted'; - public description = - 'Protect your proposals from spam and vote manipulation by requiring users to have a Gitcoin Passport.'; - - async validate(currentAddress = this.author): Promise { - const GET_PASSPORT_SCORE_URI = `https://api.scorer.gitcoin.co/registry/score/${SCORER_ID}/${currentAddress}`; - - const THRESHOLD_NUMBER = this.params.minScore || 1; - - try { - const response = await fetch(GET_PASSPORT_SCORE_URI, { - headers - }); - const passportData = await response.json(); - if (passportData.score) { - const roundedScore = Math.round(passportData.score * 100) / 100; - if (roundedScore >= THRESHOLD_NUMBER) return true; - console.log( - `Your passport score (${roundedScore}) is lower than the threshold score (${THRESHOLD_NUMBER}).` - ); - return false; - } else { - console.log( - 'You do not have a valid Gitcoin Passport. Create one by visiting https://passport.gitcoin.co/ ' - ); - return false; - } - } catch (err) { - console.log('error: ', err); - throw err; - } - } -} diff --git a/src/validations/passport-weighted/schema.json b/src/validations/passport-weighted/schema.json deleted file mode 100644 index 0d741f6a1..000000000 --- a/src/validations/passport-weighted/schema.json +++ /dev/null @@ -1,278 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$ref": "#/definitions/Validation", - "definitions": { - "Validation": { - "title": "Gitcoin passport weighted", - "type": "object", - "properties": { - "minScore": { - "type": "number", - "title": "Minimum score", - "minimum": 10 - }, - "stamps": { - "type": "array", - "title": "Stamps", - "uniqueItems": true, - "minItems": 1, - "maxItems": 32, - "items": { - "type": "object", - "properties": { - "id": { - "type": "string", - "title": "Id", - "anyOf": [ - { - "const": "Google", - "title": "Google account" - }, - { - "const": "Ens", - "title": "ENS owner" - }, - { - "const": "Poh", - "title": "Proof of humanity" - }, - { - "const": "Twitter", - "title": "Twitter account" - }, - { - "const": "TwitterTweetGT10", - "title": "Twitter followers > 10" - }, - { - "const": "TwitterFollowerGT100", - "title": "Twitter followers > 100" - }, - { - "const": "TwitterFollowerGT500", - "title": "Twitter followers > 500" - }, - { - "const": "TwitterFollowerGTE1000", - "title": "Twitter followers > 1000" - }, - { - "const": "TwitterFollowerGT5000", - "title": "Twitter followers > 5000" - }, - { - "const": "POAP", - "title": "POAP owner" - }, - { - "const": "Facebook", - "title": "Facebook account" - }, - { - "const": "FacebookFriends", - "title": "Facebook friends > 100" - }, - { - "const": "FacebookProfilePicture", - "title": "Facebook profile picture" - }, - { - "const": "Brightid", - "title": "Brightid" - }, - { - "const": "Github", - "title": "Github account" - }, - { - "const": "FiveOrMoreGithubRepos", - "title": "Github repos > 4" - }, - { - "const": "ForkedGithubRepoProvider", - "title": "Github repo forked" - }, - { - "const": "StarredGithubRepoProvider", - "title": "Github repo starred" - }, - { - "const": "TenOrMoreGithubFollowers", - "title": "Github followers > 9" - }, - { - "const": "FiftyOrMoreGithubFollowers", - "title": "Github followers > 49" - }, - { - "const": "GitcoinContributorStatistics#numGrantsContributeToGte#1", - "title": "Grants contributed > 1" - }, - - { - "const": "GitcoinContributorStatistics#numGrantsContributeToGte#10", - "title": "Grants contributed > 10" - }, - { - "const": "GitcoinContributorStatistics#numGrantsContributeToGte#25", - "title": "Grants contributed > 25" - }, - { - "const": "GitcoinContributorStatistics#numGrantsContributeToGte#100", - "title": "Grants contributed > 100" - }, - { - "const": "GitcoinContributorStatistics#totalContributionAmountGte#10", - "title": "Grant contributions > $10" - }, - { - "const": "GitcoinContributorStatistics#totalContributionAmountGte#100", - "title": "Grant contributions > $100" - }, - { - "const": "GitcoinContributorStatistics#totalContributionAmountGte#1000", - "title": "Grant contributions > $1000" - }, - { - "const": "GitcoinGranteeStatistics#numOwnedGrants#1", - "title": "Grant owner > 1" - }, - { - "const": "GitcoinGranteeStatistics#numGrantContributors#10", - "title": "Grant contributors > 10" - }, - { - "const": "GitcoinGranteeStatistics#numGrantContributors#25", - "title": "Grant contributors > 25" - }, - - { - "const": "GitcoinGranteeStatistics#numGrantContributors#100", - "title": "Grant contributors > 100" - }, - { - "const": "GitcoinGranteeStatistics#totalContributionAmount#100", - "title": "Grant contributions > $100" - }, - { - "const": "GitcoinGranteeStatistics#totalContributionAmount#1000", - "title": "Grant contributions > $1000" - }, - { - "const": "GitcoinGranteeStatistics#totalContributionAmount#10000", - "title": "Grant contributions > $10000" - }, - { - "const": "GitcoinGranteeStatistics#numGrantsInEcoAndCauseRound#1", - "title": "Grant owner Eco & Cause" - }, - { - "const": "Linkedin", - "title": "Linkedin account" - }, - { - "const": "Discord", - "title": "Discord account" - }, - { - "const": "SnapshotVotesProvider", - "title": "Snapshot voter" - }, - { - "const": "SnapshotProposalsProvider", - "title": "Snapshot proposer" - }, - { - "const": "ethPossessionsGte#1", - "title": "ETH > 1" - }, - { - "const": "ethPossessionsGte#10", - "title": "ETH > 10" - }, - { - "const": "ethPossessionsGte#32", - "title": "ETH > 32" - }, - { - "const": "FirstEthTxnProvider", - "title": "First ETH > 30 days" - }, - { - "const": "EthGTEOneTxnProvider", - "title": "ETH tx > 1" - }, - { - "const": "EthGasProvider", - "title": "ETH gas > 0.5" - }, - { - "const": "gtcPossessionsGte#10", - "title": "Gitcoin GTC > 10" - }, - { - "const": "gtcPossessionsGte#100", - "title": "Gitcoin GTC > 100" - }, - { - "const": "SelfStakingBronze", - "title": "GTC staked > 1" - }, - { - "const": "SelfStakingSilver", - "title": "GTC staked > 10" - }, - { - "const": "SelfStakingGold", - "title": "GTC staked > 100" - }, - { - "const": "CommunityStakingBronze", - "title": "Comm GTC staked > 1" - }, - { - "const": "CommunityStakingSilver", - "title": "Comm GTC staked > 10" - }, - { - "const": "CommunityStakingGold", - "title": "Comm GTC staked > 100" - }, - { - "const": "NFT", - "title": "NFT holder" - }, - { - "const": "ZkSync", - "title": "ZkSync account" - }, - { - "const": "Lens", - "title": "Lens account" - }, - { - "const": "GnosisSafe", - "title": "GnosisSafe singer/owner" - } - ] - }, - "weight": { - "type": "number", - "title": "Weight" - } - }, - "default": { "id": "Ens", "weight": "1" }, - "required": ["id", "weight"], - "additionalProperties": false - } - }, - "min_weight": { - "type": "number", - "title": "Min. weight" - } - }, - "required": ["stamps", "min_weight"], - "additionalProperties": false - } - } -} diff --git a/test/validation.test.ts b/test/validation.test.ts index 0a2664d52..4b379624d 100644 --- a/test/validation.test.ts +++ b/test/validation.test.ts @@ -20,18 +20,31 @@ const examples = require(`../src/validations/${id}/examples.json`).map( (example, index) => ({ index, example }) ); -const [{ example }] = examples; - describe('Validation', () => { it(`validate: ${id}`, async () => { - const validation = new snapshot.validations[id].validation( - example.author, - example.space, - example.network, - example.snapshot, - example.params + await Promise.all( + examples.map(async ({ example }) => { + const validation = new snapshot.validations[id].validation( + example.author, + example.space, + example.network, + example.snapshot, + example.params + ); + + // edge-case when using setTimeout to wait for the Passport API to process a job request + if (id === 'passport-gated') jest.useRealTimers(); + + const exampleValidation = await validation.validate(); + const expectedValue = + example.valid !== undefined ? example.valid : true; + console.log( + `Example ${example.author} -> Expected: ${example.valid} Actual: ${exampleValidation}` + ); + + expect(exampleValidation).toBe(expectedValue); + }) ); - expect(await validation.validate()).toBe(true); }, 30e3); // Check schema is valid with examples.json @@ -45,9 +58,11 @@ describe('Validation', () => { 'Check schema (if available) is valid with examples.json', async () => { expect(typeof schema).toBe('object'); - expect(snapshotjs.utils.validateSchema(schema, example.params)).toBe( - true - ); + for (const { example } of examples) { + expect(snapshotjs.utils.validateSchema(schema, example.params)).toBe( + true + ); + } } ); }); From b05ce3cc1a381362cba05bfd4a8c5619e3d64308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Espen=20H=C3=B8jsgaard?= Date: Tue, 26 Sep 2023 19:04:28 +0200 Subject: [PATCH 501/815] [dss-vest-unpaid] Add DssVest dss-vest-unpaid strategy (#1290) * [dss-vest-unpaid] Add DssVest dss-vest-unpaid strategy * [dss-vest-unpaid] Limit number of vestings that can be handled To avoid future memory issues --- src/strategies/dss-vest-unpaid/README.md | 3 + src/strategies/dss-vest-unpaid/examples.json | 23 +++++++ src/strategies/dss-vest-unpaid/index.ts | 63 ++++++++++++++++++++ src/strategies/dss-vest-unpaid/schema.json | 27 +++++++++ src/strategies/index.ts | 4 +- 5 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 src/strategies/dss-vest-unpaid/README.md create mode 100644 src/strategies/dss-vest-unpaid/examples.json create mode 100644 src/strategies/dss-vest-unpaid/index.ts create mode 100644 src/strategies/dss-vest-unpaid/schema.json diff --git a/src/strategies/dss-vest-unpaid/README.md b/src/strategies/dss-vest-unpaid/README.md new file mode 100644 index 000000000..2df84f8d1 --- /dev/null +++ b/src/strategies/dss-vest-unpaid/README.md @@ -0,0 +1,3 @@ +# dss-vest-unpaid + +This strategy returns the vested but yet unclaimed tokens of the voters in a [DssVest](https://github.com/makerdao/dss-vest) token vesting contract. diff --git a/src/strategies/dss-vest-unpaid/examples.json b/src/strategies/dss-vest-unpaid/examples.json new file mode 100644 index 000000000..6bb5fd6f0 --- /dev/null +++ b/src/strategies/dss-vest-unpaid/examples.json @@ -0,0 +1,23 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "dss-vest-unpaid", + "params": { + "address": "0x370F850180FDDCdc521Ed11900a7a27D08B2d402", + "decimals": 18 + } + }, + "network": "1", + "addresses": [ + "0xfe564B3579bAde0E1f22EADC2a9Be471fDCdc01c", + "0xb6d52aA63532A0d1c50B3Bb782e6B511bd973645", + "0xAC9ba72fb61aA7c31A95df0A8b6ebA6f41EF875e", + "0x3d6Affb8CAfE78F640edFfcCD2d2afe6dF151C5c", + "0x112F0732E59E7600768dFc35Ba744b89F2356Cd8", + "0x6e0a1dDAD894e6466d405Bb73377F0A257278D74", + "0xCD252d6AB26b7363E75d7451029C0f0729783AcE" + ], + "snapshot": 18036242 + } +] diff --git a/src/strategies/dss-vest-unpaid/index.ts b/src/strategies/dss-vest-unpaid/index.ts new file mode 100644 index 000000000..bc144d87b --- /dev/null +++ b/src/strategies/dss-vest-unpaid/index.ts @@ -0,0 +1,63 @@ +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Contract } from '@ethersproject/contracts'; +import { Multicaller } from '../../utils'; + +export const author = 'espendk'; +export const version = '1.0.0'; + +// To avoid future memory issues, we limit the number of vestings supported by the strategy +const MAX_VESTINGS = 500; + +const abi = [ + 'function ids() external view returns (uint256)', + 'function usr(uint256 id) external view returns (address)', + 'function unpaid(uint256 id) external view returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + // Get the number of vestings + const dssVestContract = new Contract(options.address, abi, provider); + const idCount = await dssVestContract.ids(); + if (idCount > MAX_VESTINGS) { + throw new Error( + `Max number (${MAX_VESTINGS}) of vestings exceeded: ${idCount}` + ); + } + + // Get the vesting addresses and unpaid amounts + const multi = new Multicaller(network, provider, abi, { blockTag }); + for (let id = 1; id <= idCount; ++id) { + multi.call('usr' + id, options.address, 'usr', [id]); + multi.call('unpaid' + id, options.address, 'unpaid', [id]); + } + const unclaimedVestings: Record = + await multi.execute(); + + // Set score to 0 for all addresses + const result = {}; + addresses.forEach((address) => { + result[address] = 0; + }); + + // Add the unclaimed vesting amounts to the addresses + for (let id = 1; id <= idCount; ++id) { + const address = unclaimedVestings['usr' + id] as string; + if (addresses.includes(address)) { + result[address] += parseFloat( + formatUnits(unclaimedVestings['unpaid' + id], options.decimals) + ); + } + } + + return result; +} diff --git a/src/strategies/dss-vest-unpaid/schema.json b/src/strategies/dss-vest-unpaid/schema.json new file mode 100644 index 000000000..fcd74a631 --- /dev/null +++ b/src/strategies/dss-vest-unpaid/schema.json @@ -0,0 +1,27 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "address": { + "type": "string", + "title": "DssVest contract address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 18"] + } + }, + "required": [], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 7eb9fd0c3..d3c0d8eab 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -462,6 +462,7 @@ import * as erc4626AssetsOf from './erc4626-assets-of'; import * as sdVoteBoostTWAVPV2 from './sd-vote-boost-twavp-v2'; import * as friendTech from './friend-tech'; import * as moonbase from './moonbase'; +import * as dssVestUnpaid from './dss-vest-unpaid'; const strategies = { 'cap-voting-power': capVotingPower, @@ -932,7 +933,8 @@ const strategies = { 'erc4626-assets-of': erc4626AssetsOf, 'friend-tech': friendTech, 'sd-vote-boost-twavp-v2': sdVoteBoostTWAVPV2, - moonbase: moonbase + moonbase: moonbase, + 'dss-vest-unpaid': dssVestUnpaid }; Object.keys(strategies).forEach(function (strategyName) { From 0c543855b6cb46d559134e71e288325739a60fad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Espen=20H=C3=B8jsgaard?= Date: Wed, 27 Sep 2023 08:38:25 +0200 Subject: [PATCH 502/815] [dss-vest-balance-and-unpaid] Add DssVest vesting contract strategies (#1289) * [dss-vest-unpaid] Add DssVest dss-vest-unpaid strategy * [dss-vest-balance-and-unpaid] Add DssVest dss-vest-balance-and-unpaid strategy * [dss-vest-unpaid] Limit number of vestings that can be handled To avoid future memory issues --- .../dss-vest-balance-and-unpaid/README.md | 3 ++ .../dss-vest-balance-and-unpaid/examples.json | 25 +++++++++++ .../dss-vest-balance-and-unpaid/index.ts | 37 +++++++++++++++++ .../dss-vest-balance-and-unpaid/schema.json | 41 +++++++++++++++++++ src/strategies/index.ts | 4 +- 5 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 src/strategies/dss-vest-balance-and-unpaid/README.md create mode 100644 src/strategies/dss-vest-balance-and-unpaid/examples.json create mode 100644 src/strategies/dss-vest-balance-and-unpaid/index.ts create mode 100644 src/strategies/dss-vest-balance-and-unpaid/schema.json diff --git a/src/strategies/dss-vest-balance-and-unpaid/README.md b/src/strategies/dss-vest-balance-and-unpaid/README.md new file mode 100644 index 000000000..6c4bb4c5a --- /dev/null +++ b/src/strategies/dss-vest-balance-and-unpaid/README.md @@ -0,0 +1,3 @@ +# dss-vest-balance-and-unpaid + +For an ERC20 token with a [DssVest](https://github.com/makerdao/dss-vest) token vesting contract, this strategy returns the sum of the voters' token balance and the vested but yet unclaimed tokens of the voters. diff --git a/src/strategies/dss-vest-balance-and-unpaid/examples.json b/src/strategies/dss-vest-balance-and-unpaid/examples.json new file mode 100644 index 000000000..e822a02da --- /dev/null +++ b/src/strategies/dss-vest-balance-and-unpaid/examples.json @@ -0,0 +1,25 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "dss-vest-balance-and-unpaid", + "params": { + "dssVestAddress": "0x370F850180FDDCdc521Ed11900a7a27D08B2d402", + "tokenAddress": "0x7777F41A060377B3640F8B5E3bB78e37BD487777", + "symbol": "MGV", + "decimals": 18 + } + }, + "network": "1", + "addresses": [ + "0xfe564B3579bAde0E1f22EADC2a9Be471fDCdc01c", + "0xb6d52aA63532A0d1c50B3Bb782e6B511bd973645", + "0xAC9ba72fb61aA7c31A95df0A8b6ebA6f41EF875e", + "0x3d6Affb8CAfE78F640edFfcCD2d2afe6dF151C5c", + "0x112F0732E59E7600768dFc35Ba744b89F2356Cd8", + "0x6e0a1dDAD894e6466d405Bb73377F0A257278D74", + "0xCD252d6AB26b7363E75d7451029C0f0729783AcE" + ], + "snapshot": 18036242 + } +] diff --git a/src/strategies/dss-vest-balance-and-unpaid/index.ts b/src/strategies/dss-vest-balance-and-unpaid/index.ts new file mode 100644 index 000000000..dc0f072d4 --- /dev/null +++ b/src/strategies/dss-vest-balance-and-unpaid/index.ts @@ -0,0 +1,37 @@ +import { strategy as erc20BalanceOfStrategy } from '../erc20-balance-of'; +import { strategy as dssVestUnpaidStrategy } from '../dss-vest-unpaid'; + +export const author = 'espendk'; +export const version = '1.0.0'; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const score = await dssVestUnpaidStrategy( + space, + network, + provider, + addresses, + { address: options.dssVestAddress, ...options }, + snapshot + ); + const mgvScore = await erc20BalanceOfStrategy( + space, + network, + provider, + addresses, + { address: options.tokenAddress, ...options }, + snapshot + ); + + for (const address of Object.keys(score)) { + score[address] += mgvScore[address]; + } + + return score; +} diff --git a/src/strategies/dss-vest-balance-and-unpaid/schema.json b/src/strategies/dss-vest-balance-and-unpaid/schema.json new file mode 100644 index 000000000..5158954bb --- /dev/null +++ b/src/strategies/dss-vest-balance-and-unpaid/schema.json @@ -0,0 +1,41 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "dssVestAddress": { + "type": "string", + "title": "DssVest contract address", + "examples": ["e.g. 0x370F850180FDDCdc521Ed11900a7a27D08B2d402"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "tokenAddress": { + "type": "string", + "title": "ERC20 contract address", + "examples": ["e.g. 0x7777F41A060377B3640F8B5E3bB78e37BD487777"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. MGV"], + "maxLength": 16 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 18"] + } + }, + "required": [], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index d3c0d8eab..3a06c15e5 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -463,6 +463,7 @@ import * as sdVoteBoostTWAVPV2 from './sd-vote-boost-twavp-v2'; import * as friendTech from './friend-tech'; import * as moonbase from './moonbase'; import * as dssVestUnpaid from './dss-vest-unpaid'; +import * as dssVestBalanceAndUnpaid from './dss-vest-balance-and-unpaid'; const strategies = { 'cap-voting-power': capVotingPower, @@ -934,7 +935,8 @@ const strategies = { 'friend-tech': friendTech, 'sd-vote-boost-twavp-v2': sdVoteBoostTWAVPV2, moonbase: moonbase, - 'dss-vest-unpaid': dssVestUnpaid + 'dss-vest-unpaid': dssVestUnpaid, + 'dss-vest-balance-and-unpaid': dssVestBalanceAndUnpaid }; Object.keys(strategies).forEach(function (strategyName) { From 25ae6a700f39425621bf4c8855aec5d901e7c444 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 28 Sep 2023 15:40:51 +0530 Subject: [PATCH 503/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.6.3 (#1293) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index c02fff4be..de0987f12 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.6.2", + "@snapshot-labs/snapshot.js": "^0.6.3", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 8c050a765..bc58c4063 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.6.2": - version "0.6.2" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.6.2.tgz#0f9ddf591ec50912aeed545c807b5295365d4e2f" - integrity sha512-hQjZ0I9uLu2sUpuR05maYCq9KLi6yNJnCCkjIutDQjFFEzmeMqJ0Lru1tOdcRMsPW3g5ktdo5xi265ESEBDPdA== +"@snapshot-labs/snapshot.js@^0.6.3": + version "0.6.3" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.6.3.tgz#a24cccfaaa0ec39db366518bcc4a8f03f42468db" + integrity sha512-RDbObv32FyG2WYapyXQ7kLU+31Sr1YxszAbgeU2WuIJvYFoIp1qJ6BQRrbQOMKea1c9TTlf7XY50NGZPWXXw7w== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 1aa63ccb7a079036b85ba5539d9663121841e989 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 1 Oct 2023 22:15:27 +0530 Subject: [PATCH 504/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.7.0 (#1294) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index de0987f12..4d7418c4d 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.6.3", + "@snapshot-labs/snapshot.js": "^0.7.0", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index bc58c4063..cdd598ab0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.6.3": - version "0.6.3" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.6.3.tgz#a24cccfaaa0ec39db366518bcc4a8f03f42468db" - integrity sha512-RDbObv32FyG2WYapyXQ7kLU+31Sr1YxszAbgeU2WuIJvYFoIp1qJ6BQRrbQOMKea1c9TTlf7XY50NGZPWXXw7w== +"@snapshot-labs/snapshot.js@^0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.7.0.tgz#50c16ada2bc7011a77edb02c38ddbc08e6331050" + integrity sha512-rmV4vlhEugnegHOUm7pq+p8OlzqiHv9JUMP5ZYc2vxAbLkibopk3x5o4ggaKxxNzDDzfOZMMCOZf3nzGMTMVCw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 82a7ef8f8c566c60b006c204ac19973c0cdfa70c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 3 Oct 2023 23:49:59 +0530 Subject: [PATCH 505/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.7.2 (#1295) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 4d7418c4d..852e47af0 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.7.0", + "@snapshot-labs/snapshot.js": "^0.7.2", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index cdd598ab0..e4222f70f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.7.0": - version "0.7.0" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.7.0.tgz#50c16ada2bc7011a77edb02c38ddbc08e6331050" - integrity sha512-rmV4vlhEugnegHOUm7pq+p8OlzqiHv9JUMP5ZYc2vxAbLkibopk3x5o4ggaKxxNzDDzfOZMMCOZf3nzGMTMVCw== +"@snapshot-labs/snapshot.js@^0.7.2": + version "0.7.2" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.7.2.tgz#fd0a9d5e161b9cc088771efc26f6c2bc4e887177" + integrity sha512-rdrS0Fj5PHYSlQrfsrNb7Vv7olRA+Lbe7f7DUNgOfzI9tQvIJJFMrQqxafyiWfnJnk4ild5iOcU5uPQPHjYVjw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 17a129fa9bce58e938fd3c07d4feb4f2400f8b85 Mon Sep 17 00:00:00 2001 From: Marsot Pierre Date: Tue, 3 Oct 2023 20:51:20 +0200 Subject: [PATCH 506/815] [sd-vote-boost-twavp-v3] Add new strategy (#1291) * v3 * readme * Update src/strategies/sd-vote-boost-twavp-v3/index.ts * max 5 multicall * Update src/strategies/sd-vote-boost-twavp-v3/index.ts * max pools --------- Co-authored-by: Chaitanya --- src/strategies/index.ts | 2 + .../sd-vote-boost-twavp-v3/README.md | 28 +++ .../sd-vote-boost-twavp-v3/examples.json | 29 +++ .../sd-vote-boost-twavp-v3/index.ts | 199 ++++++++++++++++++ 4 files changed, 258 insertions(+) create mode 100644 src/strategies/sd-vote-boost-twavp-v3/README.md create mode 100644 src/strategies/sd-vote-boost-twavp-v3/examples.json create mode 100644 src/strategies/sd-vote-boost-twavp-v3/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 3a06c15e5..dc703a5af 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -460,6 +460,7 @@ import * as sablierV2 from './sablier-v2'; import * as gelatoStaking from './gelato-staking'; import * as erc4626AssetsOf from './erc4626-assets-of'; import * as sdVoteBoostTWAVPV2 from './sd-vote-boost-twavp-v2'; +import * as sdVoteBoostTWAVPV3 from './sd-vote-boost-twavp-v3'; import * as friendTech from './friend-tech'; import * as moonbase from './moonbase'; import * as dssVestUnpaid from './dss-vest-unpaid'; @@ -934,6 +935,7 @@ const strategies = { 'erc4626-assets-of': erc4626AssetsOf, 'friend-tech': friendTech, 'sd-vote-boost-twavp-v2': sdVoteBoostTWAVPV2, + 'sd-vote-boost-twavp-v3': sdVoteBoostTWAVPV3, moonbase: moonbase, 'dss-vest-unpaid': dssVestUnpaid, 'dss-vest-balance-and-unpaid': dssVestBalanceAndUnpaid diff --git a/src/strategies/sd-vote-boost-twavp-v3/README.md b/src/strategies/sd-vote-boost-twavp-v3/README.md new file mode 100644 index 000000000..20f94d0ea --- /dev/null +++ b/src/strategies/sd-vote-boost-twavp-v3/README.md @@ -0,0 +1,28 @@ +# sd-vote-boost-twavp-v3 + +This strategy is used by Stake DAO to vote with sdToken using Time Weigthed Averaged Voting Power (TWAVP) system and adapted for veSDT boost delegation with possibility to whiteliste address to by pass TWAVP. + +``` +VotingPower(user) = veToken.balanceOf(liquidLocker) * (average.sdTokenGauge.working_balances(user) / sdTokenGauge.working_supply) +``` + +>_sampleSize: in days_ +>_sampleStep: the number of block for `average` calculation (max 5)_ + +Here is an example of parameters: + +```json +{ + "veToken": "0x5f3b5DfEb7B28CDbD7FAba78963EE202a494e2A2", + "liquidLocker": "0x52f541764E6e90eeBc5c21Ff570De0e2D63766B6", + "sdTokenGauge": "0x7f50786A0b15723D741727882ee99a0BF34e3466", + "sdToken": "0xD1b5651E55D4CeeD36251c61c50C889B36F6abB5", + "pools": ["0xca0253a98d16e9c1e3614cafda19318ee69772d0"], + "symbol": "sdToken", + "decimals": 18, + "sampleSize": 10, + "sampleStep": 5, + "botAddress": "", + "whiteListedAddress": ["0x1c0D72a330F2768dAF718DEf8A19BAb019EEAd09"] +} +``` \ No newline at end of file diff --git a/src/strategies/sd-vote-boost-twavp-v3/examples.json b/src/strategies/sd-vote-boost-twavp-v3/examples.json new file mode 100644 index 000000000..2beab0de2 --- /dev/null +++ b/src/strategies/sd-vote-boost-twavp-v3/examples.json @@ -0,0 +1,29 @@ +[ + { + "name": "Stake DAO vote boost using TWAVP V3", + "strategy": { + "name": "sd-vote-boost-twavp-v3", + "params": { + "veToken": "0x5f3b5DfEb7B28CDbD7FAba78963EE202a494e2A2", + "liquidLocker": "0x52f541764E6e90eeBc5c21Ff570De0e2D63766B6", + "sdTokenGauge": "0x7f50786A0b15723D741727882ee99a0BF34e3466", + "sdToken": "0xD1b5651E55D4CeeD36251c61c50C889B36F6abB5", + "pools": ["0xca0253a98d16e9c1e3614cafda19318ee69772d0"], + "symbol": "sdToken", + "decimals": 18, + "sampleSize": 10, + "sampleStep": 5, + "botAddress": "", + "whiteListedAddress": ["0x1c0D72a330F2768dAF718DEf8A19BAb019EEAd09"] + } + }, + "network": "1", + "addresses": [ + "0x26a5994176d34D128C5e6ab80Fa0882A7df4fF00", + "0xDdB50FfDbA4D89354E1088e4EA402de895562173", + "0xE1F7eaD40d33eeF30dCf15eB5efC45409001aAB8", + "0x1c0D72a330F2768dAF718DEf8A19BAb019EEAd09" + ], + "snapshot": 17835000 + } +] diff --git a/src/strategies/sd-vote-boost-twavp-v3/index.ts b/src/strategies/sd-vote-boost-twavp-v3/index.ts new file mode 100644 index 000000000..67c9e8ba0 --- /dev/null +++ b/src/strategies/sd-vote-boost-twavp-v3/index.ts @@ -0,0 +1,199 @@ +import { multicall } from '../../utils'; +import { BigNumber } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; + +export const author = 'pierremarsotlyon1'; +export const version = '0.0.1'; + +// Used ABI +const abi = [ + 'function balanceOf(address account) external view returns (uint256)', + 'function working_supply() external view returns (uint256)', + 'function totalSupply() external view returns (uint256)', + 'function working_balances(address account) external view returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + // Maximum of 5 multicall! + if (options.sampleStep > 5) { + throw new Error('maximum of 5 call'); + } + + // Maximum of 20 whitelisted address + if (options.whiteListedAddress.length > 20) { + throw new Error('maximum of 20 whitelisted address'); + } + + // Maximum of 500 pools address + if (options.pools.length > 500) { + throw new Error('maximum of 500 pools'); + } + + const calls: any[] = []; + for(const pool of options.pools) { + calls.push([options.sdToken, 'balanceOf', [pool]]); + } + calls.push([options.veToken, 'balanceOf', [options.liquidLocker]]); + + // --- Create block number list for twavp + // Obtain last block number + // Create block tag + let blockTag = 0; + if (typeof snapshot === 'number') { + blockTag = snapshot; + } else { + blockTag = await provider.getBlockNumber(); + } + + // Create block list + const blockList = getPreviousBlocks( + blockTag, + options.sampleStep, + options.sampleSize + ); + + // Query working balance of users + const workingBalanceQuery = addresses.map((address: any) => [ + options.sdTokenGauge, + 'working_balances', + [address] + ]); + + // Execute multicall `sampleStep` times + const response: any[] = []; + for (let i = 0; i < options.sampleStep; i++) { + // Use good block number + blockTag = blockList[i]; + + const loopCalls: any[] = []; + + // Add mutlicall response to array + if (i === options.sampleStep - 1) { + // End + loopCalls.push([options.sdTokenGauge, 'working_supply']); + loopCalls.push([options.sdTokenGauge, 'totalSupply']); + loopCalls.push(...workingBalanceQuery); + loopCalls.push(...calls); + + } else { + loopCalls.push(...workingBalanceQuery); + } + + response.push( + await multicall( + network, + provider, + abi, + loopCalls, + { blockTag } + ) + ); + } + + // Get working supply + const workingSupply = response[response.length - 1].shift()[0]; // Last response, latest block + + // Get voting power of liquid locker + const sdTokenGaugeTotalSupply = response[response.length - 1].shift()[0]; // Last response, latest block + + return Object.fromEntries( + Array(addresses.length) + .fill('x') + .map((_, i) => { + // Init array of working balances for user + const userWorkingBalances: BigNumber[] = []; + + for (let j = 0; j < options.sampleStep; j++) { + // Add working balance to array. + userWorkingBalances.push(response[j].shift()[0]); + } + + if (addresses[i].toLowerCase() === options.botAddress.toLowerCase()) { + const poolsBalances = options.pools.map(() => response[response.length - 1].shift()); + const sumPoolsBalance = poolsBalances.reduce((acc, balance) => acc.add(balance[0]), BigNumber.from(0)); + + const votingPowerLiquidLocker = response[response.length - 1].shift()[0]; + + const total = sumPoolsBalance.mul(4).div(10).mul(votingPowerLiquidLocker).div(sdTokenGaugeTotalSupply); + return [addresses[i], Number(parseFloat(formatUnits(total, options.decimals)))]; + } else { + // Get average working balance. + const averageWorkingBalance = average( + userWorkingBalances, + addresses[i], + options.whiteListedAddress + ); + + const averageWorkingBalanceF = parseFloat(formatUnits(averageWorkingBalance, 18)); + const sdTokenGaugeTotalSupplyF = parseFloat(formatUnits(sdTokenGaugeTotalSupply, 18)); + const workingSupplyF = parseFloat(formatUnits(workingSupply, 18)); + + // Calculate voting power. + const votingPower = + workingSupply != 0 + ? averageWorkingBalanceF * sdTokenGaugeTotalSupplyF / workingSupplyF + : 0; + + // Return address and voting power + return [addresses[i], Number(votingPower)]; + } + + }) + ); +} + +function getPreviousBlocks( + currentBlockNumber: number, + numberOfBlocks: number, + daysInterval: number +): number[] { + // Estimate number of blocks per day + const blocksPerDay = 86400 / 12; + // Calculate total blocks interval + const totalBlocksInterval = blocksPerDay * daysInterval; + // Calculate block interval + const blockInterval = totalBlocksInterval / (numberOfBlocks - 1); + + // Init array of block numbers + const blockNumbers: number[] = []; + + for (let i = 0; i < numberOfBlocks; i++) { + // Calculate block number + const blockNumber = + currentBlockNumber - totalBlocksInterval + blockInterval * i; + // Add block number to array + blockNumbers.push(Math.round(blockNumber)); + } + + // Return array of block numbers + return blockNumbers; +} + +function average( + numbers: BigNumber[], + address: string, + whiteListedAddress: string[] +): BigNumber { + // If no numbers, return 0 to avoid division by 0. + if (numbers.length === 0) return BigNumber.from(0); + + // If address is whitelisted, return most recent working balance. i.e. no twavp applied. + if (whiteListedAddress.includes(address)) return numbers[numbers.length - 1]; + + // Init sum + let sum = BigNumber.from(0); + // Loop through all elements and add them to sum + for (let i = 0; i < numbers.length; i++) { + sum = sum.add(numbers[i]); + } + + // Return sum divided by array length to get mean + return sum.div(numbers.length); +} From 907c8bb3e8525c41d85da6020118cb932d28ff16 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Wed, 4 Oct 2023 17:05:25 +0530 Subject: [PATCH 507/815] Refactor: Usuage of getBlockNumber (#1298) --- src/strategies/aave-governance-power/index.ts | 9 ++++----- src/strategies/nouns-rfp-power/index.ts | 5 +---- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/strategies/aave-governance-power/index.ts b/src/strategies/aave-governance-power/index.ts index a7157abf3..315a7743c 100644 --- a/src/strategies/aave-governance-power/index.ts +++ b/src/strategies/aave-governance-power/index.ts @@ -27,16 +27,15 @@ export async function strategy( options, snapshot ) { - const blockTag = - typeof snapshot === 'number' - ? snapshot - : await provider.getBlockNumber(snapshot); + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; // Early return 0 voting power if governanceStrategy or powerType is not correctly set if (!options.governanceStrategy || !powerTypesToMethod[options.powerType]) { return Object.fromEntries(addresses.map((address) => [address, '0'])); } + const blockNumber = + blockTag === 'latest' ? await provider.getBlockNumber(network) : blockTag; const response: BigNumber[] = await multicall( network, provider, @@ -44,7 +43,7 @@ export async function strategy( addresses.map((address: any) => [ options.governanceStrategy, powerTypesToMethod[options.powerType], - [address.toLowerCase(), blockTag] + [address.toLowerCase(), blockNumber] ]), { blockTag } ); diff --git a/src/strategies/nouns-rfp-power/index.ts b/src/strategies/nouns-rfp-power/index.ts index f0dbbb86a..336097972 100644 --- a/src/strategies/nouns-rfp-power/index.ts +++ b/src/strategies/nouns-rfp-power/index.ts @@ -28,10 +28,7 @@ export async function strategy( options, snapshot ) { - const blockTag = - typeof snapshot === 'number' - ? snapshot - : await provider.getBlockNumber(snapshot); + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; // Early return 0 voting power if governanceStrategy or powerType is not correctly set if (!options.governanceStrategy || !powerTypesToMethod[options.powerType]) { From 1be7cbdeede50310564f849f046313870213fe19 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Wed, 4 Oct 2023 18:09:57 +0530 Subject: [PATCH 508/815] Update dependabot.yml (#1299) --- .github/dependabot.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 4f1006822..37c901824 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -10,5 +10,5 @@ updates: schedule: interval: "daily" allow: - # Allow updates for snapshot.js only - - dependency-name: "@snapshot-labs/snapshot.js" + # Allow updates for @snapshot-labs/* only + - dependency-name: "@snapshot-labs/*" From cf9e7bfbef2b2d3d7efb859492580c1740f082c1 Mon Sep 17 00:00:00 2001 From: Sam <51686767+samuveth@users.noreply.github.com> Date: Thu, 5 Oct 2023 09:54:16 +0700 Subject: [PATCH 509/815] Fix type aave-governance-power (#1300) --- src/strategies/aave-governance-power/schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategies/aave-governance-power/schema.json b/src/strategies/aave-governance-power/schema.json index 25cedec86..48869bba1 100644 --- a/src/strategies/aave-governance-power/schema.json +++ b/src/strategies/aave-governance-power/schema.json @@ -26,7 +26,7 @@ "enum": ["vote", "proposition"] }, "decimals": { - "type": "integer", + "type": "number", "title": "Decimals", "examples": ["e.g. 18"], "minimum": 0, From 234c315c2c16c221470c995fd2600591504fbd47 Mon Sep 17 00:00:00 2001 From: DEFI FOUNDATION <106986644+DEFI-Foundation@users.noreply.github.com> Date: Thu, 5 Oct 2023 20:13:11 +0200 Subject: [PATCH 510/815] [eoa-balance-and-staking-pools] added (#1297) * [eoa-balance-and-staking-pools] added * updates after pr #1297 comments --------- Co-authored-by: Marco Braglia --- .../eoa-balance-and-staking-pools/README.md | 51 +++++++++++++ .../examples.json | 37 ++++++++++ .../eoa-balance-and-staking-pools/index.ts | 72 +++++++++++++++++++ src/strategies/index.ts | 4 +- 4 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 src/strategies/eoa-balance-and-staking-pools/README.md create mode 100644 src/strategies/eoa-balance-and-staking-pools/examples.json create mode 100644 src/strategies/eoa-balance-and-staking-pools/index.ts diff --git a/src/strategies/eoa-balance-and-staking-pools/README.md b/src/strategies/eoa-balance-and-staking-pools/README.md new file mode 100644 index 000000000..f2403aac3 --- /dev/null +++ b/src/strategies/eoa-balance-and-staking-pools/README.md @@ -0,0 +1,51 @@ +# Token holders and staking pool partecipants strategy + +This strategy returns the balances of the voters from both staking pools and ERC20 XMT tokens on Ethereum mainnet. + +## Accepted options + +- **stakingPoolMiddleware:** Staking pool middleware address (automatically fetches current staking pool added to the official MetalSwap DAO). + +- **tokenAddress:** ERC20 XMT token address. + +## Examples + +```JSON +[ + { + "name": "EOA token holders and staking pool participants", + "strategy": { + "name": "holders-and-staking-pools", + "params": { + "stakingPoolMiddlewareAddress": "0x99f0dD3aB8a94b01AD3C00B22f605394bfC03bF8", + "tokenAddress": "0x3E5D9D8a63CC8a88748f229999CF59487e90721e", + "symbol": "XMT", + "decimals": 18 + } + }, + "network": "1", + "addresses": [ + "0x59e110d2E5353500106AD1D79931054cdd74Ac7C", + "0xeFd52DCFACC73c8f96e143DFa7957C644D3466f1", + "0x0EBe1447634d9ACCF94F020535De4674d61aaf81", + "0x583CAf74d967dD0cc0F82968263A9b541014492A", + "0x75daeC947e200864D5bB20aFe5B60E084b5Bd155", + "0x1e75C0eEE13678260bfdD156272BBA9a1123d088", + "0x494d9a664D2be7e6824118d4a494a740df1dcC17", + "0xA6904f85cbf670eD8F834F2AfDcb9D9cB29173B6", + "0xD132D1a418d350a938C733EC8f1fcD22Edd3f448", + "0xE2A8fbEe6D1d0315bF7a06a8483233e2d619AC75", + "0xAF58ac3C1141b178DFa11cFA85DB4C0FD5646A90", + "0xd94a0e2aB6C08e1884D3187FAc0E83116c644c60", + "0xbF35741a0C151fbDc37Dad5C6b8a14cD21277CF4", + "0x54c9eb4D8B1df9D7A23ca30f3B9B03F9F4c9CA27", + "0xa893522dc7874746664126dC330fdfC7b7749b05", + "0x05c2974d048D90EC5Bfa124B6369396727B900fd", + "0xd11D7D2cb0aFF72A61Df37fD016EE1bd9F180633", + "0xb62990101E92C7e5809e48e7343f70d86d7E004C", + "0x8aaE7dAad73dcaD1Fdf145163941B996c672589A" + ], + "snapshot": 18220909 + } +] +``` \ No newline at end of file diff --git a/src/strategies/eoa-balance-and-staking-pools/examples.json b/src/strategies/eoa-balance-and-staking-pools/examples.json new file mode 100644 index 000000000..f150a5226 --- /dev/null +++ b/src/strategies/eoa-balance-and-staking-pools/examples.json @@ -0,0 +1,37 @@ +[ + { + "name": "EOA token holders and staking pool participants", + "strategy": { + "name": "eoa-balance-and-staking-pools", + "params": { + "stakingPoolMiddlewareAddress": "0x99f0dD3aB8a94b01AD3C00B22f605394bfC03bF8", + "tokenAddress": "0x3E5D9D8a63CC8a88748f229999CF59487e90721e", + "symbol": "XMT", + "decimals": 18 + } + }, + "network": "1", + "addresses": [ + "0x59e110d2E5353500106AD1D79931054cdd74Ac7C", + "0xeFd52DCFACC73c8f96e143DFa7957C644D3466f1", + "0x0EBe1447634d9ACCF94F020535De4674d61aaf81", + "0x583CAf74d967dD0cc0F82968263A9b541014492A", + "0x75daeC947e200864D5bB20aFe5B60E084b5Bd155", + "0x1e75C0eEE13678260bfdD156272BBA9a1123d088", + "0x494d9a664D2be7e6824118d4a494a740df1dcC17", + "0xA6904f85cbf670eD8F834F2AfDcb9D9cB29173B6", + "0xD132D1a418d350a938C733EC8f1fcD22Edd3f448", + "0xE2A8fbEe6D1d0315bF7a06a8483233e2d619AC75", + "0xAF58ac3C1141b178DFa11cFA85DB4C0FD5646A90", + "0xd94a0e2aB6C08e1884D3187FAc0E83116c644c60", + "0xbF35741a0C151fbDc37Dad5C6b8a14cD21277CF4", + "0x54c9eb4D8B1df9D7A23ca30f3B9B03F9F4c9CA27", + "0xa893522dc7874746664126dC330fdfC7b7749b05", + "0x05c2974d048D90EC5Bfa124B6369396727B900fd", + "0xd11D7D2cb0aFF72A61Df37fD016EE1bd9F180633", + "0xb62990101E92C7e5809e48e7343f70d86d7E004C", + "0x8aaE7dAad73dcaD1Fdf145163941B996c672589A" + ], + "snapshot": 18220909 + } +] diff --git a/src/strategies/eoa-balance-and-staking-pools/index.ts b/src/strategies/eoa-balance-and-staking-pools/index.ts new file mode 100644 index 000000000..275e18f89 --- /dev/null +++ b/src/strategies/eoa-balance-and-staking-pools/index.ts @@ -0,0 +1,72 @@ +import { formatEther } from '@ethersproject/units'; +import { multicall } from '../../utils'; +import { BigNumber } from '@ethersproject/bignumber'; + +export const author = 'DEFI-Foundation'; +export const version = '0.1.1'; + +const tokenAbi = [ + 'function balanceOf(address account) external view returns (uint256)' +]; + +const abiStakingPool = [ + 'function getSmartPoolVotes (address account, uint256 blockNumber) public view returns (uint256 votes)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = + typeof snapshot === 'number' + ? snapshot + : await provider.getBlockNumber(snapshot); + + const { stakingPoolMiddlewareAddress, tokenAddress } = options; + + const tokenResponse: BigNumber[] = await multicall( + network, + provider, + tokenAbi, + addresses.map((address: any) => { + return [tokenAddress, 'balanceOf', [address.toLowerCase()]]; + }), + { blockTag } + ); + + const tokenBalances = Object.fromEntries( + Object.entries(tokenResponse).map(([address, balance]) => [ + address, + formatEther(balance.toString()) + ]) + ); + + const poolVotes = await multicall( + network, + provider, + abiStakingPool, + addresses.map((address: any) => { + return [ + stakingPoolMiddlewareAddress, + 'getSmartPoolVotes', + [address.toLowerCase(), blockTag] + ]; + }), + { blockTag } + ); + + return Object.fromEntries( + poolVotes.map((value, index) => [ + addresses[index], + parseFloat( + formatEther(value.votes.toString()) ?? + 0 + +tokenBalances[addresses[index]] ?? + 0 + ) + ]) + ); +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index dc703a5af..c830c8494 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -465,6 +465,7 @@ import * as friendTech from './friend-tech'; import * as moonbase from './moonbase'; import * as dssVestUnpaid from './dss-vest-unpaid'; import * as dssVestBalanceAndUnpaid from './dss-vest-balance-and-unpaid'; +import * as eoaBalanceAndStakingPools from './eoa-balance-and-staking-pools'; const strategies = { 'cap-voting-power': capVotingPower, @@ -938,7 +939,8 @@ const strategies = { 'sd-vote-boost-twavp-v3': sdVoteBoostTWAVPV3, moonbase: moonbase, 'dss-vest-unpaid': dssVestUnpaid, - 'dss-vest-balance-and-unpaid': dssVestBalanceAndUnpaid + 'dss-vest-balance-and-unpaid': dssVestBalanceAndUnpaid, + 'eoa-balance-and-staking-pools': eoaBalanceAndStakingPools }; Object.keys(strategies).forEach(function (strategyName) { From ae535af09eac8821e52ae26390d793ecae791dbd Mon Sep 17 00:00:00 2001 From: omahs <73983677+omahs@users.noreply.github.com> Date: Fri, 6 Oct 2023 10:27:56 +0200 Subject: [PATCH 511/815] Fix typos (#1303) * fix typos * fix typos * fix typo * fix typos * fix typo * fix typos --- src/strategies/api/README.md | 2 +- src/strategies/brightid/README.md | 4 ++-- src/strategies/ctoken/README.md | 4 ++-- .../hopr-stake-and-balance-qv/README.md | 16 ++++++++-------- .../masterchef-pool-balance-price/README.md | 4 ++-- src/strategies/pancake/README.md | 2 +- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/strategies/api/README.md b/src/strategies/api/README.md index dfebc906b..7525ada6a 100644 --- a/src/strategies/api/README.md +++ b/src/strategies/api/README.md @@ -2,7 +2,7 @@ Voting strategy using a REST API endpoint. Number of votes depends on the return of the API endpoint. -## Cosntructing the API URL +## Constructing the API URL This strategy will create an `api_url` based on the supplied parameters and the Proposal&Space settings. `api_url` is constructed as such: diff --git a/src/strategies/brightid/README.md b/src/strategies/brightid/README.md index 6d13e591d..86cc8849e 100644 --- a/src/strategies/brightid/README.md +++ b/src/strategies/brightid/README.md @@ -7,8 +7,8 @@ This strategy returns a score of 1 for voters verified in a BrightID user regist Public registries are maintained by BrightID and can be used if a DAO has no interest on setting one up themselves. -Here is an example of parameters for using an public registry contract: -Note that when using an public registry, the network is always set to IDChain(74). +Here is an example of parameters for using a public registry contract: +Note that when using a public registry, the network is always set to IDChain(74). ```json { diff --git a/src/strategies/ctoken/README.md b/src/strategies/ctoken/README.md index c7f477140..95ac6a7d2 100644 --- a/src/strategies/ctoken/README.md +++ b/src/strategies/ctoken/README.md @@ -1,10 +1,10 @@ # Contract call strategy -Allows for calculating the voting weight of cToken holders. This strategy allows for invalidating borrowers from voting and incorperating a waiting period between minting (or receiving) cTokens and votes becoming availible. +Allows for calculating the voting weight of cToken holders. This strategy allows for invalidating borrowers from voting and incorporating a waiting period between minting (or receiving) cTokens and votes becoming available. ## Params -- `offsetCheck` - Offset (or waiting period) between minting and voting becoming availible +- `offsetCheck` - Offset (or waiting period) between minting and voting becoming available - `borrowingRestricted` - If true, borrowers will have a 0 voting weight ## Examples diff --git a/src/strategies/hopr-stake-and-balance-qv/README.md b/src/strategies/hopr-stake-and-balance-qv/README.md index 8d50dd516..f66c4d948 100644 --- a/src/strategies/hopr-stake-and-balance-qv/README.md +++ b/src/strategies/hopr-stake-and-balance-qv/README.md @@ -13,19 +13,19 @@ where: ## Parameters - "tokenAddress": Contract address of HOPR token on mainnet. Value should be `"0xf5581dfefd8fb0e4aec526be659cfab1f8c781da"` - "symbol": Token Symbol. Value should be `"HOPR"`. -- "season": Number of the on-going season. E.g. `7`. +- "season": Number of the ongoing season. E.g. `7`. - "fallbackGnosisBlock": Fallback block number on Gnosis chain, in case Gnosis block number cannot be translated from Ethereum mainnet due to subgraph issues. E.g. `27852687`, -- "subgraphStudioProdQueryApiKey": Production decetralized subgraph studio query API key. If no key can be provided, use `null`. +- "subgraphStudioProdQueryApiKey": Production decentralized subgraph studio query API key. If no key can be provided, use `null`. - "subgraphStudioDevAccountId": Development subgraph studio account ID. Note that this ID should not be exposed normally. If unknown, use `null`. -- "subgraphHostedAccountName": Legacy hosted subgraph account name. Vallue is `"hoprnet"`. -- "useStake": If the staking program should be consided. If `false`, `S1 + S2 === 0`. Value should be set to `true`. -- "useHoprOnGnosis": If tokens on Gnosis chain should be consided. If `false`, `B2 + B3 === 0`. Value should be set to `true`. -- "useHoprOnMainnet": If tokens on Ethereum mainnet should be consided. If `false`, `B1 === 0`. Value should be set to `true`. -- "subgraphStudioProdAllSeasonQueryId": Production stake all season subgraph ID .Value is `"DrkbaCvNGVcNH1RghepLRy6NSHFi8Dmwp4T2LN3LqcjY"`. +- "subgraphHostedAccountName": Legacy hosted subgraph account name. Value is `"hoprnet"`. +- "useStake": If the staking program should be considered. If `false`, `S1 + S2 === 0`. Value should be set to `true`. +- "useHoprOnGnosis": If tokens on Gnosis chain should be considered. If `false`, `B2 + B3 === 0`. Value should be set to `true`. +- "useHoprOnMainnet": If tokens on Ethereum mainnet should be considered. If `false`, `B1 === 0`. Value should be set to `true`. +- "subgraphStudioProdAllSeasonQueryId": Production stake all season subgraph ID. Value is `"DrkbaCvNGVcNH1RghepLRy6NSHFi8Dmwp4T2LN3LqcjY"`. - "subgraphStudioDevAllSeasonVersion": Latest development version of the stake all season subgraph. E.g. `"v0.0.9"` - "subgraphStudioDevAllSeasonSubgraphName": Name of the staking subgraph in Graph Studio. Value should be `"hopr-stake-all-seasons"`. - "subgraphHostedAllSeasonSubgraphName": Name of the staking subgraph in Graph Hosted service. Value should be `"hopr-stake-all-seasons"`. - "subgraphStudioProdHoprOnGnosisQueryId": Latest development version of the HOPR token balances on Gnosis subgraph. Value should be `"njToE7kpetd3P9sJdYQPSq6yQjBs7w9DahQpBj6WAoD"`. - "subgraphStudioDevHoprOnGnosisSubgraphName": Name of the HOPR token balances on Gnosis subgraph in Graph Studio. Value should be "hopr-on-gnosis"` - "subgraphStudioDevHoprOnGnosisVersion": Latest development version of the HOPR token balances on Gnosis subgraph. E.g. "v0.0.2"` -- "subgraphHostedHoprOnGnosisSubgraphName": Name of the the HOPR token balances on Gnosis in Graph Hosted service. Value should be `"hopr-on-xdai"` +- "subgraphHostedHoprOnGnosisSubgraphName": Name of the HOPR token balances on Gnosis in Graph Hosted service. Value should be `"hopr-on-xdai"` diff --git a/src/strategies/masterchef-pool-balance-price/README.md b/src/strategies/masterchef-pool-balance-price/README.md index 2781f46ad..8b60d7f01 100644 --- a/src/strategies/masterchef-pool-balance-price/README.md +++ b/src/strategies/masterchef-pool-balance-price/README.md @@ -6,7 +6,7 @@ This strategy gets the balance or price of any combination of tokens for a pool It allows to get the balance or price of any of the pool pair tokens separately or the combination of both. -Optionally, an anti-whale measure can be applied to reduce the impact of big wallets in the the resulting value. +Optionally, an anti-whale measure can be applied to reduce the impact of big wallets in the resulting value. The price is sourced from CoinGecko. @@ -14,7 +14,7 @@ The price is sourced from CoinGecko. - **chefAddress:** masterchef contract address -- **pid:** mastechef pool id (starting with zero) +- **pid:** masterchef pool id (starting with zero) - **uniPairAddress:** Address of a uniswap pair (or a sushi pair or any other with the same interface) - If the uniPairAddress option is provided, converts staked LP token balance to base token balance (based on the pair total supply and base token reserve) diff --git a/src/strategies/pancake/README.md b/src/strategies/pancake/README.md index 5a0b734fe..97daeff86 100644 --- a/src/strategies/pancake/README.md +++ b/src/strategies/pancake/README.md @@ -1,6 +1,6 @@ # Contract call strategy -Allows the tokens staked in chef conttracts to be used to calculate voter scores. +Allows the tokens staked in chef contracts to be used to calculate voter scores. ## Examples From ec1cc158b53353508927a2576b2045fbeff44167 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Fri, 6 Oct 2023 15:00:37 +0530 Subject: [PATCH 512/815] [api-v2] Send secret in header to know requests are coming from snapshot (#1301) * [api-v2] Send secret in header to know requests are coming from snapshot * [api-v2] Send secret in header to know requests are coming from snapshot --- .env.example | 3 +++ src/strategies/api-v2/index.ts | 7 ++++++- src/utils.ts | 5 +++++ 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 .env.example diff --git a/.env.example b/.env.example new file mode 100644 index 000000000..e8f1655fe --- /dev/null +++ b/.env.example @@ -0,0 +1,3 @@ +SNAPSHOT_API_STRATEGY_SALT=12345 # Salt for the snapshot API strategy to send a key in header (optional) +PASSPORT_API_KEY= # API key for the passport API (optional for other strategies) +PASSPORT_SCORER_ID= # Scorer ID for the passport API (optional for other strategies) diff --git a/src/strategies/api-v2/index.ts b/src/strategies/api-v2/index.ts index a7903c608..505e6804d 100644 --- a/src/strategies/api-v2/index.ts +++ b/src/strategies/api-v2/index.ts @@ -1,6 +1,7 @@ import { getAddress } from '@ethersproject/address'; import fetch from 'cross-fetch'; import { formatUnits } from '@ethersproject/units'; +import { sha256 } from '../../utils'; export const author = 'snapshot-labs'; export const version = '0.1.0'; @@ -37,12 +38,16 @@ export async function strategy( }; body = JSON.stringify(requestBody); } + const snapshotSecretHeader = sha256( + `${url}${process.env.SNAPSHOT_API_STRATEGY_SALT}` + ); const response = await fetch(url, { method, headers: { Accept: 'application/json', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', + 'X-Snapshot-API-Strategy-Secret': snapshotSecretHeader }, body }); diff --git a/src/utils.ts b/src/utils.ts index ed4d1372c..f83ed6012 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -3,6 +3,11 @@ import _strategies from './strategies'; import snapshot from '@snapshot-labs/snapshot.js'; import { getDelegations } from './utils/delegation'; import { getVp, getDelegations as getCoreDelegations } from './utils/vp'; +import { createHash } from 'crypto'; + +export function sha256(str) { + return createHash('sha256').update(str).digest('hex'); +} async function callStrategy(space, network, addresses, strategy, snapshot) { if ( From ccfecb7956f18538205e2d478eb46539b200db19 Mon Sep 17 00:00:00 2001 From: Manboy <2156509+manboy-eth@users.noreply.github.com> Date: Sat, 7 Oct 2023 10:47:44 +0200 Subject: [PATCH 513/815] [delegate-registry-v2] Add the delegate registry v2 startegy (#1205) * Add delegate-registry strategy * Rename strategy * Make it possible to add a cutom backend URL * Update index.ts * Update index.ts * Update src/strategies/delegate-registry-v2/examples.json * Update src/strategies/delegate-registry-v2/examples.json * Fix author * Add doc * Add the `strategy-zero-gated` validation strategy * Update src/strategies/delegate-registry-v2/index.ts Co-authored-by: Chaitanya * Add strategies into the delegation-registry-v2 params * Add todo * Remove the zero-gated-strategy * Full implementation with strategies wrapped in the strategy param * [Delegation Registry 2] Set the maximum number of trategise to 8 --------- Co-authored-by: Chaitanya --- src/strategies/delegate-registry-v2/README.md | 11 ++ .../delegate-registry-v2/examples.json | 45 ++++++++ src/strategies/delegate-registry-v2/index.ts | 109 ++++++++++++++++++ src/strategies/index.ts | 2 + 4 files changed, 167 insertions(+) create mode 100644 src/strategies/delegate-registry-v2/README.md create mode 100644 src/strategies/delegate-registry-v2/examples.json create mode 100644 src/strategies/delegate-registry-v2/index.ts diff --git a/src/strategies/delegate-registry-v2/README.md b/src/strategies/delegate-registry-v2/README.md new file mode 100644 index 000000000..42730b585 --- /dev/null +++ b/src/strategies/delegate-registry-v2/README.md @@ -0,0 +1,11 @@ +# Delegate Registry v2 + +A general-purpose delegate registry. + +In order to utilize this, the 'Strategy Zero Gated' validation strategy is necessary. This is to prevent the delegator from also using the votes that have been delegated. + +This strategy: + +- returns a score of 0 for addresses that are delegating to other addresses (PS: addresses that return a score of 0 should not be allowed to vote), +- returns a score greater than 0 for addresses that are delegated to and are not delegating (PS: only the amount delegated to the address is returned; this needs to be merged with the scores from other strategies in the space to get the addresses total score), +- returns nothing for addresses that are not delegating to other addresses or delegated to. diff --git a/src/strategies/delegate-registry-v2/examples.json b/src/strategies/delegate-registry-v2/examples.json new file mode 100644 index 000000000..930f4c022 --- /dev/null +++ b/src/strategies/delegate-registry-v2/examples.json @@ -0,0 +1,45 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "delegate-registry-v2", + "params": { + "backendUrl": "https://delegate-registry-backend.vercel.app", + "strategies": [ + { + "name": "erc20-balance-of", + "params": { + "address": "0x6b175474e89094c44da98b954eedeac495271d0f", + "symbol": "DAI", + "decimals": 18 + } + }, + { + "name": "gno", + "params": { + "symbol": "GNO", + "decimals": 18, + "SUBGRAPH_URL": "https://api.thegraph.com/subgraphs/id/QmduKVUHCPjR5tmNEgooXHBMGKqDJWrUPdp6dEMeJM6Kqa" + } + } + ] + } + }, + "network": "1", + "addresses": [ + "0x000e37ed92d86a7667f520c53b73b01ff5c206eb", + "0x000dbf2733da51135c1b21c8ef71a3d474383f0d", + "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", + "0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11", + "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", + "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", + "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", + "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e", + "0x1d5E65a087eBc3d03a294412E46CE5D6882969f4", + "0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11", + "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", + "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad" + ], + "snapshot": 17463998 + } +] diff --git a/src/strategies/delegate-registry-v2/index.ts b/src/strategies/delegate-registry-v2/index.ts new file mode 100644 index 000000000..6304fee96 --- /dev/null +++ b/src/strategies/delegate-registry-v2/index.ts @@ -0,0 +1,109 @@ +import fetch from 'cross-fetch'; +import { StaticJsonRpcProvider } from '@ethersproject/providers'; +import { Strategy } from '@snapshot-labs/snapshot.js/dist/voting/types'; +import { getScoresDirect } from '../../utils'; +import { getAddress } from '@ethersproject/address'; + +export const author = 'gnosis'; +export const version = '0.0.1'; + +const DEFAULT_BACKEND_URL = 'https://delegate-registry-backend.vercel.app'; + +type Params = { + backendUrl: string; + strategies: Strategy[]; +}; + +/* + This strategy: + - returns a score of 0 for addresses that are delegating to other addresses (PS: addresses that returns a score of 0, should not be allowed to vote), + - returns a score greater than 0, for addresses that are delegated to (PS: only the amount delegated to the address us returned, this needs to be merged with the scores from other strategies in the space), + - returns nothing for addresses that are not delegating to other addresses or delegated to. +*/ +export async function strategy( + space: string, + network: string, + provider: StaticJsonRpcProvider, + addresses: string[], + options: Params = { backendUrl: DEFAULT_BACKEND_URL, strategies: [] }, + snapshot: string | number +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + if (options.strategies.length > 8) + throw new Error('Maximum 8 strategies allowed'); + + const response = await fetch( + `${options.backendUrl}/api/${space}/snapshot/${blockTag}/strategy-formatted-vote-weights`, + { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + addresses: addresses, + strategies: options.strategies + }) + } + ); + + const delegationScores = (await response.json()) as [ + address: string, + voteWeight: string + ][]; + + // gets an array of all addresses that are in the addresses array, but not present in the response + const addressesNotDelegatingOrDelegatedTo = addresses.filter( + (address) => !delegationScores.find((score) => score[0] === address) + ); + + const addressesDelegating = delegationScores.filter( + (score) => score[1] === '0' + ); + + const addressesDelegatedTo = delegationScores.filter( + (score) => score[1] !== '0' + ); + + const addressesOwnScore = await getScoresDirect( + space, + options.strategies, + network, + provider, + [ + ...addressesNotDelegatingOrDelegatedTo, + ...addressesDelegatedTo.map(([address]) => address) + ], + snapshot + ); + + const delegationObject = addressesDelegatedTo.reduce( + (pre, [address, score]) => { + pre[getAddress(address)] = score; + return pre; + }, + {} + ); + + const addressesScores = addressesOwnScore.reduce((pre, address) => { + const addressKeys = Object.keys(address); + const addressValues = Object.values(address); + addressKeys.forEach((key, index) => { + if (pre.hasOwnProperty(key)) { + pre[getAddress(key)] = pre[getAddress(key)] + addressValues[index]; + } else { + pre[getAddress(key)] = addressValues[index]; + } + }); + return pre; + }, delegationObject); + + // add a 0 score for all addressesDelegating + const finalScores = addressesDelegating.reduce((pre, [address]) => { + pre[getAddress(address)] = 0; + return pre; + }, addressesScores); + + return finalScores; +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index c830c8494..ccd16428b 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -451,6 +451,7 @@ import * as erc721CollateralHeld from './erc721-collateral-held'; import * as starlayVeBalanceOfLockerId from './starlay-ve-balance-of-locker-id'; import * as winrStaking from './winr-staking'; import * as spaceid from './spaceid'; +import * as delegateRegistryV2 from './delegate-registry-v2'; import * as hatsProtocolSingleVotePerOrg from './hats-protocol-single-vote-per-org'; import * as karmaDiscordRoles from './karma-discord-roles'; import * as seedifyHoldStakingFarming from './seedify-cumulative-voting-power-hodl-staking-farming'; @@ -925,6 +926,7 @@ const strategies = { 'starlay-ve-balance-of-locker-id': starlayVeBalanceOfLockerId, 'winr-staking': winrStaking, spaceid, + 'delegate-registry-v2': delegateRegistryV2, 'hats-protocol-single-vote-per-org': hatsProtocolSingleVotePerOrg, 'karma-discord-roles': karmaDiscordRoles, 'seedify-cumulative-voting-power-hodl-staking-farming': From 25517d3452d764b577181f3cac3db3735efbade9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 8 Oct 2023 22:52:26 +0530 Subject: [PATCH 514/815] Automated lint (#1306) Co-authored-by: ChaituVR --- .../examples.json | 70 +++++++++---------- .../sd-vote-boost-twavp-v3/index.ts | 50 +++++++------ 2 files changed, 65 insertions(+), 55 deletions(-) diff --git a/src/strategies/eoa-balance-and-staking-pools/examples.json b/src/strategies/eoa-balance-and-staking-pools/examples.json index f150a5226..8ad451844 100644 --- a/src/strategies/eoa-balance-and-staking-pools/examples.json +++ b/src/strategies/eoa-balance-and-staking-pools/examples.json @@ -1,37 +1,37 @@ [ - { - "name": "EOA token holders and staking pool participants", - "strategy": { - "name": "eoa-balance-and-staking-pools", - "params": { - "stakingPoolMiddlewareAddress": "0x99f0dD3aB8a94b01AD3C00B22f605394bfC03bF8", - "tokenAddress": "0x3E5D9D8a63CC8a88748f229999CF59487e90721e", - "symbol": "XMT", - "decimals": 18 - } - }, - "network": "1", - "addresses": [ - "0x59e110d2E5353500106AD1D79931054cdd74Ac7C", - "0xeFd52DCFACC73c8f96e143DFa7957C644D3466f1", - "0x0EBe1447634d9ACCF94F020535De4674d61aaf81", - "0x583CAf74d967dD0cc0F82968263A9b541014492A", - "0x75daeC947e200864D5bB20aFe5B60E084b5Bd155", - "0x1e75C0eEE13678260bfdD156272BBA9a1123d088", - "0x494d9a664D2be7e6824118d4a494a740df1dcC17", - "0xA6904f85cbf670eD8F834F2AfDcb9D9cB29173B6", - "0xD132D1a418d350a938C733EC8f1fcD22Edd3f448", - "0xE2A8fbEe6D1d0315bF7a06a8483233e2d619AC75", - "0xAF58ac3C1141b178DFa11cFA85DB4C0FD5646A90", - "0xd94a0e2aB6C08e1884D3187FAc0E83116c644c60", - "0xbF35741a0C151fbDc37Dad5C6b8a14cD21277CF4", - "0x54c9eb4D8B1df9D7A23ca30f3B9B03F9F4c9CA27", - "0xa893522dc7874746664126dC330fdfC7b7749b05", - "0x05c2974d048D90EC5Bfa124B6369396727B900fd", - "0xd11D7D2cb0aFF72A61Df37fD016EE1bd9F180633", - "0xb62990101E92C7e5809e48e7343f70d86d7E004C", - "0x8aaE7dAad73dcaD1Fdf145163941B996c672589A" - ], - "snapshot": 18220909 - } + { + "name": "EOA token holders and staking pool participants", + "strategy": { + "name": "eoa-balance-and-staking-pools", + "params": { + "stakingPoolMiddlewareAddress": "0x99f0dD3aB8a94b01AD3C00B22f605394bfC03bF8", + "tokenAddress": "0x3E5D9D8a63CC8a88748f229999CF59487e90721e", + "symbol": "XMT", + "decimals": 18 + } + }, + "network": "1", + "addresses": [ + "0x59e110d2E5353500106AD1D79931054cdd74Ac7C", + "0xeFd52DCFACC73c8f96e143DFa7957C644D3466f1", + "0x0EBe1447634d9ACCF94F020535De4674d61aaf81", + "0x583CAf74d967dD0cc0F82968263A9b541014492A", + "0x75daeC947e200864D5bB20aFe5B60E084b5Bd155", + "0x1e75C0eEE13678260bfdD156272BBA9a1123d088", + "0x494d9a664D2be7e6824118d4a494a740df1dcC17", + "0xA6904f85cbf670eD8F834F2AfDcb9D9cB29173B6", + "0xD132D1a418d350a938C733EC8f1fcD22Edd3f448", + "0xE2A8fbEe6D1d0315bF7a06a8483233e2d619AC75", + "0xAF58ac3C1141b178DFa11cFA85DB4C0FD5646A90", + "0xd94a0e2aB6C08e1884D3187FAc0E83116c644c60", + "0xbF35741a0C151fbDc37Dad5C6b8a14cD21277CF4", + "0x54c9eb4D8B1df9D7A23ca30f3B9B03F9F4c9CA27", + "0xa893522dc7874746664126dC330fdfC7b7749b05", + "0x05c2974d048D90EC5Bfa124B6369396727B900fd", + "0xd11D7D2cb0aFF72A61Df37fD016EE1bd9F180633", + "0xb62990101E92C7e5809e48e7343f70d86d7E004C", + "0x8aaE7dAad73dcaD1Fdf145163941B996c672589A" + ], + "snapshot": 18220909 + } ] diff --git a/src/strategies/sd-vote-boost-twavp-v3/index.ts b/src/strategies/sd-vote-boost-twavp-v3/index.ts index 67c9e8ba0..9f67a18ae 100644 --- a/src/strategies/sd-vote-boost-twavp-v3/index.ts +++ b/src/strategies/sd-vote-boost-twavp-v3/index.ts @@ -30,14 +30,14 @@ export async function strategy( if (options.whiteListedAddress.length > 20) { throw new Error('maximum of 20 whitelisted address'); } - + // Maximum of 500 pools address if (options.pools.length > 500) { throw new Error('maximum of 500 pools'); } const calls: any[] = []; - for(const pool of options.pools) { + for (const pool of options.pools) { calls.push([options.sdToken, 'balanceOf', [pool]]); } calls.push([options.veToken, 'balanceOf', [options.liquidLocker]]); @@ -51,7 +51,7 @@ export async function strategy( } else { blockTag = await provider.getBlockNumber(); } - + // Create block list const blockList = getPreviousBlocks( blockTag, @@ -81,19 +81,12 @@ export async function strategy( loopCalls.push([options.sdTokenGauge, 'totalSupply']); loopCalls.push(...workingBalanceQuery); loopCalls.push(...calls); - } else { loopCalls.push(...workingBalanceQuery); } response.push( - await multicall( - network, - provider, - abi, - loopCalls, - { blockTag } - ) + await multicall(network, provider, abi, loopCalls, { blockTag }) ); } @@ -116,13 +109,26 @@ export async function strategy( } if (addresses[i].toLowerCase() === options.botAddress.toLowerCase()) { - const poolsBalances = options.pools.map(() => response[response.length - 1].shift()); - const sumPoolsBalance = poolsBalances.reduce((acc, balance) => acc.add(balance[0]), BigNumber.from(0)); + const poolsBalances = options.pools.map(() => + response[response.length - 1].shift() + ); + const sumPoolsBalance = poolsBalances.reduce( + (acc, balance) => acc.add(balance[0]), + BigNumber.from(0) + ); - const votingPowerLiquidLocker = response[response.length - 1].shift()[0]; + const votingPowerLiquidLocker = + response[response.length - 1].shift()[0]; - const total = sumPoolsBalance.mul(4).div(10).mul(votingPowerLiquidLocker).div(sdTokenGaugeTotalSupply); - return [addresses[i], Number(parseFloat(formatUnits(total, options.decimals)))]; + const total = sumPoolsBalance + .mul(4) + .div(10) + .mul(votingPowerLiquidLocker) + .div(sdTokenGaugeTotalSupply); + return [ + addresses[i], + Number(parseFloat(formatUnits(total, options.decimals))) + ]; } else { // Get average working balance. const averageWorkingBalance = average( @@ -131,20 +137,24 @@ export async function strategy( options.whiteListedAddress ); - const averageWorkingBalanceF = parseFloat(formatUnits(averageWorkingBalance, 18)); - const sdTokenGaugeTotalSupplyF = parseFloat(formatUnits(sdTokenGaugeTotalSupply, 18)); + const averageWorkingBalanceF = parseFloat( + formatUnits(averageWorkingBalance, 18) + ); + const sdTokenGaugeTotalSupplyF = parseFloat( + formatUnits(sdTokenGaugeTotalSupply, 18) + ); const workingSupplyF = parseFloat(formatUnits(workingSupply, 18)); // Calculate voting power. const votingPower = workingSupply != 0 - ? averageWorkingBalanceF * sdTokenGaugeTotalSupplyF / workingSupplyF + ? (averageWorkingBalanceF * sdTokenGaugeTotalSupplyF) / + workingSupplyF : 0; // Return address and voting power return [addresses[i], Number(votingPower)]; } - }) ); } From 3b0e0d4fc382c73504c2c7c65feca20f63f20b07 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 8 Oct 2023 23:32:55 +0530 Subject: [PATCH 515/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.7.3 (#1302) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 852e47af0..390ddd08c 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.7.2", + "@snapshot-labs/snapshot.js": "^0.7.3", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index e4222f70f..923d0890d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.7.2": - version "0.7.2" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.7.2.tgz#fd0a9d5e161b9cc088771efc26f6c2bc4e887177" - integrity sha512-rdrS0Fj5PHYSlQrfsrNb7Vv7olRA+Lbe7f7DUNgOfzI9tQvIJJFMrQqxafyiWfnJnk4ild5iOcU5uPQPHjYVjw== +"@snapshot-labs/snapshot.js@^0.7.3": + version "0.7.3" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.7.3.tgz#54984f135b78c7d3d7d26484d7275a0793d5bc9c" + integrity sha512-T+cjaJ9ZPLlKicPTxuN6FIQXUgADjvit/QFmwsOlGWxpMzAQ79k5rWm0ldex96JTPIFucUMgqHqWLA6UZwmmTQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From ed02dc46e7ac7594cbdbba456001f5353ef1999c Mon Sep 17 00:00:00 2001 From: skyrockjsdev <144429128+skyrockjsdev@users.noreply.github.com> Date: Mon, 9 Oct 2023 14:46:55 +0300 Subject: [PATCH 516/815] [erc20-token-and-single-lp-weighted] add erc20-token-and-single-lp-weighted strategy (#1304) * [erc20-token-and-single-lp-weighted] add erc20-token-and-single-lp-weighted strategy * Update src/strategies/erc20-token-and-single-lp-weighted/index.ts Co-authored-by: Chaitanya --------- Co-authored-by: Chaitanya --- .../README.md | 19 ++++ .../examples.json | 25 +++++ .../index.ts | 91 +++++++++++++++++++ .../schema.json | 36 ++++++++ src/strategies/index.ts | 2 + 5 files changed, 173 insertions(+) create mode 100644 src/strategies/erc20-token-and-single-lp-weighted/README.md create mode 100644 src/strategies/erc20-token-and-single-lp-weighted/examples.json create mode 100644 src/strategies/erc20-token-and-single-lp-weighted/index.ts create mode 100644 src/strategies/erc20-token-and-single-lp-weighted/schema.json diff --git a/src/strategies/erc20-token-and-single-lp-weighted/README.md b/src/strategies/erc20-token-and-single-lp-weighted/README.md new file mode 100644 index 000000000..856bc7aed --- /dev/null +++ b/src/strategies/erc20-token-and-single-lp-weighted/README.md @@ -0,0 +1,19 @@ +# erc20-token-and-single-lp-weighted + +This strategy works on pancakeswap v2 style pools or contracts using token0/token1 and reserves. + +This strategy calculates the amount of the specified token within a single LP, takes both sides into account, and then uses this as a weight against the user's LP balance. + +This strategy also adds users token balance to give a token-weighted score. + +This is useful if you want to include LP and token assets and need to scale them to balance each other. + +Here is an example of a parameter: + +```json +{ + "tokenAddress": "0x06791B2117ed179dB6af1fdc8B2aA86dE76700A6", + "symbol": "WSLS", + "lpTokenAddress": "0x370165b24D97BAc5c07246976b80568985C0048B" +} +``` diff --git a/src/strategies/erc20-token-and-single-lp-weighted/examples.json b/src/strategies/erc20-token-and-single-lp-weighted/examples.json new file mode 100644 index 000000000..7b2793adb --- /dev/null +++ b/src/strategies/erc20-token-and-single-lp-weighted/examples.json @@ -0,0 +1,25 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "erc20-token-and-single-lp-weighted", + "params": { + "tokenAddress": "0x06791B2117ed179dB6af1fdc8B2aA86dE76700A6", + "symbol": "WSLS", + "lpTokenAddress": "0x370165b24D97BAc5c07246976b80568985C0048B" + } + }, + "network": "56", + "addresses": [ + "0x0504c6e9563d8756cb823fcbbf342301ddbc8066", + "0xFe0B729221f846b46B6be642425Db8326A4761FB", + "0x5e990768b0ece79f0516663a23207d4a7fd6e8f9", + "0xee7f963391afb7d1f1ec872dbe2f80ea025d0add", + "0x869191325254a82fBc858aB3cad9Bf91703Da353", + "0x011f57BD13D1cbeC630dF313B66F0339AeFE627e", + "0x2B0f0ef985b16f2C06961e409637aa7C579395eD", + "0x0AC6F108002496Ab9Ca11DCDf36c207704F29Bfa" + ], + "snapshot": 32339616 + } +] diff --git a/src/strategies/erc20-token-and-single-lp-weighted/index.ts b/src/strategies/erc20-token-and-single-lp-weighted/index.ts new file mode 100644 index 000000000..32c169f74 --- /dev/null +++ b/src/strategies/erc20-token-and-single-lp-weighted/index.ts @@ -0,0 +1,91 @@ +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller, multicall } from '../../utils'; +import { getAddress } from '@ethersproject/address'; + +export const author = 'skyrocktech'; +export const version = '0.1.0'; + +const abi = [ + 'function balanceOf(address account) external view returns (uint256)', + 'function decimals() external view returns (uint8)', + 'function token0() external view returns (address)', + 'function token1() external view returns (address)', + 'function totalSupply() external view returns (uint256)', + 'function getReserves() external view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + // fetch all token and lp contract data + + const fetchContractData = await multicall( + network, + provider, + abi, + [ + [options.lpTokenAddress, 'token0', []], + [options.lpTokenAddress, 'token1', []], + [options.lpTokenAddress, 'getReserves', []], + [options.lpTokenAddress, 'totalSupply', []], + [options.lpTokenAddress, 'decimals', []], + [options.tokenAddress, 'decimals', []] + ], + { blockTag } + ); + + // assign multicall data to variables + + const token0Address = fetchContractData[0][0]; + const token1Address = fetchContractData[1][0]; + const lpTokenReserves = fetchContractData[2]; + const lpTokenTotalSupply = fetchContractData[3][0]; + const lpTokenDecimals = fetchContractData[4][0]; + const tokenDecimals = fetchContractData[5][0]; + + // calculate single lp token weight + + let tokenWeight; + + if (token0Address === options.tokenAddress) { + tokenWeight = + parseFloat(formatUnits(lpTokenReserves._reserve0, tokenDecimals)) / + parseFloat(formatUnits(lpTokenTotalSupply, lpTokenDecimals)); + } else if (token1Address === options.tokenAddress) { + tokenWeight = + parseFloat(formatUnits(lpTokenReserves._reserve1, tokenDecimals)) / + parseFloat(formatUnits(lpTokenTotalSupply, lpTokenDecimals)); + } else { + tokenWeight = 0; + } + + const lpBalances = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => + lpBalances.call(address, options.lpTokenAddress, 'balanceOf', [address]) + ); + const lpBalancesResult: Record = + await lpBalances.execute(); + + const tokenBalances = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => + tokenBalances.call(address, options.tokenAddress, 'balanceOf', [address]) + ); + const tokenBalancesResult: Record = + await tokenBalances.execute(); + + return Object.fromEntries( + Object.entries(lpBalancesResult).map(([address, balance]) => [ + getAddress(address), + parseFloat(formatUnits(balance, lpTokenDecimals)) * tokenWeight + + parseFloat(formatUnits(tokenBalancesResult[address], tokenDecimals)) + ]) + ); +} diff --git a/src/strategies/erc20-token-and-single-lp-weighted/schema.json b/src/strategies/erc20-token-and-single-lp-weighted/schema.json new file mode 100644 index 000000000..f937c97ec --- /dev/null +++ b/src/strategies/erc20-token-and-single-lp-weighted/schema.json @@ -0,0 +1,36 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Token symbol", + "examples": ["e.g. MIST"], + "maxLength": 16 + }, + "tokenAddress": { + "type": "string", + "title": "Token address", + "examples": ["e.g. 0x88ACDd2a6425c3FaAE4Bc9650Fd7E27e0Bebb7aB"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "lpTokenAddress": { + "type": "string", + "title": "LP address", + "examples": ["e.g. 0xcd6bcca48069f8588780dfa274960f15685aee0e"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } + }, + "required": ["tokenAddress", "lpTokenAddress"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index ccd16428b..8242f8518 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -213,6 +213,7 @@ import * as membership from './membership'; import * as holdsTokens from './holds-tokens'; import * as crucibleERC20BalanceOf from './crucible-erc20-balance-of'; import * as erc20TokenAndLpWeighted from './erc20-token-and-lp-weighted'; +import * as erc20TokenAndSingleLpWeighted from './erc20-token-and-single-lp-weighted'; import * as crucibleERC20TokenAndLpWeighted from './crucible-erc20-token-and-lp-weighted'; import * as hasrock from './has-rock'; import * as flexaCapacityStaking from './flexa-capacity-staking'; @@ -692,6 +693,7 @@ const strategies = { meebitsdao, 'crucible-erc20-balance-of': crucibleERC20BalanceOf, 'erc20-token-and-lp-weighted': erc20TokenAndLpWeighted, + 'erc20-token-and-single-lp-weighted': erc20TokenAndSingleLpWeighted, 'crucible-erc20-token-and-lp-weighted': crucibleERC20TokenAndLpWeighted, 'has-rock': hasrock, 'flexa-capacity-staking': flexaCapacityStaking, From a6e305f7768d728bf026a2339851a8b5cb4f9792 Mon Sep 17 00:00:00 2001 From: DEFI FOUNDATION <106986644+DEFI-Foundation@users.noreply.github.com> Date: Mon, 9 Oct 2023 19:38:16 +0200 Subject: [PATCH 517/815] [eoa-balance-and-staking-pools] update eoa-balance-and-staking-pools strategy (#1307) * updatet eoa-balance-and-staking-pools strategy * Update src/strategies/eoa-balance-and-staking-pools/index.ts * Update src/strategies/eoa-balance-and-staking-pools/index.ts --------- Co-authored-by: Marco Braglia Co-authored-by: Chaitanya --- .../eoa-balance-and-staking-pools/index.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/strategies/eoa-balance-and-staking-pools/index.ts b/src/strategies/eoa-balance-and-staking-pools/index.ts index 275e18f89..fae805385 100644 --- a/src/strategies/eoa-balance-and-staking-pools/index.ts +++ b/src/strategies/eoa-balance-and-staking-pools/index.ts @@ -60,13 +60,12 @@ export async function strategy( ); return Object.fromEntries( - poolVotes.map((value, index) => [ - addresses[index], - parseFloat( - formatEther(value.votes.toString()) ?? - 0 + +tokenBalances[addresses[index]] ?? - 0 - ) - ]) + poolVotes.map((value, index) => { + const formattedVote = +(formatEther(value.votes.toString()) ?? 0); + const formattedBalance = +(tokenBalances[index] ?? 0); + const sum = formattedBalance + formattedVote; + + return [addresses[index], sum]; + }) ); } From 5350548ce61feae3b388e0d059c37bb1121825ba Mon Sep 17 00:00:00 2001 From: Razvan Gabriel Apostu Date: Wed, 11 Oct 2023 21:29:24 +0200 Subject: [PATCH 518/815] fix: sablier-v2 latest block sync (#1310) --- src/strategies/sablier-v2/index.ts | 4 +-- src/strategies/sablier-v2/queries.ts | 43 ++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/strategies/sablier-v2/index.ts b/src/strategies/sablier-v2/index.ts index 3967349e8..4d8ea9b2e 100644 --- a/src/strategies/sablier-v2/index.ts +++ b/src/strategies/sablier-v2/index.ts @@ -4,6 +4,7 @@ import type { StaticJsonRpcProvider } from '@ethersproject/providers'; import { deployments, policies } from './configuration'; import { + getLatestBlock, getRecipientDepositedAmounts, getRecipientReservedAmounts, getRecipientStreams, @@ -48,8 +49,7 @@ export async function strategy( options: IOptions, snapshot: number ): Promise> { - const snap = typeof snapshot === 'number' ? snapshot : undefined; - const block = snap || (await provider.getBlockNumber()) - 1; + const block = await getLatestBlock(network, provider, snapshot); const setup = { block, network, provider }; await validate(network, addresses, options); diff --git a/src/strategies/sablier-v2/queries.ts b/src/strategies/sablier-v2/queries.ts index e344f0434..6d82bec16 100644 --- a/src/strategies/sablier-v2/queries.ts +++ b/src/strategies/sablier-v2/queries.ts @@ -9,6 +9,7 @@ import type { import { abi, deployments, queries, page } from './configuration'; import { multicall, subgraphRequest } from '../../utils'; +import fetch from 'cross-fetch'; /** * Query the subgraph for all the streams owned by all recipients. @@ -438,7 +439,49 @@ async function getRecipientReservedAmounts( return { amounts }; } +async function getLatestBlock( + network: string, + provider: StaticJsonRpcProvider, + snapshot: number | 'latest' +): Promise { + try { + /** For clear numeric snapshots, assume the user picked the number on purpose */ + if (typeof snapshot === 'number') { + return snapshot; + } + + if (snapshot === 'latest') { + const endpoint = deployments[network].subgraph; + const name = endpoint.split('/subgraphs/name/')[1]; + const url = new URL('https://api.thegraph.com/index-node/graphql'); + + const query = `{indexingStatusForCurrentVersion(subgraphName: \"${name}\"){ chains { latestBlock { number }}}}`; + + const response = await fetch(url, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ query }), + credentials: 'omit' + }); + + const { data } = await response.json(); + const block = data.indexingStatusForCurrentVersion.chains[0].latestBlock; + const result = Number(block.number); + + console.log('=== SABLIER V2 ==='); + console.log(`Fetched latest subgraph indexed block at {${result}}`); + + return result; + } + } catch (error) { + console.error(error); + } + + return await provider.getBlockNumber(); +} + export { + getLatestBlock, getRecipientDepositedAmounts, getRecipientReservedAmounts, getRecipientStreams, From 6faeb19dfbfe43135eed167ff209808196066315 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Espen=20H=C3=B8jsgaard?= Date: Thu, 12 Oct 2023 17:09:59 +0200 Subject: [PATCH 519/815] [dss-vest-unpaid] Add missing blockTag to vesting contract call (#1311) --- src/strategies/dss-vest-unpaid/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/strategies/dss-vest-unpaid/index.ts b/src/strategies/dss-vest-unpaid/index.ts index bc144d87b..5347cd157 100644 --- a/src/strategies/dss-vest-unpaid/index.ts +++ b/src/strategies/dss-vest-unpaid/index.ts @@ -4,7 +4,7 @@ import { Contract } from '@ethersproject/contracts'; import { Multicaller } from '../../utils'; export const author = 'espendk'; -export const version = '1.0.0'; +export const version = '1.0.1'; // To avoid future memory issues, we limit the number of vestings supported by the strategy const MAX_VESTINGS = 500; @@ -27,7 +27,7 @@ export async function strategy( // Get the number of vestings const dssVestContract = new Contract(options.address, abi, provider); - const idCount = await dssVestContract.ids(); + const idCount = await dssVestContract.ids({ blockTag }); if (idCount > MAX_VESTINGS) { throw new Error( `Max number (${MAX_VESTINGS}) of vestings exceeded: ${idCount}` From ab6b0e27385e117bc854a381c5c928917f1e99f3 Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Thu, 12 Oct 2023 16:14:47 +0100 Subject: [PATCH 520/815] refactor: remove Sablier V2 documentation (#1312) --- src/strategies/sablier-v2/README.md | 134 ++-------------------------- 1 file changed, 6 insertions(+), 128 deletions(-) diff --git a/src/strategies/sablier-v2/README.md b/src/strategies/sablier-v2/README.md index fd1a2ffd8..4362a1b2a 100644 --- a/src/strategies/sablier-v2/README.md +++ b/src/strategies/sablier-v2/README.md @@ -1,134 +1,12 @@ # Sablier V2 Strategies -In Sablier V2, a stream creator locks up an amount of ERC-20 tokens in a contract that progressively allocates the funds to the designated -recipient. The tokens are released by the second, and the recipient can withdraw them at any time. +In Sablier V2, the sender of a payment stream first deposits a specific amount of ERC-20 tokens in a contract. Then, the contract +progressively allocates the funds to the recipient, who can access them as they become available over time. The payment +rate is influenced by various factors, including the start and end times, as well as the total amount of tokens +deposited. The strategies in this folder read the various amounts that can be found in Sablier V2 streams. -### Example Setup +## Documentation -```json -{ - "address": "0x97cb342cf2f6ecf48c1285fb8668f5a4237bf862", - "symbol": "DAI", - "decimals": 18, - "policy": "withdrawable-recipient" // recommended, -} -``` - -#### Other parameters - -Aside from this example setup, we use Snapshot's base parameters `Network`, `Snapshot` (block), and `Addresses`. - -Based on the chosen strategy, the values filled in the `Addresses` field will represent a list (>= 1) of senders or recipients. - -### Policies - -#### Primary policies - -| Policy | Methodology | -| :--------------------- | :---------------------------------------------------------------- | -| withdrawable-recipient | Tokens that are available for the stream's recipient to withdraw. | -| reserved-recipient | Tokens available for withdraw aggregated with unstreamed tokens. | - -#### Secondary policies - -These policies are designed to address specific edge cases. We strongly recommend using the primary policies. - -| Policy | Methodology | -| :------------------- | :------------------------------------------------------------------------------------ | -| deposited-recipient | Tokens that have been deposited in streams the recipient owned at snapshot time. | -| deposited-sender | Tokens that have been deposited in streams started by the sender before the snapshot. | -| streamed-recipient | Tokens that have been streamed to the recipient until the snapshot. | -| unstreamed-recipient | Tokens that have not yet been streamed to the recipient at the time of snapshot. | - -### Example - -```text -Sablier V2 Stream #000001 ---- -Deposited: TKN 1000 for 30 days -Withdrawn: TKN 450 before snapshot -Snapshot: Day 15 (midway) with a streamed amount of TKN 500 - -+------------------------+----------+ -| POLICY | POWER | -+------------------------+----------+ -| erc20-balance-of | TKN 450 | -+------------------------+----------+ -| withdrawable-recipient | TKN 50 | -+------------------------+----------+ -| reserved-recipient | TKN 550 | -+------------------------+----------+ -| deposited-recipient | TKN 1000 | -+------------------------+----------+ -| deposited-sender | TKN 1000 | -+------------------------+----------+ -| streamed-recipient | TKN 500 | -+------------------------+----------+ -| unstreamed-recipient | TKN 500 | -+------------------------+----------+ -``` - -### Recommendation - -For the best results, we recommend using the primary policies. - -1. The best option is to combine the `withdrawable-recipient` policy with `erc20-balance-of`. Doing so will aggregate - tokens streamed but not withdrawn yet, as well as tokens in the user's wallet. -2. The second best option is to combine `reserved-recipient` with `erc20-balance-of`. They will aggregate (i) tokens - streamed but not withdrawn yet, (ii) unstreamed funds (which will become available in the future), and (iii) the - tokens in the user's wallet. - -### Details and Caveats - -#### `withdrawable-recipient` ⭐️ - -The withdrawable amount counts tokens that have been streamed but not withdrawn yet by the recipient. - -This is provided using the -[`withdrawableAmountOf`](/contracts/v2/reference/core/abstracts/abstract.SablierV2Lockup#withdrawableamountof) contract -method. - -Voting power: realized (present). - -#### `reserved-recipient` ⭐️ - -The reserved amount combines tokens that have been streamed but not withdrawn yet (similar to `withdrawable-recipient`) -with tokens that haven't been streamed (which will become available in the future). Can be computed as -`reserved = withdrawable + unstreamed === deposited - withdrawn`. Canceled streams will only count the final -withdrawable amount, if any. - -Voting power: realized (present) + expected (future). - ---- - -#### `deposited-recipient` - -It aggregates historical deposits up to the snapshot time, counting only the streams owned by the recipient. - -:warning: Caveat: streaming, canceling and streaming again will cause tokens to be counted multiple times. - -#### `deposited-sender` - -It aggregates historical deposits up to the snapshot time, counting only the streams started by the sender. - -:warning: Caveats: - -- Streaming, canceling and streaming again will cause tokens to be counted multiple times. -- It takes into account streams created through [PRBProxy](https://docs.sablier.com/contracts/v2/reference/overview#periphery) instances configured through the official [Sablier Interface](https://app.sablier.com/). - -#### `streamed-recipient` - -It aggregates historical amounts that have already been streamed to the recipient. Crucially, it includes already withdrawn tokens. - -It relies on the `streamedAmountOf` methods in the [LockupLinear](https://docs.sablier.com/contracts/v2/reference/core/contract.SablierV2LockupLinear#streamedamountof) and [LockupDynamic](https://docs.sablier.com/contracts/v2/reference/core/contract.SablierV2LockupDynamic#streamedamountof) contracts. - -:warning: Caveats: - -- Using this policy alongside `erc20-balance-of` may double count tokens. In the example above, `TNK 500` was streamed, but the recipient withdrew `TKN 450`, so the total voting power would be `TKN 950`. -- If funds are recycled (streamed, withdrawn and streamed again) the voting power may be increased artificially. - -#### `unstreamed-recipient` - -The opposite of `streamed-recipient`, counting amounts that have not been streamed yet (locked, but will become available in the future). It subtracts the `streamed` amount from the initial `deposit`. For canceled streams, the unstreamed amount will be `0`. +In-depth documentation for how to use the Sablier V2 strategies is available at [docs.sablier.com](https://docs.sablier.com/contracts/v2/guides/snapshot-voting). From 9fca6ad553c6f062f75a2348973d0a517e8c72d6 Mon Sep 17 00:00:00 2001 From: Marsot Pierre Date: Thu, 12 Oct 2023 17:22:24 +0200 Subject: [PATCH 521/815] fix bot voting power (#1314) Co-authored-by: Chaitanya --- .../sd-vote-boost-twavp-v3/index.ts | 55 ++++++++----------- 1 file changed, 22 insertions(+), 33 deletions(-) diff --git a/src/strategies/sd-vote-boost-twavp-v3/index.ts b/src/strategies/sd-vote-boost-twavp-v3/index.ts index 9f67a18ae..a06c597af 100644 --- a/src/strategies/sd-vote-boost-twavp-v3/index.ts +++ b/src/strategies/sd-vote-boost-twavp-v3/index.ts @@ -30,14 +30,14 @@ export async function strategy( if (options.whiteListedAddress.length > 20) { throw new Error('maximum of 20 whitelisted address'); } - + // Maximum of 500 pools address if (options.pools.length > 500) { throw new Error('maximum of 500 pools'); } const calls: any[] = []; - for (const pool of options.pools) { + for(const pool of options.pools) { calls.push([options.sdToken, 'balanceOf', [pool]]); } calls.push([options.veToken, 'balanceOf', [options.liquidLocker]]); @@ -51,7 +51,7 @@ export async function strategy( } else { blockTag = await provider.getBlockNumber(); } - + // Create block list const blockList = getPreviousBlocks( blockTag, @@ -81,12 +81,19 @@ export async function strategy( loopCalls.push([options.sdTokenGauge, 'totalSupply']); loopCalls.push(...workingBalanceQuery); loopCalls.push(...calls); + } else { loopCalls.push(...workingBalanceQuery); } response.push( - await multicall(network, provider, abi, loopCalls, { blockTag }) + await multicall( + network, + provider, + abi, + loopCalls, + { blockTag } + ) ); } @@ -96,6 +103,11 @@ export async function strategy( // Get voting power of liquid locker const sdTokenGaugeTotalSupply = response[response.length - 1].shift()[0]; // Last response, latest block + const votingPowerLiquidLocker = response[response.length - 1].pop()[0]; + const poolsBalances = options.pools.map(() => response[response.length - 1].pop()); + const sumPoolsBalance = poolsBalances.reduce((acc, balance) => acc.add(balance[0]), BigNumber.from(0)); + const total = sumPoolsBalance.mul(4).div(10).mul(votingPowerLiquidLocker).div(sdTokenGaugeTotalSupply); + return Object.fromEntries( Array(addresses.length) .fill('x') @@ -109,26 +121,7 @@ export async function strategy( } if (addresses[i].toLowerCase() === options.botAddress.toLowerCase()) { - const poolsBalances = options.pools.map(() => - response[response.length - 1].shift() - ); - const sumPoolsBalance = poolsBalances.reduce( - (acc, balance) => acc.add(balance[0]), - BigNumber.from(0) - ); - - const votingPowerLiquidLocker = - response[response.length - 1].shift()[0]; - - const total = sumPoolsBalance - .mul(4) - .div(10) - .mul(votingPowerLiquidLocker) - .div(sdTokenGaugeTotalSupply); - return [ - addresses[i], - Number(parseFloat(formatUnits(total, options.decimals))) - ]; + return [addresses[i], Number(parseFloat(formatUnits(total, options.decimals)))]; } else { // Get average working balance. const averageWorkingBalance = average( @@ -137,24 +130,20 @@ export async function strategy( options.whiteListedAddress ); - const averageWorkingBalanceF = parseFloat( - formatUnits(averageWorkingBalance, 18) - ); - const sdTokenGaugeTotalSupplyF = parseFloat( - formatUnits(sdTokenGaugeTotalSupply, 18) - ); + const averageWorkingBalanceF = parseFloat(formatUnits(averageWorkingBalance, 18)); + const sdTokenGaugeTotalSupplyF = parseFloat(formatUnits(sdTokenGaugeTotalSupply, 18)); const workingSupplyF = parseFloat(formatUnits(workingSupply, 18)); // Calculate voting power. const votingPower = workingSupply != 0 - ? (averageWorkingBalanceF * sdTokenGaugeTotalSupplyF) / - workingSupplyF + ? averageWorkingBalanceF * sdTokenGaugeTotalSupplyF / workingSupplyF : 0; - + // Return address and voting power return [addresses[i], Number(votingPower)]; } + }) ); } From d31c3b5315a200b98bb78ac6e3afdd1a761af58b Mon Sep 17 00:00:00 2001 From: Wan <495709+wa0x6e@users.noreply.github.com> Date: Sun, 15 Oct 2023 20:11:49 +0900 Subject: [PATCH 522/815] chore: auto run linter on new commit (#1319) --- .github/workflows/build.yml | 1 - .github/workflows/fix-lint.yml | 28 +++++++++++ .github/workflows/lint.yml | 28 ++--------- package.json | 4 +- .../sd-vote-boost-twavp-v3/index.ts | 49 +++++++++++-------- 5 files changed, 64 insertions(+), 46 deletions(-) create mode 100644 .github/workflows/fix-lint.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cbe485b91..60c3f7ef6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,4 +20,3 @@ jobs: run: | yarn install --frozen-lockfile yarn build - yarn lint diff --git a/.github/workflows/fix-lint.yml b/.github/workflows/fix-lint.yml new file mode 100644 index 000000000..48449671a --- /dev/null +++ b/.github/workflows/fix-lint.yml @@ -0,0 +1,28 @@ +name: Fix lint +on: + workflow_dispatch: + schedule: + - cron: 0 10 * * 0 + +jobs: + fix-lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v1 + with: + node-version: '16.10.x' + - name: Run lint script + run: | + yarn install --frozen-lockfile + yarn lint:fix + - name: Create Pull Request + uses: peter-evans/create-pull-request@v3 + with: + commit-message: Automated lint + title: Automated lint + body: | + - Changes from lint script + + Auto-generated by Github Actions + branch: automated-lint diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 3b9e5d41d..0ef1f53ea 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,28 +1,8 @@ name: Lint -on: - workflow_dispatch: - schedule: - - cron: 0 10 * * 0 + +on: [push] jobs: lint: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v1 - with: - node-version: '16.10.x' - - name: Run lint script - run: | - yarn install --frozen-lockfile - yarn lint - - name: Create Pull Request - uses: peter-evans/create-pull-request@v3 - with: - commit-message: Automated lint - title: Automated lint - body: | - - Changes from lint script - - Auto-generated by Github Actions - branch: automated-lint + uses: snapshot-labs/actions/.github/workflows/lint.yml@main + secrets: inherit diff --git a/package.json b/package.json index 390ddd08c..aa2320fc5 100755 --- a/package.json +++ b/package.json @@ -20,7 +20,9 @@ "prepublishOnly": "npm run build", "postinstall": "npm run build", "postbuild": "copyfiles -u 1 \"src/**/*.md\" dist/ && copyfiles -u 1 \"src/**/*.json\" dist/", - "lint": "eslint src/ test/ --ext .ts,.json --fix" + "typecheck": "tsc --noEmit", + "lint": "eslint src/ test/ --ext .ts,.json", + "lint:fix": "yarn lint --fix" }, "dependencies": { "@ethersproject/abi": "^5.6.4", diff --git a/src/strategies/sd-vote-boost-twavp-v3/index.ts b/src/strategies/sd-vote-boost-twavp-v3/index.ts index a06c597af..24ea4298c 100644 --- a/src/strategies/sd-vote-boost-twavp-v3/index.ts +++ b/src/strategies/sd-vote-boost-twavp-v3/index.ts @@ -30,14 +30,14 @@ export async function strategy( if (options.whiteListedAddress.length > 20) { throw new Error('maximum of 20 whitelisted address'); } - + // Maximum of 500 pools address if (options.pools.length > 500) { throw new Error('maximum of 500 pools'); } const calls: any[] = []; - for(const pool of options.pools) { + for (const pool of options.pools) { calls.push([options.sdToken, 'balanceOf', [pool]]); } calls.push([options.veToken, 'balanceOf', [options.liquidLocker]]); @@ -51,7 +51,7 @@ export async function strategy( } else { blockTag = await provider.getBlockNumber(); } - + // Create block list const blockList = getPreviousBlocks( blockTag, @@ -81,19 +81,12 @@ export async function strategy( loopCalls.push([options.sdTokenGauge, 'totalSupply']); loopCalls.push(...workingBalanceQuery); loopCalls.push(...calls); - } else { loopCalls.push(...workingBalanceQuery); } response.push( - await multicall( - network, - provider, - abi, - loopCalls, - { blockTag } - ) + await multicall(network, provider, abi, loopCalls, { blockTag }) ); } @@ -104,9 +97,18 @@ export async function strategy( const sdTokenGaugeTotalSupply = response[response.length - 1].shift()[0]; // Last response, latest block const votingPowerLiquidLocker = response[response.length - 1].pop()[0]; - const poolsBalances = options.pools.map(() => response[response.length - 1].pop()); - const sumPoolsBalance = poolsBalances.reduce((acc, balance) => acc.add(balance[0]), BigNumber.from(0)); - const total = sumPoolsBalance.mul(4).div(10).mul(votingPowerLiquidLocker).div(sdTokenGaugeTotalSupply); + const poolsBalances = options.pools.map(() => + response[response.length - 1].pop() + ); + const sumPoolsBalance = poolsBalances.reduce( + (acc, balance) => acc.add(balance[0]), + BigNumber.from(0) + ); + const total = sumPoolsBalance + .mul(4) + .div(10) + .mul(votingPowerLiquidLocker) + .div(sdTokenGaugeTotalSupply); return Object.fromEntries( Array(addresses.length) @@ -121,7 +123,10 @@ export async function strategy( } if (addresses[i].toLowerCase() === options.botAddress.toLowerCase()) { - return [addresses[i], Number(parseFloat(formatUnits(total, options.decimals)))]; + return [ + addresses[i], + Number(parseFloat(formatUnits(total, options.decimals))) + ]; } else { // Get average working balance. const averageWorkingBalance = average( @@ -130,20 +135,24 @@ export async function strategy( options.whiteListedAddress ); - const averageWorkingBalanceF = parseFloat(formatUnits(averageWorkingBalance, 18)); - const sdTokenGaugeTotalSupplyF = parseFloat(formatUnits(sdTokenGaugeTotalSupply, 18)); + const averageWorkingBalanceF = parseFloat( + formatUnits(averageWorkingBalance, 18) + ); + const sdTokenGaugeTotalSupplyF = parseFloat( + formatUnits(sdTokenGaugeTotalSupply, 18) + ); const workingSupplyF = parseFloat(formatUnits(workingSupply, 18)); // Calculate voting power. const votingPower = workingSupply != 0 - ? averageWorkingBalanceF * sdTokenGaugeTotalSupplyF / workingSupplyF + ? (averageWorkingBalanceF * sdTokenGaugeTotalSupplyF) / + workingSupplyF : 0; - + // Return address and voting power return [addresses[i], Number(votingPower)]; } - }) ); } From f41b1f67f1e6842ccc366169a55a5749676a5e67 Mon Sep 17 00:00:00 2001 From: Wan <495709+wa0x6e@users.noreply.github.com> Date: Tue, 17 Oct 2023 16:10:41 +0900 Subject: [PATCH 523/815] fix: throw an error when the network is not supported (#1322) --- src/strategies/erc1155-all-balances-of/index.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/strategies/erc1155-all-balances-of/index.ts b/src/strategies/erc1155-all-balances-of/index.ts index d73fce64e..8bf056aea 100644 --- a/src/strategies/erc1155-all-balances-of/index.ts +++ b/src/strategies/erc1155-all-balances-of/index.ts @@ -28,6 +28,11 @@ export async function strategy( const subgraphURL = isHosted ? HOSTED_SUBGRAPH_URL[network] : SUBGRAPH_URL[network]; + + if (!subgraphURL) { + throw new Error(`Unsupported network with id:${network}`); + } + const eip1155BalancesParams: any = { balances: { __aliasFor: 'erc1155Balances', From 39e38f3db2fef06aa9901078f3f3a32574551757 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 17 Oct 2023 22:46:48 +0530 Subject: [PATCH 524/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.7.4 (#1323) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index aa2320fc5..d85aac19d 100755 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.7.3", + "@snapshot-labs/snapshot.js": "^0.7.4", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 923d0890d..1dfee20a9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.7.3": - version "0.7.3" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.7.3.tgz#54984f135b78c7d3d7d26484d7275a0793d5bc9c" - integrity sha512-T+cjaJ9ZPLlKicPTxuN6FIQXUgADjvit/QFmwsOlGWxpMzAQ79k5rWm0ldex96JTPIFucUMgqHqWLA6UZwmmTQ== +"@snapshot-labs/snapshot.js@^0.7.4": + version "0.7.4" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.7.4.tgz#83828d9c8bdaf126e47f140f7b41f6175bce15e4" + integrity sha512-Ca4mlXUbuoeSJIw+KbOzGvceVP/Bm64FHV5UWc0WojIghN2K+F5OPqV0iGalnrNlpLyYcUDg0UFGUMfuiSLAcg== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From abc0a15d6def74bb300fca004e3f343e44d2298d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Espen=20H=C3=B8jsgaard?= Date: Wed, 18 Oct 2023 11:21:08 +0200 Subject: [PATCH 525/815] [dss-vest-unpaid] Export function for getting vestings and include accrued (#1315) This will allow other strategies to reuse the reading of vestings and determine accruals. This will be needed for the Mangrove DAO multistakeholder governance. --- src/strategies/dss-vest-unpaid/index.ts | 74 ++++++++++++++++++------- 1 file changed, 55 insertions(+), 19 deletions(-) diff --git a/src/strategies/dss-vest-unpaid/index.ts b/src/strategies/dss-vest-unpaid/index.ts index 5347cd157..4076e3ef8 100644 --- a/src/strategies/dss-vest-unpaid/index.ts +++ b/src/strategies/dss-vest-unpaid/index.ts @@ -4,7 +4,7 @@ import { Contract } from '@ethersproject/contracts'; import { Multicaller } from '../../utils'; export const author = 'espendk'; -export const version = '1.0.1'; +export const version = '1.1.0'; // To avoid future memory issues, we limit the number of vestings supported by the strategy const MAX_VESTINGS = 500; @@ -12,21 +12,27 @@ const MAX_VESTINGS = 500; const abi = [ 'function ids() external view returns (uint256)', 'function usr(uint256 id) external view returns (address)', + 'function accrued(uint256 id) external view returns (uint256)', 'function unpaid(uint256 id) external view returns (uint256)' ]; -export async function strategy( - space, +export type Vesting = { + id: number; + usr: string; + accrued: number; + unpaid: number; +}; + +export async function getAllVestings( network, provider, - addresses, - options, - snapshot -): Promise> { + snapshot, + dssVestAddress: string, + decimals: number +): Promise { const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - // Get the number of vestings - const dssVestContract = new Contract(options.address, abi, provider); + const dssVestContract = new Contract(dssVestAddress, abi, provider); const idCount = await dssVestContract.ids({ blockTag }); if (idCount > MAX_VESTINGS) { throw new Error( @@ -34,14 +40,46 @@ export async function strategy( ); } - // Get the vesting addresses and unpaid amounts const multi = new Multicaller(network, provider, abi, { blockTag }); for (let id = 1; id <= idCount; ++id) { - multi.call('usr' + id, options.address, 'usr', [id]); - multi.call('unpaid' + id, options.address, 'unpaid', [id]); + multi.call('usr' + id, dssVestAddress, 'usr', [id]); + multi.call('accrued' + id, dssVestAddress, 'accrued', [id]); + multi.call('unpaid' + id, dssVestAddress, 'unpaid', [id]); + } + const vestings: Record = await multi.execute(); + + const result: Vesting[] = []; + + for (let id = 1; id <= idCount; ++id) { + const usr = vestings['usr' + id] as string; + const accrued = parseFloat(formatUnits(vestings['accrued' + id], decimals)); + const unpaid = parseFloat(formatUnits(vestings['unpaid' + id], decimals)); + result.push({ + id, + usr, + accrued, + unpaid + }); } - const unclaimedVestings: Record = - await multi.execute(); + + return result; +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const vestings = await getAllVestings( + network, + provider, + snapshot, + options.address, + options.decimals + ); // Set score to 0 for all addresses const result = {}; @@ -50,12 +88,10 @@ export async function strategy( }); // Add the unclaimed vesting amounts to the addresses - for (let id = 1; id <= idCount; ++id) { - const address = unclaimedVestings['usr' + id] as string; + for (const vesting of vestings) { + const address = vesting.usr; if (addresses.includes(address)) { - result[address] += parseFloat( - formatUnits(unclaimedVestings['unpaid' + id], options.decimals) - ); + result[address] += vesting.unpaid; } } From e3c41401fa4bbf31f74049a66163add6c871ed98 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 18 Oct 2023 21:06:33 +0530 Subject: [PATCH 526/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.7.5 (#1325) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index d85aac19d..568d9abeb 100755 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.7.4", + "@snapshot-labs/snapshot.js": "^0.7.5", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 1dfee20a9..051fc5e81 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.7.4": - version "0.7.4" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.7.4.tgz#83828d9c8bdaf126e47f140f7b41f6175bce15e4" - integrity sha512-Ca4mlXUbuoeSJIw+KbOzGvceVP/Bm64FHV5UWc0WojIghN2K+F5OPqV0iGalnrNlpLyYcUDg0UFGUMfuiSLAcg== +"@snapshot-labs/snapshot.js@^0.7.5": + version "0.7.5" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.7.5.tgz#f424248c3fa69e47d5c681f51291f8f473d0324a" + integrity sha512-em0PB0/aUGpi08BmNv/U23qqHLQlU3cq0WB8Eh++Tn1Z+YJVqJLHvgNWYuEYe3rsOHGGohqBBTL/3oP/siTSBQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From a994b68dcc93cdb29654bae81bd9d5a98db53e30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Espen=20H=C3=B8jsgaard?= Date: Wed, 18 Oct 2023 19:50:33 +0200 Subject: [PATCH 527/815] [station-score-if-badge] Add Station GroupOS voting strategy for members with specific badge (#1316) --- src/strategies/index.ts | 4 +- .../station-score-if-badge/README.md | 3 + .../station-score-if-badge/examples.json | 27 ++ .../station-score-if-badge/index.ts | 266 ++++++++++++++++++ .../station-score-if-badge/schema.json | 72 +++++ 5 files changed, 371 insertions(+), 1 deletion(-) create mode 100644 src/strategies/station-score-if-badge/README.md create mode 100644 src/strategies/station-score-if-badge/examples.json create mode 100644 src/strategies/station-score-if-badge/index.ts create mode 100644 src/strategies/station-score-if-badge/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 8242f8518..1fc9710af 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -468,6 +468,7 @@ import * as moonbase from './moonbase'; import * as dssVestUnpaid from './dss-vest-unpaid'; import * as dssVestBalanceAndUnpaid from './dss-vest-balance-and-unpaid'; import * as eoaBalanceAndStakingPools from './eoa-balance-and-staking-pools'; +import * as stationScoreIfBadge from './station-score-if-badge'; const strategies = { 'cap-voting-power': capVotingPower, @@ -944,7 +945,8 @@ const strategies = { moonbase: moonbase, 'dss-vest-unpaid': dssVestUnpaid, 'dss-vest-balance-and-unpaid': dssVestBalanceAndUnpaid, - 'eoa-balance-and-staking-pools': eoaBalanceAndStakingPools + 'eoa-balance-and-staking-pools': eoaBalanceAndStakingPools, + 'station-score-if-badge': stationScoreIfBadge }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/station-score-if-badge/README.md b/src/strategies/station-score-if-badge/README.md new file mode 100644 index 000000000..05250d6b7 --- /dev/null +++ b/src/strategies/station-score-if-badge/README.md @@ -0,0 +1,3 @@ +# station-score-if-badge + +This strategy returns a score for members of a [Station](https://www.station.express/) [GroupOS](https://groupos.xyz/) group that have a specific badge. diff --git a/src/strategies/station-score-if-badge/examples.json b/src/strategies/station-score-if-badge/examples.json new file mode 100644 index 000000000..b90eef440 --- /dev/null +++ b/src/strategies/station-score-if-badge/examples.json @@ -0,0 +1,27 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "station-score-if-badge", + "params": { + "membershipERC721": "0xd71c8619209cc95a81f8d9ba4fd704d9eff3ddd6", + "badgesERC1155": "0xd775e55e314164cce7f71f9f70fc905c907fc65e", + "badgeId": 1, + "scoreERC20": "0x30D602cBfe96FC2C83fF31Bdf79d48De65f80733", + "scoreDecimals": 18, + "erc6551Registry": "0x02101dfB77FDE026414827Fdc604ddAF224F0921", + "erc6551Implementation": "0x2d25602551487c3f3354dd80d76d54383a243358", + "erc6551Salt": 0 + } + }, + "network": "5", + "addresses": [ + "0x4D7f3AEA074C6e8136C7e81ff8Af8BccdA3a7d89", + "0x4B977dC5bF15eC7FB9B2062CA15092B99d13b8F1", + "0xf78E7a442ea032a4D30FBA984c16a73Af5C915a0", + "0xAa01DeC5307CF17F20881A3286dcaA062578cea7", + "0xCD252d6AB26b7363E75d7451029C0f0729783AcE" + ], + "snapshot": 9852748 + } +] diff --git a/src/strategies/station-score-if-badge/index.ts b/src/strategies/station-score-if-badge/index.ts new file mode 100644 index 000000000..9014a4d9c --- /dev/null +++ b/src/strategies/station-score-if-badge/index.ts @@ -0,0 +1,266 @@ +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Contract } from '@ethersproject/contracts'; +import { Multicaller } from '../../utils'; + +export const author = 'espendk'; +export const version = '1.0.0'; + +// To avoid future memory issues, we limit the number of members supported by the strategy +export const MAX_MEMBERS = 500; + +export const erc721_abi = [ + 'function totalMinted() external view returns (uint256)', + 'function ownerOf(uint256 tokenId) external view returns (address)' +]; + +export const erc6551_registry_abi = [ + 'function account(address implementation, uint256 chainId, address tokenContract, uint256 tokenId, uint256 salt) external view returns (address)' +]; + +export const erc1155_abi = [ + 'function balanceOf(address account, uint256 id) external view returns (uint256)' +]; + +export const erc20_abi = [ + 'function balanceOf(address account) external view returns (uint256)' +]; + +export type TokenBoundAccount = { + tokenID: number; + address: string; + badgeBalance?: number; + score?: number; +}; + +export type Member = { + address: string; + TBAs: TokenBoundAccount[]; +}; + +/** Enumerates all accounts with a membership NFT and returns a map of their + * addresses to their membership NFT ID and the corresponding token-bound account (TBA). + * + * Assumptions: + * - Membership NFTs are never burned. + */ +export async function getAllMembers( + network, + provider, + snapshot, + membershipERC721: string, + erc6551Registry: string, + erc6551Implementation: string, + erc6551Salt: number +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + // Get the number of membership NFTs that have been minted + const membershipERC721Contract = new Contract( + membershipERC721, + erc721_abi, + provider + ); + const totalMinted = await membershipERC721Contract.totalMinted({ blockTag }); + if (totalMinted > MAX_MEMBERS) { + throw new Error( + `Max number (${MAX_MEMBERS}) of members exceeded: ${totalMinted}` + ); + } + + // Get the member addresses and TBAs for all the membership NFTs that have been minted + const membershipERC721Multicaller = new Multicaller( + network, + provider, + erc721_abi, + { blockTag } + ); + const erc6551RegistryMulticaller = new Multicaller( + network, + provider, + erc6551_registry_abi, + { blockTag } + ); + + for (let id = 1; id <= totalMinted; ++id) { + membershipERC721Multicaller.call(id, membershipERC721, 'ownerOf', [id]); + erc6551RegistryMulticaller.call(id, erc6551Registry, 'account', [ + erc6551Implementation, + network, + membershipERC721, + id, + erc6551Salt + ]); + } + + const ownerByTokenIdPromise: Promise> = + membershipERC721Multicaller.execute(); + const tokenBoundAccountsByTokenId: Record = + await erc6551RegistryMulticaller.execute(); + const ownerByTokenId: Record = await ownerByTokenIdPromise; + + const members = new Map(); + for (let id = 1; id <= totalMinted; ++id) { + const memberAddress = ownerByTokenId[id]; + const tba = tokenBoundAccountsByTokenId[id]; + let member = members.get(memberAddress); + if (member === undefined) { + member = { address: memberAddress, TBAs: [] }; + members.set(memberAddress, member); + } + member.TBAs.push({ tokenID: id, address: tba }); + } + + return members; +} + +/** Fetches the badge balance for all the given members' TBA's. */ +export async function fetchBadgeBalances( + network, + provider, + snapshot, + members: Map, + badgesERC1155: string, + badgeId: number +) { + if (members.size === 0) { + return; + } + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + // Get the Badge balances for all the token bound accounts + const erc1155Multicaller = new Multicaller(network, provider, erc1155_abi, { + blockTag + }); + for (const [, member] of members) { + for (const tba of member.TBAs) { + erc1155Multicaller.call(tba.address, badgesERC1155, 'balanceOf', [ + tba.address, + badgeId + ]); + } + } + + const badgeBalanceByTBA: Record = + await erc1155Multicaller.execute(); + + for (const [, member] of members) { + for (const tba of member.TBAs) { + tba.badgeBalance = parseInt(badgeBalanceByTBA[tba.address]); + } + } +} + +/** Fetches the score for all the given members' TBA's. */ +export async function fetchScores( + network, + provider, + snapshot, + members: Map, + scoreERC20: string, + scoreDecimals: number +) { + if (members.size === 0) { + return; + } + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + // Get the Scores for all the members with the badge + const erc20Multicaller = new Multicaller(network, provider, erc20_abi, { + blockTag + }); + for (const [, member] of members) { + for (const tba of member.TBAs) { + erc20Multicaller.call(tba.address, scoreERC20, 'balanceOf', [ + tba.address + ]); + } + } + + const scoreByMember: Record = + await erc20Multicaller.execute(); + + for (const [, member] of members) { + for (const tba of member.TBAs) { + tba.score = parseFloat( + formatUnits(scoreByMember[tba.address], scoreDecimals) + ); + } + } +} + +/** Filters the members by a predicate. */ +export function filterMembers( + members: Map, + predicate: (member: Member) => boolean +): Map { + const result = new Map(); + + for (const [, member] of members) { + if (predicate(member)) { + result.set(member.address, member); + } + } + + return result; +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + let members = await getAllMembers( + network, + provider, + snapshot, + options.membershipERC721, + options.erc6551Registry, + options.erc6551Implementation, + options.erc6551Salt + ); + + // Keep only members in the list of queried addresses + members = filterMembers(members, (member) => + addresses.includes(member.address) + ); + + await fetchBadgeBalances( + network, + provider, + snapshot, + members, + options.badgesERC1155, + options.badgeId + ); + + // Keep only members with a badge + members = filterMembers(members, (member) => + member.TBAs.some((tba) => (tba.badgeBalance ?? 0) > 0) + ); + + await fetchScores( + network, + provider, + snapshot, + members, + options.scoreERC20, + options.scoreDecimals + ); + + // Build address -> score mapping + // Include only scores for TBA's with a badge + const result = {}; + for (const [, member] of members) { + result[member.address] = 0; + for (const tba of member.TBAs) { + if ((tba.badgeBalance ?? 0) > 0) { + result[member.address] += tba.score; + } + } + } + return result; +} diff --git a/src/strategies/station-score-if-badge/schema.json b/src/strategies/station-score-if-badge/schema.json new file mode 100644 index 000000000..4eb2b4df1 --- /dev/null +++ b/src/strategies/station-score-if-badge/schema.json @@ -0,0 +1,72 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "membershipERC721": { + "type": "string", + "title": "Membership ERC721 contract address", + "examples": ["e.g. 0xd71c8619209cc95a81f8d9ba4fd704d9eff3ddd6"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "badgesERC1155": { + "type": "string", + "title": "Badges ERC1155 contract address", + "examples": ["e.g. 0xd775e55e314164cce7f71f9f70fc905c907fc65e"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "badgeId": { + "type": "number", + "title": "ERC115 token ID for the Badge members should have", + "examples": ["e.g. 1"], + "minimum": 0 + }, + "scoreERC20": { + "type": "string", + "title": "Member score ERC20 contract address", + "examples": ["e.g. 0x30D602cBfe96FC2C83fF31Bdf79d48De65f80733"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "scoreDecimals": { + "type": "number", + "title": "Member score decimals", + "examples": ["e.g. 18"], + "minimum": 0 + }, + "erc6551Registry": { + "type": "string", + "title": "ERC6551 registry address", + "examples": ["e.g. 0x02101dfB77FDE026414827Fdc604ddAF224F0921"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "erc6551Implementation": { + "type": "string", + "title": "ERC6551 implementation address", + "examples": ["e.g. 0x2d25602551487c3f3354dd80d76d54383a243358"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "erc6551Salt": { + "type": "number", + "title": "ERC6551 salt", + "examples": ["e.g. 0"], + "minimum": 0 + } + }, + "required": [], + "additionalProperties": false + } + } +} From eaf28f556939709585119d89391fc6ebd1bfeffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Espen=20H=C3=B8jsgaard?= Date: Wed, 18 Oct 2023 20:49:52 +0200 Subject: [PATCH 528/815] [station-constant-if-badge] Add Station GroupOS validation strategy for members with a specific badge (#1317) --- src/strategies/index.ts | 4 +- .../station-constant-if-badge/README.md | 5 ++ .../station-constant-if-badge/examples.json | 26 ++++++++ .../station-constant-if-badge/index.ts | 53 ++++++++++++++++ .../station-constant-if-badge/schema.json | 63 +++++++++++++++++++ 5 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 src/strategies/station-constant-if-badge/README.md create mode 100644 src/strategies/station-constant-if-badge/examples.json create mode 100644 src/strategies/station-constant-if-badge/index.ts create mode 100644 src/strategies/station-constant-if-badge/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 1fc9710af..ba3111d7f 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -469,6 +469,7 @@ import * as dssVestUnpaid from './dss-vest-unpaid'; import * as dssVestBalanceAndUnpaid from './dss-vest-balance-and-unpaid'; import * as eoaBalanceAndStakingPools from './eoa-balance-and-staking-pools'; import * as stationScoreIfBadge from './station-score-if-badge'; +import * as stationConstantIfBadge from './station-constant-if-badge'; const strategies = { 'cap-voting-power': capVotingPower, @@ -946,7 +947,8 @@ const strategies = { 'dss-vest-unpaid': dssVestUnpaid, 'dss-vest-balance-and-unpaid': dssVestBalanceAndUnpaid, 'eoa-balance-and-staking-pools': eoaBalanceAndStakingPools, - 'station-score-if-badge': stationScoreIfBadge + 'station-score-if-badge': stationScoreIfBadge, + 'station-constant-if-badge': stationConstantIfBadge }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/station-constant-if-badge/README.md b/src/strategies/station-constant-if-badge/README.md new file mode 100644 index 000000000..1a91af583 --- /dev/null +++ b/src/strategies/station-constant-if-badge/README.md @@ -0,0 +1,5 @@ +# station-constant-if-badge + +This strategy returns a constant if a voter/proposer has a specific badge in a [Station](https://www.station.express/) [GroupOS](https://groupos.xyz/) group; If not, zero is returned. + +This strategy can be used as a validation strategy that only allows certain members to vote/propose. diff --git a/src/strategies/station-constant-if-badge/examples.json b/src/strategies/station-constant-if-badge/examples.json new file mode 100644 index 000000000..a56264370 --- /dev/null +++ b/src/strategies/station-constant-if-badge/examples.json @@ -0,0 +1,26 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "station-constant-if-badge", + "params": { + "membershipERC721": "0xd71c8619209cc95a81f8d9ba4fd704d9eff3ddd6", + "badgesERC1155": "0xd775e55e314164cce7f71f9f70fc905c907fc65e", + "badgeId": 1, + "constant": 1337, + "erc6551Registry": "0x02101dfB77FDE026414827Fdc604ddAF224F0921", + "erc6551Implementation": "0x2d25602551487c3f3354dd80d76d54383a243358", + "erc6551Salt": 0 + } + }, + "network": "5", + "addresses": [ + "0x4D7f3AEA074C6e8136C7e81ff8Af8BccdA3a7d89", + "0x4B977dC5bF15eC7FB9B2062CA15092B99d13b8F1", + "0xf78E7a442ea032a4D30FBA984c16a73Af5C915a0", + "0xAa01DeC5307CF17F20881A3286dcaA062578cea7", + "0xCD252d6AB26b7363E75d7451029C0f0729783AcE" + ], + "snapshot": 9852748 + } +] diff --git a/src/strategies/station-constant-if-badge/index.ts b/src/strategies/station-constant-if-badge/index.ts new file mode 100644 index 000000000..0720abd67 --- /dev/null +++ b/src/strategies/station-constant-if-badge/index.ts @@ -0,0 +1,53 @@ +import { + getAllMembers, + filterMembers, + fetchBadgeBalances +} from '../station-score-if-badge'; + +export const author = 'espendk'; +export const version = '1.0.0'; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + let members = await getAllMembers( + network, + provider, + snapshot, + options.membershipERC721, + options.erc6551Registry, + options.erc6551Implementation, + options.erc6551Salt + ); + + // Keep only members in the list of queried addresses + members = filterMembers(members, (member) => + addresses.includes(member.address) + ); + + await fetchBadgeBalances( + network, + provider, + snapshot, + members, + options.badgesERC1155, + options.badgeId + ); + + // Keep only members with a badge + members = filterMembers(members, (member) => + member.TBAs.some((tba) => (tba.badgeBalance ?? 0) > 0) + ); + + // Build address -> const + const result = {}; + for (const [, member] of members) { + result[member.address] = options.constant; + } + return result; +} diff --git a/src/strategies/station-constant-if-badge/schema.json b/src/strategies/station-constant-if-badge/schema.json new file mode 100644 index 000000000..0b578d763 --- /dev/null +++ b/src/strategies/station-constant-if-badge/schema.json @@ -0,0 +1,63 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "membershipERC721": { + "type": "string", + "title": "Membership ERC721 contract address", + "examples": ["e.g. 0x651bf9C1A1dEC27b49061F2356482F7c6F3D18fb"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "badgesERC1155": { + "type": "string", + "title": "Badges ERC1155 contract address", + "examples": ["e.g. 0xd775e55e314164cce7f71f9f70fc905c907fc65e"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "badgeId": { + "type": "number", + "title": "ERC115 token ID for the Badge members should have", + "examples": ["e.g. 1"], + "minimum": 0 + }, + "constant": { + "type": "number", + "title": "Constant to return for voters who have the badge", + "examples": ["e.g. 1337"] + }, + "erc6551Registry": { + "type": "string", + "title": "ERC6551 registry address", + "examples": ["e.g. 0x02101dfB77FDE026414827Fdc604ddAF224F0921"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "erc6551Implementation": { + "type": "string", + "title": "ERC6551 implementation address", + "examples": ["e.g. 0x2d25602551487c3f3354dd80d76d54383a243358"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "erc6551Salt": { + "type": "number", + "title": "ERC6551 salt", + "examples": ["e.g. 0"], + "minimum": 0 + } + }, + "required": [], + "additionalProperties": false + } + } +} From b1aa7159c49cda5d4b93188b97a821765d0122af Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 19 Oct 2023 00:32:47 +0530 Subject: [PATCH 529/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.7.8 (#1326) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 568d9abeb..0931d339b 100755 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.7.5", + "@snapshot-labs/snapshot.js": "^0.7.8", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 051fc5e81..a905d42eb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.7.5": - version "0.7.5" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.7.5.tgz#f424248c3fa69e47d5c681f51291f8f473d0324a" - integrity sha512-em0PB0/aUGpi08BmNv/U23qqHLQlU3cq0WB8Eh++Tn1Z+YJVqJLHvgNWYuEYe3rsOHGGohqBBTL/3oP/siTSBQ== +"@snapshot-labs/snapshot.js@^0.7.8": + version "0.7.8" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.7.8.tgz#9a94b2a6de1331ccee5ffea3877af62dde4c2b33" + integrity sha512-TD0GQ+CKPsQWh7Ir5kELLjjdrvmDtH/UbKVgEx+wJYOMHn6IIfqA2Cw3OqmV2WG8SNqAj85hbalIzCBWMDbZ4A== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From d6ed2f635579141be53d3a5dc7b2af0f35f117ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Espen=20H=C3=B8jsgaard?= Date: Thu, 19 Oct 2023 12:15:19 +0200 Subject: [PATCH 530/815] [mangrove-station-qv-scaled-to-mgv] Add Mangrove Station GroupOS voting strategy (#1318) --- src/strategies/index.ts | 4 +- .../README.md | 10 ++ .../examples.json | 29 ++++++ .../index.ts | 95 +++++++++++++++++++ .../schema.json | 85 +++++++++++++++++ 5 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 src/strategies/mangrove-station-qv-scaled-to-mgv/README.md create mode 100644 src/strategies/mangrove-station-qv-scaled-to-mgv/examples.json create mode 100644 src/strategies/mangrove-station-qv-scaled-to-mgv/index.ts create mode 100644 src/strategies/mangrove-station-qv-scaled-to-mgv/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index ba3111d7f..11ed43679 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -470,6 +470,7 @@ import * as dssVestBalanceAndUnpaid from './dss-vest-balance-and-unpaid'; import * as eoaBalanceAndStakingPools from './eoa-balance-and-staking-pools'; import * as stationScoreIfBadge from './station-score-if-badge'; import * as stationConstantIfBadge from './station-constant-if-badge'; +import * as mangroveStationQVScaledToMGV from './mangrove-station-qv-scaled-to-mgv'; const strategies = { 'cap-voting-power': capVotingPower, @@ -948,7 +949,8 @@ const strategies = { 'dss-vest-balance-and-unpaid': dssVestBalanceAndUnpaid, 'eoa-balance-and-staking-pools': eoaBalanceAndStakingPools, 'station-score-if-badge': stationScoreIfBadge, - 'station-constant-if-badge': stationConstantIfBadge + 'station-constant-if-badge': stationConstantIfBadge, + 'mangrove-station-qv-scaled-to-mgv': mangroveStationQVScaledToMGV }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/mangrove-station-qv-scaled-to-mgv/README.md b/src/strategies/mangrove-station-qv-scaled-to-mgv/README.md new file mode 100644 index 000000000..1dbdf5130 --- /dev/null +++ b/src/strategies/mangrove-station-qv-scaled-to-mgv/README.md @@ -0,0 +1,10 @@ +# mangrove-station-qv-scaled-to-mgv + +This strategy allows active members of one of the Mangrove DAO governance groups (Builders Group and Pods Group) to vote in the Mangrove multistakeholder governance. + +Quadratic voting is applied to each member's score and then the voting weight is scaled such that the total voting weight of the group is equal to the circulating supply of MGV tokens. This ensures that the three stakeholder groups have equal voting weights. + +## Notes +Mangrove DAO governance groups are [Station](https://www.station.express/) [GroupOS](https://groupos.xyz/) groups on-chain, and active members have a ERC-1155 badge. + +The circulating supply of MGV tokens is the total number of allocated, claimable tokens. diff --git a/src/strategies/mangrove-station-qv-scaled-to-mgv/examples.json b/src/strategies/mangrove-station-qv-scaled-to-mgv/examples.json new file mode 100644 index 000000000..425f88e26 --- /dev/null +++ b/src/strategies/mangrove-station-qv-scaled-to-mgv/examples.json @@ -0,0 +1,29 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "mangrove-station-qv-scaled-to-mgv", + "params": { + "membershipERC721": "0xd71c8619209cc95a81f8d9ba4fd704d9eff3ddd6", + "badgesERC1155": "0xd775e55e314164cce7f71f9f70fc905c907fc65e", + "activeBadgeId": 1, + "activityScoreERC20": "0x30D602cBfe96FC2C83fF31Bdf79d48De65f80733", + "activityScoreDecimals": 18, + "erc6551Registry": "0x02101dfB77FDE026414827Fdc604ddAF224F0921", + "erc6551Implementation": "0x2d25602551487c3f3354dd80d76d54383a243358", + "erc6551Salt": 0, + "dssVestAddress": "0xc67A1EB2BD5794C070cC555fD4533CF8E28E7162", + "dssVestDecimals": 18 + } + }, + "network": "5", + "addresses": [ + "0x4D7f3AEA074C6e8136C7e81ff8Af8BccdA3a7d89", + "0x4B977dC5bF15eC7FB9B2062CA15092B99d13b8F1", + "0xf78E7a442ea032a4D30FBA984c16a73Af5C915a0", + "0xAa01DeC5307CF17F20881A3286dcaA062578cea7", + "0xCD252d6AB26b7363E75d7451029C0f0729783AcE" + ], + "snapshot": 9855099 + } +] diff --git a/src/strategies/mangrove-station-qv-scaled-to-mgv/index.ts b/src/strategies/mangrove-station-qv-scaled-to-mgv/index.ts new file mode 100644 index 000000000..f78089700 --- /dev/null +++ b/src/strategies/mangrove-station-qv-scaled-to-mgv/index.ts @@ -0,0 +1,95 @@ +import { + getAllMembers, + fetchBadgeBalances, + fetchScores +} from '../station-score-if-badge'; +import { getAllVestings } from '../dss-vest-unpaid'; + +export const author = 'espendk'; +export const version = '1.0.0'; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const members = await getAllMembers( + network, + provider, + snapshot, + options.membershipERC721, + options.erc6551Registry, + options.erc6551Implementation, + options.erc6551Salt + ); + + await fetchBadgeBalances( + network, + provider, + snapshot, + members, + options.badgesERC1155, + options.activeBadgeId + ); + + // Keep only TBAs and members with a badge + for (const [, member] of members) { + member.TBAs = member.TBAs.filter((tba) => (tba.badgeBalance ?? 0) > 0); + if (member.TBAs.length === 0) { + members.delete(member.address); + } + } + + await fetchScores( + network, + provider, + snapshot, + members, + options.activityScoreERC20, + options.activityScoreDecimals + ); + + // Aggregate membership scores and apply quadratic voting + const activeMemberScores = new Map(); + let totalScore = 0; + for (const [, member] of members) { + let score = 0; + for (const tba of member.TBAs) { + score += tba.score ?? 0; + } + score = Math.sqrt(score); + activeMemberScores.set(member.address, score); + totalScore += score; + } + + // Get the circulating supply of the vesting token + const allVestings = await getAllVestings( + network, + provider, + snapshot, + options.dssVestAddress, + options.dssVestDecimals + ); + const circulatingSupply = allVestings.reduce( + (acc, vesting) => acc + vesting.accrued, + 0 + ); + + // Scale scores to the circulating supply of the vesting token + const scale = circulatingSupply / totalScore; + for (const [address, score] of activeMemberScores) { + activeMemberScores.set(address, score * scale); + } + + // Build address -> scaled score for the queried addresses + const result = {}; + for (const [address, score] of activeMemberScores) { + if (addresses.includes(address)) { + result[address] = score; + } + } + return result; +} diff --git a/src/strategies/mangrove-station-qv-scaled-to-mgv/schema.json b/src/strategies/mangrove-station-qv-scaled-to-mgv/schema.json new file mode 100644 index 000000000..690760156 --- /dev/null +++ b/src/strategies/mangrove-station-qv-scaled-to-mgv/schema.json @@ -0,0 +1,85 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "membershipERC721": { + "type": "string", + "title": "Membership ERC721 contract address", + "examples": ["e.g. 0x651bf9C1A1dEC27b49061F2356482F7c6F3D18fb"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "badgesERC1155": { + "type": "string", + "title": "Badges ERC1155 contract address", + "examples": ["e.g. 0xd775e55e314164cce7f71f9f70fc905c907fc65e"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "activeBadgeId": { + "type": "number", + "title": "ERC115 token ID for the Active Badge that indicate current members", + "examples": ["e.g. 1"], + "minimum": 0 + }, + "activityScoreERC20": { + "type": "string", + "title": "Member score ERC20 contract address", + "examples": ["e.g. 0x30D602cBfe96FC2C83fF31Bdf79d48De65f80733"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "activityScoreDecimals": { + "type": "number", + "title": "Member score decimals", + "examples": ["e.g. 18"], + "minimum": 0 + }, + "erc6551Registry": { + "type": "string", + "title": "ERC6551 registry address", + "examples": ["e.g. 0x02101dfB77FDE026414827Fdc604ddAF224F0921"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "erc6551Implementation": { + "type": "string", + "title": "ERC6551 implementation address", + "examples": ["e.g. 0x2d25602551487c3f3354dd80d76d54383a243358"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "erc6551Salt": { + "type": "number", + "title": "ERC6551 salt", + "examples": ["e.g. 0"], + "minimum": 0 + }, + "dssVestAddress": { + "type": "string", + "title": "DssVest contract address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "dssVestDecimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 18"] + } + }, + "required": [], + "additionalProperties": false + } + } +} From 9e9e71ec9ed94b15cc76fd1bd2802b603dbf6d55 Mon Sep 17 00:00:00 2001 From: vuittont60 <81072379+vuittont60@users.noreply.github.com> Date: Tue, 24 Oct 2023 14:21:51 +0800 Subject: [PATCH 531/815] docs: fix typos (#1328) --- src/strategies/proof-of-humanity/README.md | 2 +- src/strategies/sd-boost-twavp/README.md | 2 +- src/strategies/sd-vote-boost-twavp-v2/README.md | 2 +- src/strategies/sd-vote-boost-twavp-v3/README.md | 2 +- src/strategies/sd-vote-boost-twavp/README.md | 2 +- src/validations/passport-gated/README.md | 6 +++--- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/strategies/proof-of-humanity/README.md b/src/strategies/proof-of-humanity/README.md index f4853e1d6..34cff1329 100644 --- a/src/strategies/proof-of-humanity/README.md +++ b/src/strategies/proof-of-humanity/README.md @@ -2,7 +2,7 @@ It checks if an address is registered with Proof of Humanity. -It takes the address of the Proof of Humanity contract as a paramter: +It takes the address of the Proof of Humanity contract as a parameter: ```json { diff --git a/src/strategies/sd-boost-twavp/README.md b/src/strategies/sd-boost-twavp/README.md index 2cbcb284b..e59b9b189 100644 --- a/src/strategies/sd-boost-twavp/README.md +++ b/src/strategies/sd-boost-twavp/README.md @@ -1,6 +1,6 @@ # sd-boost-twavp -This strategy is used by StakeDAO to vote with sdToken with Time Weigthed Averaged Voting Power system and veSDT voting boost. +This strategy is used by StakeDAO to vote with sdToken with Time Weighted Averaged Voting Power system and veSDT voting boost. _sampleSize is in days_ _sampleStep is the number of block for TWAVP_ _avgBlockTime is in seconds_ diff --git a/src/strategies/sd-vote-boost-twavp-v2/README.md b/src/strategies/sd-vote-boost-twavp-v2/README.md index 6dee8304a..11d613f6b 100644 --- a/src/strategies/sd-vote-boost-twavp-v2/README.md +++ b/src/strategies/sd-vote-boost-twavp-v2/README.md @@ -1,6 +1,6 @@ # sd-vote-boost-twavp-v2 -This strategy is used by Stake DAO to vote with sdToken using Time Weigthed Averaged Voting Power (TWAVP) system and adapted for veSDT boost delegation with possibility to whiteliste address to by pass TWAVP. +This strategy is used by Stake DAO to vote with sdToken using Time Weighted Averaged Voting Power (TWAVP) system and adapted for veSDT boost delegation with possibility to whiteliste address to by pass TWAVP. ``` VotingPower(user) = veToken.balanceOf(liquidLocker) * (average.sdTokenGauge.working_balances(user) / sdTokenGauge.working_supply) diff --git a/src/strategies/sd-vote-boost-twavp-v3/README.md b/src/strategies/sd-vote-boost-twavp-v3/README.md index 20f94d0ea..4042db7bb 100644 --- a/src/strategies/sd-vote-boost-twavp-v3/README.md +++ b/src/strategies/sd-vote-boost-twavp-v3/README.md @@ -1,6 +1,6 @@ # sd-vote-boost-twavp-v3 -This strategy is used by Stake DAO to vote with sdToken using Time Weigthed Averaged Voting Power (TWAVP) system and adapted for veSDT boost delegation with possibility to whiteliste address to by pass TWAVP. +This strategy is used by Stake DAO to vote with sdToken using Time Weighted Averaged Voting Power (TWAVP) system and adapted for veSDT boost delegation with possibility to whiteliste address to by pass TWAVP. ``` VotingPower(user) = veToken.balanceOf(liquidLocker) * (average.sdTokenGauge.working_balances(user) / sdTokenGauge.working_supply) diff --git a/src/strategies/sd-vote-boost-twavp/README.md b/src/strategies/sd-vote-boost-twavp/README.md index 8b15abd26..8991546b3 100644 --- a/src/strategies/sd-vote-boost-twavp/README.md +++ b/src/strategies/sd-vote-boost-twavp/README.md @@ -1,6 +1,6 @@ # sd-vote-boost-twavp -This strategy is used by Stake DAO to vote with sdToken using Time Weigthed Averaged Voting Power (TWAVP) system and adapted for veSDT boost delegation. +This strategy is used by Stake DAO to vote with sdToken using Time Weighted Averaged Voting Power (TWAVP) system and adapted for veSDT boost delegation. ``` VotingPower(user) = veToken.balanceOf(liquidLocker) * (average.sdTokenGauge.working_balances(user) / sdTokenGauge.working_supply) diff --git a/src/validations/passport-gated/README.md b/src/validations/passport-gated/README.md index 9e41bc9ca..fd7349598 100644 --- a/src/validations/passport-gated/README.md +++ b/src/validations/passport-gated/README.md @@ -30,7 +30,7 @@ Strategy schema & parameters are defined under [schema.json](./schema.json). In ## Code Explanation -The main function (validate()) first fetches the following paramaters: +The main function (validate()) first fetches the following parameters: * `stamps` (required): a list of Stamps that a passport should own. * `operator` (required): (and/or) whether a Passport should own all or at least one of the required stamps. @@ -38,8 +38,8 @@ The main function (validate()) first fetches the following paramaters: Then, it calls the following validation methods: -* `validateStamps`: it uses the API to fetch the current user's Passport stamps and verifies that each has valid issuance and isn't expired. Then, depending on the `operator`, it will iterate through the requred `stamps` and check that the user holds at least one verifiable credential that makes the passport eligible for that stamp. Finally, a Passport will be set as valid if it meets the criteria. -* `validatePassportScore`: if `scoreThreshold` is set to zero this function will be ommited. Otherwise when called, it uses the Scorer API to submit the passport for scoring and get the latest score. If the API response returns a payload with `status === 'DONE'` it will return the result of evaluating the scoring threshold criteria, otherwise the implementation will make periodic requests (up to `PASSPORT_SCORER_MAX_ATTEMPTS`) to the Scorer API until getting a `DONE` status. +* `validateStamps`: it uses the API to fetch the current user's Passport stamps and verifies that each has valid issuance and isn't expired. Then, depending on the `operator`, it will iterate through the required `stamps` and check that the user holds at least one verifiable credential that makes the passport eligible for that stamp. Finally, a Passport will be set as valid if it meets the criteria. +* `validatePassportScore`: if `scoreThreshold` is set to zero this function will be omitted. Otherwise when called, it uses the Scorer API to submit the passport for scoring and get the latest score. If the API response returns a payload with `status === 'DONE'` it will return the result of evaluating the scoring threshold criteria, otherwise the implementation will make periodic requests (up to `PASSPORT_SCORER_MAX_ATTEMPTS`) to the Scorer API until getting a `DONE` status. Finally, it checks the results of both eval functions and returns a boolean value indicating whether the user has a valid Passport. From 6fefb8ddf1d103112edade87d666082166894c74 Mon Sep 17 00:00:00 2001 From: Koyomi Araragi Date: Sun, 29 Oct 2023 23:39:22 -0300 Subject: [PATCH 532/815] [floki] add floki strategy (#1329) --- src/strategies/floki/README.md | 14 ++++++ src/strategies/floki/examples.json | 22 ++++++++ src/strategies/floki/index.ts | 80 ++++++++++++++++++++++++++++++ src/strategies/floki/schema.json | 49 ++++++++++++++++++ src/strategies/index.ts | 4 +- 5 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 src/strategies/floki/README.md create mode 100644 src/strategies/floki/examples.json create mode 100644 src/strategies/floki/index.ts create mode 100644 src/strategies/floki/schema.json diff --git a/src/strategies/floki/README.md b/src/strategies/floki/README.md new file mode 100644 index 000000000..9a1d903b4 --- /dev/null +++ b/src/strategies/floki/README.md @@ -0,0 +1,14 @@ +# FLOKI + +This is the strategy used by FLOKI DAO. It returns the FLOKI balance, as well as staked amount with pool's multiplier taken into account (which depends on how long the tokens were staked for). + +Here is an example of parameters: + +```json +{ + "tokenAddress": "0xcf0C122c6b73ff809C693DB761e7BaeBe62b6a2E", + "stakingPoolAddress": "0xb8D2471E35eE033Db509e0456c8eFc4135f4EE43", + "stakingPoolMultiplierAddress": "0xB254CC6c1D178C2dE8182CEDE6113A986bB90721", + "decimals": 9 +} +``` diff --git a/src/strategies/floki/examples.json b/src/strategies/floki/examples.json new file mode 100644 index 000000000..e2cf4483f --- /dev/null +++ b/src/strategies/floki/examples.json @@ -0,0 +1,22 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "floki", + "params": { + "tokenAddress": "0xcf0C122c6b73ff809C693DB761e7BaeBe62b6a2E", + "stakingPoolAddress": "0xb8D2471E35eE033Db509e0456c8eFc4135f4EE43", + "stakingPoolMultiplierAddress": "0xB254CC6c1D178C2dE8182CEDE6113A986bB90721", + "decimals": 9 + } + }, + "network": "1", + "addresses": [ + "0x78C4f5CEF16333804394fE736fC5868351968Fd7", + "0x2cc848EA4C5313Fe5a264D12c7c2181f14f0A5E7", + "0x5BA9e392Baf5D082d968E1BFA945F99e54BF8123", + "0x308DA792A0b9c332D5254bB2afB78640d363e2d1" + ], + "snapshot": 18458827 + } +] diff --git a/src/strategies/floki/index.ts b/src/strategies/floki/index.ts new file mode 100644 index 000000000..911a8e0d9 --- /dev/null +++ b/src/strategies/floki/index.ts @@ -0,0 +1,80 @@ +import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'AlissonRS'; +export const version = '0.0.1'; + +const tokenAbi = [ + 'function balanceOf(address account) external view returns (uint256)' +]; + +const poolAbi = [ + 'function getUserStakes(address _user) external view returns (tuple(uint256 stakedAmount, uint256 minimumStakeTimestamp, uint256 duration, uint256 rewardPerTokenPaid, uint256 rewards)[])' +]; + +const multiplierAbi = [ + 'function applyMultiplier(uint256 _amount, uint256 _duration) external view returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const balanceMulti = new Multicaller(network, provider, tokenAbi, { + blockTag + }); + addresses.forEach((address) => + balanceMulti.call(address, options.tokenAddress, 'balanceOf', [address]) + ); + const balanceResult: Record = + await balanceMulti.execute(); + + // Find the staked tokens + const stakingMulti = new Multicaller(network, provider, poolAbi, { + blockTag + }); + addresses.forEach((address) => + stakingMulti.call(address, options.stakingPoolAddress, 'getUserStakes', [ + address + ]) + ); + const stakingResult: Record = await stakingMulti.execute(); + + // Get the multiplier factor for each wallet + const multiplierMulti = new Multicaller(network, provider, multiplierAbi, { + blockTag + }); + Object.entries(stakingResult).forEach(([address, stakesInfo]) => { + stakesInfo.forEach((stakeInfo, i) => + multiplierMulti.call( + `${address}-${i}`, + options.stakingPoolMultiplierAddress, + 'applyMultiplier', + [stakeInfo.stakedAmount, stakeInfo.duration] + ) + ); + }); + const multiResult: Record = await multiplierMulti.execute(); + + // Add staking tokens to the balance + Object.entries(multiResult).forEach(([addressPos, stakeBalance]) => { + const address = addressPos.substring(0, 42); + balanceResult[address] = BigNumber.from(balanceResult[address]).add( + stakeBalance + ); + }); + + return Object.fromEntries( + Object.entries(balanceResult).map(([address, balance]) => [ + address, + parseFloat(formatUnits(balance, options.decimals)) + ]) + ); +} diff --git a/src/strategies/floki/schema.json b/src/strategies/floki/schema.json new file mode 100644 index 000000000..d20eb6bae --- /dev/null +++ b/src/strategies/floki/schema.json @@ -0,0 +1,49 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. FLOKI"], + "maxLength": 16 + }, + "tokenAddress": { + "type": "string", + "title": "Token address", + "examples": ["e.g. 0xcf0C122c6b73ff809C693DB761e7BaeBe62b6a2E"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "stakingPoolAddress": { + "type": "string", + "title": "Staking Pool address", + "examples": ["e.g. 0xb8D2471E35eE033Db509e0456c8eFc4135f4EE43"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "stakingPoolMultiplierAddress": { + "type": "string", + "title": "Staking Pool Multiplier address", + "examples": ["e.g. 0xB254CC6c1D178C2dE8182CEDE6113A986bB90721"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 9"] + } + }, + "required": ["tokenAddress", "stakingPoolAddress", "stakingPoolMultiplierAddress", "decimals"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 11ed43679..00b037886 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -471,6 +471,7 @@ import * as eoaBalanceAndStakingPools from './eoa-balance-and-staking-pools'; import * as stationScoreIfBadge from './station-score-if-badge'; import * as stationConstantIfBadge from './station-constant-if-badge'; import * as mangroveStationQVScaledToMGV from './mangrove-station-qv-scaled-to-mgv'; +import * as floki from './floki'; const strategies = { 'cap-voting-power': capVotingPower, @@ -950,7 +951,8 @@ const strategies = { 'eoa-balance-and-staking-pools': eoaBalanceAndStakingPools, 'station-score-if-badge': stationScoreIfBadge, 'station-constant-if-badge': stationConstantIfBadge, - 'mangrove-station-qv-scaled-to-mgv': mangroveStationQVScaledToMGV + 'mangrove-station-qv-scaled-to-mgv': mangroveStationQVScaledToMGV, + floki }; Object.keys(strategies).forEach(function (strategyName) { From 05c70be665f65dfe146aa1b89ac278399f57361f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 31 Oct 2023 00:01:55 +0530 Subject: [PATCH 533/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.7.9 (#1330) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 0931d339b..b5b125dc2 100755 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.7.8", + "@snapshot-labs/snapshot.js": "^0.7.9", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index a905d42eb..726ba681e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.7.8": - version "0.7.8" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.7.8.tgz#9a94b2a6de1331ccee5ffea3877af62dde4c2b33" - integrity sha512-TD0GQ+CKPsQWh7Ir5kELLjjdrvmDtH/UbKVgEx+wJYOMHn6IIfqA2Cw3OqmV2WG8SNqAj85hbalIzCBWMDbZ4A== +"@snapshot-labs/snapshot.js@^0.7.9": + version "0.7.9" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.7.9.tgz#6e0117b8601c794af7aefd1ad1daf4d354c8c078" + integrity sha512-YcQXQ7CeEemPHwR1HfDPNN3qdGL3xPsmP/iKiVcD93pJzl7vXOoTmKjiBW8qRPNS2JI65OY72V+5Zt4geaBWaw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From b256f6117c55a0a9e40c75b434d29737d44f9572 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 31 Oct 2023 16:30:42 +0530 Subject: [PATCH 534/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.8.0 (#1331) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index b5b125dc2..884473cca 100755 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.7.9", + "@snapshot-labs/snapshot.js": "^0.8.0", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 726ba681e..e6c275a7a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.7.9": - version "0.7.9" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.7.9.tgz#6e0117b8601c794af7aefd1ad1daf4d354c8c078" - integrity sha512-YcQXQ7CeEemPHwR1HfDPNN3qdGL3xPsmP/iKiVcD93pJzl7vXOoTmKjiBW8qRPNS2JI65OY72V+5Zt4geaBWaw== +"@snapshot-labs/snapshot.js@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.8.0.tgz#f440c60a34cdc886d9bfc9f578278bb14ee0aa21" + integrity sha512-FnTwofZuI57l2n7+krYGIYh7LkF955ItM6T+vsAH7gaVSUlMWYcA3tGOcgsj0STwjge3Y8JwgUsfPf3SadOYow== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 65610aafeb27d6d8c020170a9f6277f98e510363 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 1 Nov 2023 23:33:06 +0530 Subject: [PATCH 535/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.8.1 (#1332) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 884473cca..5531a9c98 100755 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.8.0", + "@snapshot-labs/snapshot.js": "^0.8.1", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index e6c275a7a..2b7404231 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.8.0": - version "0.8.0" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.8.0.tgz#f440c60a34cdc886d9bfc9f578278bb14ee0aa21" - integrity sha512-FnTwofZuI57l2n7+krYGIYh7LkF955ItM6T+vsAH7gaVSUlMWYcA3tGOcgsj0STwjge3Y8JwgUsfPf3SadOYow== +"@snapshot-labs/snapshot.js@^0.8.1": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.8.1.tgz#1bd8e939ec354dde89fbe284366bd11e8103c0c6" + integrity sha512-TTKfMBMaf+jQqpgsPezQ6pz5d3IXqO4z2P+Kwfa5W9Noz4+XfrvOHo2ADl4TuCBp922EvF7bfxLQVvKAakQZPA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 0dcef508503082d9f5af0d7820e8f53cb3500ed3 Mon Sep 17 00:00:00 2001 From: JD <103535732+JD0x2e@users.noreply.github.com> Date: Thu, 2 Nov 2023 12:17:30 +0000 Subject: [PATCH 536/815] [rdnt-capital-voting] Add Ethereum mainnet to rdnt-capital-voting (#1333) * [rdnt-capital-dlp] added total dlp check strategy * Create README.md * Added rdnt-capital-locked-dlp strategy * Reverted strategy back to lockedBalances as uint * Updated strategy which returns rdnt amount in locked dLP * added BSC functionality * RDNT in LP strat * Updated name * Update examples.json * Update src/strategies/rdnt-capital-voting/README.md Co-authored-by: Chaitanya * Update README.md * Add ethereum to rdnt-capital-voting --------- Co-authored-by: TomBrandy <103236817+TomBrandy@users.noreply.github.com> Co-authored-by: JD <103535732+JDoy99@users.noreply.github.com> Co-authored-by: Chaitanya --- .../rdnt-capital-voting/examples.json | 20 +++++++++++++++++++ src/strategies/rdnt-capital-voting/index.ts | 4 ++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/strategies/rdnt-capital-voting/examples.json b/src/strategies/rdnt-capital-voting/examples.json index cffa2db05..a5805037b 100644 --- a/src/strategies/rdnt-capital-voting/examples.json +++ b/src/strategies/rdnt-capital-voting/examples.json @@ -36,5 +36,25 @@ "0x2eAA7327e9B5Ff46bc2B7452acE9e44A1528eb84" ], "snapshot": 26920121 + }, + { + "name": "RDNT in dLP - Mainnet", + "strategy": { + "name": "rdnt-capital-voting", + "params": { + "rdnt": "0x137dDB47Ee24EaA998a535Ab00378d6BFa84F893", + "lpToken": "0xcF7b51ce5755513d4bE016b0e28D6EDEffa1d52a", + "lockingContract": "0x28E395a54a64284DBA39652921Cd99924f4e3797", + "balancerPoolId": "0xcf7b51ce5755513d4be016b0e28d6edeffa1d52a000200000000000000000617", + "balancerVault": "0xBA12222222228d8Ba445958a75a0704d566BF2C8" + } + }, + "network": "1", + "addresses": [ + "0x2eAA7327e9B5Ff46bc2B7452acE9e44A1528eb84", + "0x8EDdC30B12A5Cc60d046fc1B1b887eb2c1353a87", + "0x4011091Dbe57bd4521F598616fe4BB3978ea3005" + ], + "snapshot": 18483999 } ] diff --git a/src/strategies/rdnt-capital-voting/index.ts b/src/strategies/rdnt-capital-voting/index.ts index 72ad21a47..57a64cd9a 100644 --- a/src/strategies/rdnt-capital-voting/index.ts +++ b/src/strategies/rdnt-capital-voting/index.ts @@ -2,7 +2,7 @@ import { BigNumberish } from '@ethersproject/bignumber'; import { formatUnits } from '@ethersproject/units'; import { Multicaller, multicall, call } from '../../utils'; -export const author = 'JDoy99'; +export const author = 'JD0x2e'; export const version = '0.1.0'; const erc20Abi = [ @@ -84,7 +84,7 @@ export async function strategy( // Get RDNT per LP token (LP provider dependent) let rdntPerLp; - if (network === '42161') { + if (network === '42161' || network === '1') { rdntPerLp = await rdntPerBalancerLpToken( network, provider, From ab596ccd7d0f6cf32d42da011bc36687d98af241 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 5 Nov 2023 21:49:26 +0530 Subject: [PATCH 537/815] Automated lint (#1334) Co-authored-by: ChaituVR --- src/strategies/floki/schema.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/strategies/floki/schema.json b/src/strategies/floki/schema.json index d20eb6bae..bc871a542 100644 --- a/src/strategies/floki/schema.json +++ b/src/strategies/floki/schema.json @@ -42,7 +42,12 @@ "examples": ["e.g. 9"] } }, - "required": ["tokenAddress", "stakingPoolAddress", "stakingPoolMultiplierAddress", "decimals"], + "required": [ + "tokenAddress", + "stakingPoolAddress", + "stakingPoolMultiplierAddress", + "decimals" + ], "additionalProperties": false } } From 9240a7ab3617cb63342cf4ed66ea00b632e5a60b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 9 Nov 2023 13:50:10 +0530 Subject: [PATCH 538/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.8.2 (#1336) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 5531a9c98..6d5d5a1f9 100755 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.8.1", + "@snapshot-labs/snapshot.js": "^0.8.2", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 2b7404231..3851a460f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.8.1": - version "0.8.1" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.8.1.tgz#1bd8e939ec354dde89fbe284366bd11e8103c0c6" - integrity sha512-TTKfMBMaf+jQqpgsPezQ6pz5d3IXqO4z2P+Kwfa5W9Noz4+XfrvOHo2ADl4TuCBp922EvF7bfxLQVvKAakQZPA== +"@snapshot-labs/snapshot.js@^0.8.2": + version "0.8.2" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.8.2.tgz#3707bbe4e65cff68e9a745be86d0b38d6cd53789" + integrity sha512-xeUwz5cIVUTmiC0UcPo9j9Zyx7198H8iwJXATaPl8+gMLH9Q5ktxHQZIIQyY9WiDFVX30NFO7ivGEjD1u4gFsA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 4fb365fc3d7a5be31969feff46147f9bd4c18261 Mon Sep 17 00:00:00 2001 From: Jacob Homanics <32080359+Hotmanics@users.noreply.github.com> Date: Fri, 10 Nov 2023 05:22:51 -0600 Subject: [PATCH 539/815] [hats-protocol-hat-ids] added hat ids stategy (#1339) * added hat ids stategy * Update src/strategies/hats-protocol-hat-ids/README.md Co-authored-by: Chaitanya * updated read me --------- Co-authored-by: Chaitanya --- .../hats-protocol-hat-ids/README.md | 30 ++ .../hats-protocol-hat-ids/examples.json | 26 ++ src/strategies/hats-protocol-hat-ids/index.ts | 259 ++++++++++++++++++ .../hats-protocol-hat-ids/schema.json | 34 +++ src/strategies/index.ts | 4 +- 5 files changed, 352 insertions(+), 1 deletion(-) create mode 100644 src/strategies/hats-protocol-hat-ids/README.md create mode 100644 src/strategies/hats-protocol-hat-ids/examples.json create mode 100644 src/strategies/hats-protocol-hat-ids/index.ts create mode 100644 src/strategies/hats-protocol-hat-ids/schema.json diff --git a/src/strategies/hats-protocol-hat-ids/README.md b/src/strategies/hats-protocol-hat-ids/README.md new file mode 100644 index 000000000..5b6a324fc --- /dev/null +++ b/src/strategies/hats-protocol-hat-ids/README.md @@ -0,0 +1,30 @@ +# hats-protocol-hat-ids + +Grants voting power based on if voter has a set of specified hat (IP based). + +Here is an example of parameters: + +```json +{ + "address": "0x3bc1A0Ad72417f2d411118085256fC53CBdDd137", + "hatIds": "[\"68\"]" +} +``` + +or + +```json +{ + "address": "0x3bc1A0Ad72417f2d411118085256fC53CBdDd137", + "hatIds": "[\"68\", \"68.1\"]" +} +``` + +or + +```json +{ + "address": "0x3bc1A0Ad72417f2d411118085256fC53CBdDd137", + "hatIds": "[\"68\", \"68.1\", \"68.1.1\"]" +} +``` diff --git a/src/strategies/hats-protocol-hat-ids/examples.json b/src/strategies/hats-protocol-hat-ids/examples.json new file mode 100644 index 000000000..23215aa25 --- /dev/null +++ b/src/strategies/hats-protocol-hat-ids/examples.json @@ -0,0 +1,26 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "hats-protocol-hat-ids", + "params": { + "address": "0x3bc1A0Ad72417f2d411118085256fC53CBdDd137", + "hatIds": [ + "68", + "68.1", + "68.1.1", + "68.1.1.1" + ] + } + }, + "network": "5", + "addresses": [ + "0xc4f6578c24c599F195c0758aD3D4861758d703A3", + "0xa6aF0566EF4eF7E8f38913f69d4e55c06F00A5aC", + "0x00e7332F9Cd4C05a0645AC959Fb1Be60ec24F94f", + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "0x4D6Ed22Ed0850384622EF129932aE29D27a89eD3" + ], + "snapshot": 10015682 + } +] \ No newline at end of file diff --git a/src/strategies/hats-protocol-hat-ids/index.ts b/src/strategies/hats-protocol-hat-ids/index.ts new file mode 100644 index 000000000..ca9ec1321 --- /dev/null +++ b/src/strategies/hats-protocol-hat-ids/index.ts @@ -0,0 +1,259 @@ +import { subgraphRequest } from '../../utils'; +import { getAddress } from '@ethersproject/address'; +import { StaticJsonRpcProvider } from '@ethersproject/providers'; +import { multicall } from '../../utils'; + +export const author = 'hotmanics'; +export const version = '1.0.0'; + +const abi = [ + 'function isWearerOfHat(address _user, uint256 _hatId) external view returns (bool isWearer)' +]; + +async function subgraphRequestHats({ url, snapshot, treeIp }) { + + let treeHex = treeIdDecimalToHex(treeIp); + + const params = { + tree: { + __args: { + id: treeHex + }, + id: true, + hats: { + id: true, + wearers: { + id: true + } + } + } + }; + + if (snapshot !== 'latest') { + // @ts-ignore + params.tree.__args.block = { number: snapshot }; + } + const result = await subgraphRequest(url, params); + return result; +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + //This strategy currently enforces that all hatIds passed in are from the same tree. + for (let i = 0; i < options.hatIds.length; i++) { + let lhs = treeIpFromIp(options.hatIds[i]); + + for (let j = 0; j < options.hatIds.length; j++) { + let rhs = treeIpFromIp(options.hatIds[j]); + if (lhs !== rhs) { + throw Error("You can only use hats from the same tree!"); + } + } + } + + //all hatIds are assumed to be from the same tree, set selectedTree to any, and continue. + let selectedTree = treeIpFromIp(options.hatIds[0]); + + const request = { + url: getActiveNetworkSubgraphURL(network), + snapshot, + treeIp: selectedTree + } + + const result = await subgraphRequestHats(request); + + let validHats: any[] = []; + + for (let j = 0; j < options.hatIds.length; j++) { + for (let i = 0; i < result.tree.hats.length; i++) { + + let hatIpHex = HatIpToHex(options.hatIds[j]); + + if (hatIpHex === result.tree.hats[i].id) { + validHats.push(result.tree.hats[i]); + break; + } + } + } + + let wearersInAddresses = []; + + addresses.forEach((address) => { + const wearer = checkIfExists(address, validHats); + wearersInAddresses = wearersInAddresses.concat(wearer); + }); + + const multi = new Multicaller(network, provider, abi, { blockTag }); + + wearersInAddresses.forEach((wearer) => { + multi.call(wearer.address, options.address, 'isWearerOfHat', [ + wearer.address, + wearer.hat + ]); + }); + + const multiResult = await multi.execute(); + + const myObj = {}; + + wearersInAddresses.forEach((wearer) => { + myObj[wearer.address] = 0; + for (const result of multiResult) { + if (wearer.address === result.address) { + myObj[wearer.address] = 1; + break; + } + } + }); + + return myObj; +} + +function getActiveNetworkSubgraphURL(network) { + + let url; + + switch (network) { + case '1': + url = 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-ethereum'; + break; + case '10': + url = 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-optimism'; + break; + case '5': + url = 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-goerli'; + break; + case '137': + url = 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-polygon'; + break; + case '100': + url = 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-gnosis-chain'; + break; + case '42161': + url = 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-arbitrum'; + break; + } + + return url; +} + +function checkIfExists(address, hats) { + const addressWithHats = []; + hats.forEach((hat) => { + hat.wearers.forEach((wearer) => { + if (getAddress(wearer.id) === address) { + const addressWithHat = { + address: getAddress(wearer.id), + hat: BigInt(hat.id) + }; + addressWithHats.push(addressWithHat); + } + }); + }); + return addressWithHats; +} + +function treeIdDecimalToHex(treeId: number): string { + return "0x" + treeId.toString(16).padStart(8, "0"); +} + +function HatIpToHex(hatIp) { + let observedChunk = hatIp; + + const sections: Number[] = []; + + while (true) { + if (observedChunk.indexOf(".") === -1) { + let section = observedChunk.substring(0, observedChunk.length); + sections.push(Number(section)); + break; + } + + let section = observedChunk.substring(0, observedChunk.indexOf(".")); + observedChunk = observedChunk.substring(observedChunk.indexOf(".") + 1, observedChunk.length); + + sections.push(Number(section)); + } + + let constructedResult = "0x"; + + for (let i = 0; i < sections.length; i++) { + let hex = sections[i].toString(16); + + if (i === 0) { + constructedResult += hex.padStart(10 - hex.length, "0"); + } else { + constructedResult += hex.padStart(5 - hex.length, "0"); + } + + } + + constructedResult = constructedResult.padEnd(66, "0"); + return constructedResult; +} + +function treeIpFromIp(hatIp) { + let treeIp; + + if (hatIp.indexOf(".") === -1) + treeIp = hatIp; + else + treeIp = hatIp.substring(0, hatIp.indexOf(".")); + + return Number(treeIp); +} + +class Multicaller { + public network: string; + public provider: StaticJsonRpcProvider; + public abi: any[]; + public options: any = {}; + public calls: any[] = []; + public paths: any[] = []; + + constructor( + network: string, + provider: StaticJsonRpcProvider, + abi: any[], + options? + ) { + this.network = network; + this.provider = provider; + this.abi = abi; + this.options = options || {}; + } + + call(path, address, fn, params?): Multicaller { + this.calls.push([address, fn, params]); + this.paths.push(path); + return this; + } + + async execute(): Promise { + const obj = []; + const result = await multicall( + this.network, + this.provider, + this.abi, + this.calls, + this.options + ); + result.forEach((r, i) => { + obj.push({ + address: this.paths[i], + value: r + }); + }); + this.calls = []; + this.paths = []; + return obj; + } +} \ No newline at end of file diff --git a/src/strategies/hats-protocol-hat-ids/schema.json b/src/strategies/hats-protocol-hat-ids/schema.json new file mode 100644 index 000000000..6c64583cb --- /dev/null +++ b/src/strategies/hats-protocol-hat-ids/schema.json @@ -0,0 +1,34 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "address": { + "type": "string", + "title": "Contract address", + "examples": [ + "e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984" + ], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "hatIds": { + "type": "array", + "title": "Hat Ids", + "examples": [ + "e.g. [\"68\", \"68.1\", \"68.1.1\", \"68.1.1.1\"" + ] + } + }, + "required": [ + "address", + "hatIds" + ], + "additionalProperties": false + } + } +} \ No newline at end of file diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 00b037886..af349d5f2 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -472,6 +472,7 @@ import * as stationScoreIfBadge from './station-score-if-badge'; import * as stationConstantIfBadge from './station-constant-if-badge'; import * as mangroveStationQVScaledToMGV from './mangrove-station-qv-scaled-to-mgv'; import * as floki from './floki'; +import * as hatsProtocolHatIds from "./hats-protocol-hat-ids"; const strategies = { 'cap-voting-power': capVotingPower, @@ -952,7 +953,8 @@ const strategies = { 'station-score-if-badge': stationScoreIfBadge, 'station-constant-if-badge': stationConstantIfBadge, 'mangrove-station-qv-scaled-to-mgv': mangroveStationQVScaledToMGV, - floki + floki, + 'hats-protocol-hat-ids': hatsProtocolHatIds }; Object.keys(strategies).forEach(function (strategyName) { From 67e3c363dbd1fa53d698c64037f2eb93ee0b92f1 Mon Sep 17 00:00:00 2001 From: Jacob Homanics <32080359+Hotmanics@users.noreply.github.com> Date: Fri, 10 Nov 2023 05:27:29 -0600 Subject: [PATCH 540/815] added in hat id strategy (#1340) Co-authored-by: Chaitanya --- src/strategies/hats-protocol-hat-id/README.md | 30 ++++ .../hats-protocol-hat-id/examples.json | 21 +++ src/strategies/hats-protocol-hat-id/index.ts | 135 ++++++++++++++++++ .../hats-protocol-hat-id/schema.json | 34 +++++ src/strategies/index.ts | 2 + 5 files changed, 222 insertions(+) create mode 100644 src/strategies/hats-protocol-hat-id/README.md create mode 100644 src/strategies/hats-protocol-hat-id/examples.json create mode 100644 src/strategies/hats-protocol-hat-id/index.ts create mode 100644 src/strategies/hats-protocol-hat-id/schema.json diff --git a/src/strategies/hats-protocol-hat-id/README.md b/src/strategies/hats-protocol-hat-id/README.md new file mode 100644 index 000000000..6fc08b89e --- /dev/null +++ b/src/strategies/hats-protocol-hat-id/README.md @@ -0,0 +1,30 @@ +# hats-protocol-hat-id + +Grants voting power based on if voter has a specific hat (IP based). + +Here is an example of parameters: + +```json +{ + "address": "0x3bc1A0Ad72417f2d411118085256fC53CBdDd137", + "hatId": "68" +} +``` + +or + +```json +{ + "address": "0x3bc1A0Ad72417f2d411118085256fC53CBdDd137", + "hatId": "68.1" +} +``` + +or + +```json +{ + "address": "0x3bc1A0Ad72417f2d411118085256fC53CBdDd137", + "hatId": "68.1.1" +} +``` diff --git a/src/strategies/hats-protocol-hat-id/examples.json b/src/strategies/hats-protocol-hat-id/examples.json new file mode 100644 index 000000000..8b1f5fdeb --- /dev/null +++ b/src/strategies/hats-protocol-hat-id/examples.json @@ -0,0 +1,21 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "hats-protocol-hat-id", + "params": { + "address": "0x3bc1A0Ad72417f2d411118085256fC53CBdDd137", + "hatId": "68.1.1.1" + } + }, + "network": "5", + "addresses": [ + "0xc4f6578c24c599F195c0758aD3D4861758d703A3", + "0xa6aF0566EF4eF7E8f38913f69d4e55c06F00A5aC", + "0x00e7332F9Cd4C05a0645AC959Fb1Be60ec24F94f", + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", + "0x4D6Ed22Ed0850384622EF129932aE29D27a89eD3" + ], + "snapshot": 10015682 + } +] \ No newline at end of file diff --git a/src/strategies/hats-protocol-hat-id/index.ts b/src/strategies/hats-protocol-hat-id/index.ts new file mode 100644 index 000000000..e96158a5f --- /dev/null +++ b/src/strategies/hats-protocol-hat-id/index.ts @@ -0,0 +1,135 @@ +import { subgraphRequest } from '../../utils'; +import { getAddress } from '@ethersproject/address'; + +export const author = 'hotmanics'; +export const version = '1.0.0'; + +async function subgraphRequestHats(url, snapshot, hatIp) { + + let hatHex = HatIpToHex(hatIp); + + const params = { + hat: { + __args: { + id: hatHex + }, + id: true, + wearers: { + id: true + }, + } + } + + if (snapshot !== 'latest') { + // @ts-ignore + params.hat.__args.block = { number: snapshot }; + } + const result = await subgraphRequest(url, params); + return result; +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + let result; + + switch (network) { + case '1': + result = await subgraphRequestHats( + 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-ethereum', + snapshot, + options.hatId + ); + break; + case '10': + result = await subgraphRequestHats( + 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-optimism', + snapshot, + options.hatId + ); + break; + case '5': + result = await subgraphRequestHats( + 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-goerli', + snapshot, + options.hatId + ); + break; + case '137': + result = await subgraphRequestHats( + 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-polygon', + snapshot, + options.hatId + ); + break; + case '100': + result = await subgraphRequestHats( + 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-gnosis-chain', + snapshot, + options.hatId + ); + break; + case '42161': + result = await subgraphRequestHats( + 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-arbitrum', + snapshot, + options.hatId + ); + break; + } + + const myObj = {}; + + addresses.forEach((address) => { + myObj[address] = 0; + + for (let i = 0; i < result.hat.wearers.length; i++) { + if (address === getAddress(result.hat.wearers[i].id)) { + myObj[address] = 1; + break; + } + } + }) + + return myObj; +} + +function HatIpToHex(hatIp) { + let observedChunk = hatIp; + + const sections: Number[] = []; + + while (true) { + if (observedChunk.indexOf(".") === -1) { + let section = observedChunk.substring(0, observedChunk.length); + sections.push(Number(section)); + break; + } + + let section = observedChunk.substring(0, observedChunk.indexOf(".")); + observedChunk = observedChunk.substring(observedChunk.indexOf(".") + 1, observedChunk.length); + + sections.push(Number(section)); + } + + let constructedResult = "0x"; + + for (let i = 0; i < sections.length; i++) { + let hex = sections[i].toString(16); + + if (i === 0) { + constructedResult += hex.padStart(10 - hex.length, "0"); + } else { + constructedResult += hex.padStart(5 - hex.length, "0"); + } + + } + + constructedResult = constructedResult.padEnd(66, "0"); + return constructedResult; +} \ No newline at end of file diff --git a/src/strategies/hats-protocol-hat-id/schema.json b/src/strategies/hats-protocol-hat-id/schema.json new file mode 100644 index 000000000..51865a8c0 --- /dev/null +++ b/src/strategies/hats-protocol-hat-id/schema.json @@ -0,0 +1,34 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "address": { + "type": "string", + "title": "Contract address", + "examples": [ + "e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984" + ], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "hatId": { + "type": "string", + "title": "Hat Id", + "examples": [ + "e.g. 68, 68.1, 68.1.1, 68.1.1.1 etc" + ] + } + }, + "required": [ + "address", + "hatId" + ], + "additionalProperties": false + } + } +} \ No newline at end of file diff --git a/src/strategies/index.ts b/src/strategies/index.ts index af349d5f2..94171ca2f 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -472,6 +472,7 @@ import * as stationScoreIfBadge from './station-score-if-badge'; import * as stationConstantIfBadge from './station-constant-if-badge'; import * as mangroveStationQVScaledToMGV from './mangrove-station-qv-scaled-to-mgv'; import * as floki from './floki'; +import * as hatsProtocolHatId from "./hats-protocol-hat-id"; import * as hatsProtocolHatIds from "./hats-protocol-hat-ids"; const strategies = { @@ -954,6 +955,7 @@ const strategies = { 'station-constant-if-badge': stationConstantIfBadge, 'mangrove-station-qv-scaled-to-mgv': mangroveStationQVScaledToMGV, floki, + 'hats-protocol-hat-id': hatsProtocolHatId, 'hats-protocol-hat-ids': hatsProtocolHatIds }; From 22a1e11f4789956369cf651aaa910d491dbc2c65 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 10 Nov 2023 17:05:02 +0530 Subject: [PATCH 541/815] Automated lint (#1342) Co-authored-by: ChaituVR --- .../hats-protocol-hat-id/examples.json | 2 +- src/strategies/hats-protocol-hat-id/index.ts | 35 ++++----- .../hats-protocol-hat-id/schema.json | 15 ++-- .../hats-protocol-hat-ids/examples.json | 9 +-- src/strategies/hats-protocol-hat-ids/index.ts | 71 ++++++++++--------- .../hats-protocol-hat-ids/schema.json | 15 ++-- src/strategies/index.ts | 4 +- 7 files changed, 68 insertions(+), 83 deletions(-) diff --git a/src/strategies/hats-protocol-hat-id/examples.json b/src/strategies/hats-protocol-hat-id/examples.json index 8b1f5fdeb..e165ad767 100644 --- a/src/strategies/hats-protocol-hat-id/examples.json +++ b/src/strategies/hats-protocol-hat-id/examples.json @@ -18,4 +18,4 @@ ], "snapshot": 10015682 } -] \ No newline at end of file +] diff --git a/src/strategies/hats-protocol-hat-id/index.ts b/src/strategies/hats-protocol-hat-id/index.ts index e96158a5f..a494a0588 100644 --- a/src/strategies/hats-protocol-hat-id/index.ts +++ b/src/strategies/hats-protocol-hat-id/index.ts @@ -5,8 +5,7 @@ export const author = 'hotmanics'; export const version = '1.0.0'; async function subgraphRequestHats(url, snapshot, hatIp) { - - let hatHex = HatIpToHex(hatIp); + const hatHex = HatIpToHex(hatIp); const params = { hat: { @@ -16,9 +15,9 @@ async function subgraphRequestHats(url, snapshot, hatIp) { id: true, wearers: { id: true - }, + } } - } + }; if (snapshot !== 'latest') { // @ts-ignore @@ -94,7 +93,7 @@ export async function strategy( break; } } - }) + }); return myObj; } @@ -102,34 +101,36 @@ export async function strategy( function HatIpToHex(hatIp) { let observedChunk = hatIp; - const sections: Number[] = []; + const sections: number[] = []; while (true) { - if (observedChunk.indexOf(".") === -1) { - let section = observedChunk.substring(0, observedChunk.length); + if (observedChunk.indexOf('.') === -1) { + const section = observedChunk.substring(0, observedChunk.length); sections.push(Number(section)); break; } - let section = observedChunk.substring(0, observedChunk.indexOf(".")); - observedChunk = observedChunk.substring(observedChunk.indexOf(".") + 1, observedChunk.length); + const section = observedChunk.substring(0, observedChunk.indexOf('.')); + observedChunk = observedChunk.substring( + observedChunk.indexOf('.') + 1, + observedChunk.length + ); sections.push(Number(section)); } - let constructedResult = "0x"; + let constructedResult = '0x'; for (let i = 0; i < sections.length; i++) { - let hex = sections[i].toString(16); + const hex = sections[i].toString(16); if (i === 0) { - constructedResult += hex.padStart(10 - hex.length, "0"); + constructedResult += hex.padStart(10 - hex.length, '0'); } else { - constructedResult += hex.padStart(5 - hex.length, "0"); + constructedResult += hex.padStart(5 - hex.length, '0'); } - } - constructedResult = constructedResult.padEnd(66, "0"); + constructedResult = constructedResult.padEnd(66, '0'); return constructedResult; -} \ No newline at end of file +} diff --git a/src/strategies/hats-protocol-hat-id/schema.json b/src/strategies/hats-protocol-hat-id/schema.json index 51865a8c0..1e21753bd 100644 --- a/src/strategies/hats-protocol-hat-id/schema.json +++ b/src/strategies/hats-protocol-hat-id/schema.json @@ -9,9 +9,7 @@ "address": { "type": "string", "title": "Contract address", - "examples": [ - "e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984" - ], + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], "pattern": "^0x[a-fA-F0-9]{40}$", "minLength": 42, "maxLength": 42 @@ -19,16 +17,11 @@ "hatId": { "type": "string", "title": "Hat Id", - "examples": [ - "e.g. 68, 68.1, 68.1.1, 68.1.1.1 etc" - ] + "examples": ["e.g. 68, 68.1, 68.1.1, 68.1.1.1 etc"] } }, - "required": [ - "address", - "hatId" - ], + "required": ["address", "hatId"], "additionalProperties": false } } -} \ No newline at end of file +} diff --git a/src/strategies/hats-protocol-hat-ids/examples.json b/src/strategies/hats-protocol-hat-ids/examples.json index 23215aa25..c316ce14f 100644 --- a/src/strategies/hats-protocol-hat-ids/examples.json +++ b/src/strategies/hats-protocol-hat-ids/examples.json @@ -5,12 +5,7 @@ "name": "hats-protocol-hat-ids", "params": { "address": "0x3bc1A0Ad72417f2d411118085256fC53CBdDd137", - "hatIds": [ - "68", - "68.1", - "68.1.1", - "68.1.1.1" - ] + "hatIds": ["68", "68.1", "68.1.1", "68.1.1.1"] } }, "network": "5", @@ -23,4 +18,4 @@ ], "snapshot": 10015682 } -] \ No newline at end of file +] diff --git a/src/strategies/hats-protocol-hat-ids/index.ts b/src/strategies/hats-protocol-hat-ids/index.ts index ca9ec1321..9ccb9372f 100644 --- a/src/strategies/hats-protocol-hat-ids/index.ts +++ b/src/strategies/hats-protocol-hat-ids/index.ts @@ -11,8 +11,7 @@ const abi = [ ]; async function subgraphRequestHats({ url, snapshot, treeIp }) { - - let treeHex = treeIdDecimalToHex(treeIp); + const treeHex = treeIdDecimalToHex(treeIp); const params = { tree: { @@ -49,33 +48,32 @@ export async function strategy( //This strategy currently enforces that all hatIds passed in are from the same tree. for (let i = 0; i < options.hatIds.length; i++) { - let lhs = treeIpFromIp(options.hatIds[i]); + const lhs = treeIpFromIp(options.hatIds[i]); for (let j = 0; j < options.hatIds.length; j++) { - let rhs = treeIpFromIp(options.hatIds[j]); + const rhs = treeIpFromIp(options.hatIds[j]); if (lhs !== rhs) { - throw Error("You can only use hats from the same tree!"); + throw Error('You can only use hats from the same tree!'); } } } //all hatIds are assumed to be from the same tree, set selectedTree to any, and continue. - let selectedTree = treeIpFromIp(options.hatIds[0]); + const selectedTree = treeIpFromIp(options.hatIds[0]); const request = { url: getActiveNetworkSubgraphURL(network), snapshot, treeIp: selectedTree - } + }; const result = await subgraphRequestHats(request); - let validHats: any[] = []; + const validHats: any[] = []; for (let j = 0; j < options.hatIds.length; j++) { for (let i = 0; i < result.tree.hats.length; i++) { - - let hatIpHex = HatIpToHex(options.hatIds[j]); + const hatIpHex = HatIpToHex(options.hatIds[j]); if (hatIpHex === result.tree.hats[i].id) { validHats.push(result.tree.hats[i]); @@ -118,27 +116,32 @@ export async function strategy( } function getActiveNetworkSubgraphURL(network) { - let url; switch (network) { case '1': - url = 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-ethereum'; + url = + 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-ethereum'; break; case '10': - url = 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-optimism'; + url = + 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-optimism'; break; case '5': - url = 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-goerli'; + url = + 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-goerli'; break; case '137': - url = 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-polygon'; + url = + 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-polygon'; break; case '100': - url = 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-gnosis-chain'; + url = + 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-gnosis-chain'; break; case '42161': - url = 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-arbitrum'; + url = + 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-arbitrum'; break; } @@ -162,51 +165,51 @@ function checkIfExists(address, hats) { } function treeIdDecimalToHex(treeId: number): string { - return "0x" + treeId.toString(16).padStart(8, "0"); + return '0x' + treeId.toString(16).padStart(8, '0'); } function HatIpToHex(hatIp) { let observedChunk = hatIp; - const sections: Number[] = []; + const sections: number[] = []; while (true) { - if (observedChunk.indexOf(".") === -1) { - let section = observedChunk.substring(0, observedChunk.length); + if (observedChunk.indexOf('.') === -1) { + const section = observedChunk.substring(0, observedChunk.length); sections.push(Number(section)); break; } - let section = observedChunk.substring(0, observedChunk.indexOf(".")); - observedChunk = observedChunk.substring(observedChunk.indexOf(".") + 1, observedChunk.length); + const section = observedChunk.substring(0, observedChunk.indexOf('.')); + observedChunk = observedChunk.substring( + observedChunk.indexOf('.') + 1, + observedChunk.length + ); sections.push(Number(section)); } - let constructedResult = "0x"; + let constructedResult = '0x'; for (let i = 0; i < sections.length; i++) { - let hex = sections[i].toString(16); + const hex = sections[i].toString(16); if (i === 0) { - constructedResult += hex.padStart(10 - hex.length, "0"); + constructedResult += hex.padStart(10 - hex.length, '0'); } else { - constructedResult += hex.padStart(5 - hex.length, "0"); + constructedResult += hex.padStart(5 - hex.length, '0'); } - } - constructedResult = constructedResult.padEnd(66, "0"); + constructedResult = constructedResult.padEnd(66, '0'); return constructedResult; } function treeIpFromIp(hatIp) { let treeIp; - if (hatIp.indexOf(".") === -1) - treeIp = hatIp; - else - treeIp = hatIp.substring(0, hatIp.indexOf(".")); + if (hatIp.indexOf('.') === -1) treeIp = hatIp; + else treeIp = hatIp.substring(0, hatIp.indexOf('.')); return Number(treeIp); } @@ -256,4 +259,4 @@ class Multicaller { this.paths = []; return obj; } -} \ No newline at end of file +} diff --git a/src/strategies/hats-protocol-hat-ids/schema.json b/src/strategies/hats-protocol-hat-ids/schema.json index 6c64583cb..1d83a4e15 100644 --- a/src/strategies/hats-protocol-hat-ids/schema.json +++ b/src/strategies/hats-protocol-hat-ids/schema.json @@ -9,9 +9,7 @@ "address": { "type": "string", "title": "Contract address", - "examples": [ - "e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984" - ], + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], "pattern": "^0x[a-fA-F0-9]{40}$", "minLength": 42, "maxLength": 42 @@ -19,16 +17,11 @@ "hatIds": { "type": "array", "title": "Hat Ids", - "examples": [ - "e.g. [\"68\", \"68.1\", \"68.1.1\", \"68.1.1.1\"" - ] + "examples": ["e.g. [\"68\", \"68.1\", \"68.1.1\", \"68.1.1.1\""] } }, - "required": [ - "address", - "hatIds" - ], + "required": ["address", "hatIds"], "additionalProperties": false } } -} \ No newline at end of file +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 94171ca2f..5c3b93514 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -472,8 +472,8 @@ import * as stationScoreIfBadge from './station-score-if-badge'; import * as stationConstantIfBadge from './station-constant-if-badge'; import * as mangroveStationQVScaledToMGV from './mangrove-station-qv-scaled-to-mgv'; import * as floki from './floki'; -import * as hatsProtocolHatId from "./hats-protocol-hat-id"; -import * as hatsProtocolHatIds from "./hats-protocol-hat-ids"; +import * as hatsProtocolHatId from './hats-protocol-hat-id'; +import * as hatsProtocolHatIds from './hats-protocol-hat-ids'; const strategies = { 'cap-voting-power': capVotingPower, From b855dfd3b99d8ab1ce01c7742693ee8c42af1a3a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 10 Nov 2023 17:16:09 +0530 Subject: [PATCH 542/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.8.3 (#1337) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 6d5d5a1f9..476ace073 100755 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.8.2", + "@snapshot-labs/snapshot.js": "^0.8.3", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 3851a460f..624ff7f1f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.8.2": - version "0.8.2" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.8.2.tgz#3707bbe4e65cff68e9a745be86d0b38d6cd53789" - integrity sha512-xeUwz5cIVUTmiC0UcPo9j9Zyx7198H8iwJXATaPl8+gMLH9Q5ktxHQZIIQyY9WiDFVX30NFO7ivGEjD1u4gFsA== +"@snapshot-labs/snapshot.js@^0.8.3": + version "0.8.3" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.8.3.tgz#a514d879d472e9da7a762c610371e65ceef3f604" + integrity sha512-BU3esG+M7NP3qAdE+Kzlxgg+mgQFsjaxCGh6MKGWLLwgkA8Jg6i/EpYf9cBhhXQSdgPuBxfXC+OtK1ATnAzRkQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From a45c638bc55e1fdde129b15f19c68469372447a0 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Mon, 13 Nov 2023 10:50:42 +0530 Subject: [PATCH 543/815] [hats-protocol-hat-ids] fix: Arrays in schema should contain items property (#1343) --- .../hats-protocol-hat-ids/schema.json | 5 ++++- test/strategy.test.ts | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/strategies/hats-protocol-hat-ids/schema.json b/src/strategies/hats-protocol-hat-ids/schema.json index 1d83a4e15..fe8c6a7f7 100644 --- a/src/strategies/hats-protocol-hat-ids/schema.json +++ b/src/strategies/hats-protocol-hat-ids/schema.json @@ -17,7 +17,10 @@ "hatIds": { "type": "array", "title": "Hat Ids", - "examples": ["e.g. [\"68\", \"68.1\", \"68.1.1\", \"68.1.1.1\""] + "examples": ["e.g. [\"68\", \"68.1\", \"68.1.1\", \"68.1.1.1\""], + "items": { + "type": "string" + } } }, "required": ["address", "hatIds"], diff --git a/test/strategy.test.ts b/test/strategy.test.ts index 081d1de12..5e729838a 100644 --- a/test/strategy.test.ts +++ b/test/strategy.test.ts @@ -238,6 +238,23 @@ describe.each(examples)( ).toBe(true); } ); + (schema ? it : it.skip)( + 'Check schema (if available) all arrays in all levels should contain `items` property', + async () => { + const strategyParamsSchema = schema.definitions.Strategy.properties; + function checkArrayItems(schema: any) { + Object.keys(schema).forEach((key) => { + if (typeof schema[key] === 'object') { + checkArrayItems(schema[key]); + } else if (schema.type === 'array') { + expect(schema.items).toBeTruthy(); + } + }); + } + + checkArrayItems(strategyParamsSchema); + } + ); (schema ? it : it.skip)( 'Strategy should work even when strategy symbol is null', async () => { From 2615e58789c21757e89f2427009bdfe6c2b576f9 Mon Sep 17 00:00:00 2001 From: Santiago Gonzalez Toral Date: Tue, 14 Nov 2023 01:58:29 -0500 Subject: [PATCH 544/815] [passport-gated]: update required parameters (#1309) --- src/validations/passport-gated/examples.json | 16 ++++++++++++++-- src/validations/passport-gated/index.ts | 6 ++++-- src/validations/passport-gated/schema.json | 13 +++++++++---- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/validations/passport-gated/examples.json b/src/validations/passport-gated/examples.json index d5347bd99..b89c9a402 100644 --- a/src/validations/passport-gated/examples.json +++ b/src/validations/passport-gated/examples.json @@ -1,4 +1,15 @@ [ + { + "name": "Example of a passport gated validation", + "author": "0x000000000000000000000000000000000000dead", + "space": "fabien.eth", + "network": "1", + "snapshot": "latest", + "params": { + "scoreThreshold": 0 + }, + "valid": true + }, { "name": "Example of a passport gated validation", "author": "0x24F15402C6Bb870554489b2fd2049A85d75B982f", @@ -6,6 +17,7 @@ "network": "1", "snapshot": "latest", "params": { + "scoreThreshold": 20, "stamps": ["Ens", "Github", "Snapshot"], "operator": "OR" }, @@ -18,9 +30,9 @@ "network": "1", "snapshot": "latest", "params": { + "scoreThreshold": 20, "stamps": ["Ens", "Github", "Snapshot"], - "operator": "OR", - "scoreThreshold": 20 + "operator": "OR" }, "valid": false } diff --git a/src/validations/passport-gated/index.ts b/src/validations/passport-gated/index.ts index a920582cf..e5c8bf22a 100644 --- a/src/validations/passport-gated/index.ts +++ b/src/validations/passport-gated/index.ts @@ -167,8 +167,10 @@ export default class extends Validation { async validate(currentAddress = this.author): Promise { const requiredStamps = this.params.stamps || []; const operator = this.params.operator; - const scoreThreshold = this.params.scoreThreshold || 0; - if (!operator) throw new Error('Operator is required'); + const scoreThreshold = this.params.scoreThreshold; + + if (scoreThreshold === undefined) throw new Error('Score threshold is required'); + if (requiredStamps.length > 0 && !operator) throw new Error('Operator is required'); const provider = snapshot.utils.getProvider(this.network); const proposalTs = (await provider.getBlock(this.snapshot)).timestamp; diff --git a/src/validations/passport-gated/schema.json b/src/validations/passport-gated/schema.json index effaa435a..5e84f589f 100644 --- a/src/validations/passport-gated/schema.json +++ b/src/validations/passport-gated/schema.json @@ -9,8 +9,9 @@ "stamps": { "type": "array", "title": "Stamps", + "description": "List of Eligible Passport Stamps (Optional).", "uniqueItems": true, - "minItems": 1, + "minItems": 0, "maxItems": 27, "items": { "type": "string", @@ -129,7 +130,7 @@ "operator": { "type": "string", "title": "Approval operator", - "description": "Control how many or which stamps are required to vote.", + "description": "Control how many stamps are required to become eligible.", "anyOf": [ { "const": "AND", @@ -138,19 +139,23 @@ { "const": "OR", "title": "Require at least one stamp" + }, + { + "const": "", + "title": "Any (Stamps MUST be empty)" } ] }, "scoreThreshold": { "type": "number", "title": "Passport Score Threshold", - "description": "Minimum Passport score threshold (>) to be eligible as a valid Passport", + "description": "Minimum Passport score threshold (>=) to be eligible as a valid Passport", "minimum": 0, "maximum": 100, "default": 0 } }, - "required": ["stamps", "operator"], + "required": ["scoreThreshold"], "additionalProperties": false } } From 8c388009e1e34a42805264050abae2c063e012d9 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Tue, 14 Nov 2023 12:33:03 +0530 Subject: [PATCH 545/815] Update index.ts --- src/validations/passport-gated/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/validations/passport-gated/index.ts b/src/validations/passport-gated/index.ts index e5c8bf22a..419374b41 100644 --- a/src/validations/passport-gated/index.ts +++ b/src/validations/passport-gated/index.ts @@ -170,7 +170,7 @@ export default class extends Validation { const scoreThreshold = this.params.scoreThreshold; if (scoreThreshold === undefined) throw new Error('Score threshold is required'); - if (requiredStamps.length > 0 && !operator) throw new Error('Operator is required'); + if (requiredStamps.length > 0 && !operator) throw new Error('Operator is required when selecting required stamps'); const provider = snapshot.utils.getProvider(this.network); const proposalTs = (await provider.getBlock(this.snapshot)).timestamp; From f768e8e8e25292d8fd1ce08ffd342dd5b786ba2a Mon Sep 17 00:00:00 2001 From: Marcelo Morgado Date: Tue, 14 Nov 2023 13:34:19 +0000 Subject: [PATCH 546/815] Update Vesper's voting power contract (#1344) --- src/strategies/vesper/examples.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/strategies/vesper/examples.json b/src/strategies/vesper/examples.json index 27a266598..951d1d500 100644 --- a/src/strategies/vesper/examples.json +++ b/src/strategies/vesper/examples.json @@ -4,21 +4,21 @@ "strategy": { "name": "vesper", "params": { - "token": "0x1b40183efb4dd766f11bda7a7c3ad8982e998421", + "token": "0x1b40183EFB4Dd766f11bDa7A7c3AD8982e998421", "symbol": "VSP", - "votingPower": "0xEbedFD259c9FB1F5c0ab9A9f24E79F8d80E29B23", + "votingPower": "0xD744320abd3bD4445Dc3C90C889391bD454D5B30", "decimals": 18, "blocksPerPeriod": 40320, - "minBlock": 13545210 + "minBlock": 18569909 } }, "network": "1", "addresses": [ - "0xb92792552e590339a7dbf1e0d6114fbc7395c86b", - "0xf4087b7ab24bde9c445ddd0bc4df257f81277214", - "0x8b01d375e274213c860ef6ac013dbdd5286cd816", - "0xdbc13e67f678cc00591920cece4dca6322a79ac7" + "0xb92792552e590339A7DbF1E0D6114fbc7395c86b", + "0xf4087b7AB24Bde9c445ddD0bc4DF257F81277214", + "0x8b01d375e274213c860eF6ac013DBDd5286CD816", + "0xDBC13E67F678Cc00591920ceCe4dCa6322a79AC7" ], - "snapshot": 13545210 + "snapshot": 18569909 } ] From 96aafc0983e3d37659be7aa14d3327acbaf5326f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 16 Nov 2023 11:13:32 +0530 Subject: [PATCH 547/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.9.0 (#1346) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 476ace073..71ebf5a63 100755 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.8.3", + "@snapshot-labs/snapshot.js": "^0.9.0", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 624ff7f1f..4eaa1bf4d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.8.3": - version "0.8.3" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.8.3.tgz#a514d879d472e9da7a762c610371e65ceef3f604" - integrity sha512-BU3esG+M7NP3qAdE+Kzlxgg+mgQFsjaxCGh6MKGWLLwgkA8Jg6i/EpYf9cBhhXQSdgPuBxfXC+OtK1ATnAzRkQ== +"@snapshot-labs/snapshot.js@^0.9.0": + version "0.9.0" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.9.0.tgz#36e1da862511b334197c4421e23ea1774926ea9b" + integrity sha512-cTE9hYhzcoblt0uJ3j4BgCo+2tN7sXTpZu9DE5tEwPMoPYUmkmyRklbFzFChT/kumUGP06XO1NDALnnWP3IEUg== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 121fe3e61e2318dabeb31229f60af8956a7cf606 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 17 Nov 2023 15:22:12 +0530 Subject: [PATCH 548/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.9.1 (#1347) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 71ebf5a63..ff91cdeb1 100755 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.9.0", + "@snapshot-labs/snapshot.js": "^0.9.1", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 4eaa1bf4d..5ef5376e3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.9.0": - version "0.9.0" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.9.0.tgz#36e1da862511b334197c4421e23ea1774926ea9b" - integrity sha512-cTE9hYhzcoblt0uJ3j4BgCo+2tN7sXTpZu9DE5tEwPMoPYUmkmyRklbFzFChT/kumUGP06XO1NDALnnWP3IEUg== +"@snapshot-labs/snapshot.js@^0.9.1": + version "0.9.1" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.9.1.tgz#297f67f1d47ca5e9b0d87fba72cce497ff4e3221" + integrity sha512-IZR63i52E1w7V6ngr3/DiTiCmZHSGV8CXhDRY2JbBOojwFRFaWgStE1TkJDE4tLy45xICwWw0YHuVySlrWfU1w== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From e7a8bf0d035c346af9a32c171f22fc8bbb2ace3a Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Fri, 17 Nov 2023 17:56:49 +0530 Subject: [PATCH 549/815] [passport-gated] Fix operator in schema (#1348) * [passport-gated] Fix operator in schema * Update schema.json * Update index.ts --------- Co-authored-by: Sam <51686767+samuveth@users.noreply.github.com> --- src/validations/passport-gated/index.ts | 6 ++- src/validations/passport-gated/schema.json | 54 +++++++++++----------- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/src/validations/passport-gated/index.ts b/src/validations/passport-gated/index.ts index 419374b41..6bad1f765 100644 --- a/src/validations/passport-gated/index.ts +++ b/src/validations/passport-gated/index.ts @@ -169,8 +169,10 @@ export default class extends Validation { const operator = this.params.operator; const scoreThreshold = this.params.scoreThreshold; - if (scoreThreshold === undefined) throw new Error('Score threshold is required'); - if (requiredStamps.length > 0 && !operator) throw new Error('Operator is required when selecting required stamps'); + if (scoreThreshold === undefined) + throw new Error('Score threshold is required'); + if (requiredStamps.length > 0 && (!operator || operator === 'NONE')) + throw new Error('Operator is required when selecting required stamps'); const provider = snapshot.utils.getProvider(this.network); const proposalTs = (await provider.getBlock(this.snapshot)).timestamp; diff --git a/src/validations/passport-gated/schema.json b/src/validations/passport-gated/schema.json index 5e84f589f..aa69cc61f 100644 --- a/src/validations/passport-gated/schema.json +++ b/src/validations/passport-gated/schema.json @@ -6,6 +6,33 @@ "title": "Gitcoin passport gated", "type": "object", "properties": { + "scoreThreshold": { + "type": "number", + "title": "Passport Score Threshold", + "description": "Minimum Passport score threshold (>=) to be eligible as a valid Passport", + "minimum": 0, + "maximum": 100, + "default": 0 + }, + "operator": { + "type": "string", + "title": "Approval operator", + "description": "Control how many stamps are required to become eligible.", + "anyOf": [ + { + "const": "NONE", + "title": "No operator" + }, + { + "const": "AND", + "title": "Require all stamps" + }, + { + "const": "OR", + "title": "Require at least one stamp" + }, + ] + }, "stamps": { "type": "array", "title": "Stamps", @@ -126,33 +153,6 @@ } ] } - }, - "operator": { - "type": "string", - "title": "Approval operator", - "description": "Control how many stamps are required to become eligible.", - "anyOf": [ - { - "const": "AND", - "title": "Require all stamps" - }, - { - "const": "OR", - "title": "Require at least one stamp" - }, - { - "const": "", - "title": "Any (Stamps MUST be empty)" - } - ] - }, - "scoreThreshold": { - "type": "number", - "title": "Passport Score Threshold", - "description": "Minimum Passport score threshold (>=) to be eligible as a valid Passport", - "minimum": 0, - "maximum": 100, - "default": 0 } }, "required": ["scoreThreshold"], From 8cfcb76419f45d0ffe184c94f68b679d4b041eab Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Fri, 17 Nov 2023 18:09:58 +0530 Subject: [PATCH 550/815] fix typo --- src/validations/passport-gated/schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/validations/passport-gated/schema.json b/src/validations/passport-gated/schema.json index aa69cc61f..9b430e8aa 100644 --- a/src/validations/passport-gated/schema.json +++ b/src/validations/passport-gated/schema.json @@ -30,7 +30,7 @@ { "const": "OR", "title": "Require at least one stamp" - }, + } ] }, "stamps": { From e057ca6252246a55124018a7bfd6fd4bf50b9ae6 Mon Sep 17 00:00:00 2001 From: vpoklopic <78506565+vpoklopic@users.noreply.github.com> Date: Fri, 17 Nov 2023 19:37:21 +0100 Subject: [PATCH 551/815] [thales] Update Thales strategy to include Base stakers (#1349) * Thales strategy * Change Thales strategy to pull data from OP mainnet * Update src/strategies/thales/index.ts Co-authored-by: Chaitanya * Update subgraph link for Thales strategy * Update src/strategies/thales/index.ts Co-authored-by: Chaitanya * Update Thales strategy to include Arbitrum stakers * Update Thales strategy to include Base stakers --------- Co-authored-by: Chaitanya --- src/strategies/thales/examples.json | 8 ++- src/strategies/thales/index.ts | 78 +++++++++++++++++++++-------- 2 files changed, 59 insertions(+), 27 deletions(-) diff --git a/src/strategies/thales/examples.json b/src/strategies/thales/examples.json index 5e0375bac..0a4f41e03 100644 --- a/src/strategies/thales/examples.json +++ b/src/strategies/thales/examples.json @@ -5,15 +5,13 @@ "name": "thales", "params": { "symbol": "THALES", - "decimals": 18, - "blockOptimism": 88627878, - "blockArbitrum": 78979794 + "decimals": 18 } }, "network": "10", "addresses": [ "0x9f8e4ee788D9b00A3409584E18034aA7B736C396", - "0x0bc3668d2AaFa53eD5E5134bA13ec74ea195D000", + "0x0D858351A5FB419C9A3760647900d2F7aD526c83", "0xcAc59F91E4536Bc0E79aB816a5cD54e89f10433C", "0x6dc88B231Cd04Dd1b1e525161162993F47140006", "0x935D2fD458fdf41B6F7B62471f593797866a3Ce6", @@ -21,6 +19,6 @@ "0x49be88f0fcc3a8393a59d3688480d7d253c37d2a", "0x27Cc4d6bc95b55a3a981BF1F1c7261CDa7bB0931" ], - "snapshot": 5003555 + "snapshot": 111660236 } ] diff --git a/src/strategies/thales/index.ts b/src/strategies/thales/index.ts index cbb2bcc15..05ef5a460 100644 --- a/src/strategies/thales/index.ts +++ b/src/strategies/thales/index.ts @@ -1,19 +1,26 @@ import { getAddress } from '@ethersproject/address'; import { formatUnits } from '@ethersproject/units'; -import { subgraphRequest } from '../../utils'; +import { getSnapshots, subgraphRequest } from '../../utils'; export const author = 'vpoklopic'; -export const version = '1.0.3'; +export const version = '1.0.4'; + +enum NetworkId { + Optimism = 10, + Arbitrum = 42161, + Base = 8453 +} const THALES_SUBGRAPH_URL = { optimism: 'https://api.thegraph.com/subgraphs/name/thales-markets/thales-token', arbitrum: - 'https://api.thegraph.com/subgraphs/name/thales-markets/thales-token-arbitrum' + 'https://api.thegraph.com/subgraphs/name/thales-markets/thales-token-arbitrum', + base: 'https://api.studio.thegraph.com/query/11948/thales-token-base/version/latest' }; -function returnGraphParams(addresses: string[]) { - return { +function returnGraphParams(addresses: string[], block: string | number) { + const graphParams = { stakers: { __args: { first: 1000, @@ -29,6 +36,15 @@ function returnGraphParams(addresses: string[]) { totalStakedAmount: true } }; + + if (block !== 'latest') { + // @ts-ignore + graphParams.stakers.__args.block = { + number: block + }; + } + + return graphParams; } export async function strategy( @@ -36,29 +52,31 @@ export async function strategy( _network, _provider, addresses, - options + options, + snapshot ) { - const optimismGraphParams = returnGraphParams(addresses); - if (options.blockOptimism !== undefined) { - // @ts-ignore - optimismGraphParams.stakers.__args.block = { - number: options.blockOptimism - }; - } + const blocks = await getSnapshots(_network, snapshot, _provider, [ + NetworkId.Optimism, + NetworkId.Arbitrum, + NetworkId.Base + ]); - const arbitrumGraphParams = returnGraphParams(addresses); - if (options.blockArbitrum !== undefined) { - // @ts-ignore - arbitrumGraphParams.stakers.__args.block = { - number: options.blockArbitrum - }; - } + const optimismGraphParams = returnGraphParams( + addresses, + blocks[NetworkId.Optimism] + ); + const arbitrumGraphParams = returnGraphParams( + addresses, + blocks[NetworkId.Arbitrum] + ); + const baseGraphParams = returnGraphParams(addresses, blocks[NetworkId.Base]); const score = {}; - const [optimismStakers, arbitrumStakers] = await Promise.all([ + const [optimismStakers, arbitrumStakers, baseStakers] = await Promise.all([ subgraphRequest(THALES_SUBGRAPH_URL.optimism, optimismGraphParams), - subgraphRequest(THALES_SUBGRAPH_URL.arbitrum, arbitrumGraphParams) + subgraphRequest(THALES_SUBGRAPH_URL.arbitrum, arbitrumGraphParams), + subgraphRequest(THALES_SUBGRAPH_URL.base, baseGraphParams) ]); // We are starting by mapping all Optimism stakers @@ -86,5 +104,21 @@ export async function strategy( }); } + // If the Optimism or Arbitrum staker is also staker on Base, add an amount + // Otherwise, just set Base staked amount as a score + if (baseStakers && baseStakers.stakers) { + baseStakers.stakers.forEach((staker) => { + const key = getAddress(staker.id); + const stakedAmount = parseFloat( + formatUnits(staker.totalStakedAmount, options.decimals) + ); + if (!!score[key]) { + score[key] += stakedAmount; + } else { + score[key] = stakedAmount; + } + }); + } + return score || {}; } From 52d6e6070f804093ecfb777c6508fb581fafdf5a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 18 Nov 2023 01:01:26 +0530 Subject: [PATCH 552/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.9.2 (#1350) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index ff91cdeb1..905c00a45 100755 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.9.1", + "@snapshot-labs/snapshot.js": "^0.9.2", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 5ef5376e3..f16ace042 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.9.1": - version "0.9.1" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.9.1.tgz#297f67f1d47ca5e9b0d87fba72cce497ff4e3221" - integrity sha512-IZR63i52E1w7V6ngr3/DiTiCmZHSGV8CXhDRY2JbBOojwFRFaWgStE1TkJDE4tLy45xICwWw0YHuVySlrWfU1w== +"@snapshot-labs/snapshot.js@^0.9.2": + version "0.9.2" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.9.2.tgz#1d4ab0046c342c259b7409f030a46aeddf65becd" + integrity sha512-kdZvBZ4nLFwY7ONpM9ad7+VpLvo091ogq/eeDxoUpDQ9F+z2RiH/xNi4wxdNBGtAPT1cn2Pv3StbjoYrdUnvxw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 5c8be9007e8da16d39c7ec9fae48974f7ec34abd Mon Sep 17 00:00:00 2001 From: fla <101691949+flaflafla@users.noreply.github.com> Date: Sat, 18 Nov 2023 17:34:37 +0000 Subject: [PATCH 553/815] [bubblegum-kids] add bubblegum-kids strategy (#1351) * add bubblegum-kids strategy * add more test ids + comments * rm unnecessary schema * tweak comment --- src/strategies/bubblegum-kids/README.md | 3 + src/strategies/bubblegum-kids/examples.json | 22 +++++ src/strategies/bubblegum-kids/index.ts | 98 +++++++++++++++++++++ src/strategies/index.ts | 4 +- 4 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 src/strategies/bubblegum-kids/README.md create mode 100644 src/strategies/bubblegum-kids/examples.json create mode 100644 src/strategies/bubblegum-kids/index.ts diff --git a/src/strategies/bubblegum-kids/README.md b/src/strategies/bubblegum-kids/README.md new file mode 100644 index 000000000..a5571fdb1 --- /dev/null +++ b/src/strategies/bubblegum-kids/README.md @@ -0,0 +1,3 @@ +# bubblegum-kids + +This strategy determines voting power based on an address' holdings of Bubblegum Kids and Bubblegum Puppies NFTs, including staked NFTs. diff --git a/src/strategies/bubblegum-kids/examples.json b/src/strategies/bubblegum-kids/examples.json new file mode 100644 index 000000000..d659782ef --- /dev/null +++ b/src/strategies/bubblegum-kids/examples.json @@ -0,0 +1,22 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "bubblegum-kids" + }, + "network": "1", + "addresses": [ + "0xfec4465b6aeac9c90e552ae7766bdc0ee0d8dbc9", + "0x146860d31ab0f6dc858106f1a5d7a52bd6c86d1d", + "0x8edc7272a444057d1556df2a1173e6799c3c5ae0", + "0x8af2bd409ea0290029c14aac5d1be77d5c9a114f", + "0x41636ddf4abb1aa78863101626acdc861d4e8a0b", + "0xd341108b067cd308cf8cc7e13fb9982b0cba2f4e", + "0xdf05770b388ee62362917bea9dc96f0dee3b246e", + "0xf98e849c4b0de9750630f1c23c1bea9e79b4edb3", + "0xf68b74b89093315c5bf018348886c9fdd8308d7f", + "0x95222290dd7278aa3ddd389cc1e1d165cc4bafe5" + ], + "snapshot": 18589032 + } +] diff --git a/src/strategies/bubblegum-kids/index.ts b/src/strategies/bubblegum-kids/index.ts new file mode 100644 index 000000000..d9382344b --- /dev/null +++ b/src/strategies/bubblegum-kids/index.ts @@ -0,0 +1,98 @@ +import { getAddress } from '@ethersproject/address'; +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'flaflafla'; +export const version = '0.1.1'; + +// contracts available on Ethereum mainnet and Goerli testnet +const kidsAddressByNetwork = { + 1: '0xa5ae87B40076745895BB7387011ca8DE5fde37E0', + 5: '0x66B04973b83ea796960D6f8ea22856714e01765f' +}; + +const puppiesAddressByNetwork = { + 1: '0x86e9C5ad3D4b5519DA2D2C19F5c71bAa5Ef40933', + 5: '0x053A3213E75b78c0b80b2f88e243cf519e834c02' +}; + +const stakingAddressByNetwork = { + 1: '0xf48415039913DBdF17e337e681de922A9cb04010', + 5: '0xe5f1433b6eCc6bE74E413b54f4c1eA2671b1cA0F' +}; + +const abi = [ + // Kids and Puppies contracts + 'function balanceOf(address owner) external view returns (uint256)', + // staking contract + 'function depositsOf(address account) external view returns (uint256[][2])' +]; + +/** + * Voting power is calculated as the sum of a user's Bubblegum Kids + * and Bubblegum Puppies holdings, with each NFT counting as 1. Kids + * and Puppies deposited to the staking contract also count as 1. + */ +export async function strategy( + _space, + network, + provider, + addresses, + _options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multi = new Multicaller(network, provider, abi, { blockTag }); + + addresses.forEach((address) => { + // get Kids balance + multi.call(`${address}.kids`, kidsAddressByNetwork[network], 'balanceOf', [ + address + ]); + + // get Puppies balance + multi.call( + `${address}.puppies`, + puppiesAddressByNetwork[network], + 'balanceOf', + [address] + ); + + // get staking deposits (returns and array of two arrays: + // a list of Kids ids and a list of Puppies ids) + multi.call( + `${address}.staking`, + stakingAddressByNetwork[network], + 'depositsOf', + [address] + ); + }); + + const result: { + address: { + kids: BigNumberish; + puppies: BigNumberish; + staking: [Array, Array]; + }; + } = await multi.execute(); + + return Object.fromEntries( + Object.entries(result).map(([address, { kids, puppies, staking }]) => { + const [stakedKids, stakedPuppies] = staking; + + const kidsCount = parseFloat(formatUnits(kids, 0)); + const stakedKidsCount = stakedKids.length; + + const puppiesCount = parseFloat(formatUnits(puppies, 0)); + const stakedPuppiesCount = stakedPuppies.length; + + // calculate total voting power + const votingPower = + kidsCount + stakedKidsCount + puppiesCount + stakedPuppiesCount; + + return [getAddress(address), votingPower]; + }) + ); +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 5c3b93514..d1dec8ae8 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -474,6 +474,7 @@ import * as mangroveStationQVScaledToMGV from './mangrove-station-qv-scaled-to-m import * as floki from './floki'; import * as hatsProtocolHatId from './hats-protocol-hat-id'; import * as hatsProtocolHatIds from './hats-protocol-hat-ids'; +import * as bubblegumKids from './bubblegum-kids'; const strategies = { 'cap-voting-power': capVotingPower, @@ -956,7 +957,8 @@ const strategies = { 'mangrove-station-qv-scaled-to-mgv': mangroveStationQVScaledToMGV, floki, 'hats-protocol-hat-id': hatsProtocolHatId, - 'hats-protocol-hat-ids': hatsProtocolHatIds + 'hats-protocol-hat-ids': hatsProtocolHatIds, + 'bubblegum-kids': bubblegumKids, }; Object.keys(strategies).forEach(function (strategyName) { From 1c9783175c9ed626695d7cdd30c76b24c8c36669 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 10:11:21 +0530 Subject: [PATCH 554/815] Automated lint (#1352) Co-authored-by: ChaituVR --- src/strategies/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategies/index.ts b/src/strategies/index.ts index d1dec8ae8..2c3606302 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -958,7 +958,7 @@ const strategies = { floki, 'hats-protocol-hat-id': hatsProtocolHatId, 'hats-protocol-hat-ids': hatsProtocolHatIds, - 'bubblegum-kids': bubblegumKids, + 'bubblegum-kids': bubblegumKids }; Object.keys(strategies).forEach(function (strategyName) { From 14b2a178f24c5f7b42226e9086f169c8f3192cee Mon Sep 17 00:00:00 2001 From: 0xRusty <84294992+CryptoTrades20@users.noreply.github.com> Date: Wed, 22 Nov 2023 21:09:44 +1100 Subject: [PATCH 555/815] [clipper-staked-sail] add clipper-staked-sail strategy (#1355) * Update index.ts Include clipper-staked-sail strategy * Add files via upload * Update README.md * Update index.ts removed comma * Update README.md * Update README.md * Update src/strategies/clipper-staked-sail/index.ts * Update src/strategies/clipper-staked-sail/index.ts * Update src/strategies/clipper-staked-sail/index.ts * Update src/strategies/clipper-staked-sail/index.ts --------- Co-authored-by: Chaitanya --- src/strategies/clipper-staked-sail/README.md | 15 ++++ .../clipper-staked-sail/examples.json | 20 ++++++ src/strategies/clipper-staked-sail/index.ts | 69 +++++++++++++++++++ src/strategies/index.ts | 4 +- 4 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 src/strategies/clipper-staked-sail/README.md create mode 100644 src/strategies/clipper-staked-sail/examples.json create mode 100644 src/strategies/clipper-staked-sail/index.ts diff --git a/src/strategies/clipper-staked-sail/README.md b/src/strategies/clipper-staked-sail/README.md new file mode 100644 index 000000000..caab3c5b5 --- /dev/null +++ b/src/strategies/clipper-staked-sail/README.md @@ -0,0 +1,15 @@ +# AdmiralDao Staked Sail + +This strategy returns the voting power of an address that has staked sail in the vesail staking contract [VeSail](https://etherscan.io/token/0x26fe2f89a1fef1bc90b8a89d8ad18a1891166ff5). +The voting power is calculated as: +- The amount of vesail held in their address. +- The result is then used to interract with the tosail method in the contract to get the sail equivalent. +- Lastly it will take the equivalent sail amount and apply a square root operation. + +```JSON +{ + "strategies": [ + ["clipper-staked-sail"] + ] +} +``` diff --git a/src/strategies/clipper-staked-sail/examples.json b/src/strategies/clipper-staked-sail/examples.json new file mode 100644 index 000000000..153837b5e --- /dev/null +++ b/src/strategies/clipper-staked-sail/examples.json @@ -0,0 +1,20 @@ +[ + { + "name": "Example of clipper-staked-sail Strategy", + "strategy": { + "name": "clipper-staked-sail" + }, + "network": "1", +"decimals":18, + "addresses": [ + "0x3334829670F9e8D309C9D9F318C4E6876755eDe2", +"0x8e70Ca936a2f2d81cBbF1Dc84Aabe4213C87b8E9", +"0x314C0695273Ba259Bb60074f2C92c67AC7ae6D40", +"0x2c2e209465D5312e6dF0cd5F7D1066f1aff9a953", +"0x4d768cFDb6E0077aD0a971678fa84DBcac32CE62", +"0x26f8435Bf2a7B8b4771F0D5317beb09fB1F197C3" + ], + "snapshot": 18558302 + } +] + diff --git a/src/strategies/clipper-staked-sail/index.ts b/src/strategies/clipper-staked-sail/index.ts new file mode 100644 index 000000000..53c06be5c --- /dev/null +++ b/src/strategies/clipper-staked-sail/index.ts @@ -0,0 +1,69 @@ +import { multicall } from '../../utils'; +import { BigNumber } from '@ethersproject/bignumber'; + +const vesailTokenAddress = '0x26fE2f89a1FEf1bC90b8a89D8AD18a1891166ff5'; +const decimals = 18; + +export const author = 'cryptotrades20'; +export const version = '0.1.0'; + +//read vesail balance +const vesailBalanceOfABI = [ + 'function balanceOf(address account) view returns (uint256)' +]; + +//vesail to sail conversion +const toSAILABI = [ + 'function toSAIL(uint256 sailAmount) view returns (uint256)' +]; + + +/** + * Voting power is calculated as the conversion of their vesail balance to sail + * Then take that sail amount and apply square root operation to it + */ +async function getVesailBalance(network, provider, snapshot, addresses) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const response = await multicall( + network, + provider, + vesailBalanceOfABI, + addresses.map((address) => [vesailTokenAddress, 'balanceOf', [address]]), + { blockTag } + ); + return response.map((result) => result[0]); +} + +//read vesail to sail balance +async function readToSail(network, provider, snapshot, addresses, vesailBalances) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const response = await multicall( + network, + provider, + toSAILABI, + addresses.map((address, index) => [vesailTokenAddress, 'toSAIL', [vesailBalances[index]]]), + { blockTag } + ); + return response.map((result) => result[0]); +} + + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const vesailBalances = await getVesailBalance(network, provider, snapshot, addresses); + const sailAmounts = await readToSail(network, provider, snapshot, addresses, vesailBalances); + +return Object.fromEntries( + addresses.map((address, index) => [ + address, + //square root the resulting vesail to sail amount + Math.sqrt(Number(BigNumber.from(sailAmounts[index].toString())) / 10 ** decimals), + ]) +); +} \ No newline at end of file diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 2c3606302..9256bdd02 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -475,6 +475,7 @@ import * as floki from './floki'; import * as hatsProtocolHatId from './hats-protocol-hat-id'; import * as hatsProtocolHatIds from './hats-protocol-hat-ids'; import * as bubblegumKids from './bubblegum-kids'; +import * as clipperStakedSail from './clipper-staked-sail'; const strategies = { 'cap-voting-power': capVotingPower, @@ -958,7 +959,8 @@ const strategies = { floki, 'hats-protocol-hat-id': hatsProtocolHatId, 'hats-protocol-hat-ids': hatsProtocolHatIds, - 'bubblegum-kids': bubblegumKids + 'bubblegum-kids': bubblegumKids, + 'clipper-staked-sail' : clipperStakedSail }; Object.keys(strategies).forEach(function (strategyName) { From 390dd1749058d3c9a7c9c4c81ed62e6fb4816550 Mon Sep 17 00:00:00 2001 From: Manboy <2156509+manboy-eth@users.noreply.github.com> Date: Thu, 23 Nov 2023 13:08:17 +0100 Subject: [PATCH 556/815] [delegate-registry-v2] Add optional v1 support (#1353) * [delegate-registry-v2] Add optional v1 support * Improve example * Fix: bug regarding addressesOwnScore --- .../delegate-registry-v2/examples.json | 24 ++++++++++++------- src/strategies/delegate-registry-v2/index.ts | 12 ++++++---- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/strategies/delegate-registry-v2/examples.json b/src/strategies/delegate-registry-v2/examples.json index 930f4c022..c4f6a3a28 100644 --- a/src/strategies/delegate-registry-v2/examples.json +++ b/src/strategies/delegate-registry-v2/examples.json @@ -5,21 +5,24 @@ "name": "delegate-registry-v2", "params": { "backendUrl": "https://delegate-registry-backend.vercel.app", + "delegationV1VChainIds": [1, 100], "strategies": [ { "name": "erc20-balance-of", "params": { - "address": "0x6b175474e89094c44da98b954eedeac495271d0f", - "symbol": "DAI", + "symbol": "ST", + "address": "0xE666Ad68a6e2897CD06A9ff378ED8b0d71093398", + "network": "5", "decimals": 18 - } + }, + "network": "5" }, { - "name": "gno", + "name": "erc20-balance-of", "params": { - "symbol": "GNO", - "decimals": 18, - "SUBGRAPH_URL": "https://api.thegraph.com/subgraphs/id/QmduKVUHCPjR5tmNEgooXHBMGKqDJWrUPdp6dEMeJM6Kqa" + "address": "0x6b175474e89094c44da98b954eedeac495271d0f", + "symbol": "DAI", + "decimals": 18 } } ] @@ -27,6 +30,11 @@ }, "network": "1", "addresses": [ + "0x2011c83e8f75c0ceb90ec140d8e8adfc836e3685", + "0xde1e6a7ed0ad3f61d531a8a78e83ccddbd6e0c49", + "0x007de57773b6eb4ebbf6a740dfde1efdd5629630", + "0x6cc5b30cd0a93c1f85c7868f5f2620ab8c458190", + "0xd028d504316fec029cfa36bdc3a8f053f6e5a6e4", "0x000e37ed92d86a7667f520c53b73b01ff5c206eb", "0x000dbf2733da51135c1b21c8ef71a3d474383f0d", "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", @@ -40,6 +48,6 @@ "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad" ], - "snapshot": 17463998 + "snapshot": 18478898 } ] diff --git a/src/strategies/delegate-registry-v2/index.ts b/src/strategies/delegate-registry-v2/index.ts index 6304fee96..e22fb4805 100644 --- a/src/strategies/delegate-registry-v2/index.ts +++ b/src/strategies/delegate-registry-v2/index.ts @@ -5,13 +5,14 @@ import { getScoresDirect } from '../../utils'; import { getAddress } from '@ethersproject/address'; export const author = 'gnosis'; -export const version = '0.0.1'; +export const version = '0.0.2'; const DEFAULT_BACKEND_URL = 'https://delegate-registry-backend.vercel.app'; type Params = { backendUrl: string; strategies: Strategy[]; + delegationV1VChainIds?: number[]; // add this to include v1 delegations }; /* @@ -42,8 +43,11 @@ export async function strategy( 'Content-Type': 'application/json' }, body: JSON.stringify({ - addresses: addresses, - strategies: options.strategies + spaceParams: { + ...options, + mainChainId: Number(network) + }, + addresses }) } ); @@ -75,7 +79,7 @@ export async function strategy( ...addressesNotDelegatingOrDelegatedTo, ...addressesDelegatedTo.map(([address]) => address) ], - snapshot + blockTag ); const delegationObject = addressesDelegatedTo.reduce( From 245465e43b765764c5c1a73e0db3e2bf8777ad8e Mon Sep 17 00:00:00 2001 From: kaiserpy <40641743+kaiserpy@users.noreply.github.com> Date: Thu, 23 Nov 2023 09:30:34 -0500 Subject: [PATCH 557/815] [snote] add staked-note strategy (#1356) * [snote] add staked-note strategy Changes proposed in this pull request: * Add a voting strategy for staked NOTE to avoid double counting between delegated sNOTE and undelegated sNOTE. * Review fixes Review fixes --------- Co-authored-by: Chaitanya --- src/strategies/index.ts | 4 +- src/strategies/snote/examples.json | 16 +++++++ src/strategies/snote/index.ts | 76 ++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 src/strategies/snote/examples.json create mode 100644 src/strategies/snote/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 9256bdd02..cda3b1a1e 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -476,6 +476,7 @@ import * as hatsProtocolHatId from './hats-protocol-hat-id'; import * as hatsProtocolHatIds from './hats-protocol-hat-ids'; import * as bubblegumKids from './bubblegum-kids'; import * as clipperStakedSail from './clipper-staked-sail'; +import * as snote from './snote'; const strategies = { 'cap-voting-power': capVotingPower, @@ -960,7 +961,8 @@ const strategies = { 'hats-protocol-hat-id': hatsProtocolHatId, 'hats-protocol-hat-ids': hatsProtocolHatIds, 'bubblegum-kids': bubblegumKids, - 'clipper-staked-sail' : clipperStakedSail + 'clipper-staked-sail' : clipperStakedSail, + snote }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/snote/examples.json b/src/strategies/snote/examples.json new file mode 100644 index 000000000..3a4e6abfb --- /dev/null +++ b/src/strategies/snote/examples.json @@ -0,0 +1,16 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "snote", + "params": {"symbol": "sNOTE"} + }, + "network": "1", + "addresses": [ + "0xCece1920D4dBb96BAf88705ce0A6Eb3203ed2eB1", + "0x4E8014fF5bacE498DAB1a9E2B5c3f4240bC059B6", + "0x741AA7CFB2c7bF2A1E7D4dA2e3Df6a56cA4131F3" + ], + "snapshot": 18629000 + } +] diff --git a/src/strategies/snote/index.ts b/src/strategies/snote/index.ts new file mode 100644 index 000000000..59ebc3040 --- /dev/null +++ b/src/strategies/snote/index.ts @@ -0,0 +1,76 @@ +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'kaiserpy'; +export const version = '0.1.0'; + +const abi = [ + 'function getVotes(address account) external view returns (uint256)', + 'function votingPowerWithoutDelegation(address account) external view returns (uint256)', + 'function delegates(address account) external view returns (address)' +]; + +const STAKED_NOTE_CONTRACT_ADDRESS = '0x38de42f4ba8a35056b33a746a6b45be9b1c3b9d2'; + +interface VotingInfo { + [address: string]: BigNumberish; +} + +export async function strategy( + space: any, + network: string, + provider: any, + addresses: string[], + options: any, + snapshot: number | string +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + // Helper function to fetch data using multicall + async function fetchMulticallData(method: string) { + const multi = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => + multi.call(address, STAKED_NOTE_CONTRACT_ADDRESS, method, [address]) + ); + return await multi.execute(); + } + + // Fetch delegate votes, non-delegated votes, and delegation information + const delegatedVotes: VotingInfo = await fetchMulticallData('getVotes'); + const nonDelegatedVotes: VotingInfo = await fetchMulticallData('votingPowerWithoutDelegation'); + const delegationInfo: Record = await fetchMulticallData('delegates') + .then((result2: Record) => + Object.fromEntries( + Object.entries(result2).map(([address, delegate]) => [ + address, + delegate.toLowerCase() === '0x0000000000000000000000000000000000000000', + ]) + ) + ); + + // Process and filter the data + const delegateVotingPowers = Object.fromEntries( + Object.entries(delegatedVotes).map(([address, balance]) => [ + address, + parseFloat(formatUnits(balance, 8)), + ]) + ); + const votingPowers = Object.fromEntries( + Object.entries(nonDelegatedVotes).map(([address, balance]) => [ + address, + parseFloat(formatUnits(balance, 8)), + ]) + ); + + const filteredBalances: Record = {}; + addresses.forEach((address) => { + if (delegationInfo[address]) { + const delegateVotingPower = delegateVotingPowers[address] || 0; + const votingPower = votingPowers[address] || 0; + filteredBalances[address] = delegateVotingPower + votingPower; + } + }); + + return filteredBalances; +} From 6a52f1392d89a6413cce3b0fee513362aa191534 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Fri, 24 Nov 2023 10:29:28 +0530 Subject: [PATCH 558/815] fix: Tests mismatch snapshot and fix lint errors (#1360) --- .../clipper-staked-sail/examples.json | 13 +++-- src/strategies/clipper-staked-sail/index.ts | 49 +++++++++++++------ src/strategies/index.ts | 2 +- src/strategies/snote/examples.json | 2 +- src/strategies/snote/index.ts | 30 +++++++----- test/__snapshots__/delegation.test.ts.snap | 4 +- test/__snapshots__/vp.test.ts.snap | 8 +-- 7 files changed, 66 insertions(+), 42 deletions(-) diff --git a/src/strategies/clipper-staked-sail/examples.json b/src/strategies/clipper-staked-sail/examples.json index 153837b5e..16cc02da6 100644 --- a/src/strategies/clipper-staked-sail/examples.json +++ b/src/strategies/clipper-staked-sail/examples.json @@ -5,16 +5,15 @@ "name": "clipper-staked-sail" }, "network": "1", -"decimals":18, + "decimals": 18, "addresses": [ "0x3334829670F9e8D309C9D9F318C4E6876755eDe2", -"0x8e70Ca936a2f2d81cBbF1Dc84Aabe4213C87b8E9", -"0x314C0695273Ba259Bb60074f2C92c67AC7ae6D40", -"0x2c2e209465D5312e6dF0cd5F7D1066f1aff9a953", -"0x4d768cFDb6E0077aD0a971678fa84DBcac32CE62", -"0x26f8435Bf2a7B8b4771F0D5317beb09fB1F197C3" + "0x8e70Ca936a2f2d81cBbF1Dc84Aabe4213C87b8E9", + "0x314C0695273Ba259Bb60074f2C92c67AC7ae6D40", + "0x2c2e209465D5312e6dF0cd5F7D1066f1aff9a953", + "0x4d768cFDb6E0077aD0a971678fa84DBcac32CE62", + "0x26f8435Bf2a7B8b4771F0D5317beb09fB1F197C3" ], "snapshot": 18558302 } ] - diff --git a/src/strategies/clipper-staked-sail/index.ts b/src/strategies/clipper-staked-sail/index.ts index 53c06be5c..83154b61f 100644 --- a/src/strategies/clipper-staked-sail/index.ts +++ b/src/strategies/clipper-staked-sail/index.ts @@ -17,7 +17,6 @@ const toSAILABI = [ 'function toSAIL(uint256 sailAmount) view returns (uint256)' ]; - /** * Voting power is calculated as the conversion of their vesail balance to sail * Then take that sail amount and apply square root operation to it @@ -35,19 +34,28 @@ async function getVesailBalance(network, provider, snapshot, addresses) { } //read vesail to sail balance -async function readToSail(network, provider, snapshot, addresses, vesailBalances) { +async function readToSail( + network, + provider, + snapshot, + addresses, + vesailBalances +) { const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; const response = await multicall( network, provider, toSAILABI, - addresses.map((address, index) => [vesailTokenAddress, 'toSAIL', [vesailBalances[index]]]), + addresses.map((address, index) => [ + vesailTokenAddress, + 'toSAIL', + [vesailBalances[index]] + ]), { blockTag } ); return response.map((result) => result[0]); } - export async function strategy( space, network, @@ -56,14 +64,27 @@ export async function strategy( options, snapshot ) { - const vesailBalances = await getVesailBalance(network, provider, snapshot, addresses); - const sailAmounts = await readToSail(network, provider, snapshot, addresses, vesailBalances); + const vesailBalances = await getVesailBalance( + network, + provider, + snapshot, + addresses + ); + const sailAmounts = await readToSail( + network, + provider, + snapshot, + addresses, + vesailBalances + ); -return Object.fromEntries( - addresses.map((address, index) => [ - address, - //square root the resulting vesail to sail amount - Math.sqrt(Number(BigNumber.from(sailAmounts[index].toString())) / 10 ** decimals), - ]) -); -} \ No newline at end of file + return Object.fromEntries( + addresses.map((address, index) => [ + address, + //square root the resulting vesail to sail amount + Math.sqrt( + Number(BigNumber.from(sailAmounts[index].toString())) / 10 ** decimals + ) + ]) + ); +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index cda3b1a1e..139583bb0 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -961,7 +961,7 @@ const strategies = { 'hats-protocol-hat-id': hatsProtocolHatId, 'hats-protocol-hat-ids': hatsProtocolHatIds, 'bubblegum-kids': bubblegumKids, - 'clipper-staked-sail' : clipperStakedSail, + 'clipper-staked-sail': clipperStakedSail, snote }; diff --git a/src/strategies/snote/examples.json b/src/strategies/snote/examples.json index 3a4e6abfb..1ec38cd4e 100644 --- a/src/strategies/snote/examples.json +++ b/src/strategies/snote/examples.json @@ -3,7 +3,7 @@ "name": "Example query", "strategy": { "name": "snote", - "params": {"symbol": "sNOTE"} + "params": { "symbol": "sNOTE" } }, "network": "1", "addresses": [ diff --git a/src/strategies/snote/index.ts b/src/strategies/snote/index.ts index 59ebc3040..1eae9a07a 100644 --- a/src/strategies/snote/index.ts +++ b/src/strategies/snote/index.ts @@ -11,7 +11,8 @@ const abi = [ 'function delegates(address account) external view returns (address)' ]; -const STAKED_NOTE_CONTRACT_ADDRESS = '0x38de42f4ba8a35056b33a746a6b45be9b1c3b9d2'; +const STAKED_NOTE_CONTRACT_ADDRESS = + '0x38de42f4ba8a35056b33a746a6b45be9b1c3b9d2'; interface VotingInfo { [address: string]: BigNumberish; @@ -38,28 +39,31 @@ export async function strategy( // Fetch delegate votes, non-delegated votes, and delegation information const delegatedVotes: VotingInfo = await fetchMulticallData('getVotes'); - const nonDelegatedVotes: VotingInfo = await fetchMulticallData('votingPowerWithoutDelegation'); - const delegationInfo: Record = await fetchMulticallData('delegates') - .then((result2: Record) => - Object.fromEntries( - Object.entries(result2).map(([address, delegate]) => [ - address, - delegate.toLowerCase() === '0x0000000000000000000000000000000000000000', - ]) - ) - ); + const nonDelegatedVotes: VotingInfo = await fetchMulticallData( + 'votingPowerWithoutDelegation' + ); + const delegationInfo: Record = await fetchMulticallData( + 'delegates' + ).then((result2: Record) => + Object.fromEntries( + Object.entries(result2).map(([address, delegate]) => [ + address, + delegate.toLowerCase() === '0x0000000000000000000000000000000000000000' + ]) + ) + ); // Process and filter the data const delegateVotingPowers = Object.fromEntries( Object.entries(delegatedVotes).map(([address, balance]) => [ address, - parseFloat(formatUnits(balance, 8)), + parseFloat(formatUnits(balance, 8)) ]) ); const votingPowers = Object.fromEntries( Object.entries(nonDelegatedVotes).map(([address, balance]) => [ address, - parseFloat(formatUnits(balance, 8)), + parseFloat(formatUnits(balance, 8)) ]) ); diff --git a/test/__snapshots__/delegation.test.ts.snap b/test/__snapshots__/delegation.test.ts.snap index 50cfedd58..662b921f5 100644 --- a/test/__snapshots__/delegation.test.ts.snap +++ b/test/__snapshots__/delegation.test.ts.snap @@ -1,8 +1,8 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[` getDelegations 1`] = ` -Object { - "in": Array [ +{ + "in": [ "0x073aBA73177668Ba1c6661A4CCddbF77dfC8809a", "0x0D996171E7883A286eF720030935f72D0Bac8219", "0x186E20ae3530520C9F3E6C46F2f5d1062b784761", diff --git a/test/__snapshots__/vp.test.ts.snap b/test/__snapshots__/vp.test.ts.snap index 80a296baa..973d41de0 100644 --- a/test/__snapshots__/vp.test.ts.snap +++ b/test/__snapshots__/vp.test.ts.snap @@ -1,9 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[` getVp with delegation 1`] = ` -Object { +{ "vp": 10.077130335431244, - "vp_by_strategy": Array [ + "vp_by_strategy": [ 0, 10.028706352441185, 0, @@ -14,9 +14,9 @@ Object { `; exports[` getVp without delegation 1`] = ` -Object { +{ "vp": 21.55404462002206, - "vp_by_strategy": Array [ + "vp_by_strategy": [ 0, 9.998985610441185, 11.506635026590818, From 72fcc3bf7b6dfab8bf566863878e1fed47f95b2e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Nov 2023 10:41:27 +0530 Subject: [PATCH 559/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.9.3 (#1358) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 905c00a45..209352325 100755 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.9.2", + "@snapshot-labs/snapshot.js": "^0.9.3", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index f16ace042..e43c66531 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.9.2": - version "0.9.2" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.9.2.tgz#1d4ab0046c342c259b7409f030a46aeddf65becd" - integrity sha512-kdZvBZ4nLFwY7ONpM9ad7+VpLvo091ogq/eeDxoUpDQ9F+z2RiH/xNi4wxdNBGtAPT1cn2Pv3StbjoYrdUnvxw== +"@snapshot-labs/snapshot.js@^0.9.3": + version "0.9.3" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.9.3.tgz#6b236681dbc126071fed0db8f2a460344d3dce69" + integrity sha512-9c3Ge/nfFvys6/NxIk3UqrLaUc+1UUWr7xIg2yArKX85oVDTNvZOm6o2hJ0b60Ks4RzkYBesbt9FaXePlBeCaA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From cb62cd66d0de9187c3bde26178b097555487fe80 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 25 Nov 2023 00:35:03 +0530 Subject: [PATCH 560/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.9.4 (#1361) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 209352325..81ac158fc 100755 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.9.3", + "@snapshot-labs/snapshot.js": "^0.9.4", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index e43c66531..6168bb5b0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.9.3": - version "0.9.3" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.9.3.tgz#6b236681dbc126071fed0db8f2a460344d3dce69" - integrity sha512-9c3Ge/nfFvys6/NxIk3UqrLaUc+1UUWr7xIg2yArKX85oVDTNvZOm6o2hJ0b60Ks4RzkYBesbt9FaXePlBeCaA== +"@snapshot-labs/snapshot.js@^0.9.4": + version "0.9.4" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.9.4.tgz#e2e287e3fb97849e785e177b369727eed7e2c62a" + integrity sha512-G80S7YQqEJDOuLzqUf7MH3QLWE7A6hRj94eLzGS5cSxGv9o4aAM/1x8z1QL+Pl4j5dlV7z7Gb6pAKvtC8Olaqw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From cd01f3bea5635840a788913dd3c5d40e32b44153 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 25 Nov 2023 17:44:44 +0530 Subject: [PATCH 561/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.9.5 (#1362) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 81ac158fc..623867b84 100755 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.9.4", + "@snapshot-labs/snapshot.js": "^0.9.5", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 6168bb5b0..f26d1d88b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.9.4": - version "0.9.4" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.9.4.tgz#e2e287e3fb97849e785e177b369727eed7e2c62a" - integrity sha512-G80S7YQqEJDOuLzqUf7MH3QLWE7A6hRj94eLzGS5cSxGv9o4aAM/1x8z1QL+Pl4j5dlV7z7Gb6pAKvtC8Olaqw== +"@snapshot-labs/snapshot.js@^0.9.5": + version "0.9.5" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.9.5.tgz#2fe0f12b0d913d43121a2fb23e99ac160a3cd41f" + integrity sha512-+Vqn+kms+Yw2pa87cSSp0aIKoJim6wiuUVxl0DIZ2e4yWe8YGZGbJuLXMgozZhwMRVtjW3QX9sHE7lyI1cjMpg== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 2d3a0709623483e5f249ab7879df8d7e04899ec7 Mon Sep 17 00:00:00 2001 From: J <64942520+jeeraponnnnnnnn@users.noreply.github.com> Date: Tue, 28 Nov 2023 13:32:47 +0700 Subject: [PATCH 562/815] [plearn] Add plearn strategy (#1357) * feat: Add Plearn strategy * fix: Change object ABI to string ABI * docs: Update plearn strategy Readme * fix: Add limit address arrays to max 5 * fix: Refactor multicall implementation for Limit network requests * fix: Refactor score calculation logic * fix: Refactor score calculation logic * fix: Improve code and add Types * fix: Improve code and types * fix: Check result is undefined, null * fix: Refactor transformResults to use lambda function for balance processing * fix: Remove check amount is null and undefined * Refactor index.ts * Update index.ts * fix: Add import BigNumber and change let to const --------- Co-authored-by: Tia --- src/strategies/index.ts | 2 + src/strategies/plearn/README.md | 47 +++++++++ src/strategies/plearn/examples.json | 38 ++++++++ src/strategies/plearn/index.ts | 144 ++++++++++++++++++++++++++++ 4 files changed, 231 insertions(+) create mode 100644 src/strategies/plearn/README.md create mode 100644 src/strategies/plearn/examples.json create mode 100644 src/strategies/plearn/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 139583bb0..24c150bc8 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -476,6 +476,7 @@ import * as hatsProtocolHatId from './hats-protocol-hat-id'; import * as hatsProtocolHatIds from './hats-protocol-hat-ids'; import * as bubblegumKids from './bubblegum-kids'; import * as clipperStakedSail from './clipper-staked-sail'; +import * as plearn from './plearn'; import * as snote from './snote'; const strategies = { @@ -962,6 +963,7 @@ const strategies = { 'hats-protocol-hat-ids': hatsProtocolHatIds, 'bubblegum-kids': bubblegumKids, 'clipper-staked-sail': clipperStakedSail, + plearn, snote }; diff --git a/src/strategies/plearn/README.md b/src/strategies/plearn/README.md new file mode 100644 index 000000000..45f64f8e2 --- /dev/null +++ b/src/strategies/plearn/README.md @@ -0,0 +1,47 @@ +# Plearn + +This is the most common strategy, it returns the balances of the voters for a balances PLN token +in Plearn project(pools, token). + +Here is an example of parameters: + +```json +[ + { + "name": "Example query", + "strategy": { + "name": "plearn", + "params": { + "lockedPoolAddresses": [ + { + "address": "0xc38d542326545470a12B06Bf8e315DE55B0B6B46" + }, + { + "address": "0x9b45a8eeD3eF6DA3bE222147533Da542aa384006" + } + ], + "foundingInvestorPoolAddresses": [], + "pendingWithdrawalAddresses": [ + { + "address": "0x7E4e06C81B41284198C0693cd98eb357257Fc3d9" + }, + { + "address": "0xC26a3E07D8CCF34195e943C0bb705f206Dd57030" + } + ], + "symbol": "PLN", + "address": "0xBe0D3526fc797583Dada3F30BC390013062A048B", + "decimals": 18 + } + }, + "network": "56", + "addresses": [ + "0xE0d54117600e592E7a78C985996d11b8Fb1B69C3", + "0x3C97c372B45cC96Fe73814721ebbE6db02C9D88E", + "0xB6605F98A5562b1AC821Bc5f2B75934239e8c6D6", + "0x8900cCBdC60fD97E3B7c8529A9987F8c0f8A1125" + ], + "snapshot": 33739024 + } +] +``` diff --git a/src/strategies/plearn/examples.json b/src/strategies/plearn/examples.json new file mode 100644 index 000000000..e64080805 --- /dev/null +++ b/src/strategies/plearn/examples.json @@ -0,0 +1,38 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "plearn", + "params": { + "lockedPoolAddresses": [ + { + "address": "0xc38d542326545470a12B06Bf8e315DE55B0B6B46" + }, + { + "address": "0x9b45a8eeD3eF6DA3bE222147533Da542aa384006" + } + ], + "foundingInvestorPoolAddresses": [], + "pendingWithdrawalAddresses": [ + { + "address": "0x7E4e06C81B41284198C0693cd98eb357257Fc3d9" + }, + { + "address": "0xC26a3E07D8CCF34195e943C0bb705f206Dd57030" + } + ], + "symbol": "PLN", + "address": "0xBe0D3526fc797583Dada3F30BC390013062A048B", + "decimals": 18 + } + }, + "network": "56", + "addresses": [ + "0xE0d54117600e592E7a78C985996d11b8Fb1B69C3", + "0x3C97c372B45cC96Fe73814721ebbE6db02C9D88E", + "0xB6605F98A5562b1AC821Bc5f2B75934239e8c6D6", + "0x8900cCBdC60fD97E3B7c8529A9987F8c0f8A1125" + ], + "snapshot": 33739024 + } +] diff --git a/src/strategies/plearn/index.ts b/src/strategies/plearn/index.ts new file mode 100644 index 000000000..be80146f2 --- /dev/null +++ b/src/strategies/plearn/index.ts @@ -0,0 +1,144 @@ +import { Provider } from '@ethersproject/providers'; +import { formatUnits } from '@ethersproject/units'; +import { BigNumber } from '@ethersproject/bignumber'; +import { multicall } from '../../utils'; +import { strategy as erc20BalanceOfStrategy } from '../erc20-balance-of'; + +export const author = 'plearnclub'; +export const version = '0.0.1'; + +const lockedPoolabi = [ + 'function userInfo(address) view returns (uint256 amount)' +]; + +const foundingInvestorPoolabi = [ + 'function userInfo(address) view returns (uint256 initialAmount, uint256 amount)' +]; + +const pendingWithdrawalabi = [ + 'function lockedBalances(address user) view returns (uint256 total, uint256 unlockable, uint256 locked, tuple(uint256 amount, uint256 unlockTime)[] lockData)' +]; + +function transformResults( + res: any[], + addresses: string[], + balanceTransformer: (result: any) => number +): { [address: string]: number } { + return res.reduce((acc: { [address: string]: number }, result, index) => { + const address = addresses[index % addresses.length]; + if (!acc[address]) { + acc[address] = 0; + } + + const amount = balanceTransformer(result); + acc[address] += amount; + return acc; + }, {}); +} + +export async function strategy( + space: string, + network: string, + provider: Provider, + addresses: string[], + options: { + lockedPoolAddresses: { address: string }[]; + foundingInvestorPoolAddresses: { address: string }[]; + pendingWithdrawalAddresses: { address: string }[]; + symbol: string; + address: string; + decimals: number; + }, + snapshot: number | string +): Promise<{ [address: string]: number }> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const score = await erc20BalanceOfStrategy( + space, + network, + provider, + addresses, + options, + snapshot + ); + + const lockedPoolCalls = options.lockedPoolAddresses.flatMap((item) => + addresses.map((address) => [ + item.address, + 'userInfo', + [address], + { blockTag } + ]) + ); + + const foundingInvestorPoolCalls = + options.foundingInvestorPoolAddresses.flatMap((item) => + addresses.map((address) => [ + item.address, + 'userInfo', + [address], + { blockTag } + ]) + ); + + const pendingWithdrawalCalls = options.pendingWithdrawalAddresses.flatMap( + (item) => + addresses.map((address) => [ + item.address, + 'lockedBalances', + [address], + { blockTag } + ]) + ); + + const [ + lockedPoolBalancesRes, + foundingInvestorPoolBalancesRes, + pendingWithdrawalBalancesRes + ] = await Promise.all([ + multicall(network, provider, lockedPoolabi, lockedPoolCalls, { blockTag }), + multicall( + network, + provider, + foundingInvestorPoolabi, + foundingInvestorPoolCalls, + { blockTag } + ), + multicall(network, provider, pendingWithdrawalabi, pendingWithdrawalCalls, { + blockTag + }) + ]); + + const pf = (amount: BigNumber) => + parseFloat(formatUnits(amount, options.decimals)); + + const lockedPoolScore = transformResults( + lockedPoolBalancesRes, + addresses, + (r) => pf(r.amount) + ); + const foundingInvestorPoolScore = transformResults( + foundingInvestorPoolBalancesRes, + addresses, + (r) => pf(r.amount) + ); + const pendingWithdrawalScore = transformResults( + pendingWithdrawalBalancesRes, + addresses, + (r) => pf(r.total) + ); + + const finalScore = Object.keys(score).reduce( + (acc: { [address: string]: number }, address) => { + acc[address] = Math.trunc( + score[address] + + (lockedPoolScore[address] || 0) + + (foundingInvestorPoolScore[address] || 0) + + (pendingWithdrawalScore[address] || 0) + ); + return acc; + }, + {} + ); + + return finalScore; +} From 991bc5259daccde96bb758f74571ddbdfd4afde6 Mon Sep 17 00:00:00 2001 From: johnmark13 Date: Tue, 28 Nov 2023 08:50:10 +0000 Subject: [PATCH 563/815] [nation3-passport-coop-with-delegations] Add minimum token holding to determine passport validity (#1363) * Make sure we have all the ERc20 balances that we need. * I think this is more simple.... * Still not beautiful, but in testing I believe that this is simplified and covers our use cases * Update index.ts Bump version as requested! * How cooperative model might work * Strip out the ERC20 * Update src/strategies/nation3-passport-coop-with-delegations/index.ts Co-authored-by: Chaitanya * Update src/strategies/nation3-passport-coop-with-delegations/index.ts Co-authored-by: Chaitanya * Update src/strategies/nation3-passport-coop-with-delegations/index.ts Co-authored-by: Chaitanya * Update index.ts As requested * Fix from breaking PR suggestions * Create CODEOWNERS * Largely untested, but passes unit tests * Checked with additional adresses and lower balances * Lint * Fix lint issues * Did we ever have a passport 0? * Update nation3-passport-coop-with-delegations to version to 0.3.0 * Remove CODEOWNERS --------- Co-authored-by: JohnMark13 Co-authored-by: Chaitanya Co-authored-by: Aahna Ashina <95955389+aahna-ashina@users.noreply.github.com> --- .../README.md | 6 +- .../examples.json | 6 +- .../index.ts | 61 ++++++++++++++++--- .../schema.json | 10 ++- .../nation3-votes-with-delegations/index.ts | 2 +- 5 files changed, 71 insertions(+), 14 deletions(-) diff --git a/src/strategies/nation3-passport-coop-with-delegations/README.md b/src/strategies/nation3-passport-coop-with-delegations/README.md index f6b726178..34703bf40 100644 --- a/src/strategies/nation3-passport-coop-with-delegations/README.md +++ b/src/strategies/nation3-passport-coop-with-delegations/README.md @@ -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** diff --git a/src/strategies/nation3-passport-coop-with-delegations/examples.json b/src/strategies/nation3-passport-coop-with-delegations/examples.json index 91f7dd490..b7689e4c2 100644 --- a/src/strategies/nation3-passport-coop-with-delegations/examples.json +++ b/src/strategies/nation3-passport-coop-with-delegations/examples.json @@ -4,11 +4,13 @@ "strategy": { "name": "nation3-passport-coop-with-delegations", "params": { - "erc721": "0x3337dac9f251d4e403d6030e18e3cfb6a2cb1333" + "erc721": "0x3337dac9f251d4e403d6030e18e3cfb6a2cb1333", + "erc20": "0xf7def1d2fbda6b74bee7452fdf7894da9201065d" } }, "network": "1", "addresses": [ + "0x61c872A66d79d932F9aEE874b397F2D50Ed78326", "0xEdd000B7Db3cb8931d4E0cb1D0DBe6B947Ceb09A", "0x47d80912400ef8f8224531EBEB1ce8f2ACf4b75a", "0x636d65212C815b93B8E5b069f7082169cec851b7", @@ -16,6 +18,6 @@ "0xfafda3727fe0406e50230bf6092be5ded68cd9e9", "0x79438224Bc21b0E6B45ECF9F8caADfBdB874DedD" ], - "snapshot": 17683972 + "snapshot": 18611783 } ] diff --git a/src/strategies/nation3-passport-coop-with-delegations/index.ts b/src/strategies/nation3-passport-coop-with-delegations/index.ts index 833a030cb..6fd51d1ea 100644 --- a/src/strategies/nation3-passport-coop-with-delegations/index.ts +++ b/src/strategies/nation3-passport-coop-with-delegations/index.ts @@ -1,8 +1,17 @@ -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'; +export const version = '0.3.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)' @@ -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, @@ -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 = - await erc721SignerCaller.execute(); + const [erc721Signers, erc721Owners]: [ + Record, + Record + ] = 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 = + 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])) || []; } diff --git a/src/strategies/nation3-passport-coop-with-delegations/schema.json b/src/strategies/nation3-passport-coop-with-delegations/schema.json index 6fc8cdccd..8318dcad9 100644 --- a/src/strategies/nation3-passport-coop-with-delegations/schema.json +++ b/src/strategies/nation3-passport-coop-with-delegations/schema.json @@ -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", @@ -15,7 +23,7 @@ "maxLength": 42 } }, - "required": ["erc721"], + "required": ["erc20", "erc721"], "additionalProperties": false } } diff --git a/src/strategies/nation3-votes-with-delegations/index.ts b/src/strategies/nation3-votes-with-delegations/index.ts index 4843fa03c..190afe909 100644 --- a/src/strategies/nation3-votes-with-delegations/index.ts +++ b/src/strategies/nation3-votes-with-delegations/index.ts @@ -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]); } From aa3bfb5a62850eb7b0e5a0ed3e42afe6461ff717 Mon Sep 17 00:00:00 2001 From: Sam <51686767+samuveth@users.noreply.github.com> Date: Wed, 29 Nov 2023 17:34:53 +0700 Subject: [PATCH 564/815] chore: Remove strategies with space count 0 and last edited longer than 6 months (#1359) * Remove strategies with space count 0 and older than 6 month * Fix index file * Add back meebitsdao * Add back synthetix * Add back xdai-posdao-staking * Add back digitalax * Fix lint * Run lint:fix * Add back nested stategies * Add back goldfinch-voting-power and goldfinch-membership --------- Co-authored-by: Chaitanya --- .../README.md | 3 +- .../aavegotchi-agip-37-wap-ghst/README.md | 2 +- src/strategies/apeswap/README.md | 33 -- src/strategies/apeswap/examples.json | 24 -- src/strategies/apeswap/index.ts | 58 --- .../aura-balance-of-vlaura-vebal/README.md | 30 -- .../examples.json | 20 - .../aura-balance-of-vlaura-vebal/index.ts | 58 --- .../aura-balance-of-vlaura-vebal/schema.json | 38 -- .../README.md | 30 -- .../examples.json | 22 -- .../aura-vlaura-vebal-with-overrides/index.ts | 76 ---- .../schema.json | 38 -- src/strategies/aura-vlaura-vebal/README.md | 28 -- .../aura-vlaura-vebal/examples.json | 20 - src/strategies/aura-vlaura-vebal/index.ts | 59 --- src/strategies/aura-vlaura-vebal/schema.json | 38 -- .../avn-balance-of-staked/examples.json | 19 - src/strategies/avn-balance-of-staked/index.ts | 162 --------- src/strategies/babywealthyclub/examples.json | 23 -- src/strategies/babywealthyclub/index.ts | 48 --- src/strategies/badgeth/examples.json | 27 -- src/strategies/badgeth/index.ts | 47 --- .../balancer-delegation/examples.json | 33 -- src/strategies/balancer-delegation/index.ts | 29 -- .../README.md | 14 - .../examples.json | 37 -- .../index.ts | 37 -- .../blockzerolabs-cryptonauts/README.md | 16 - .../blockzerolabs-cryptonauts/examples.json | 22 -- .../blockzerolabs-cryptonauts/index.ts | 88 ----- src/strategies/capitaldao-staking/README.md | 15 - .../capitaldao-staking/examples.json | 21 -- src/strategies/capitaldao-staking/index.ts | 49 --- .../clqdr-balance-with-lp/examples.json | 35 -- src/strategies/clqdr-balance-with-lp/index.ts | 148 -------- src/strategies/coordinape/README.md | 11 - src/strategies/coordinape/examples.json | 19 - src/strategies/coordinape/index.ts | 34 -- src/strategies/cream/examples.json | 58 --- src/strategies/cream/index.ts | 301 --------------- src/strategies/cronaswap/README.md | 45 --- src/strategies/cronaswap/examples.json | 35 -- src/strategies/cronaswap/index.ts | 120 ------ src/strategies/ctsi-staking/README.md | 23 -- src/strategies/ctsi-staking/examples.json | 26 -- src/strategies/ctsi-staking/index.ts | 172 --------- src/strategies/ctsi-staking/schema.json | 23 -- src/strategies/cyberkongz-v3/examples.json | 58 --- src/strategies/cyberkongz-v3/index.ts | 97 ----- src/strategies/cyberkongz/examples.json | 27 -- src/strategies/cyberkongz/index.ts | 52 --- .../digitalax-deco-to-mona/README.md | 14 - .../digitalax-deco-to-mona/examples.json | 21 -- .../digitalax-deco-to-mona/index.ts | 55 --- .../digitalax-mona-quickswap/README.md | 11 +- src/strategies/dopamine/README.md | 14 - src/strategies/dopamine/examples.json | 36 -- src/strategies/dopamine/index.ts | 86 ----- src/strategies/dopamine/schema.json | 40 -- .../README.md | 15 - .../examples.json | 37 -- .../index.ts | 79 ---- .../schema.json | 51 --- .../echelon-cached-erc1155-decay/README.md | 24 -- .../examples.json | 28 -- .../echelon-cached-erc1155-decay/index.ts | 51 --- .../README.md | 36 -- .../examples.json | 37 -- .../index.ts | 99 ----- src/strategies/erc20-rebase-wrapper/README.md | 13 - .../erc20-rebase-wrapper/examples.json | 16 - src/strategies/erc20-rebase-wrapper/index.ts | 45 --- .../erc3525-vesting-voucher/examples.json | 16 - .../erc3525-vesting-voucher/index.ts | 102 ------ .../erc3525-vesting-voucher/utils.ts | 36 -- src/strategies/esd-delegation/examples.json | 22 -- src/strategies/esd-delegation/index.ts | 37 -- src/strategies/esd/README.md | 29 -- src/strategies/esd/examples.json | 27 -- src/strategies/esd/index.ts | 97 ----- src/strategies/eth-philanthropy/README.md | 105 ------ src/strategies/eth-philanthropy/examples.json | 24 -- src/strategies/eth-philanthropy/index.ts | 38 -- .../eth-received/ElasticSearchTxResult.ts | 81 ----- src/strategies/eth-received/README.md | 90 ----- src/strategies/eth-received/examples.json | 70 ---- src/strategies/eth-received/index.ts | 83 ----- .../ethercats-founder-series/examples.json | 14 - .../ethercats-founder-series/index.ts | 60 --- src/strategies/gin-finance/examples.json | 15 - src/strategies/gin-finance/index.ts | 88 ----- src/strategies/giveth-xdai-balance/README.md | 12 - .../giveth-xdai-balance/examples.json | 19 - src/strategies/giveth-xdai-balance/index.ts | 141 ------- src/strategies/gysr-pending-rewards/README.md | 16 - .../gysr-pending-rewards/examples.json | 21 -- src/strategies/gysr-pending-rewards/index.ts | 85 ----- .../gysr-pending-rewards/schema.json | 36 -- src/strategies/h2o/README.md | 2 +- .../hashflow-governance-power/README.md | 19 - .../hashflow-governance-power/examples.json | 68 ---- .../hashflow-governance-power/index.ts | 62 ---- .../hashflow-governance-power/schema.json | 38 -- src/strategies/hedgey-multi/README.md | 16 - src/strategies/hedgey-multi/examples.json | 27 -- src/strategies/hedgey-multi/index.ts | 217 ----------- src/strategies/hopr-staking/examples.json | 61 ---- src/strategies/hopr-staking/index.ts | 104 ------ src/strategies/index.ts | 208 +---------- src/strategies/iotex-balance/examples.json | 19 - src/strategies/iotex-balance/index.ts | 56 --- src/strategies/jade-smrt/README.md | 7 - src/strategies/jade-smrt/examples.json | 73 ---- src/strategies/jade-smrt/index.ts | 170 --------- src/strategies/lrc-nft-dao-search/README.md | 28 -- .../lrc-nft-dao-search/examples.json | 21 -- src/strategies/lrc-nft-dao-search/index.ts | 126 ------- src/strategies/minmax-mcn-farm/README.md | 15 - src/strategies/minmax-mcn-farm/examples.json | 24 -- src/strategies/minmax-mcn-farm/index.ts | 90 ----- src/strategies/minto-balance-of-all/README.md | 15 - .../minto-balance-of-all/examples.json | 36 -- src/strategies/minto-balance-of-all/index.ts | 63 ---- src/strategies/multichain-serie/examples.json | 36 -- src/strategies/multichain-serie/index.ts | 53 --- src/strategies/ocean-marketplace-v4/README.md | 51 --- .../ocean-marketplace-v4/examples.json | 94 ----- src/strategies/ocean-marketplace-v4/index.ts | 171 --------- .../ocean-marketplace-v4/oceanUtils.ts | 31 -- src/strategies/piedao/examples.json | 23 -- src/strategies/piedao/index.ts | 136 ------- src/strategies/planet-finance/examples.json | 16 - src/strategies/planet-finance/index.ts | 221 ----------- src/strategies/pod-leader/README.md | 36 -- src/strategies/pod-leader/examples.json | 63 ---- src/strategies/pod-leader/index.ts | 343 ------------------ .../protofi-erc721-tier-weighted/README.md | 15 - .../examples.json | 23 -- .../protofi-erc721-tier-weighted/index.ts | 109 ------ .../README.md | 5 - .../examples.json | 20 - .../proxyprotocol-erc1155-balance-of/index.ts | 60 --- .../proxyprotocol-erc20-balance-of/README.md | 5 - .../examples.json | 19 - .../proxyprotocol-erc20-balance-of/index.ts | 60 --- .../schema.json | 33 -- .../radicle-community-tokens/README.md | 13 - .../radicle-community-tokens/examples.json | 19 - .../radicle-community-tokens/index.ts | 86 ----- src/strategies/rebased/examples.json | 24 -- src/strategies/rebased/index.ts | 103 ------ .../riskharbor-underwriter/README.md | 10 - .../riskharbor-underwriter/examples.json | 22 -- .../riskharbor-underwriter/index.ts | 79 ---- .../riskharbor-underwriter/schema.json | 29 -- src/strategies/ruler-staked-token/README.md | 14 - .../ruler-staked-token/examples.json | 22 -- src/strategies/ruler-staked-token/index.ts | 61 ---- src/strategies/saddle-finance-v2/README.md | 3 - .../saddle-finance-v2/examples.json | 20 - src/strategies/saddle-finance-v2/index.ts | 153 -------- .../saddle-finance-v2/vestingContractAddrs.ts | 74 ---- src/strategies/saddle-finance/README.md | 3 - src/strategies/saddle-finance/examples.json | 20 - src/strategies/saddle-finance/index.ts | 153 -------- .../saddle-finance/vestingContractAddrs.ts | 74 ---- src/strategies/safe-vested/examples.json | 0 src/strategies/safe-vested/index.ts | 0 .../safety-module-bpt-power/README.md | 18 - .../safety-module-bpt-power/examples.json | 37 -- .../safety-module-bpt-power/index.ts | 227 ------------ .../safety-module-bpt-power/schema.json | 66 ---- src/strategies/selfswap/README.md | 9 - src/strategies/selfswap/examples.json | 19 - src/strategies/selfswap/index.ts | 224 ------------ .../single-staking-vault-balanceof/README.md | 13 - .../examples.json | 20 - .../single-staking-vault-balanceof/index.ts | 39 -- src/strategies/snowswap/README.md | 12 - src/strategies/snowswap/examples.json | 20 - src/strategies/snowswap/index.ts | 51 --- .../solv-voucher-claimable/README.md | 14 - .../solv-voucher-claimable/examples.json | 42 --- .../solv-voucher-claimable/index.ts | 78 ---- .../solv-voucher-claimable/schema.json | 28 -- src/strategies/squadz-power/README.md | 15 - src/strategies/squadz-power/examples.json | 36 -- src/strategies/squadz-power/index.ts | 50 --- .../stakedao-governance-update/README.md | 18 - .../stakedao-governance-update/examples.json | 26 -- .../stakedao-governance-update/index.ts | 135 ------- src/strategies/sumami-holders/README.md | 16 - src/strategies/sumami-holders/examples.json | 37 -- src/strategies/sumami-holders/index.ts | 70 ---- src/strategies/sunder/examples.json | 20 - src/strategies/sunder/index.ts | 37 -- src/strategies/svs-staking/examples.json | 23 -- src/strategies/svs-staking/index.ts | 55 --- src/strategies/swapr/README.md | 13 - src/strategies/swapr/commons.ts | 15 - src/strategies/swapr/examples.json | 15 - src/strategies/swapr/index.ts | 55 --- src/strategies/swapr/swapr-lps.ts | 211 ----------- .../synthetix-non-quadratic/README.md | 15 - .../synthetix-non-quadratic/examples.json | 24 -- .../synthetix-non-quadratic/index.ts | 184 ---------- .../synthetix-non-quadratic_2/README.md | 15 - .../synthetix-non-quadratic_2/examples.json | 27 -- .../synthetix-non-quadratic_2/index.ts | 153 -------- .../synthetix-quadratic_2/README.md | 15 - .../synthetix-quadratic_2/examples.json | 27 -- src/strategies/synthetix-quadratic_2/index.ts | 151 -------- src/strategies/tomyumswap/README.md | 9 - src/strategies/tomyumswap/examples.json | 17 - src/strategies/tomyumswap/index.ts | 132 ------- src/strategies/uma-voting/README.md | 46 --- src/strategies/uma-voting/examples.json | 56 --- src/strategies/uma-voting/index.ts | 64 ---- .../vault-token-lp-balance/README.md | 17 - .../vault-token-lp-balance/examples.json | 24 -- .../vault-token-lp-balance/index.ts | 62 ---- src/strategies/volt-voting-power/README.md | 10 +- src/strategies/vsta-pool-staking/README.md | 27 -- .../vsta-pool-staking/examples.json | 24 -- src/strategies/vsta-pool-staking/index.ts | 55 --- src/strategies/vsta-pool-staking/schema.json | 73 ---- src/strategies/xkawa-farm/README.md | 3 - src/strategies/xkawa-farm/examples.json | 21 -- src/strategies/xkawa-farm/index.ts | 53 --- .../examples.json | 37 -- .../index.ts | 58 --- src/strategies/zorro/README.md | 33 -- src/strategies/zorro/examples.json | 31 -- src/strategies/zorro/index.ts | 36 -- src/strategies/zorro/schema.json | 30 -- 236 files changed, 15 insertions(+), 12168 deletions(-) delete mode 100644 src/strategies/apeswap/README.md delete mode 100644 src/strategies/apeswap/examples.json delete mode 100644 src/strategies/apeswap/index.ts delete mode 100644 src/strategies/aura-balance-of-vlaura-vebal/README.md delete mode 100644 src/strategies/aura-balance-of-vlaura-vebal/examples.json delete mode 100644 src/strategies/aura-balance-of-vlaura-vebal/index.ts delete mode 100644 src/strategies/aura-balance-of-vlaura-vebal/schema.json delete mode 100644 src/strategies/aura-vlaura-vebal-with-overrides/README.md delete mode 100644 src/strategies/aura-vlaura-vebal-with-overrides/examples.json delete mode 100644 src/strategies/aura-vlaura-vebal-with-overrides/index.ts delete mode 100644 src/strategies/aura-vlaura-vebal-with-overrides/schema.json delete mode 100644 src/strategies/aura-vlaura-vebal/README.md delete mode 100644 src/strategies/aura-vlaura-vebal/examples.json delete mode 100644 src/strategies/aura-vlaura-vebal/index.ts delete mode 100644 src/strategies/aura-vlaura-vebal/schema.json delete mode 100644 src/strategies/avn-balance-of-staked/examples.json delete mode 100644 src/strategies/avn-balance-of-staked/index.ts delete mode 100644 src/strategies/babywealthyclub/examples.json delete mode 100644 src/strategies/babywealthyclub/index.ts delete mode 100644 src/strategies/badgeth/examples.json delete mode 100644 src/strategies/badgeth/index.ts delete mode 100644 src/strategies/balancer-delegation/examples.json delete mode 100644 src/strategies/balancer-delegation/index.ts delete mode 100644 src/strategies/balancer-erc20-internal-balance-of/README.md delete mode 100644 src/strategies/balancer-erc20-internal-balance-of/examples.json delete mode 100644 src/strategies/balancer-erc20-internal-balance-of/index.ts delete mode 100644 src/strategies/blockzerolabs-cryptonauts/README.md delete mode 100644 src/strategies/blockzerolabs-cryptonauts/examples.json delete mode 100644 src/strategies/blockzerolabs-cryptonauts/index.ts delete mode 100644 src/strategies/capitaldao-staking/README.md delete mode 100644 src/strategies/capitaldao-staking/examples.json delete mode 100644 src/strategies/capitaldao-staking/index.ts delete mode 100644 src/strategies/clqdr-balance-with-lp/examples.json delete mode 100644 src/strategies/clqdr-balance-with-lp/index.ts delete mode 100644 src/strategies/coordinape/README.md delete mode 100644 src/strategies/coordinape/examples.json delete mode 100644 src/strategies/coordinape/index.ts delete mode 100644 src/strategies/cream/examples.json delete mode 100644 src/strategies/cream/index.ts delete mode 100644 src/strategies/cronaswap/README.md delete mode 100644 src/strategies/cronaswap/examples.json delete mode 100644 src/strategies/cronaswap/index.ts delete mode 100644 src/strategies/ctsi-staking/README.md delete mode 100644 src/strategies/ctsi-staking/examples.json delete mode 100644 src/strategies/ctsi-staking/index.ts delete mode 100644 src/strategies/ctsi-staking/schema.json delete mode 100644 src/strategies/cyberkongz-v3/examples.json delete mode 100644 src/strategies/cyberkongz-v3/index.ts delete mode 100644 src/strategies/cyberkongz/examples.json delete mode 100644 src/strategies/cyberkongz/index.ts delete mode 100644 src/strategies/digitalax-deco-to-mona/README.md delete mode 100644 src/strategies/digitalax-deco-to-mona/examples.json delete mode 100644 src/strategies/digitalax-deco-to-mona/index.ts delete mode 100644 src/strategies/dopamine/README.md delete mode 100644 src/strategies/dopamine/examples.json delete mode 100644 src/strategies/dopamine/index.ts delete mode 100644 src/strategies/dopamine/schema.json delete mode 100644 src/strategies/dsla-parametric-staking-service-credits/README.md delete mode 100644 src/strategies/dsla-parametric-staking-service-credits/examples.json delete mode 100644 src/strategies/dsla-parametric-staking-service-credits/index.ts delete mode 100644 src/strategies/dsla-parametric-staking-service-credits/schema.json delete mode 100644 src/strategies/echelon-cached-erc1155-decay/README.md delete mode 100644 src/strategies/echelon-cached-erc1155-decay/examples.json delete mode 100644 src/strategies/echelon-cached-erc1155-decay/index.ts delete mode 100644 src/strategies/echelon-wallet-prime-and-cached-key-gated/README.md delete mode 100644 src/strategies/echelon-wallet-prime-and-cached-key-gated/examples.json delete mode 100644 src/strategies/echelon-wallet-prime-and-cached-key-gated/index.ts delete mode 100644 src/strategies/erc20-rebase-wrapper/README.md delete mode 100644 src/strategies/erc20-rebase-wrapper/examples.json delete mode 100644 src/strategies/erc20-rebase-wrapper/index.ts delete mode 100644 src/strategies/erc3525-vesting-voucher/examples.json delete mode 100644 src/strategies/erc3525-vesting-voucher/index.ts delete mode 100644 src/strategies/erc3525-vesting-voucher/utils.ts delete mode 100644 src/strategies/esd-delegation/examples.json delete mode 100644 src/strategies/esd-delegation/index.ts delete mode 100644 src/strategies/esd/README.md delete mode 100644 src/strategies/esd/examples.json delete mode 100644 src/strategies/esd/index.ts delete mode 100644 src/strategies/eth-philanthropy/README.md delete mode 100644 src/strategies/eth-philanthropy/examples.json delete mode 100644 src/strategies/eth-philanthropy/index.ts delete mode 100644 src/strategies/eth-received/ElasticSearchTxResult.ts delete mode 100644 src/strategies/eth-received/README.md delete mode 100644 src/strategies/eth-received/examples.json delete mode 100644 src/strategies/eth-received/index.ts delete mode 100644 src/strategies/ethercats-founder-series/examples.json delete mode 100644 src/strategies/ethercats-founder-series/index.ts delete mode 100644 src/strategies/gin-finance/examples.json delete mode 100644 src/strategies/gin-finance/index.ts delete mode 100644 src/strategies/giveth-xdai-balance/README.md delete mode 100644 src/strategies/giveth-xdai-balance/examples.json delete mode 100644 src/strategies/giveth-xdai-balance/index.ts delete mode 100644 src/strategies/gysr-pending-rewards/README.md delete mode 100644 src/strategies/gysr-pending-rewards/examples.json delete mode 100644 src/strategies/gysr-pending-rewards/index.ts delete mode 100644 src/strategies/gysr-pending-rewards/schema.json delete mode 100644 src/strategies/hashflow-governance-power/README.md delete mode 100644 src/strategies/hashflow-governance-power/examples.json delete mode 100644 src/strategies/hashflow-governance-power/index.ts delete mode 100644 src/strategies/hashflow-governance-power/schema.json delete mode 100644 src/strategies/hedgey-multi/README.md delete mode 100644 src/strategies/hedgey-multi/examples.json delete mode 100644 src/strategies/hedgey-multi/index.ts delete mode 100644 src/strategies/hopr-staking/examples.json delete mode 100644 src/strategies/hopr-staking/index.ts delete mode 100644 src/strategies/iotex-balance/examples.json delete mode 100644 src/strategies/iotex-balance/index.ts delete mode 100644 src/strategies/jade-smrt/README.md delete mode 100644 src/strategies/jade-smrt/examples.json delete mode 100644 src/strategies/jade-smrt/index.ts delete mode 100644 src/strategies/lrc-nft-dao-search/README.md delete mode 100644 src/strategies/lrc-nft-dao-search/examples.json delete mode 100644 src/strategies/lrc-nft-dao-search/index.ts delete mode 100644 src/strategies/minmax-mcn-farm/README.md delete mode 100644 src/strategies/minmax-mcn-farm/examples.json delete mode 100644 src/strategies/minmax-mcn-farm/index.ts delete mode 100644 src/strategies/minto-balance-of-all/README.md delete mode 100644 src/strategies/minto-balance-of-all/examples.json delete mode 100644 src/strategies/minto-balance-of-all/index.ts delete mode 100644 src/strategies/multichain-serie/examples.json delete mode 100644 src/strategies/multichain-serie/index.ts delete mode 100644 src/strategies/ocean-marketplace-v4/README.md delete mode 100644 src/strategies/ocean-marketplace-v4/examples.json delete mode 100644 src/strategies/ocean-marketplace-v4/index.ts delete mode 100644 src/strategies/ocean-marketplace-v4/oceanUtils.ts delete mode 100644 src/strategies/piedao/examples.json delete mode 100644 src/strategies/piedao/index.ts delete mode 100644 src/strategies/planet-finance/examples.json delete mode 100644 src/strategies/planet-finance/index.ts delete mode 100644 src/strategies/pod-leader/README.md delete mode 100644 src/strategies/pod-leader/examples.json delete mode 100644 src/strategies/pod-leader/index.ts delete mode 100644 src/strategies/protofi-erc721-tier-weighted/README.md delete mode 100644 src/strategies/protofi-erc721-tier-weighted/examples.json delete mode 100644 src/strategies/protofi-erc721-tier-weighted/index.ts delete mode 100644 src/strategies/proxyprotocol-erc1155-balance-of/README.md delete mode 100644 src/strategies/proxyprotocol-erc1155-balance-of/examples.json delete mode 100644 src/strategies/proxyprotocol-erc1155-balance-of/index.ts delete mode 100644 src/strategies/proxyprotocol-erc20-balance-of/README.md delete mode 100644 src/strategies/proxyprotocol-erc20-balance-of/examples.json delete mode 100644 src/strategies/proxyprotocol-erc20-balance-of/index.ts delete mode 100644 src/strategies/proxyprotocol-erc20-balance-of/schema.json delete mode 100644 src/strategies/radicle-community-tokens/README.md delete mode 100644 src/strategies/radicle-community-tokens/examples.json delete mode 100644 src/strategies/radicle-community-tokens/index.ts delete mode 100644 src/strategies/rebased/examples.json delete mode 100644 src/strategies/rebased/index.ts delete mode 100644 src/strategies/riskharbor-underwriter/README.md delete mode 100644 src/strategies/riskharbor-underwriter/examples.json delete mode 100644 src/strategies/riskharbor-underwriter/index.ts delete mode 100644 src/strategies/riskharbor-underwriter/schema.json delete mode 100644 src/strategies/ruler-staked-token/README.md delete mode 100644 src/strategies/ruler-staked-token/examples.json delete mode 100644 src/strategies/ruler-staked-token/index.ts delete mode 100644 src/strategies/saddle-finance-v2/README.md delete mode 100644 src/strategies/saddle-finance-v2/examples.json delete mode 100644 src/strategies/saddle-finance-v2/index.ts delete mode 100644 src/strategies/saddle-finance-v2/vestingContractAddrs.ts delete mode 100644 src/strategies/saddle-finance/README.md delete mode 100644 src/strategies/saddle-finance/examples.json delete mode 100644 src/strategies/saddle-finance/index.ts delete mode 100644 src/strategies/saddle-finance/vestingContractAddrs.ts mode change 100755 => 100644 src/strategies/safe-vested/examples.json mode change 100755 => 100644 src/strategies/safe-vested/index.ts delete mode 100644 src/strategies/safety-module-bpt-power/README.md delete mode 100644 src/strategies/safety-module-bpt-power/examples.json delete mode 100644 src/strategies/safety-module-bpt-power/index.ts delete mode 100644 src/strategies/safety-module-bpt-power/schema.json delete mode 100644 src/strategies/selfswap/README.md delete mode 100644 src/strategies/selfswap/examples.json delete mode 100644 src/strategies/selfswap/index.ts delete mode 100644 src/strategies/single-staking-vault-balanceof/README.md delete mode 100644 src/strategies/single-staking-vault-balanceof/examples.json delete mode 100644 src/strategies/single-staking-vault-balanceof/index.ts delete mode 100644 src/strategies/snowswap/README.md delete mode 100644 src/strategies/snowswap/examples.json delete mode 100644 src/strategies/snowswap/index.ts delete mode 100644 src/strategies/solv-voucher-claimable/README.md delete mode 100644 src/strategies/solv-voucher-claimable/examples.json delete mode 100644 src/strategies/solv-voucher-claimable/index.ts delete mode 100644 src/strategies/solv-voucher-claimable/schema.json delete mode 100644 src/strategies/squadz-power/README.md delete mode 100644 src/strategies/squadz-power/examples.json delete mode 100644 src/strategies/squadz-power/index.ts delete mode 100644 src/strategies/stakedao-governance-update/README.md delete mode 100644 src/strategies/stakedao-governance-update/examples.json delete mode 100644 src/strategies/stakedao-governance-update/index.ts delete mode 100644 src/strategies/sumami-holders/README.md delete mode 100644 src/strategies/sumami-holders/examples.json delete mode 100644 src/strategies/sumami-holders/index.ts delete mode 100644 src/strategies/sunder/examples.json delete mode 100644 src/strategies/sunder/index.ts delete mode 100644 src/strategies/svs-staking/examples.json delete mode 100644 src/strategies/svs-staking/index.ts delete mode 100644 src/strategies/swapr/README.md delete mode 100644 src/strategies/swapr/commons.ts delete mode 100644 src/strategies/swapr/examples.json delete mode 100644 src/strategies/swapr/index.ts delete mode 100644 src/strategies/swapr/swapr-lps.ts delete mode 100644 src/strategies/synthetix-non-quadratic/README.md delete mode 100644 src/strategies/synthetix-non-quadratic/examples.json delete mode 100644 src/strategies/synthetix-non-quadratic/index.ts delete mode 100644 src/strategies/synthetix-non-quadratic_2/README.md delete mode 100644 src/strategies/synthetix-non-quadratic_2/examples.json delete mode 100644 src/strategies/synthetix-non-quadratic_2/index.ts delete mode 100644 src/strategies/synthetix-quadratic_2/README.md delete mode 100644 src/strategies/synthetix-quadratic_2/examples.json delete mode 100644 src/strategies/synthetix-quadratic_2/index.ts delete mode 100644 src/strategies/tomyumswap/README.md delete mode 100644 src/strategies/tomyumswap/examples.json delete mode 100644 src/strategies/tomyumswap/index.ts delete mode 100644 src/strategies/uma-voting/README.md delete mode 100644 src/strategies/uma-voting/examples.json delete mode 100644 src/strategies/uma-voting/index.ts delete mode 100644 src/strategies/vault-token-lp-balance/README.md delete mode 100644 src/strategies/vault-token-lp-balance/examples.json delete mode 100644 src/strategies/vault-token-lp-balance/index.ts delete mode 100644 src/strategies/vsta-pool-staking/README.md delete mode 100644 src/strategies/vsta-pool-staking/examples.json delete mode 100644 src/strategies/vsta-pool-staking/index.ts delete mode 100644 src/strategies/vsta-pool-staking/schema.json delete mode 100644 src/strategies/xkawa-farm/README.md delete mode 100644 src/strategies/xkawa-farm/examples.json delete mode 100644 src/strategies/xkawa-farm/index.ts delete mode 100644 src/strategies/xrook-balance-of-underlying-weighted/examples.json delete mode 100644 src/strategies/xrook-balance-of-underlying-weighted/index.ts delete mode 100644 src/strategies/zorro/README.md delete mode 100644 src/strategies/zorro/examples.json delete mode 100644 src/strategies/zorro/index.ts delete mode 100644 src/strategies/zorro/schema.json diff --git a/src/strategies/aavegotchi-agip-37-gltr-staked-lp/README.md b/src/strategies/aavegotchi-agip-37-gltr-staked-lp/README.md index 81369b718..3a448a5ca 100644 --- a/src/strategies/aavegotchi-agip-37-gltr-staked-lp/README.md +++ b/src/strategies/aavegotchi-agip-37-gltr-staked-lp/README.md @@ -13,10 +13,11 @@ This snapshot strategy enables voting power for the following assets staked in G - GHST-WMATIC LP Please note this excludes voting power from: + - Staked wapGHST and unstaked wapGHST held in a wallet (see aavegotchi-agip-37-wap-ghst) - amGHST (see erc20-balance-of) - Unstaked GHST-FUD, GHST-FOMO, GHST-ALPHA, GHST-KEK, GHST-GLTR LP tokens (see erc20-tokens-per-uni) ## References -Aavegotchi AGIP 37: https://snapshot.org/#/aavegotchi.eth/proposal/0x9923aab6825158ec2503d88e3ee2f9c5fbb12000581d06343ac9829aa59b66a6 \ No newline at end of file +Aavegotchi AGIP 37: https://snapshot.org/#/aavegotchi.eth/proposal/0x9923aab6825158ec2503d88e3ee2f9c5fbb12000581d06343ac9829aa59b66a6 diff --git a/src/strategies/aavegotchi-agip-37-wap-ghst/README.md b/src/strategies/aavegotchi-agip-37-wap-ghst/README.md index 45c8a29a7..e974b3d66 100644 --- a/src/strategies/aavegotchi-agip-37-wap-ghst/README.md +++ b/src/strategies/aavegotchi-agip-37-wap-ghst/README.md @@ -6,4 +6,4 @@ This snapshot strategy enables voting power for staked and unstaked wapGHST. ## References -Aavegotchi AGIP 37: https://snapshot.org/#/aavegotchi.eth/proposal/0x9923aab6825158ec2503d88e3ee2f9c5fbb12000581d06343ac9829aa59b66a6 \ No newline at end of file +Aavegotchi AGIP 37: https://snapshot.org/#/aavegotchi.eth/proposal/0x9923aab6825158ec2503d88e3ee2f9c5fbb12000581d06343ac9829aa59b66a6 diff --git a/src/strategies/apeswap/README.md b/src/strategies/apeswap/README.md deleted file mode 100644 index 90c90eefb..000000000 --- a/src/strategies/apeswap/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# Apeswap - -This is the most common strategy, it returns the balances of the voters for a balances GNANA token -in Apeswap project(pools, token). - -Here is an example of parameters: -```json -[ - { - "name": "Example query Apeswap", - "strategy": { - "name": "apeswap", - "params": { - "address": "0xddb3bd8645775f59496c821e4f55a7ea6a6dc299", - "symbol": "GNANA", - "decimals": 18 - } - }, - "network": "56", - "addresses": [ - "0x56E17565Ce37c0Dbb2BDDec0eC607b874785c376", - "0x0326824dB556Ab5525608851713e269Ce583B629", - "0xc47dec7ffde829043b91e904fdaf1e048bdd482c", - "0x356f74457a8002c680a0c8fa628083d619267c88", - "0x607f62572ea0c00da5048eb39d89d32110151681", - "0x75768Ea1A1C3c84121063f7A281ee3081dB1D8Ef" - ], - "snapshot": 18979451 - } -] - - -``` diff --git a/src/strategies/apeswap/examples.json b/src/strategies/apeswap/examples.json deleted file mode 100644 index 07d7dfa3f..000000000 --- a/src/strategies/apeswap/examples.json +++ /dev/null @@ -1,24 +0,0 @@ -[ - { - "name": "Example query Apeswap", - "strategy": { - "name": "apeswap", - "params": { - "address": "0xddb3bd8645775f59496c821e4f55a7ea6a6dc299", - "symbol": "GNANA", - "decimals": 18 - } - }, - "network": "56", - "addresses": [ - "0xe5EdeA54596B385C3c8dFd5010C3Cf892d547Acb", - "0x56E17565Ce37c0Dbb2BDDec0eC607b874785c376", - "0x0326824dB556Ab5525608851713e269Ce583B629", - "0xc47dec7ffde829043b91e904fdaf1e048bdd482c", - "0x356f74457a8002c680a0c8fa628083d619267c88", - "0x607f62572ea0c00da5048eb39d89d32110151681", - "0x75768Ea1A1C3c84121063f7A281ee3081dB1D8Ef" - ], - "snapshot": 18979451 - } -] diff --git a/src/strategies/apeswap/index.ts b/src/strategies/apeswap/index.ts deleted file mode 100644 index 4fab8dae6..000000000 --- a/src/strategies/apeswap/index.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; -import { formatUnits } from '@ethersproject/units'; -import { Multicaller } from '../../utils'; - -export const author = 'ApeSwapFinance'; -export const version = '0.0.1'; - -const GNANA_POOL = '0x8F97B2E6559084CFaBA140e2AB4Da9aAF23FE7F8'; -const abi = [ - 'function balanceOf(address _owner) view returns (uint256 balance)', - 'function userInfo(address) view returns (uint256 amount, uint256 rewardDebt)' -]; - -const bn = (num: any): BigNumber => { - return BigNumber.from(num.toString()); -}; - -const addUserBalance = (userBalances, user: string, balance) => { - if (userBalances[user]) { - return (userBalances[user] = userBalances[user].add(balance)); - } else { - return (userBalances[user] = balance); - } -}; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -): Promise> { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - const multicall = new Multicaller(network, provider, abi, { blockTag }); - addresses.forEach((address: any) => { - multicall.call(`token.${address}`, options.address, 'balanceOf', [address]); - multicall.call(`pool.${address}`, GNANA_POOL, 'userInfo', [address]); - }); - const result = await multicall.execute(); - - const userBalances: any = []; - for (let i = 0; i < addresses.length - 1; i++) { - userBalances[addresses[i]] = bn(0); - } - - addresses.forEach((address: any) => { - addUserBalance(userBalances, address, result.token[address] ?? 0); - addUserBalance(userBalances, address, result.pool[address][0] ?? 0); - }); - - return Object.fromEntries( - Object.entries(userBalances).map(([address, balance]) => [ - address, - parseFloat(formatUnits(balance, options.decimals)) - ]) - ); -} diff --git a/src/strategies/aura-balance-of-vlaura-vebal/README.md b/src/strategies/aura-balance-of-vlaura-vebal/README.md deleted file mode 100644 index aa1838dd7..000000000 --- a/src/strategies/aura-balance-of-vlaura-vebal/README.md +++ /dev/null @@ -1,30 +0,0 @@ -# aura-balance-of-vlaura-vebal - -This strategy returns proportional voting power for vlAURA holders based on system owned veBAL. - -The voting power is based on the raw balance, rather than delegated voting power. - -For example: -- there are 10000 vlAURA total supply -- a user has 2000 vlAURA (raw balance) -- Aura's voterProxy owns 100k veBAL - -In this example, the user has 20k veBAL balance as they own 20% of the vlAURA voting power. - -_Note: When depositing to the auraLocker, a user does not receive vlAURA until the next epoch has begun (Thursday at 00:00 UTC)_ - -## Params - -- `auraLocker` - (**Required**, `string`) Address of AuraLocker (vlAURA) contract -- `auraVoterProxy` - (**Required**, `string`) Address of Aura VoterProxy contract -- `votingEscrow` - (**Required**, `string`) Address of Balancer VotingEscrow contract - -Here is an example of parameters: - -```json -{ - "auraLocker": "0x3Fa73f1E5d8A792C80F426fc8F84FBF7Ce9bBCAC", - "auraVoterProxy": "0xaF52695E1bB01A16D33D7194C28C42b10e0Dbec2", - "votingEscrow": "0xC128a9954e6c874eA3d62ce62B468bA073093F25" -} -``` diff --git a/src/strategies/aura-balance-of-vlaura-vebal/examples.json b/src/strategies/aura-balance-of-vlaura-vebal/examples.json deleted file mode 100644 index 648742d98..000000000 --- a/src/strategies/aura-balance-of-vlaura-vebal/examples.json +++ /dev/null @@ -1,20 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "aura-balance-of-vlaura-vebal", - "params": { - "auraLocker": "0x3Fa73f1E5d8A792C80F426fc8F84FBF7Ce9bBCAC", - "auraVoterProxy": "0xaF52695E1bB01A16D33D7194C28C42b10e0Dbec2", - "votingEscrow": "0xC128a9954e6c874eA3d62ce62B468bA073093F25" - } - }, - "network": "1", - "addresses": [ - "0x512fce9B07Ce64590849115EE6B32fd40eC0f5F3", - "0x808af82545A721C06D1FcCEbea915a6F5128BeF9", - "0x0CAd1d5ea8b4EeE26959cC00B4A3677f7A11e40F" - ], - "snapshot": 15276577 - } -] diff --git a/src/strategies/aura-balance-of-vlaura-vebal/index.ts b/src/strategies/aura-balance-of-vlaura-vebal/index.ts deleted file mode 100644 index d294c271a..000000000 --- a/src/strategies/aura-balance-of-vlaura-vebal/index.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { BigNumber } from '@ethersproject/bignumber'; -import { formatUnits } from '@ethersproject/units'; -import { Multicaller } from '../../utils'; - -export const author = '0xButterfield'; -export const version = '0.1.0'; - -const abi = [ - 'function balanceOf(address account) public view returns (uint256)', - 'function totalSupply() public view returns (uint256)' -]; - -interface Params { - auraLocker: string; - auraVoterProxy: string; - votingEscrow: string; -} - -interface Response { - vlAuraTotalSupply: BigNumber; - vlAuraBalance: Record; - veBalOwnedByAura: BigNumber; -} - -export async function strategy( - space, - network, - provider, - addresses, - options: Params, - snapshot -): Promise> { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - const multi = new Multicaller(network, provider, abi, { blockTag }); - multi.call('vlAuraTotalSupply', options.auraLocker, 'totalSupply', []); - addresses.forEach((address) => - multi.call(`vlAuraBalance.${address}`, options.auraLocker, 'balanceOf', [ - address - ]) - ); - multi.call('veBalOwnedByAura', options.votingEscrow, 'balanceOf', [ - options.auraVoterProxy - ]); - const res: Response = await multi.execute(); - - return Object.fromEntries( - Object.entries(res.vlAuraBalance).map(([address, balance]) => [ - address, - parseFloat( - formatUnits( - res.veBalOwnedByAura.mul(balance).div(res.vlAuraTotalSupply), - 18 - ) - ) - ]) - ); -} diff --git a/src/strategies/aura-balance-of-vlaura-vebal/schema.json b/src/strategies/aura-balance-of-vlaura-vebal/schema.json deleted file mode 100644 index 85b8c6d26..000000000 --- a/src/strategies/aura-balance-of-vlaura-vebal/schema.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$ref": "#/definitions/Strategy", - "definitions": { - "Strategy": { - "title": "Strategy", - "type": "object", - "properties": { - "auraLocker": { - "type": "string", - "title": "auraLocker", - "examples": ["e.g. 0x3Fa73f1E5d8A792C80F426fc8F84FBF7Ce9bBCAC"], - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - }, - "auraVoterProxy": { - "type": "string", - "title": "auraVoterProxy", - "examples": ["e.g. 0xaF52695E1bB01A16D33D7194C28C42b10e0Dbec2"], - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - }, - "votingEscrow": { - "type": "string", - "title": "votingEscrow", - "examples": ["e.g. 0xC128a9954e6c874eA3d62ce62B468bA073093F25"], - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - } - }, - "required": ["auraLocker", "auraVoterProxy", "votingEscrow"], - "additionalProperties": false - } - } -} diff --git a/src/strategies/aura-vlaura-vebal-with-overrides/README.md b/src/strategies/aura-vlaura-vebal-with-overrides/README.md deleted file mode 100644 index 8f832bb4d..000000000 --- a/src/strategies/aura-vlaura-vebal-with-overrides/README.md +++ /dev/null @@ -1,30 +0,0 @@ -# aura-vlaura-vebal-with-overrides - -This strategy returns proportional voting power for vlAURA holders based on system owned veBAL. - -For example: -- there are 10000 vlAURA total supply -- a user has 2000 vlAURA (voting power, delegated to them) -- Aura's voterProxy owns 100k veBAL - -In this example, the user has 20k veBAL voting power as they own 20% of the vlAURA voting power. - -Voters can optionally override their delegated voting power. - -_Note: When depositing to the auraLocker, a user does not receive vlAURA until the next epoch has begun (Thursday at 00:00 UTC)_ - -## Params - -- `auraLocker` - (**Required**, `string`) Address of AuraLocker (vlAURA) contract -- `auraVoterProxy` - (**Required**, `string`) Address of Aura VoterProxy contract -- `votingEscrow` - (**Required**, `string`) Address of Balancer VotingEscrow contract - -Here is an example of parameters: - -```json -{ - "auraLocker": "0x3Fa73f1E5d8A792C80F426fc8F84FBF7Ce9bBCAC", - "auraVoterProxy": "0xaF52695E1bB01A16D33D7194C28C42b10e0Dbec2", - "votingEscrow": "0xC128a9954e6c874eA3d62ce62B468bA073093F25" -} -``` diff --git a/src/strategies/aura-vlaura-vebal-with-overrides/examples.json b/src/strategies/aura-vlaura-vebal-with-overrides/examples.json deleted file mode 100644 index 1442c1163..000000000 --- a/src/strategies/aura-vlaura-vebal-with-overrides/examples.json +++ /dev/null @@ -1,22 +0,0 @@ -[ - { - "name": "Example query Aura with overrides", - "strategy": { - "name": "aura-vlaura-vebal-with-overrides", - "params": { - "auraLocker": "0x3Fa73f1E5d8A792C80F426fc8F84FBF7Ce9bBCAC", - "auraVoterProxy": "0xaF52695E1bB01A16D33D7194C28C42b10e0Dbec2", - "votingEscrow": "0xC128a9954e6c874eA3d62ce62B468bA073093F25" - } - }, - "network": "1", - "addresses": [ - "0xB1f881f47baB744E7283851bC090bAA626df931d", - "0x808af82545A721C06D1FcCEbea915a6F5128BeF9", - "0x0CAd1d5ea8b4EeE26959cC00B4A3677f7A11e40F", - "0x3cde8fa1c73afe0828f672d197e082463c2ac8e2", - "0xca86d57519dbfe34a25eef0923b259ab07986b71" - ], - "snapshot": 15184638 - } -] diff --git a/src/strategies/aura-vlaura-vebal-with-overrides/index.ts b/src/strategies/aura-vlaura-vebal-with-overrides/index.ts deleted file mode 100644 index 69372c5b5..000000000 --- a/src/strategies/aura-vlaura-vebal-with-overrides/index.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { BigNumber } from '@ethersproject/bignumber'; -import { formatUnits } from '@ethersproject/units'; -import { Multicaller } from '../../utils'; -import { strategy as erc20VotesWithOverrideStrategy } from '../erc20-votes-with-override'; - -export const author = '0xMaharishi'; -export const version = '0.1.0'; - -const abi = [ - 'function delegates(address account) external view returns (address)', - 'function getVotes(address account) external view returns (uint256)', - 'function totalSupply() public view returns (uint256)', - 'function balanceOf(address account) public view returns (uint256)' -]; - -interface Options { - auraLocker: string; - auraVoterProxy: string; - votingEscrow: string; - includeSnapshotDelegations?: boolean; - delegationSpace?: string; -} - -interface Response { - vlAuraTotalSupply: BigNumber; - veBalOwnedByAura: BigNumber; -} - -/* - Based on the `erc20-votes-with-override` strategy, with global vote scaling - to represent the share of Aura's veBAL. -*/ -export async function strategy( - space, - network, - provider, - addresses, - options: Options, - snapshot -): Promise> { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - const multi = new Multicaller(network, provider, abi, { blockTag }); - multi.call('vlAuraTotalSupply', options.auraLocker, 'totalSupply', []); - multi.call('veBalOwnedByAura', options.votingEscrow, 'balanceOf', [ - options.auraVoterProxy - ]); - const res: Response = await multi.execute(); - - const scores: Record = await erc20VotesWithOverrideStrategy( - space, - network, - provider, - addresses, - { - address: options.auraLocker, - delegatesName: 'delegates', - balanceOfName: 'balanceOf', - getVotesName: 'getVotes', - decimals: 18, - includeSnapshotDelegations: options.includeSnapshotDelegations, - delegationSpace: options.delegationSpace - }, - snapshot - ); - - const veBalOwnedByAura = parseFloat(formatUnits(res.veBalOwnedByAura)); - const vlAuraTotalSupply = parseFloat(formatUnits(res.vlAuraTotalSupply)); - - return Object.fromEntries( - Object.entries(scores).map(([address, score]) => [ - address, - (veBalOwnedByAura * score) / vlAuraTotalSupply - ]) - ); -} diff --git a/src/strategies/aura-vlaura-vebal-with-overrides/schema.json b/src/strategies/aura-vlaura-vebal-with-overrides/schema.json deleted file mode 100644 index 85b8c6d26..000000000 --- a/src/strategies/aura-vlaura-vebal-with-overrides/schema.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$ref": "#/definitions/Strategy", - "definitions": { - "Strategy": { - "title": "Strategy", - "type": "object", - "properties": { - "auraLocker": { - "type": "string", - "title": "auraLocker", - "examples": ["e.g. 0x3Fa73f1E5d8A792C80F426fc8F84FBF7Ce9bBCAC"], - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - }, - "auraVoterProxy": { - "type": "string", - "title": "auraVoterProxy", - "examples": ["e.g. 0xaF52695E1bB01A16D33D7194C28C42b10e0Dbec2"], - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - }, - "votingEscrow": { - "type": "string", - "title": "votingEscrow", - "examples": ["e.g. 0xC128a9954e6c874eA3d62ce62B468bA073093F25"], - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - } - }, - "required": ["auraLocker", "auraVoterProxy", "votingEscrow"], - "additionalProperties": false - } - } -} diff --git a/src/strategies/aura-vlaura-vebal/README.md b/src/strategies/aura-vlaura-vebal/README.md deleted file mode 100644 index 2ccf3397c..000000000 --- a/src/strategies/aura-vlaura-vebal/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# aura-vlaura-vebal - -This strategy returns proportional voting power for vlAURA holders based on system owned veBAL. - -For example: -- there are 10000 vlAURA total supply -- a user has 2000 vlAURA (voting power, delegated to them) -- Aura's voterProxy owns 100k veBAL - -In this example, the user has 20k veBAL voting power as they own 20% of the vlAURA voting power. - -_Note: When depositing to the auraLocker, a user does not receive vlAURA until the next epoch has begun (Thursday at 00:00 UTC)_ - -## Params - -- `auraLocker` - (**Required**, `string`) Address of AuraLocker (vlAURA) contract -- `auraVoterProxy` - (**Required**, `string`) Address of Aura VoterProxy contract -- `votingEscrow` - (**Required**, `string`) Address of Balancer VotingEscrow contract - -Here is an example of parameters: - -```json -{ - "auraLocker": "0x3Fa73f1E5d8A792C80F426fc8F84FBF7Ce9bBCAC", - "auraVoterProxy": "0xaF52695E1bB01A16D33D7194C28C42b10e0Dbec2", - "votingEscrow": "0xC128a9954e6c874eA3d62ce62B468bA073093F25" -} -``` diff --git a/src/strategies/aura-vlaura-vebal/examples.json b/src/strategies/aura-vlaura-vebal/examples.json deleted file mode 100644 index 6d4f34d9c..000000000 --- a/src/strategies/aura-vlaura-vebal/examples.json +++ /dev/null @@ -1,20 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "aura-vlaura-vebal", - "params": { - "auraLocker": "0x3Fa73f1E5d8A792C80F426fc8F84FBF7Ce9bBCAC", - "auraVoterProxy": "0xaF52695E1bB01A16D33D7194C28C42b10e0Dbec2", - "votingEscrow": "0xC128a9954e6c874eA3d62ce62B468bA073093F25" - } - }, - "network": "1", - "addresses": [ - "0xB1f881f47baB744E7283851bC090bAA626df931d", - "0x808af82545A721C06D1FcCEbea915a6F5128BeF9", - "0x0CAd1d5ea8b4EeE26959cC00B4A3677f7A11e40F" - ], - "snapshot": 14974420 - } -] diff --git a/src/strategies/aura-vlaura-vebal/index.ts b/src/strategies/aura-vlaura-vebal/index.ts deleted file mode 100644 index 8b4e6886c..000000000 --- a/src/strategies/aura-vlaura-vebal/index.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { BigNumber } from '@ethersproject/bignumber'; -import { formatUnits } from '@ethersproject/units'; -import { Multicaller } from '../../utils'; - -export const author = '0xMaharishi'; -export const version = '0.1.0'; - -const abi = [ - 'function getVotes(address account) external view returns (uint256)', - 'function totalSupply() public view returns (uint256)', - 'function balanceOf(address account) public view returns (uint256)' -]; - -interface Params { - auraLocker: string; - auraVoterProxy: string; - votingEscrow: string; -} - -interface Response { - vlAuraTotalSupply: BigNumber; - vlAuraVotes: Record; - veBalOwnedByAura: BigNumber; -} - -export async function strategy( - space, - network, - provider, - addresses, - options: Params, - snapshot -): Promise> { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - const multi = new Multicaller(network, provider, abi, { blockTag }); - multi.call('vlAuraTotalSupply', options.auraLocker, 'totalSupply', []); - addresses.forEach((address) => - multi.call(`vlAuraVotes.${address}`, options.auraLocker, 'getVotes', [ - address - ]) - ); - multi.call('veBalOwnedByAura', options.votingEscrow, 'balanceOf', [ - options.auraVoterProxy - ]); - const res: Response = await multi.execute(); - - return Object.fromEntries( - Object.entries(res.vlAuraVotes).map(([address, votes]) => [ - address, - parseFloat( - formatUnits( - res.veBalOwnedByAura.mul(votes).div(res.vlAuraTotalSupply), - 18 - ) - ) - ]) - ); -} diff --git a/src/strategies/aura-vlaura-vebal/schema.json b/src/strategies/aura-vlaura-vebal/schema.json deleted file mode 100644 index 85b8c6d26..000000000 --- a/src/strategies/aura-vlaura-vebal/schema.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$ref": "#/definitions/Strategy", - "definitions": { - "Strategy": { - "title": "Strategy", - "type": "object", - "properties": { - "auraLocker": { - "type": "string", - "title": "auraLocker", - "examples": ["e.g. 0x3Fa73f1E5d8A792C80F426fc8F84FBF7Ce9bBCAC"], - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - }, - "auraVoterProxy": { - "type": "string", - "title": "auraVoterProxy", - "examples": ["e.g. 0xaF52695E1bB01A16D33D7194C28C42b10e0Dbec2"], - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - }, - "votingEscrow": { - "type": "string", - "title": "votingEscrow", - "examples": ["e.g. 0xC128a9954e6c874eA3d62ce62B468bA073093F25"], - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - } - }, - "required": ["auraLocker", "auraVoterProxy", "votingEscrow"], - "additionalProperties": false - } - } -} diff --git a/src/strategies/avn-balance-of-staked/examples.json b/src/strategies/avn-balance-of-staked/examples.json deleted file mode 100644 index eaf1f1141..000000000 --- a/src/strategies/avn-balance-of-staked/examples.json +++ /dev/null @@ -1,19 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "avn-balance-of-staked", - "params": { - "vrAddress": "0x8D9D42AF6D048B296cDE8B28693b276dF5e8bfB1", - "vr2Address": "0xE30dE0b5d61B297Da4CA00cFF583CaEdEDaa0C42", - "tokenAddress": "0x0d88ed6e74bbfd96b831231638b66c05571e824f", - "symbol": "AVT", - "decimals": 18, - "start": 11750517 - } - }, - "network": "1", - "addresses": ["0xeEfbADa5539f9ae2c87C1151Cdb2057398383342"], - "snapshot": 12273608 - } -] diff --git a/src/strategies/avn-balance-of-staked/index.ts b/src/strategies/avn-balance-of-staked/index.ts deleted file mode 100644 index 519e6de85..000000000 --- a/src/strategies/avn-balance-of-staked/index.ts +++ /dev/null @@ -1,162 +0,0 @@ -import { BigNumber } from '@ethersproject/bignumber'; -import { formatUnits } from '@ethersproject/units'; -import { multicall } from '../../utils'; - -export const author = 'andrew-frank'; -export const version = '0.1.1'; - -const AVT_ABI = [ - { - constant: true, - inputs: [ - { - internalType: 'address', - name: 'account', - type: 'address' - } - ], - name: 'balanceOf', - outputs: [ - { - internalType: 'uint256', - name: '', - type: 'uint256' - } - ], - payable: false, - stateMutability: 'view', - type: 'function' - } -]; - -const VR_ABI = [ - { - inputs: [ - { internalType: 'uint8', name: 'node', type: 'uint8' }, - { internalType: 'address', name: 'staker', type: 'address' } - ], - name: 'getStakerBalance', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - stateMutability: 'view', - type: 'function' - } -]; - -const NUM_NODES = 10; -// [0, 1, ... , 9] for convinience -const NODES_INDICES = Array.from(Array(NUM_NODES).keys()); -const STAKES_MULTIPLIER = 1; - -class EthCall { - constructor( - public readonly contract: string, - public readonly method: string, - public readonly args: Array - ) {} - get ethCall(): any[] { - return [this.contract, this.method, this.args]; - } -} - -/** creates flat array of eth calls for each user's stake in each VR contract in each node */ -function serializeVrMultiCalls( - vr1Address: string, - vr2Address: string, - userAddresses: string[] -) { - // [ [0, 1, ... , 19], [0, 1, ... , 19] , ..., [0, 1, ... 19], ... ] - const userCalls: EthCall[][] = userAddresses.map((user: string) => { - const method = 'getStakerBalance'; - // map to objects to prevent flatting eth call arrays - const vr1Calls = NODES_INDICES.map( - (node: number) => new EthCall(vr1Address, method, [node, user]) - ); - const vr2Calls = NODES_INDICES.map( - (node: number) => new EthCall(vr2Address, method, [node, user]) - ); - // * [0-9] calls for each node in VR1 - // * [10-19] calls for each node in VR2 - return vr1Calls.concat(vr2Calls); - }); - // flat it and map to a list of the call primitives - const objCalls = userCalls.flat(); - return objCalls.map((obj) => obj.ethCall); -} - -/** splits array into chunks */ -function chunkArray(arr: T[], length: number): T[][] { - const chunks: T[][] = []; - let i = 0; - const n = arr.length; - - while (i < n) { - chunks.push(arr.slice(i, (i += length))); - } - - return chunks; -} - -/** sums big numbers in array */ -function sumNumbers(arr: BigNumber[]): BigNumber { - return arr.reduce((previus, current) => { - return previus.add(current[0]); - }, BigNumber.from(0)); -} - -/** - * Parses multicall response - * @param response multicall response - * @returns summed AVT staked for each user in every node in every VR contract - */ -// eslint-disable-next-line @typescript-eslint/no-unused-vars -function parseVrResponse(response: BigNumber[], users: string[]): BigNumber[] { - return chunkArray(response, 2 * NUM_NODES).map(sumNumbers); -} - -export async function strategy( - _space, - network, - provider, - addresses, - options, - snapshot -) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - // users AVTs - const avtResponses: Array<[BigNumber]> = await multicall( - network, - provider, - AVT_ABI, - addresses.map((address: any) => [ - options.tokenAddress, - 'balanceOf', - [address] - ]), - { blockTag } - ); - const avtValues = avtResponses.map((value) => value[0]); - - // users AVT staked in VR contracts - const vrMultiResponse = await multicall( - network, - provider, - VR_ABI, - serializeVrMultiCalls(options.vrAddress, options.vr2Address, addresses), - { blockTag } - ); - const stakes = parseVrResponse(vrMultiResponse, addresses); - - // calculate the scores - const vrVotes = stakes.map((v) => v.mul(STAKES_MULTIPLIER)); - const scores = avtValues.map((value, i) => { - return value.add(vrVotes[i]); - }); - - return Object.fromEntries( - scores.map((value, i) => [ - addresses[i], - parseFloat(formatUnits(value.toString(), options.decimals)) - ]) - ); -} diff --git a/src/strategies/babywealthyclub/examples.json b/src/strategies/babywealthyclub/examples.json deleted file mode 100644 index d77fe1f8a..000000000 --- a/src/strategies/babywealthyclub/examples.json +++ /dev/null @@ -1,23 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "babywealthyclub", - "params": { - "address": "0x1f9655c660B915b4344b71e2A6d3155C57AD1bB6", - "symbol": "BRC", - "decimals": "9", - "weighted": 20000000000 - } - }, - "network": "56", - "addresses": [ - "0x7F57612b01689a0E4f133730AE20cC19E3dF0208", - "0x4A7998DF2Cd16815271bb6b7d3aE7EB30f50a73a", - "0x08D816526BdC9d077DD685Bd9FA49F58A5Ab8e48", - "0x21fF20E7e1B820020415707298b92299CF0951fE", - "0xa7A01B93B889ff0639d5ec02914A77529924a46F" - ], - "snapshot": 23976608 - } -] diff --git a/src/strategies/babywealthyclub/index.ts b/src/strategies/babywealthyclub/index.ts deleted file mode 100644 index aea541d04..000000000 --- a/src/strategies/babywealthyclub/index.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { strategy as erc20BalanceOfStrategy } from '../erc20-balance-of'; -import { formatUnits } from '@ethersproject/units'; -import { multicall } from '../../utils'; - -export const author = 'gp6284'; -export const version = '0.1.0'; - -const abi = [ - 'function balanceOf(address account) external view returns (uint256)' -]; -const BWC_ADDRESS = '0xb7F7c7D91Ede27b019e265F8ba04c63333991e02'; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - const erc20Balance = await erc20BalanceOfStrategy( - space, - network, - provider, - addresses, - options, - snapshot - ); - const response = await multicall( - network, - provider, - abi, - addresses.map((address: any) => [BWC_ADDRESS, 'balanceOf', [address]]), - { blockTag } - ); - - return Object.fromEntries( - addresses.map((address, i) => [ - address, - parseFloat(formatUnits(response[i].toString(), 0)) > 0 - ? Math.floor( - erc20Balance[addresses[i]] / (options.weighted || 10000000000) - ) - : 0 - ]) - ); -} diff --git a/src/strategies/badgeth/examples.json b/src/strategies/badgeth/examples.json deleted file mode 100644 index 7e78410a1..000000000 --- a/src/strategies/badgeth/examples.json +++ /dev/null @@ -1,27 +0,0 @@ -[ - { - "name": "Badgeth", - "strategy": { - "name": "badgeth", - "params": { - "symbol": "BADGETH" - } - }, - "network": "4", - "snapshot": 8876318, - "addresses": [ - "0xBcE0b2edcA1fBE32891Ac6096b8ea7408dd099c2", - "0x8cABEC8fe71A3604E21e6E2BB55463EC6e26fBf8", - "0x85924aA0B2cb5a0BbeC583Dd090bF7CEdBa5D2Ea", - "0x9149B2b87159c4CC9e2f10C2711357720Da4DA08", - "0xa0710d3b4BA0f848f7edf9CC827aF70A183EAd26", - "0xAE1220f6bFEb414Ed0A95fbb5A6Ecc303b10aa46", - "0xebe986802F7858E1919451C6Ff893e294F31CE54", - "0x2d7cAA8462023af022A5004dA7b781b8ccF81Da7", - "0xE26217836Dd71f49c58a68aD70DabFA1E6d0B75b", - "0x7C572bE1751DdCFeE930286836bF21E6d87c10e6", - "0x6fDcfFDBa2699543a926f0C092F769f3302D3519", - "0x0f6feb3ba20c56e94cfbcd98339e99bce629d912" - ] - } -] diff --git a/src/strategies/badgeth/index.ts b/src/strategies/badgeth/index.ts deleted file mode 100644 index 5135caf32..000000000 --- a/src/strategies/badgeth/index.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { subgraphRequest } from '../../utils'; -import { getAddress } from '@ethersproject/address'; - -export const author = 'Badgeth'; -export const version = '0.1.0'; - -const BADGETH_SUBGRAPH_URL = - 'https://api.thegraph.com/subgraphs/name/hardforksoverknives/badgeth-dev'; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const params = { - voters: { - __args: { - where: { - id_in: addresses, - votingPower_gt: 0 - }, - first: 1000, - orderBy: 'votingPower', - orderDirection: 'desc' - }, - id: true, - votingPower: true - } - }; - if (snapshot !== 'latest') { - // @ts-ignore - params.voters.__args.block = { number: snapshot }; - } - - const score = {}; - const result = await subgraphRequest(BADGETH_SUBGRAPH_URL, params); - if (result && result.voters) { - result.voters.forEach((voter) => { - score[getAddress(voter.id)] = parseInt(voter.votingPower); - }); - } - - return score || {}; -} diff --git a/src/strategies/balancer-delegation/examples.json b/src/strategies/balancer-delegation/examples.json deleted file mode 100644 index b6a21bf60..000000000 --- a/src/strategies/balancer-delegation/examples.json +++ /dev/null @@ -1,33 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "balancer-delegation", - "params": { - "address": "0xba100000625a3754423978a60c9317c58a424e3D", - "symbol": "BAL BPT V1+V2 (delegated)", - "decimals": 18 - } - }, - "network": "1", - "addresses": [ - "0x808A023B72260170c95d831F589A1ae0DCa1e43E", - "0xC0810E5f17915dFe97b57947A3d84094572689ac", - "0x7dd508a1e4Da1243789B799a480f8B45e58b1B5b", - "0x512fce9B07Ce64590849115EE6B32fd40eC0f5F3", - "0x055b441729041DC9F25a296f48604bf6a36B12F2", - "0x3839AcF1ee7699D1F46b1BE840D8aD8317FDf757", - "0x2FAf55a544c5F73666438BC185aeCC9D685E6E3C", - "0xa586Cbf75fB4b8987bAb7d24BE4545fcaa0e757C", - "0x78993bfE37DA5a8DF2D5a8d7213A41c26B20B49D", - "0xB0331b22161cA290A15f825A29C008dCB5e1ff68", - "0x8b6545E4Fd7D5Cc858BE7Ad449F88eF1b2f7a577", - "0xdB19c47E87Ed3Ff37425a99B9Dee1f4920F755b9", - "0x562821C81BBbFFa42443064917Ee4D90036Fba7c", - "0x2fcDa75f0038D54BD0f0d88D5Db2a62EA298AF36", - "0x39D787fdf7384597C7208644dBb6FDa1CcA4eBdf", - "0xD142c9cfE2F0BEF4c14594358fB65aeE1B726d2C" - ], - "snapshot": 11706500 - } -] diff --git a/src/strategies/balancer-delegation/index.ts b/src/strategies/balancer-delegation/index.ts deleted file mode 100644 index 5151cb484..000000000 --- a/src/strategies/balancer-delegation/index.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { strategy as delegation } from '../delegation'; - -export const author = 'bonustrack'; -export const version = '0.1.0'; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - return await delegation( - space, - network, - provider, - addresses, - { - strategies: [ - { - name: 'balancer', - params: options - } - ] - }, - snapshot - ); -} diff --git a/src/strategies/balancer-erc20-internal-balance-of/README.md b/src/strategies/balancer-erc20-internal-balance-of/README.md deleted file mode 100644 index 78369ef8f..000000000 --- a/src/strategies/balancer-erc20-internal-balance-of/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# balancer-erc20-internal-balance-of - -This returns the internal balances of the voters for a specific ERC20 token in the Balancer V2 Vault. - -Here is an example of parameters: - -```json -{ - "vault": "0xba12222222228d8ba445958a75a0704d566bf2c8", - "token": "0xba100000625a3754423978a60c9317c58a424e3D", - "symbol": "BAL", - "decimals": 18 -} -``` diff --git a/src/strategies/balancer-erc20-internal-balance-of/examples.json b/src/strategies/balancer-erc20-internal-balance-of/examples.json deleted file mode 100644 index b5fa0811e..000000000 --- a/src/strategies/balancer-erc20-internal-balance-of/examples.json +++ /dev/null @@ -1,37 +0,0 @@ -[ - { - "name": "Internal Balance", - "strategy": { - "name": "balancer-erc20-internal-balance-of", - "params": { - "vault": "0xba12222222228d8ba445958a75a0704d566bf2c8", - "token": "0xba100000625a3754423978a60c9317c58a424e3D", - "symbol": "BAL", - "decimals": 18 - } - }, - "network": "1", - "addresses": [ - "0xa478c2975ab1ea89e8196811f51a7b7ade33eb11", - "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", - "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", - "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", - "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e", - "0x1d5E65a087eBc3d03a294412E46CE5D6882969f4", - "0x1f254336E5c46639A851b9CfC165697150a6c327", - "0x2ec3F80BeDA63Ede96BA20375032CDD3aAfb3030", - "0x4AcBcA6BE2f8D2540bBF4CA77E45dA0A4a095Fa2", - "0x4F3D348a6D09837Ae7961B1E0cEe2cc118cec777", - "0x6D7f23A509E212Ba7773EC1b2505d1A134f54fbe", - "0x07a1f6fc89223c5ebD4e4ddaE89Ac97629856A0f", - "0x8d5F05270da470e015b67Ab5042BDbE2D2FEFB48", - "0x8d07D225a769b7Af3A923481E1FdF49180e6A265", - "0x8f60501dE5b9b01F9EAf1214dbE1924aA97F7fd0", - "0x9B8e8dD9151260c21CB6D7cc59067cd8DF306D58", - "0x17ea92D6FfbAA1c7F6B117c1E9D0c88ABdc8b84C", - "0x38C0039247A31F3939baE65e953612125cB88268", - "0x794846f3291E55E00662d37Ef048Aa716dF9ECbf" - ], - "snapshot": 13043171 - } -] diff --git a/src/strategies/balancer-erc20-internal-balance-of/index.ts b/src/strategies/balancer-erc20-internal-balance-of/index.ts deleted file mode 100644 index b3a808a2d..000000000 --- a/src/strategies/balancer-erc20-internal-balance-of/index.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { BigNumberish } from '@ethersproject/bignumber'; -import { formatUnits } from '@ethersproject/units'; -import { Multicaller } from '../../utils'; - -export const author = 'gerrrg'; -export const version = '0.0.1'; - -const abi = [ - 'function getInternalBalance(address user, address[] tokens) external view returns (uint256[] balances)' -]; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -): Promise> { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - const multi = new Multicaller(network, provider, abi, { blockTag }); - addresses.forEach((address) => - multi.call(address, options.vault, 'getInternalBalance', [ - address, - [options.token] - ]) - ); - const result: Record = await multi.execute(); - - return Object.fromEntries( - Object.entries(result).map(([address, balance]) => [ - address, - parseFloat(formatUnits(balance[0], options.decimals)) - ]) - ); -} diff --git a/src/strategies/blockzerolabs-cryptonauts/README.md b/src/strategies/blockzerolabs-cryptonauts/README.md deleted file mode 100644 index 9bd8c17bd..000000000 --- a/src/strategies/blockzerolabs-cryptonauts/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# blockzerolabs-cryptonauts - -This strategy is to be used for Blockzero Labs. It will return the underlying XIO tokens held in the NFT Vault. These -XIO can then be used towards voting. - -Here is an example of parameters: - -```json -{ - "symbol": "CRYPTONAUTS", - "totalSupply": 110, - "decimals": 18, - "_nftTokenAddress": "0x1d48ddb875d1e540ee0715dbb7b019d02a3ba4db", - "_vaultAddress": "0x6d9d87fd57fb8ae3bf005e564a950124fc83dd1a" -} -``` diff --git a/src/strategies/blockzerolabs-cryptonauts/examples.json b/src/strategies/blockzerolabs-cryptonauts/examples.json deleted file mode 100644 index e2c7d07b5..000000000 --- a/src/strategies/blockzerolabs-cryptonauts/examples.json +++ /dev/null @@ -1,22 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "blockzerolabs-cryptonauts", - "params": { - "symbol": "CRYPTONAUTS", - "totalSupply": 110, - "decimals": 18, - "_nftTokenAddress": "0x1d48ddb875d1e540ee0715dbb7b019d02a3ba4db", - "_vaultAddress": "0x6d9d87fd57fb8ae3bf005e564a950124fc83dd1a" - } - }, - "network": "1", - "addresses": [ - "0xa478c2975ab1ea89e8196811f51a7b7ade33eb11", - "0x693a3fc85e373dc89239e9eda24edbf4c1d8fefd", - "0x2231e35dae9f0c33141c9eab05b1c1bc4fb1df36" - ], - "snapshot": 13594719 - } -] diff --git a/src/strategies/blockzerolabs-cryptonauts/index.ts b/src/strategies/blockzerolabs-cryptonauts/index.ts deleted file mode 100644 index 36a23f879..000000000 --- a/src/strategies/blockzerolabs-cryptonauts/index.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; -import { getAddress } from '@ethersproject/address'; -import { Multicaller } from '../../utils'; -import { formatUnits } from '@ethersproject/units'; - -export const author = 'blockzerolabs'; -export const version = '0.1.0'; - -const abi = [ - 'function totalSupply() external view returns (uint256)', - 'function exists(uint256) external view returns (bool)', - 'function ownerOf(uint256) external view returns (address)', - 'function balanceOf(uint256) external view returns (uint256)' -]; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -): Promise> { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - // Step 1. Retrieve the total supply of Cryptonauts - const totalSupply = options.totalSupply; - - // Step 2. Determine which ones still exist (i.e not burned) - const nftExistsMulti = new Multicaller(network, provider, abi, { blockTag }); - for (let _nftId = 0; _nftId < totalSupply; _nftId++) { - nftExistsMulti.call( - _nftId, - options._nftTokenAddress, // This is a static address - 'exists', - [_nftId] - ); - } - const nftExists: Record = await nftExistsMulti.execute(); - - // Step 3. Determine owners for NFTs that still exist - const nftOwnersMulti = new Multicaller(network, provider, abi, { blockTag }); - for (let _nftId = 0; _nftId < totalSupply; _nftId++) { - // If the NFT exists, get the owner - if (nftExists[_nftId]) { - nftOwnersMulti.call(_nftId, options._nftTokenAddress, 'ownerOf', [ - _nftId - ]); - } - } - const nftOwners: Record = await nftOwnersMulti.execute(); - - // Step 4. Get the balance of each NFT from the Vault - const vaultBalanceMulti = new Multicaller(network, provider, abi, { - blockTag - }); - for (let _nftId = 0; _nftId < totalSupply; _nftId++) { - // If the NFT exists, get the owner - if (nftExists[_nftId]) { - vaultBalanceMulti.call(_nftId, options._vaultAddress, 'balanceOf', [ - _nftId - ]); - } - } - const vaultBalance: Record = - await vaultBalanceMulti.execute(); - - // Iterate over each address provided - const balances: Record = {}; - addresses.forEach((address) => { - let totalBalance = BigNumber.from(0); - // Iterate over each NFT - for (let _nftId = 0; _nftId < totalSupply; _nftId++) { - // Ensure the NFT Exists before continuing to add balance - if (nftExists[_nftId]) { - // Ensure this address is the owner before continuing to add balance - if (nftOwners[_nftId] == getAddress(address)) { - // Add the balance - totalBalance = totalBalance.add(vaultBalance[_nftId]); - } - } - } - // Format the balance with 18 decimals (fixed) - balances[address] = parseFloat(formatUnits(totalBalance, options.decimals)); - }); - - return balances; -} diff --git a/src/strategies/capitaldao-staking/README.md b/src/strategies/capitaldao-staking/README.md deleted file mode 100644 index c90f799d3..000000000 --- a/src/strategies/capitaldao-staking/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# Capital Dao Staking Token - -This strategy returns balances of the underlying token in Capital Dao Staking pools - -Here is an example of parameters: - -```json -{ - "symbol": "CDS", - "decimals": 18, - "tokenAddress": "0x6139b11c7CE407fb2AAEc3bFdFa97e3A21330843", - "stakingAddress": "0xe157B35C9E8798f61F537a117a5d059A883C8A6F", - "poolIndex": 0 -} -``` \ No newline at end of file diff --git a/src/strategies/capitaldao-staking/examples.json b/src/strategies/capitaldao-staking/examples.json deleted file mode 100644 index 8b76e2f53..000000000 --- a/src/strategies/capitaldao-staking/examples.json +++ /dev/null @@ -1,21 +0,0 @@ -[ - { - "name": "Capital Dao Staked Token", - "strategy": { - "name": "capitaldao-staking", - "params": { - "symbol": "CDS", - "decimals": 18, - "tokenAddress": "0x6139b11c7CE407fb2AAEc3bFdFa97e3A21330843", - "stakingAddress": "0xe157B35C9E8798f61F537a117a5d059A883C8A6F", - "poolIndex": 0 - } - }, - "network": "4", - "addresses": [ - "0x95298790beb442f204e3864c5bd4073905185108", - "0xCe44798440952EBd75Cf1FDC62a996d28137eF30" - ], - "snapshot": 10343903 - } -] diff --git a/src/strategies/capitaldao-staking/index.ts b/src/strategies/capitaldao-staking/index.ts deleted file mode 100644 index 70d65a9b8..000000000 --- a/src/strategies/capitaldao-staking/index.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { multicall } from '../../utils'; -import { formatUnits } from '@ethersproject/units'; -import { BigNumber } from '@ethersproject/bignumber'; - -export const author = 'capitaldao'; -export const version = '0.1.0'; - -const masterChefAbi = [ - 'function users(uint256, address) view returns (uint256 amount, uint256 rewardDebt, uint256 lastDepositAt)' -]; - -function bn(num: any): BigNumber { - return BigNumber.from(num.toString()); -} - -export async function strategy( - _space, - network, - provider, - addresses, - options, - snapshot -) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - // Get staked LP in staking contract - const response = await multicall( - network, - provider, - masterChefAbi, - [ - ...addresses.map((address: any) => [ - options.stakingAddress, - 'users', - [options.poolIndex, address] - ]) - ], - { blockTag } - ); - - return Object.fromEntries( - response.map((user, i) => { - const parsedAmount = parseFloat( - formatUnits(bn(user.amount), options.decimal) - ); - return [addresses[i], parsedAmount]; - }) - ); -} diff --git a/src/strategies/clqdr-balance-with-lp/examples.json b/src/strategies/clqdr-balance-with-lp/examples.json deleted file mode 100644 index e497c6675..000000000 --- a/src/strategies/clqdr-balance-with-lp/examples.json +++ /dev/null @@ -1,35 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "clqdr-balance-with-lp", - "params": { - "address": "0x814c66594a22404e101FEcfECac1012D8d75C156", - "symbol": "cLQDR", - "decimals": 18 - } - }, - "network": "250", - "addresses": [ - "0xf4c5b06ff9cd8f685ddcc58202597e56f1c0faee", - "0x70ECC7FecAea8D67e820035ED48c53706E7F2079", - "0xb5ae3c648709913ef9739e9f6edb5a821c6ab160", - "0x9675fe51fcfa05dbff4d027706f0a97b74fe5dc7", - "0x85644679fd440cd55c7046f2748ec5479cb3c3ab", - "0x1d5E65a087eBc3d03a294412E46CE5D6882969f4", - "0x1f254336E5c46639A851b9CfC165697150a6c327", - "0x2ec3F80BeDA63Ede96BA20375032CDD3aAfb3030", - "0x4AcBcA6BE2f8D2540bBF4CA77E45dA0A4a095Fa2", - "0x4F3D348a6D09837Ae7961B1E0cEe2cc118cec777", - "0x6D7f23A509E212Ba7773EC1b2505d1A134f54fbe", - "0x07a1f6fc89223c5ebD4e4ddaE89Ac97629856A0f", - "0x8d5F05270da470e015b67Ab5042BDbE2D2FEFB48", - "0x8d07D225a769b7Af3A923481E1FdF49180e6A265", - "0x8f60501dE5b9b01F9EAf1214dbE1924aA97F7fd0", - "0x9B8e8dD9151260c21CB6D7cc59067cd8DF306D58", - "0x17ea92D6FfbAA1c7F6B117c1E9D0c88ABdc8b84C", - "0x38C0039247A31F3939baE65e953612125cB88268" - ], - "snapshot": 49467339 - } -] diff --git a/src/strategies/clqdr-balance-with-lp/index.ts b/src/strategies/clqdr-balance-with-lp/index.ts deleted file mode 100644 index 6dcd9d743..000000000 --- a/src/strategies/clqdr-balance-with-lp/index.ts +++ /dev/null @@ -1,148 +0,0 @@ -import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; -import { formatUnits } from '@ethersproject/units'; -import { Multicaller, multicall } from '../../utils'; - -export const author = 'LiquidDriver-finance'; -export const version = '0.0.1'; - -const liquidMasterAddress = '0x6e2ad6527901c9664f016466b8DA1357a004db0f'; -const beetsMasterAddress = '0x8166994d9ebBe5829EC86Bd81258149B87faCfd3'; -const lpAddress = '0xEAdCFa1F34308b144E96FcD7A07145E027A8467d'; -const beetsVaultAddress = '0x20dd72Ed959b6147912C2e529F0a0C651c33c9ce'; -const clqdrPoolId = - '0xeadcfa1f34308b144e96fcd7a07145e027a8467d000000000000000000000331'; - -const contractAbi = [ - 'function userInfo(uint256, address) view returns (uint256 amount, int256 rewardDebt)', - 'function totalSupply() view returns (uint256)', - 'function balanceOf(address _owner) view returns (uint256 balance)', - 'function getPoolTokens(bytes32 poolId) view returns (uint256[], uint256[], uint256)', - 'function getVirtualSupply() external view returns (uint256)' -]; - -const bn = (num: any): BigNumber => { - return BigNumber.from(num.toString()); -}; - -const addUserBalance = (userBalances, user: string, balance) => { - if (userBalances[user]) { - return (userBalances[user] = userBalances[user].add(balance)); - } else { - return (userBalances[user] = balance); - } -}; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -): Promise> { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - const res = await multicall( - network, - provider, - contractAbi, - [ - [beetsVaultAddress, 'getPoolTokens', [clqdrPoolId]], - [lpAddress, 'getVirtualSupply', []] - ], - { blockTag } - ); - - const totalClqdrInBeets = bn(res[0][1][1]); - - const virtualSupply = bn(res[1]); - - const userCLqdrBalances: any = []; - for (let i = 0; i < addresses.length - 1; i++) { - userCLqdrBalances[addresses[i]] = bn(0); - } - - const clqdrMulti = new Multicaller(network, provider, contractAbi, { - blockTag - }); - addresses.forEach((address) => - clqdrMulti.call(address, options.address, 'balanceOf', [address]) - ); - const clqdrToken: Record = await clqdrMulti.execute(); - - Object.fromEntries( - Object.entries(clqdrToken).map(([address, balance]) => { - return addUserBalance(userCLqdrBalances, address, balance); - }) - ); - - const userLpBalances: any = []; - for (let i = 0; i < addresses.length - 1; i++) { - userLpBalances[addresses[i]] = bn(0); - } - - const multi = new Multicaller(network, provider, contractAbi, { blockTag }); - addresses.forEach((address) => - multi.call(address, lpAddress, 'balanceOf', [address]) - ); - const resultToken: Record = await multi.execute(); - - Object.fromEntries( - Object.entries(resultToken).map(([address, balance]) => { - return addUserBalance(userLpBalances, address, balance); - }) - ); - - const multiLiquidMaster = new Multicaller(network, provider, contractAbi, { - blockTag - }); - - addresses.forEach((address) => - multiLiquidMaster.call(address, liquidMasterAddress, 'userInfo', [ - '43', - address - ]) - ); - const resultLiquidMaster: Record = - await multiLiquidMaster.execute(); - - Object.fromEntries( - Object.entries(resultLiquidMaster).map(([address, balance]) => { - return addUserBalance(userLpBalances, address, balance[0]); - }) - ); - - const multiBeetsMaster = new Multicaller(network, provider, contractAbi, { - blockTag - }); - - addresses.forEach((address) => - multiBeetsMaster.call(address, beetsMasterAddress, 'userInfo', [ - '69', - address - ]) - ); - const resultBeetsMaster: Record = - await multiBeetsMaster.execute(); - - Object.fromEntries( - Object.entries(resultBeetsMaster).map(([address, balance]) => { - return addUserBalance(userLpBalances, address, balance[0]); - }) - ); - - return Object.fromEntries( - Object.entries(userLpBalances).map(([address, balance]) => { - const clqdrBalanceInLp = totalClqdrInBeets - // @ts-ignore - .mul(balance) - .div(virtualSupply); - const totalBalance = userCLqdrBalances[address].add(clqdrBalanceInLp); - return [ - address, - // @ts-ignore - parseFloat(formatUnits(totalBalance, options.decimals)) - ]; - }) - ); -} diff --git a/src/strategies/coordinape/README.md b/src/strategies/coordinape/README.md deleted file mode 100644 index a318bd020..000000000 --- a/src/strategies/coordinape/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Coordinape - -Use Coordinape circle epoch tokens as voting power. - -Here is an example of parameters: -```json -{ - "symbol": "CIRCLE", - "circle": "92" -} -``` diff --git a/src/strategies/coordinape/examples.json b/src/strategies/coordinape/examples.json deleted file mode 100644 index 181bc2a5a..000000000 --- a/src/strategies/coordinape/examples.json +++ /dev/null @@ -1,19 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "coordinape", - "params": { - "symbol": "CIRCLE", - "circle": "92" - } - }, - "network": "1", - "addresses": [ - "0x823b92d6a4b2AED4b15675c7917c9f922ea8ADAD", - "0xd337fccaec6ea113baacca3a41eb8766706a0706", - "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7" - ], - "snapshot": 13219000 - } -] diff --git a/src/strategies/coordinape/index.ts b/src/strategies/coordinape/index.ts deleted file mode 100644 index 620881e17..000000000 --- a/src/strategies/coordinape/index.ts +++ /dev/null @@ -1,34 +0,0 @@ -import fetch from 'cross-fetch'; -import { getAddress } from '@ethersproject/address'; - -export const author = 'bonustrack'; -export const version = '0.1.0'; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const ts = (await provider.getBlock(snapshot)).timestamp; - const url = `https://api.coordinape.com/api/${options.circle}/token-gifts?latest_epoch=1×tamp=${ts}&snapshot=${snapshot}`; - const res = await fetch(url, { - method: 'GET', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json' - } - }); - const gifts = await res.json(); - const scores = {}; - gifts.forEach((gift) => { - const address = getAddress(gift.recipient_address); - if (!scores[address]) scores[address] = 0; - scores[address] += gift.tokens; - }); - return Object.fromEntries( - addresses.map((address) => [address, scores[getAddress(address)] || 0]) - ); -} diff --git a/src/strategies/cream/examples.json b/src/strategies/cream/examples.json deleted file mode 100644 index 56ead3dbd..000000000 --- a/src/strategies/cream/examples.json +++ /dev/null @@ -1,58 +0,0 @@ -[ - { - "name": "CREAM", - "strategy": { - "name": "cream", - "params": { - "token": "0x2ba592F78dB6436527729929AAf6c908497cB200", - "symbol": "CREAM", - "crCREAM": "0x892B14321a4FCba80669aE30Bd0cd99a7ECF6aC0", - "sushiswap": "0xf169CeA51EB51774cF107c88309717ddA20be167", - "uniswap": "0xddF9b7a31b32EBAF5c064C80900046C9e5b7C65F", - "balancer": "0x280267901C175565C64ACBD9A3c8F60705A72639", - "masterChef": "0xc2EdaD668740f1aA35E4D8f227fB8E17dcA888Cd", - "pid": 22, - "periods": 3, - "minVote": 1, - "pools": [ - { - "name": "CREAM", - "address": "0x2ba592F78dB6436527729929AAf6c908497cB200" - }, - { - "name": "1 Year", - "address": "0x780F75ad0B02afeb6039672E6a6CEDe7447a8b45" - }, - { - "name": "2 Year", - "address": "0xBdc3372161dfd0361161e06083eE5D52a9cE7595" - }, - { - "name": "3 Year", - "address": "0xD5586C1804D2e1795f3FBbAfB1FBB9099ee20A6c" - }, - { - "name": "4 Year", - "address": "0xE618C25f580684770f2578FAca31fb7aCB2F5945" - } - ] - } - }, - "network": "1", - "addresses": [ - "0x7dd508a1e4Da1243789B799a480f8B45e58b1B5b", - "0xB157ba30e3467DdBC844f14F02b4ba741f1d549F", - "0x6595732468A241312bc307F327bA0D64F02b3c20", - "0xdd4C3B2860f7C747C4F69414022D5FA7354Eef28", - "0xC51FA42503942cafa7b1ffc02F0Cd9564189773e", - "0x0430605323465E26Dc21fBAaA9A1A4Be6ae9d496", - "0xAdC24d7b630759A3AF7f52716d91299c999a2213", - "0x5E0b772FC4E58C470CE4551EeF2391A3B5dA5bb4", - "0x90aBCf1598ed3077861bCFb3B11EFcd1D7277223", - "0xF800d8407b1488BB6Dc3789c2D45147c25C38AF5", - "0xB662ACEAF435C5F21568FC138Ab202C6a43FFc13", - "0x99eb33756a2eAa32f5964A747722c4b59e6aF351" - ], - "snapshot": 12315029 - } -] diff --git a/src/strategies/cream/index.ts b/src/strategies/cream/index.ts deleted file mode 100644 index 16e016371..000000000 --- a/src/strategies/cream/index.ts +++ /dev/null @@ -1,301 +0,0 @@ -import { BigNumber } from '@ethersproject/bignumber'; -import { formatUnits, parseUnits } from '@ethersproject/units'; -import { strategy as erc20BalanceOf } from '../erc20-balance-of'; -import { getBlockNumber } from '../../utils'; -import { Multicaller } from '../../utils'; - -export const author = 'jeremyHD'; -export const version = '0.2.1'; - -const ONE_E18 = parseUnits('1', 18); - -const abi = [ - { - constant: true, - inputs: [ - { - internalType: 'address', - name: '', - type: 'address' - } - ], - name: 'balanceOf', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - payable: false, - stateMutability: 'view', - type: 'function' - }, - { - inputs: [], - name: 'totalSupply', - outputs: [ - { - internalType: 'uint256', - name: '', - type: 'uint256' - } - ], - stateMutability: 'view', - type: 'function' - }, - { - inputs: [ - { - internalType: 'uint256', - name: '', - type: 'uint256' - }, - { - internalType: 'address', - name: '', - type: 'address' - } - ], - name: 'userInfo', - outputs: [ - { - internalType: 'uint256', - name: 'amount', - type: 'uint256' - }, - { - internalType: 'uint256', - name: 'rewardDebt', - type: 'uint256' - } - ], - stateMutability: 'view', - type: 'function' - }, - { - constant: true, - inputs: [], - name: 'exchangeRateStored', - outputs: [ - { - internalType: 'uint256', - name: '', - type: 'uint256' - } - ], - payable: false, - stateMutability: 'view', - type: 'function' - }, - { - constant: true, - inputs: [ - { - internalType: 'address', - name: 'account', - type: 'address' - } - ], - name: 'borrowBalanceStored', - outputs: [ - { - internalType: 'uint256', - name: '', - type: 'uint256' - } - ], - payable: false, - stateMutability: 'view', - type: 'function' - } -]; - -const CREAM_VOTING_POWER = '0xb146BF59f30a54750209EF529a766D952720D0f9'; -const CREAM_VOTING_POWER_DEPLOY_BLOCK = 12315028; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const snapshotBlock = - typeof snapshot === 'number' ? snapshot : await getBlockNumber(provider); - const snapshotBlocks: number[] = []; - - for (let i = 0; i < options.periods; i++) { - const blocksPerPeriod = 80640; // 2 weeks per period, assume 15s per block - const blockTag = - snapshotBlock > blocksPerPeriod * i - ? snapshotBlock - blocksPerPeriod * i - : snapshotBlock; - snapshotBlocks.push(blockTag); - } - - const scores = await Promise.all([ - ...snapshotBlocks.map((blockTag) => - blockTag > CREAM_VOTING_POWER_DEPLOY_BLOCK - ? getScores(provider, addresses, options, blockTag) - : getLegacyScores(provider, addresses, options, blockTag) - ) - ]); - - const averageScore = {}; - addresses.forEach((address) => { - const userScore = scores - .map((score) => score[address]) - .reduce((accumulator, score) => (accumulator += score), 0); - averageScore[address] = userScore / options.periods; - }); - - return Object.fromEntries( - Array(addresses.length) - .fill('') - .map((_, i) => { - const score = averageScore[addresses[i]]; - // ignore score < minimum voting amount - if (score < options.minVote) { - return [addresses[i], 0]; - } - return [addresses[i], score]; - }) - ); -} - -async function getScores(provider, addresses, options, blockTag) { - return erc20BalanceOf( - 'cream', - '1', - provider, - addresses, - { - address: CREAM_VOTING_POWER, - decimals: 18 - }, - blockTag - ); -} - -async function getLegacyScores(provider, addresses, options, blockTag) { - const score = {}; - // Ethereum only - const multi1 = new Multicaller('1', provider, abi, { blockTag }); - multi1.call('sushiswap.cream', options.token, 'balanceOf', [ - options.sushiswap - ]); - multi1.call('sushiswap.totalSupply', options.sushiswap, 'totalSupply'); - - addresses.forEach((address) => { - multi1.call( - `sushiswap.${address}.balanceOf`, - options.sushiswap, - 'balanceOf', - [address] - ); - multi1.call( - `sushiswap.${address}.userInfo`, - options.masterChef, - 'userInfo', - [options.pid, address] - ); - }); - - const multi2 = new Multicaller('1', provider, abi, { blockTag }); - multi2.call('uniswap.cream', options.token, 'balanceOf', [options.uniswap]); - multi2.call('uniswap.totalSupply', options.uniswap, 'totalSupply'); - multi2.call('balancer.cream', options.token, 'balanceOf', [options.balancer]); - multi2.call('balancer.totalSupply', options.balancer, 'totalSupply'); - addresses.forEach((address) => { - multi2.call(`uniswap.${address}.balanceOf`, options.uniswap, 'balanceOf', [ - address - ]); - multi2.call( - `balancer.${address}.balanceOf`, - options.balancer, - 'balanceOf', - [address] - ); - }); - - const multi3 = new Multicaller('1', provider, abi, { blockTag }); - multi3.call('crCREAM.exchangeRate', options.crCREAM, 'exchangeRateStored'); - addresses.forEach((address) => { - multi3.call(`crCREAM.${address}.balanceOf`, options.crCREAM, 'balanceOf', [ - address - ]); - multi3.call( - `crCREAM.${address}.borrow`, - options.crCREAM, - 'borrowBalanceStored', - [address] - ); - }); - - const multi4 = new Multicaller('1', provider, abi, { blockTag }); - addresses.forEach((address) => { - options.pools.forEach((pool) => { - multi4.call(`pool.${address}.${pool.name}`, pool.address, 'balanceOf', [ - address - ]); - }); - }); - - const results = await Promise.all([ - multi1.execute(), - multi2.execute(), - multi3.execute(), - multi4.execute() - ]); - - const result = results.reduce((sumResult, partialResult) => { - Object.entries(partialResult).forEach(([key, value]) => { - sumResult[key] = value; - }); - return sumResult; - }, {}); - - const creamPerSushiswapLP = parseUnits( - result.sushiswap.cream.toString(), - 18 - ).div(result.sushiswap.totalSupply); - const creamPerUniswapLP = parseUnits(result.uniswap.cream.toString(), 18).div( - result.uniswap.totalSupply - ); - const creamPerBalancerLP = parseUnits( - result.balancer.cream.toString(), - 18 - ).div(result.balancer.totalSupply); - - addresses.forEach((address) => { - const userScore = score[address] || BigNumber.from(0); - const sushi = result.sushiswap[address].balanceOf - .add(result.sushiswap[address].userInfo.amount) - .mul(creamPerSushiswapLP) - .div(ONE_E18); - const uniswap = result.uniswap[address].balanceOf - .mul(creamPerUniswapLP) - .div(ONE_E18); - const balancer = result.balancer[address].balanceOf - .mul(creamPerBalancerLP) - .div(ONE_E18); - const crCREAM = result.crCREAM[address].balanceOf - .mul(result.crCREAM.exchangeRate) - .div(ONE_E18) - .sub(result.crCREAM[address].borrow); - const pools = Object.values(result.pool[address]).reduce( - (accumulator: any, poolBalance: any) => { - return accumulator.add(poolBalance); - }, - BigNumber.from(0) - ); - - score[address] = userScore - .add(sushi) - .add(uniswap) - .add(balancer) - .add(crCREAM) - .add(pools); - }); - - Object.keys(score).map((address) => { - score[address] = parseFloat(formatUnits(score[address], 18)); - }); - return score; -} diff --git a/src/strategies/cronaswap/README.md b/src/strategies/cronaswap/README.md deleted file mode 100644 index 00894b4fa..000000000 --- a/src/strategies/cronaswap/README.md +++ /dev/null @@ -1,45 +0,0 @@ -# CronaSwap - -This is the most common strategy, it returns the balances of the voters for a balances CRONA token -in CronaSwap project(pools, farms, Liquidity, token). - -Here is an example of parameters: -```json -[ - { - "name": "Example query CronaSwap", - "strategy": { - "name": "cronaswap", - "params": { - "address": "0xadbd1231fb360047525BEdF962581F3eee7b49fe", - "masterChef": "0x77ea4a4cF9F77A034E4291E8f457Af7772c2B254", - "autoCrona": "0xDf3EBc46F283eF9bdD149Bb24c9b201a70d59389", - "cronaLPs": [ - { - "address": "0xeD75347fFBe08d5cce4858C70Df4dB4Bbe8532a0", - "pid": 1 - }, - { - "address": "0x482E0eEb877091cfca439D131321bDE23ddf9bB5", - "pid": 13 - }, - { - "address": "0x0427F9C304b0028f67A5fD61ffdD613186c1894B", - "pid": 14 - } - ], - "symbol": "CRONA", - "decimals": 18 - } - }, - "network": "25", - "addresses": [ - "0xd758B37Aff75F8Ee847D606fcEfE7BD18C8ed029", - "0xB6E6d031db616cF8aC338293dC2ecFa0F01C55EC" - ], - "snapshot": 599576 - } -] - - -``` diff --git a/src/strategies/cronaswap/examples.json b/src/strategies/cronaswap/examples.json deleted file mode 100644 index 90a6c5ab0..000000000 --- a/src/strategies/cronaswap/examples.json +++ /dev/null @@ -1,35 +0,0 @@ -[ - { - "name": "Example query CronaSwap", - "strategy": { - "name": "cronaswap", - "params": { - "address": "0xadbd1231fb360047525BEdF962581F3eee7b49fe", - "masterChef": "0x77ea4a4cF9F77A034E4291E8f457Af7772c2B254", - "autoCrona": "0xDf3EBc46F283eF9bdD149Bb24c9b201a70d59389", - "cronaLPs": [ - { - "address": "0xeD75347fFBe08d5cce4858C70Df4dB4Bbe8532a0", - "pid": 1 - }, - { - "address": "0x482E0eEb877091cfca439D131321bDE23ddf9bB5", - "pid": 13 - }, - { - "address": "0x0427F9C304b0028f67A5fD61ffdD613186c1894B", - "pid": 14 - } - ], - "symbol": "CRONA", - "decimals": 18 - } - }, - "network": "25", - "addresses": [ - "0xd758B37Aff75F8Ee847D606fcEfE7BD18C8ed029", - "0xB6E6d031db616cF8aC338293dC2ecFa0F01C55EC" - ], - "snapshot": 599576 - } -] diff --git a/src/strategies/cronaswap/index.ts b/src/strategies/cronaswap/index.ts deleted file mode 100644 index 85ce55180..000000000 --- a/src/strategies/cronaswap/index.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; -import { formatUnits, parseUnits } from '@ethersproject/units'; -import { Multicaller } from '../../utils'; -import examplesFile from './examples.json'; - -export const author = 'CronaChef'; -export const version = '0.0.1'; -export const examples = examplesFile; - -const abi = [ - 'function totalSupply() view returns (uint256)', - 'function balanceOf(address _owner) view returns (uint256 balance)', - 'function userInfo(uint256, address) view returns (uint256 amount, uint256 rewardDebt)' -]; - -const autoCronaSwapAbi = [ - 'function userInfo(address) view returns (uint256 amount, uint256 rewardDebt)', - 'function getPricePerFullShare() view returns (uint256)' -]; - -const bn = (num: any): BigNumber => { - return BigNumber.from(num.toString()); -}; - -const addUserBalance = (userBalances, user: string, balance) => { - if (userBalances[user]) { - return (userBalances[user] = userBalances[user].add(balance)); - } else { - return (userBalances[user] = balance); - } -}; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -): Promise> { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - const multicall = new Multicaller(network, provider, abi, { blockTag }); - addresses.forEach((address: any) => { - multicall.call(`token.${address}`, options.address, 'balanceOf', [address]); - multicall.call(`masterChef.${address}`, options.masterChef, 'userInfo', [ - '0', - address - ]); - }); - options.cronaLPs.forEach((lp: { address: string; pid: number }) => { - multicall.call(`lp.${lp.pid}.totalSupply`, lp.address, 'totalSupply'); - multicall.call(`lp.${lp.pid}.balanceOf`, options.address, 'balanceOf', [ - lp.address - ]); - addresses.forEach((address: any) => { - multicall.call( - `lpUsers.${address}.${lp.pid}`, - options.masterChef, - 'userInfo', - [lp.pid, address] - ); - }); - }); - - const multicallAutoCompound = new Multicaller( - network, - provider, - autoCronaSwapAbi, - { - blockTag - } - ); - multicallAutoCompound.call( - 'priceShare', - options.autoCrona, - 'getPricePerFullShare' - ); - addresses.forEach((address) => { - multicallAutoCompound.call(address, options.autoCrona, 'userInfo', [ - address - ]); - }); - - const resultAutoCrona = await multicallAutoCompound.execute(); - const result = await multicall.execute(); - - const userBalances: any = []; - for (let i = 0; i < addresses.length - 1; i++) { - userBalances[addresses[i]] = bn(0); - } - - addresses.forEach((address: any) => { - addUserBalance(userBalances, address, result.token[address]); - addUserBalance(userBalances, address, result.masterChef[address][0]); - addUserBalance( - userBalances, - address, - resultAutoCrona[address][0] - .mul(resultAutoCrona.priceShare) - .div(bn(parseUnits('1', options.decimals))) - ); - options.cronaLPs.forEach((lp: { address: string; pid: number }) => { - addUserBalance( - userBalances, - address, - result.lpUsers[address][lp.pid][0] - .mul(result.lp[lp.pid].balanceOf) - .div(result.lp[lp.pid].totalSupply) - ); - }); - }); - - return Object.fromEntries( - Object.entries(userBalances).map(([address, balance]) => [ - address, - parseFloat(formatUnits(balance, options.decimals)) - ]) - ); -} diff --git a/src/strategies/ctsi-staking/README.md b/src/strategies/ctsi-staking/README.md deleted file mode 100644 index 4281a8eaf..000000000 --- a/src/strategies/ctsi-staking/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# ctsi-staking - -This strategy implements the rules of CTSI Staking, returning the staked balance of the voters. It supports direct staking, as well as delegated staking through staking pools. - -There are no parameters to configure. - -The diagram below represents Cartesi Staking system: - -```mermaid -graph TD - U1[User 1] -->|stake| Staking{Staking} - U2[User 2] -->|operate| P1 - P1(Pool 1) -->|stake| Staking - U3[User 3] -->|stake| P1 -``` - -Cartesi staking system is primarily consolidated in the [StakingImpl contract](https://etherscan.io/address/0x9EdEAdFDE65BCfD0907db3AcdB3445229c764A69#readContract). Stakers to this contract can be EOA who stake directly, as the `User 1` above, or can be a [Staking Pool](https://github.com/cartesi/staking-pool), as the `Pool 1` above. - -Staking Pools are smart contracts, so in this case the voting power is delegated to its operator, given by the `owner` of the pool smart contract, represented by `User 2` above. - -Those users who do not wish to stake directly or operate a pool can stake to a pool instead, like the `User 3` represented in the diagram. As described above, pool operators accumulates the voting power of all its stakers. - -Note that an EOA can be at the same time a direct staker and a pool operator. Voting powers are accumulated. diff --git a/src/strategies/ctsi-staking/examples.json b/src/strategies/ctsi-staking/examples.json deleted file mode 100644 index 389209388..000000000 --- a/src/strategies/ctsi-staking/examples.json +++ /dev/null @@ -1,26 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "ctsi-staking", - "params": { - "expectedResults": { - "scores": { - "0xf977814e90da44bfa03b6295a0616a897441acec": 51704200, - "0xc71c504d2a2938a173660ae71b3e97b563196bea": 36765082, - "0x2942aa4356783892c624125acfbbb80d29629a9d": 0, - "0xb5ba4a130f9e30036d1c1db11a8913caf3acdeba": 34404167.25798815 - } - } - } - }, - "network": "1", - "addresses": [ - "0xf977814e90da44bfa03b6295a0616a897441acec", - "0xc71c504d2a2938a173660ae71b3e97b563196bea", - "0x2942aa4356783892c624125acfbbb80d29629a9d", - "0xb5ba4a130f9e30036d1c1db11a8913caf3acdeba" - ], - "snapshot": 15951825 - } -] diff --git a/src/strategies/ctsi-staking/index.ts b/src/strategies/ctsi-staking/index.ts deleted file mode 100644 index 802c55ee5..000000000 --- a/src/strategies/ctsi-staking/index.ts +++ /dev/null @@ -1,172 +0,0 @@ -import { BigNumber } from '@ethersproject/bignumber'; -import { formatUnits } from '@ethersproject/units'; -import { getAddress } from '@ethersproject/address'; -import { subgraphRequest } from '../../utils'; - -export const author = 'cartesi'; -export const version = '0.1.0'; - -const SUBGRAPH_URL_ROOT = 'https://api.thegraph.com/subgraphs/name/cartesi/pos'; - -const NETWORK_KEY = { - '1': '', - '5': '-goerli' -}; - -function buildSubgraphUrl(chainId) { - const networkString = NETWORK_KEY[chainId]; - return `${SUBGRAPH_URL_ROOT}${networkString}`; -} - -async function getStakingBalance( - url, - addresses, - options, - snapshot -): Promise> { - // query for direct stakers (no pools) - const query = { - users: { - __args: { - where: { - id_in: addresses, - pool: null - }, - first: 1000 - }, - id: true, - balance: true - } - }; - if (snapshot !== 'latest') { - // @ts-ignore - query.users.__args.block = { number: snapshot }; - } - const score: Record = {}; - const result = await subgraphRequest(url, query); - if (result && result.users) { - result.users.forEach((user) => { - const address = getAddress(user.id); - const balance = BigNumber.from(user.balance); - score[address] = balance; - }); - } - - return score; -} - -async function getStakingPoolOperatorBalance( - url, - addresses, - options, - snapshot -): Promise> { - // query for StakingPools by manager (pool operator) - const query = { - stakingPools: { - __args: { - where: { - manager_in: addresses - }, - first: 1000 - }, - manager: true, - user: { - balance: true - } - } - }; - if (snapshot !== 'latest') { - // @ts-ignore - query.stakingPools.__args.block = { number: snapshot }; - } - const score: Record = {}; - const result = await subgraphRequest(url, query); - if (result && result.stakingPools) { - result.stakingPools.forEach((pool) => { - const address = getAddress(pool.manager); - const balance = BigNumber.from(pool.user.balance); - // a pool operator can operate more than one pool, so we must add the value if there is already one - score[address] = score[address] ? score[address].add(balance) : balance; - }); - } - - return score; -} - -function combineBalanceScores( - records: Record[] -): Record { - return records.reduce((aggScore, currScore) => { - for (const [address, balance] of Object.entries(currScore)) { - if (!aggScore[address]) { - aggScore[address] = balance; - } else { - aggScore[address] = aggScore[address].add(balance); // sum(L1, L2) - } - } - return aggScore; - }, {}); -} - -function verifyResults( - results: Record, - expectedResults: Record -): void { - Object.entries(results).forEach(([address, score]) => { - const expectedScore = - expectedResults[address.toLowerCase()] ?? - expectedResults[getAddress(address)]; - if (score !== expectedScore) { - console.error( - `>>> ERROR: Score do not match for address ${address}, expected ${expectedScore}, got ${score}` - ); - } - }); -} - -export async function strategy( - _space, - network, - _provider, - addresses, - options, - snapshot -): Promise> { - // convert addresses to lowercase, as in subgraph they are all lowercase - addresses = addresses.map((address) => address.toLowerCase()); - - // build subgraph URL based on network, as we have one for mainnet and another for goerli - const url = buildSubgraphUrl(network); - - // get staking balance for all direct stakers as voters (no pools, no delegators) - const directStaking = await getStakingBalance( - url, - addresses, - options, - snapshot - ); - - // get balance of pools operated by voters - const operators = await getStakingPoolOperatorBalance( - url, - addresses, - options, - snapshot - ); - - const results = combineBalanceScores([directStaking, operators]); - const scores = Object.fromEntries( - Object.entries(results).map(([address, balance]) => [ - address, - parseFloat(formatUnits(balance, 18)) - ]) - ); - - if (options.expectedResults && snapshot !== 'latest') { - // validate testing expected results - verifyResults(scores, options.expectedResults.scores); - } - - return scores; -} diff --git a/src/strategies/ctsi-staking/schema.json b/src/strategies/ctsi-staking/schema.json deleted file mode 100644 index 006ba35fb..000000000 --- a/src/strategies/ctsi-staking/schema.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$ref": "#/definitions/Strategy", - "definitions": { - "Strategy": { - "title": "Strategy", - "type": "object", - "properties": { - "expectedResults": { - "type": "object", - "properties": { - "scores": { - "type": "object", - "additionalProperties": { "type": "number" } - } - } - } - }, - "required": [], - "additionalProperties": false - } - } -} diff --git a/src/strategies/cyberkongz-v3/examples.json b/src/strategies/cyberkongz-v3/examples.json deleted file mode 100644 index 608d40280..000000000 --- a/src/strategies/cyberkongz-v3/examples.json +++ /dev/null @@ -1,58 +0,0 @@ -[ - { - "name": "Multichain CyberKongz, CyberKongz VX and Banana holdings", - "strategy": { - "name": "cyberkongz-v3", - "params": { - "symbol": "KONGZ", - "chains": [ - { - "network": "1", - "registries": { - "0x57a204aa1042f6e66dd7730813f4024114d74f37": "OG", - "0x7ea3cca10668b8346aec0bf1844a49e995527c8b": "VX", - "0xe2311ae37502105b442bbef831e9b53c5d2e9b3b": "BANANA" - } - }, - { - "network": "137", - "registries": { - "0xbc91347e80886453f3f8bbd6d7ac07c122d87735": "BANANA", - "0x05df72d911e52ab122f7d9955728bc96a718782c": "VX" - } - } - ], - "skipList": [ - "0xb14b87790643d2dab44b06692d37dd95b4b30e56", - "0x9d59eba4deaee09466ba9d4073bf912bc72982b0", - "0x0f4676178b5c53ae0a655f1b19a96387e4b8b5f2", - "0xcfa9a297a406a48d1137172c18de04c944b47ba9", - "0x820f92c1b3ad8e962e6c6d9d7caf2a550aec46fb", - "0x9ffad2ff3a59d8579e3b0edc6c8f2f591c94dfab", - "0xe058d87fc1185e38ab68893136834715b30961e1", - "0xe2311ae37502105b442bbef831e9b53c5d2e9b3b", - "0x7a08865A3E7c291f3b794210Bc51D559B49DFd15", - "0xe6f45376f64e1f568bd1404c155e5ffd2f80f7ad", - "0x40ec5b33f54e0e8a33a975908c5ba1c14e5bbbdf", - "0x0000000000000000000000000000000000000000", - "0xD6a92755Ac5384867083Abd79aD007DE389b955e", - "0x000000000000000000000000000000000000dead", - "0x70C575588B98C1F46B1382c706AdAf398A874e3E", - "0xab8eee3493a55a7bd8126865fd662b7097928088" - ] - } - }, - "network": "1", - "addresses": [ - "0xf521Bb7437bEc77b0B15286dC3f49A87b9946773", - "0x721931508df2764fd4f70c53da646cb8aed16ace", - "0xa63571f2ce7cf4e9a566a1f248f5d0ad3ba78726", - "0x9279c4cfb0e85e2dff8825ce141f9794c7c7170a", - "0x6f35b0cfc58eb1e21eef8a439bbb0ce4c929d32a", - "0xe34bded2b256430a9be53cbf5cba3b6d866d55f3", - "0xb14b87790643d2dab44b06692d37dd95b4b30e56", - "0xd32f25Dfa932b8064A81B8254E7997CAeBc85F97" - ], - "snapshot": 15021651 - } -] diff --git a/src/strategies/cyberkongz-v3/index.ts b/src/strategies/cyberkongz-v3/index.ts deleted file mode 100644 index 5788b4381..000000000 --- a/src/strategies/cyberkongz-v3/index.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { formatUnits } from '@ethersproject/units'; -import { getProvider, getSnapshots, multicall } from '../../utils'; - -export const author = 'maxbrand99'; -export const version = '1.0.0'; - -const bananaContract = '0xe2311ae37502105b442bbef831e9b53c5d2e9b3b'; - -const abi = [ - 'function balanceOf(address account) external view returns (uint256)', - 'function totalSupply() external view returns (uint256)' -]; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const allAddresses = {}; - const promises: any = []; - const blocks = await getSnapshots( - network, - snapshot, - provider, - options.chains.map((s) => s.network || network) - ); - const allCalls: any[] = []; - const chainCalls = { 1: [], 137: [] }; - options.chains.forEach((chain) => { - if (chain.network == 1 || chain.network == 137) { - Object.keys(chain.registries).forEach((registry) => { - allAddresses[registry] = chain.registries[registry]; - addresses.forEach((address: any) => { - chainCalls[chain.network].push([registry, 'balanceOf', [address]]); - allCalls.push([registry, 'balanceOf', [address]]); - }); - }); - } - }); - - Object.keys(chainCalls).forEach((chainID) => { - const blockTag = - typeof blocks[chainID] === 'number' ? blocks[chainID] : 'latest'; - promises.push( - multicall(chainID, getProvider(chainID), abi, chainCalls[chainID], { - blockTag - }) - ); - }); - - const results = await Promise.all(promises); - - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - const nanaCall = [[bananaContract, 'totalSupply', []]]; - let nanaSupply = await multicall(network, provider, abi, nanaCall, { - blockTag - }); - - const response: any[] = []; - results.forEach((result) => { - result.forEach((value) => { - response.push(value); - }); - }); - - response.forEach((value: any, i: number) => { - const address = allCalls[i][2][0]; - if ( - allAddresses[allCalls[i][0]] == 'BANANA' && - options.skipList.find((add) => add === address) - ) { - nanaSupply -= value; - } - }); - - const merged = {}; - response.forEach((value: any, i: number) => { - const address = allCalls[i][2][0]; - if (options.skipList.find((add) => add === address)) { - return; - } - merged[address] = (merged[address] || 0) as number; - if (allAddresses[allCalls[i][0]] == 'OG') - merged[address] += parseFloat(formatUnits((3 * value).toString(), 0)); - else if (allAddresses[allCalls[i][0]] == 'VX') - merged[address] += parseFloat(formatUnits(value.toString(), 0)); - else if (allAddresses[allCalls[i][0]] == 'BANANA') - merged[address] += parseFloat( - formatUnits(Math.floor((15000 * value) / nanaSupply).toString(), 0) - ); - }); - - return merged; -} diff --git a/src/strategies/cyberkongz/examples.json b/src/strategies/cyberkongz/examples.json deleted file mode 100644 index 9a51c16b1..000000000 --- a/src/strategies/cyberkongz/examples.json +++ /dev/null @@ -1,27 +0,0 @@ -[ - { - "name": "CyberKongz, CyberKongz VX and Banana holdings", - "strategy": { - "name": "cyberkongz", - "params": { - "symbol": "KONGZ", - "registries": [ - "0x57a204aa1042f6e66dd7730813f4024114d74f37", - "0x7ea3cca10668b8346aec0bf1844a49e995527c8b", - "0xe2311ae37502105b442bbef831e9b53c5d2e9b3b" - ] - } - }, - "network": "1", - "addresses": [ - "0xf521Bb7437bEc77b0B15286dC3f49A87b9946773", - "0x721931508df2764fd4f70c53da646cb8aed16ace", - "0xa63571f2ce7cf4e9a566a1f248f5d0ad3ba78726", - "0x9279c4cfb0e85e2dff8825ce141f9794c7c7170a", - "0x6f35b0cfc58eb1e21eef8a439bbb0ce4c929d32a", - "0xe34bded2b256430a9be53cbf5cba3b6d866d55f3", - "0x031c690be2932403cbdd85f8853f596794cff6c3" - ], - "snapshot": 13322697 - } -] diff --git a/src/strategies/cyberkongz/index.ts b/src/strategies/cyberkongz/index.ts deleted file mode 100644 index a47a1348f..000000000 --- a/src/strategies/cyberkongz/index.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { formatUnits } from '@ethersproject/units'; -import { multicall } from '../../utils'; - -export const author = 'cesarsld'; -export const version = '0.1.0'; - -const abi = [ - 'function balanceOf(address account) external view returns (uint256)', - 'function totalSupply() external view returns (uint256)' -]; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - const calls: any[] = []; - options.registries.forEach((registry) => { - addresses.forEach((address: any) => { - calls.push([registry, 'balanceOf', [address]]); - }); - }); - - const response = await multicall(network, provider, abi, calls, { blockTag }); - const nanaCall = [ - ['0xe2311ae37502105b442bbef831e9b53c5d2e9b3b', 'totalSupply', []] - ]; - const nanaSupply = await multicall(network, provider, abi, nanaCall, { - blockTag - }); - - const merged = {}; - response.map((value: any, i: number) => { - const address = calls[i][2][0]; - merged[address] = (merged[address] || 0) as number; - if (Math.floor(i / addresses.length) == 0) - merged[address] += parseFloat(formatUnits((3 * value).toString(), 0)); - else if (Math.floor(i / addresses.length) == 1) - merged[address] += parseFloat(formatUnits(value.toString(), 0)); - else if (Math.floor(i / addresses.length) == 2) - merged[address] += parseFloat( - formatUnits(Math.floor((15000 * value) / nanaSupply).toString(), 0) - ); - }); - - return merged; -} diff --git a/src/strategies/digitalax-deco-to-mona/README.md b/src/strategies/digitalax-deco-to-mona/README.md deleted file mode 100644 index 76c03f245..000000000 --- a/src/strategies/digitalax-deco-to-mona/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# DIGITALAX DECO to MONA conversion - -This is the DIGITALAX DECO to MONA conversion for voting purposes - -Here is an example of parameters: - -```json -{ - "symbol": "MONA", - "address": "0x200f9621cbce6ed740071ba34fde85ee03f2e113" -} -``` - - diff --git a/src/strategies/digitalax-deco-to-mona/examples.json b/src/strategies/digitalax-deco-to-mona/examples.json deleted file mode 100644 index 86fbc176d..000000000 --- a/src/strategies/digitalax-deco-to-mona/examples.json +++ /dev/null @@ -1,21 +0,0 @@ -[ - { - "name": "Digitalax Deco to Mona conversion", - "strategy": { - "name": "digitalax-deco-to-mona", - "params": { - "symbol": "MONA", - "address": "0x200f9621cbce6ed740071ba34fde85ee03f2e113" - } - }, - "network": "137", - "addresses": [ - "0xd4c4f5e108d09f4383f431d143e75ecabb703f2a", - "0x0e091edbc59d7089451b19bd54bddd3576232edc", - "0x5fc1f31a084ef781b436885d10ab8c3e24a29642", - "0x5e4038eb6f1e7316a45ed569e94c8cd1706a5ec5", - "0xab48edd90bdf367d326d827758bacd2460c59d17" - ], - "snapshot": 23986420 - } -] diff --git a/src/strategies/digitalax-deco-to-mona/index.ts b/src/strategies/digitalax-deco-to-mona/index.ts deleted file mode 100644 index 5558c0ad6..000000000 --- a/src/strategies/digitalax-deco-to-mona/index.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { multicall } from '../../utils'; -import { strategy as erc20BalanceOfStrategy } from '../erc20-balance-of'; - -export const author = 'onigiri-x'; -export const version = '0.1.0'; - -const abi = [ - 'function getReserves() external view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast)' -]; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -): Promise> { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - const pairAddresses = [ - '0x7ecb3be21714114d912469810aedd34e6fc27736', - '0x3203bf44d434452b4605c7657c51bfeaf2a0847c' - ]; - const priceResponse = await multicall( - network, - provider, - abi, - pairAddresses.map((address: any) => [address, 'getReserves', []]), - { blockTag } - ); - - const priceDecoToEth = - parseFloat(priceResponse[0]._reserve1) / - parseFloat(priceResponse[0]._reserve0); - const priceEthToMona = - parseFloat(priceResponse[1]._reserve0) / - parseFloat(priceResponse[1]._reserve1); - - const erc20Balances = await erc20BalanceOfStrategy( - space, - network, - provider, - addresses, - options, - snapshot - ); - - return Object.fromEntries( - addresses.map((address) => [ - address, - erc20Balances[address] * priceDecoToEth * priceEthToMona - ]) - ); -} diff --git a/src/strategies/digitalax-mona-quickswap/README.md b/src/strategies/digitalax-mona-quickswap/README.md index 52366e257..97208addd 100644 --- a/src/strategies/digitalax-mona-quickswap/README.md +++ b/src/strategies/digitalax-mona-quickswap/README.md @@ -10,12 +10,11 @@ Here is an example of parameters: "address": "0x82f1676ef298db09da935f4cb7bd3c44fb73d83a" } ``` -There are two pools that are currently supported. - -Mona Quick Pool: -``` "address": "0x82f1676ef298db09da935f4cb7bd3c44fb73d83a"``` -Mona USDT Pool: -``` "address": "0x856ad56defbb685db8392d9e54441df609bc5ce1"``` +There are two pools that are currently supported. +Mona Quick Pool: +` "address": "0x82f1676ef298db09da935f4cb7bd3c44fb73d83a"` +Mona USDT Pool: +` "address": "0x856ad56defbb685db8392d9e54441df609bc5ce1"` diff --git a/src/strategies/dopamine/README.md b/src/strategies/dopamine/README.md deleted file mode 100644 index 87262fd4c..000000000 --- a/src/strategies/dopamine/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# dopamine - -Combines veDope governance token holders and NFT holders, returning a combined voting power as a percentage of the total. - -Here is an example of parameters: - -```json -{ - "erc20Address": "0x6b175474e89094c44da98b954eedeac495271d0f", - "erc721Address": "0x96b0f2cf48ad9ab21bb7a8a052a3d8391ee64798", - "nftMultiplier": 10000, - "decimals": 4 -} -``` diff --git a/src/strategies/dopamine/examples.json b/src/strategies/dopamine/examples.json deleted file mode 100644 index 430389562..000000000 --- a/src/strategies/dopamine/examples.json +++ /dev/null @@ -1,36 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "dopamine", - "params": { - "tokenAddress": "0x6b175474e89094c44da98b954eedeac495271d0f", - "nftAddress": "0x96b0f2cf48ad9ab21bb7a8a052a3d8391ee64798", - "nftMultiplier": 10000, - "decimals": 8 - } - }, - "network": "1", - "addresses": [ - "0xd99c7975ef9b339d93fec21a4ab24a567d686d73", - "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", - "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", - "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", - "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e", - "0x1d5E65a087eBc3d03a294412E46CE5D6882969f4", - "0x1f254336E5c46639A851b9CfC165697150a6c327", - "0x2ec3F80BeDA63Ede96BA20375032CDD3aAfb3030", - "0x4AcBcA6BE2f8D2540bBF4CA77E45dA0A4a095Fa2", - "0x4F3D348a6D09837Ae7961B1E0cEe2cc118cec777", - "0x6D7f23A509E212Ba7773EC1b2505d1A134f54fbe", - "0x07a1f6fc89223c5ebD4e4ddaE89Ac97629856A0f", - "0x8d5F05270da470e015b67Ab5042BDbE2D2FEFB48", - "0x8d07D225a769b7Af3A923481E1FdF49180e6A265", - "0x8f60501dE5b9b01F9EAf1214dbE1924aA97F7fd0", - "0x9B8e8dD9151260c21CB6D7cc59067cd8DF306D58", - "0x17ea92D6FfbAA1c7F6B117c1E9D0c88ABdc8b84C", - "0x38C0039247A31F3939baE65e953612125cB88268" - ], - "snapshot": 15092760 - } -] diff --git a/src/strategies/dopamine/index.ts b/src/strategies/dopamine/index.ts deleted file mode 100644 index 9fe5ef5e6..000000000 --- a/src/strategies/dopamine/index.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; -import { formatUnits } from '@ethersproject/units'; -import { Multicaller, call } from '../../utils'; - -export const author = 'crypto-dump'; -export const version = '0.1.0'; - -const nftContractAbi = [ - 'function balanceOf(address account) external view returns (uint256)', - 'function totalSupply() external view returns (uint256)' -]; - -const tokenContractAbi = [ - 'function balanceOf(address account) external view returns (uint256)', - 'function totalSupply() external view returns (uint256)', - 'function decimals() external view returns (uint256)' -]; - -interface StrategyOptions { - decimals: number; - tokenAddress: string; - nftAddress: string; - nftMultiplier: number; -} - -type MultiCallResult = Record; - -export async function strategy( - space, - network, - provider, - addresses, - options: StrategyOptions, - snapshot -): Promise> { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - const callTokenDecimal = () => { - return call(provider, tokenContractAbi, [ - options.tokenAddress, - 'decimals', - [] - ]); - }; - - const makeMulticaller = (abi, contractAddress) => { - const multiCaller = new Multicaller(network, provider, abi, { - blockTag - }); - addresses.forEach((address) => - multiCaller.call(address, contractAddress, 'balanceOf', [address]) - ); - return multiCaller; - }; - - const erc20Multi = makeMulticaller(tokenContractAbi, options.tokenAddress); - const erc721Multi = makeMulticaller(nftContractAbi, options.nftAddress); - - const [tokenDecimal, tokenResults, nftResults]: [ - BigNumber, - MultiCallResult, - MultiCallResult - ] = await Promise.all([ - callTokenDecimal(), - erc20Multi.execute(), - erc721Multi.execute() - ]); - - const scores: Record = {}; - - for (const address of addresses) { - const tokenScore = BigNumber.from(tokenResults[address] || 0); - - const nftScore = BigNumber.from(nftResults[address] || 0) - .mul(options.nftMultiplier) - .mul(BigNumber.from(10).pow(tokenDecimal)); - scores[address] = tokenScore.add(nftScore); - } - - return Object.fromEntries( - Object.entries(scores).map(([address, score]) => [ - address, - parseFloat(formatUnits(score, options.decimals)) - ]) - ); -} diff --git a/src/strategies/dopamine/schema.json b/src/strategies/dopamine/schema.json deleted file mode 100644 index f09f221c1..000000000 --- a/src/strategies/dopamine/schema.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$ref": "#/definitions/Strategy", - "definitions": { - "Strategy": { - "title": "Dopamine", - "type": "object", - "properties": { - "nftMultiplier": { - "type": "number", - "title": "Symbol", - "examples": ["e.g. 10000"] - }, - "tokenAddress": { - "type": "string", - "title": "ERC20 Token Contract address", - "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - }, - "nftAddress": { - "type": "string", - "title": "ERC721 NFT Token Contract address", - "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - }, - "decimals": { - "type": "number", - "title": "Decimals", - "examples": ["e.g. 4"] - } - }, - "required": ["tokenAddress", "nftAddress", "nftMultiplier", "decimals"], - "additionalProperties": false - } - } -} diff --git a/src/strategies/dsla-parametric-staking-service-credits/README.md b/src/strategies/dsla-parametric-staking-service-credits/README.md deleted file mode 100644 index ec8724192..000000000 --- a/src/strategies/dsla-parametric-staking-service-credits/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# dsla - -DSLA's custom snapshot strategy, calculates voting score based of the staked balances of the voters for users/provider pools of Staking SLA. - -Here is an example of parameters: - -```json -{ - "LP_TOKEN": "0xAC104C0438A7bb15C714503537c6FA271FDB284E", - "SP_TOKEN": "0xcf4ea46eba95fe3643b6c954d29516d7376913dc", - "DSLA": "0x3aFfCCa64c2A6f4e3B6Bd9c64CD2C969EFd1ECBe", - "StakingSLA": "0x091ee4d4D8FfD00698c003C21F1ba69EA6310241", - "decimals": 18 -} -``` diff --git a/src/strategies/dsla-parametric-staking-service-credits/examples.json b/src/strategies/dsla-parametric-staking-service-credits/examples.json deleted file mode 100644 index bdf267123..000000000 --- a/src/strategies/dsla-parametric-staking-service-credits/examples.json +++ /dev/null @@ -1,37 +0,0 @@ -[ - { - "name": "Example query of DSLA Staking", - "strategy": { - "name": "dsla-parametric-staking-service-credits", - "params": { - "xDSLA": "0xcf4ea46eba95fe3643b6c954d29516d7376913dc", - "xDSLA_LP": "0xAC104C0438A7bb15C714503537c6FA271FDB284E", - "DSLA": "0x3aFfCCa64c2A6f4e3B6Bd9c64CD2C969EFd1ECBe", - "StakingSLA": "0x091ee4d4D8FfD00698c003C21F1ba69EA6310241", - "decimals": 18 - } - }, - "network": "1", - "addresses": [ - "0x8b0049beb72893c290a026398571a26ea4a03892", - "0x4d5c314adac838d1906992d83894fe47d6931165", - "0xe7a3b897fa52fe3e7f7d0e9803bea00fab78d12f", - "0xb6d568233e81442ded126fad8e8230ed02b6be3e", - "0x5d64d4c35345e9588f3f2233cf6e93978763012c", - "0x9e1b10bf75f339805ed3b266070001100bf87a85", - "0x57a43c9bc2b4d4447bfc1cf4e050bc6dcb72d753", - "0xb44b476a7f6a83b5e0559433b0d3ad374a0c1682", - "0x4baac6507bdcb0c9d059284c539bcf35d433d22e", - "0x66fc061aa4d8d3809876f5a6ddb3506d2d16168f", - "0x443a391e33241798d69295149cdf018e543049ea", - "0x645b28857b19c0046b10caa3bd93fcd31ce15905", - "0x20850bcea7476a0623e276c2cb9ec2e3024dcb0c", - "0xce049d2afc746f96d2ca2b6425efcbf9d44fda2c", - "0x397ef1462cf750ae2e4c387a70474c1f1c5a1637", - "0xb270814532f90969b62b37ccd04dfadfadcd3267", - "0x12b50bdab12a633d992ebfecff6eb9785aa5a09a", - "0x88c0356a46823938bcb233be05d7634aab7f40d9" - ], - "snapshot": 15825878 - } -] diff --git a/src/strategies/dsla-parametric-staking-service-credits/index.ts b/src/strategies/dsla-parametric-staking-service-credits/index.ts deleted file mode 100644 index 4e768ea62..000000000 --- a/src/strategies/dsla-parametric-staking-service-credits/index.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; -import { formatUnits } from '@ethersproject/units'; -import { Multicaller } from '../../utils'; - -export const author = 'gmtesla'; -export const version = '0.1.1'; - -// const DSLA = '0x3aFfCCa64c2A6f4e3B6Bd9c64CD2C969EFd1ECBe'; -// const StakingSLA = '0x091ee4d4D8FfD00698c003C21F1ba69EA6310241'; -// const LP_TOKEN = '0xAC104C0438A7bb15C714503537c6FA271FDB284E'; // dpToken -// const SP_TOKEN = '0xcf4ea46eba95fe3643b6c954d29516d7376913dc' // duToken - -const abi = [ - 'function balanceOf(address account) external view returns (uint256)', - 'function totalSupply() external view returns (uint256)', - 'function usersPool(address token) external view returns (uint256)', - 'function providersPool(address token) external view returns (uint256)' -]; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -): Promise> { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - // Get dpToken Balances - const multi = new Multicaller(network, provider, abi, { blockTag }); - addresses.forEach((address) => - multi.call(address, options.xDSLA_LP, 'balanceOf', [address]) - ); - const dpTokenBalances: Record = await multi.execute(); - - // Get duToken Balances - addresses.forEach((address) => - multi.call(address, options.xDSLA, 'balanceOf', [address]) - ); - const duTokenBalances: Record = await multi.execute(); - - // Get totalSupply of user/provider pools - const multi2 = new Multicaller(network, provider, abi, { blockTag }); - multi2.call('userTotalSupply', options.xDSLA, 'totalSupply', []); - multi2.call('providerTotalSupply', options.xDSLA_LP, 'totalSupply', []); - multi2.call('usersPool', options.StakingSLA, 'usersPool', [options.DSLA]); - multi2.call('providersPool', options.StakingSLA, 'providersPool', [ - options.DSLA - ]); - const res2: Record = await multi2.execute(); - - // Sum up duTokenBalance and dpTokenBalances - // dTokenBalance = staked amount * total supply / (userPools or providerPools) - // staked amount = dTokenBalance * (userPools or providerPools) / total supply - const balances = Object.fromEntries( - Object.entries(dpTokenBalances).map(([address, balance]) => [ - address, - BigNumber.from(balance) - .mul(res2.providersPool) - .div(res2.providerTotalSupply) - ]) - ); - Object.entries(duTokenBalances).forEach(([address, balance]) => { - const prevBal = BigNumber.from(balances[address]); - balances[address] = prevBal.add( - BigNumber.from(balance).mul(res2.usersPool).div(res2.userTotalSupply) - ); - }); - - const result = Object.fromEntries( - Object.entries(balances).map(([address, balance]) => [ - address, - parseFloat(formatUnits(balance, options.decimals)) - ]) - ); - - return result; -} diff --git a/src/strategies/dsla-parametric-staking-service-credits/schema.json b/src/strategies/dsla-parametric-staking-service-credits/schema.json deleted file mode 100644 index 4b27e279c..000000000 --- a/src/strategies/dsla-parametric-staking-service-credits/schema.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$ref": "#/definitions/Strategy", - "definitions": { - "Strategy": { - "title": "DSLA", - "type": "object", - "properties": { - "xDSLA": { - "type": "string", - "title": "xDSLA", - "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - }, - "xDSLA_LP": { - "type": "string", - "title": "xDSLA_LP", - "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - }, - "DSLA": { - "type": "string", - "title": "DSLA", - "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - }, - "StakingSLA": { - "type": "string", - "title": "StakingSLA", - "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - }, - "decimals": { - "type": "number", - "title": "Decimals", - "examples": ["e.g. 18"] - } - }, - "required": ["xDSLA", "xDSLA_LP", "StakingSLA", "DSLA", "decimals"], - "additionalProperties": false - } - } -} diff --git a/src/strategies/echelon-cached-erc1155-decay/README.md b/src/strategies/echelon-cached-erc1155-decay/README.md deleted file mode 100644 index 6d80e7d98..000000000 --- a/src/strategies/echelon-cached-erc1155-decay/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# echelon-cached-erc1155-decay - -This strategy looks at an ERC1155 caching (staking) contract and assigns a linearly decaying amount of voting power. The business context behind this is that each cached asset is eligible to claim a set amount of ERC20s over the same period; and thus can use those tokens to vote as well. - -For example, at block 0, the voting should have equivalent to 4000 units of voting power. A year later, they should have 0 units. - -As parameters, we pass in the base amount of voting power (e.g. 4000), starting block where there's no decay, and number of months until complete decay (e.g. 12). - -At a high level, the strategy grabs the UNIX timestamp in seconds for starting block, current block, and project timestamp of final block. It then queries the contract for the amount of cached ERC1155s. A simple slope formula is then applied to calculate the decay rate; which is then applied to determine the voting power per asset at current block. - -The final value is square rooted. - -Example of parameters: - -```json - "params": { - "symbol": "PK - PRIME", - "address": "0x3399eff96D4b6Bae8a56F4852EB55736c9C2b041", - "baseValue": 4000, - "startingBlock": 15166749, - "monthsToDecay": 12 - } -``` - diff --git a/src/strategies/echelon-cached-erc1155-decay/examples.json b/src/strategies/echelon-cached-erc1155-decay/examples.json deleted file mode 100644 index fb289d27d..000000000 --- a/src/strategies/echelon-cached-erc1155-decay/examples.json +++ /dev/null @@ -1,28 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "echelon-cached-erc1155-decay", - "params": { - "symbol": "PK - PRIME", - "address": "0x3399eff96D4b6Bae8a56F4852EB55736c9C2b041", - "baseValue": 4000, - "startingBlock": 15166749, - "monthsToDecay": 12 - } - }, - "network": "1", - "addresses": [ - "0xE6be99cbC7796F90baff870a2ffE838a540E27C9", - "0xf98A4A42853cC611eED664627087d4ae19740ED8", - "0xbdc3C931387e2c6647b0D7237Ed30c702260fa80", - "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", - "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", - "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e", - "0x1d5E65a087eBc3d03a294412E46CE5D6882969f4", - "0x1f254336E5c46639A851b9CfC165697150a6c327", - "0x2ec3F80BeDA63Ede96BA20375032CDD3aAfb3030" - ], - "snapshot": 15169750 - } -] diff --git a/src/strategies/echelon-cached-erc1155-decay/index.ts b/src/strategies/echelon-cached-erc1155-decay/index.ts deleted file mode 100644 index 1f932adca..000000000 --- a/src/strategies/echelon-cached-erc1155-decay/index.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Multicaller } from '../../utils'; - -export const author = 'brandonleung'; -export const version = '1.0.0'; - -const cachingAbi = [ - 'function cacheInfo(uint256, address) view returns (uint256 amount, int256 rewardDebt)' -]; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - const stakingPool = new Multicaller(network, provider, cachingAbi, { - blockTag - }); - - const startingBlockTimestamp = ( - await provider.getBlock(options.startingBlock) - ).timestamp; - const endingBlockTimestamp = - startingBlockTimestamp + 2628288 * options.monthsToDecay; - const currentBlockTimestamp = (await provider.getBlock(snapshot)).timestamp; - - const decayRate = - (0 - options.baseValue) / (endingBlockTimestamp - startingBlockTimestamp); - - const votingPowerPerKey = - options.baseValue + - decayRate * (currentBlockTimestamp - startingBlockTimestamp); - - addresses.forEach((address) => { - stakingPool.call(address, options.address, 'cacheInfo', [0, address]); - }); - const response = await stakingPool.execute(); - - return Object.fromEntries( - addresses.map((address) => { - return [ - address, - Math.sqrt(response[address][0].toNumber() * votingPowerPerKey) - ]; - }) - ); -} diff --git a/src/strategies/echelon-wallet-prime-and-cached-key-gated/README.md b/src/strategies/echelon-wallet-prime-and-cached-key-gated/README.md deleted file mode 100644 index 6824fa491..000000000 --- a/src/strategies/echelon-wallet-prime-and-cached-key-gated/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# echelon-wallet-prime-cached-key-gated - -This strategy looks at an ERC1155 caching (staking) contract and assigns a linearly decaying amount of voting power. The business context behind this is that each cached asset is eligible to claim a set amount of ERC20s over the same period; and thus can use those tokens to vote as well. - -For example, at block 0, the voting should have equivalent to 4000 units of voting power. A year later, they should have 0 units. - -As parameters, we pass in the base amount of voting power (e.g. 4000), starting block where there's no decay, and number of months until complete decay (e.g. 12). - -At a high level, the strategy grabs the UNIX timestamp in seconds for starting block, current block, and project timestamp of final block. It then queries the contract for the amount of cached ERC1155s. A simple slope formula is then applied to calculate the decay rate; which is then applied to determine the voting power per asset at current block. - -This strategy also makes use of the `erc20-balance-of` strategy. The erc20 balance is added to the equivalent value of the cached NFT. - -The weighted voting power is square rooted. - -In order to be eligible to vote, the address has to have a non-zero wallet erc1155 balance (using the `erc1155-all-balances-of` strategy) or be whitelisted. Additionally, the address cannot be blacklisted. - -Example of parameters: - -```json - "params": { - "symbol": "PRIME VOTE", - "address": "0xb23d80f5FefcDDaa212212F028021B41DEd428CF", - "decimals": 18, - "stakingAddress": "0x3399eff96D4b6Bae8a56F4852EB55736c9C2b041", - "baseValue": 4000, - "startingBlock": 15166749, - "monthsToDecay": 12, - "erc1155Address": "0x76BE3b62873462d2142405439777e971754E8E77", - "whitelist": [ - "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", - "0xFCfcC87E312f323768f9553255250A9357a04109" - ], - "blacklist": ["0xE6be99cbC7796F90baff870a2ffE838a540E27C9"] - } -``` - diff --git a/src/strategies/echelon-wallet-prime-and-cached-key-gated/examples.json b/src/strategies/echelon-wallet-prime-and-cached-key-gated/examples.json deleted file mode 100644 index 387c32c66..000000000 --- a/src/strategies/echelon-wallet-prime-and-cached-key-gated/examples.json +++ /dev/null @@ -1,37 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "echelon-wallet-prime-and-cached-key-gated", - "params": { - "symbol": "PRIME VOTE", - "address": "0xb23d80f5FefcDDaa212212F028021B41DEd428CF", - "decimals": 18, - "stakingAddress": "0x3399eff96D4b6Bae8a56F4852EB55736c9C2b041", - "baseValue": 4000, - "startingBlock": 15166749, - "monthsToDecay": 12, - "erc1155Address": "0x76BE3b62873462d2142405439777e971754E8E77", - "whitelist": [ - "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", - "0xFCfcC87E312f323768f9553255250A9357a04109" - ], - "blacklist": ["0xE6be99cbC7796F90baff870a2ffE838a540E27C9"] - } - }, - "network": "1", - "addresses": [ - "0xE6be99cbC7796F90baff870a2ffE838a540E27C9", - "0xf98A4A42853cC611eED664627087d4ae19740ED8", - "0xbdc3C931387e2c6647b0D7237Ed30c702260fa80", - "0x5566eec3684F3ED896740590cc372758f25f056f", - "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", - "0xFCfcC87E312f323768f9553255250A9357a04109", - "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e", - "0x1d5E65a087eBc3d03a294412E46CE5D6882969f4", - "0x1f254336E5c46639A851b9CfC165697150a6c327", - "0x2ec3F80BeDA63Ede96BA20375032CDD3aAfb3030" - ], - "snapshot": 15540462 - } -] diff --git a/src/strategies/echelon-wallet-prime-and-cached-key-gated/index.ts b/src/strategies/echelon-wallet-prime-and-cached-key-gated/index.ts deleted file mode 100644 index 79c7068a7..000000000 --- a/src/strategies/echelon-wallet-prime-and-cached-key-gated/index.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { Multicaller } from '../../utils'; -import { strategy as erc20BalanceOfStrategy } from '../erc20-balance-of'; -import { strategy as erc1155AllBalancesOf } from '../erc1155-all-balances-of'; - -export const author = 'brandonleung'; -export const version = '1.0.0'; - -const cachingAbi = [ - 'function cacheInfo(uint256, address) view returns (uint256 amount, int256 rewardDebt)' -]; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - const stakingPool = new Multicaller(network, provider, cachingAbi, { - blockTag - }); - - const startingBlockTimestamp = ( - await provider.getBlock(options.startingBlock) - ).timestamp; - const endingBlockTimestamp = - startingBlockTimestamp + 2628288 * options.monthsToDecay; - const currentBlockTimestamp = (await provider.getBlock(snapshot)).timestamp; - - const decayRate = - (0 - options.baseValue) / (endingBlockTimestamp - startingBlockTimestamp); - - const votingPowerPerKey = - options.baseValue + - decayRate * (currentBlockTimestamp - startingBlockTimestamp); - - addresses.forEach((address) => { - stakingPool.call(address, options.stakingAddress, 'cacheInfo', [ - 0, - address - ]); - }); - const contractResponse = await stakingPool.execute(); - - const cachedKeyScore = Object.fromEntries( - addresses.map((address) => { - return [ - address, - contractResponse[address][0].toNumber() * votingPowerPerKey - ]; - }) - ); - - const walletScore = await erc20BalanceOfStrategy( - space, - network, - provider, - addresses, - options, - snapshot - ); - - const erc1155Options = { - address: options.erc1155Address - }; - const erc1155Balances = await erc1155AllBalancesOf( - space, - network, - provider, - addresses, - erc1155Options, - snapshot - ); - - const votingPower = Object.entries(walletScore).reduce( - (address, [key, value]) => ({ - ...address, - [key]: (address[key] || 0) + value - }), - { ...cachedKeyScore } - ); - - Object.keys(votingPower).forEach((key) => { - const whitelistedAddress = - options.whitelist.indexOf(key) !== -1 || - (key in erc1155Balances && erc1155Balances[key] > 0); - const blacklistedAddress = options.blacklist.indexOf(key) !== -1; - - votingPower[key] = - whitelistedAddress && !blacklistedAddress - ? Math.sqrt(votingPower[key]) - : 0; - }); - - return votingPower; -} diff --git a/src/strategies/erc20-rebase-wrapper/README.md b/src/strategies/erc20-rebase-wrapper/README.md deleted file mode 100644 index 72e244f15..000000000 --- a/src/strategies/erc20-rebase-wrapper/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# erc20-rebase-wrapper - -This returns the underlying token balance from an ERC20 rebasing wrapper that exposes `exchangeRate` and `exchangeRatePrecision` methods. - -Here is an example of parameters: - -```json -{ - "wrapperAddress": "0x93Dede06AE3B5590aF1d4c111BC54C3f717E4b35", - "symbol": "gALCX", - "decimals": 18 -} -``` diff --git a/src/strategies/erc20-rebase-wrapper/examples.json b/src/strategies/erc20-rebase-wrapper/examples.json deleted file mode 100644 index b9b291ea1..000000000 --- a/src/strategies/erc20-rebase-wrapper/examples.json +++ /dev/null @@ -1,16 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "erc20-rebase-wrapper", - "params": { - "wrapperAddress": "0x93Dede06AE3B5590aF1d4c111BC54C3f717E4b35", - "symbol": "gALCX", - "decimals": 18 - } - }, - "network": "1", - "addresses": ["0x628Ece38B0FF97e1e98F4F79aD5500596deF66F9"], - "snapshot": 14399823 - } -] diff --git a/src/strategies/erc20-rebase-wrapper/index.ts b/src/strategies/erc20-rebase-wrapper/index.ts deleted file mode 100644 index f1bc31b08..000000000 --- a/src/strategies/erc20-rebase-wrapper/index.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { BigNumberish } from '@ethersproject/bignumber'; -import { formatUnits } from '@ethersproject/units'; -import { Multicaller } from '../../utils'; - -export const author = '0xfoobar'; -export const version = '0.1.0'; - -const abi = [ - 'function balanceOf(address account) external view returns (uint256)', - 'function exchangeRate() external view returns (uint256)', - 'function exchangeRatePrecision() external view returns (uint256)' -]; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -): Promise> { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - const multi = new Multicaller(network, provider, abi, { blockTag }); - multi.call('exchangeRate', options.wrapperAddress, 'exchangeRate'); - multi.call( - 'exchangeRatePrecision', - options.wrapperAddress, - 'exchangeRatePrecision' - ); - const { exchangeRate, exchangeRatePrecision } = await multi.execute(); - const rate = parseFloat(exchangeRate) / parseFloat(exchangeRatePrecision); - - addresses.forEach((address) => - multi.call(address, options.wrapperAddress, 'balanceOf', [address]) - ); - const result: Record = await multi.execute(); - - return Object.fromEntries( - Object.entries(result).map(([address, balance]) => [ - address, - parseFloat(formatUnits(balance, options.decimals)) * rate - ]) - ); -} diff --git a/src/strategies/erc3525-vesting-voucher/examples.json b/src/strategies/erc3525-vesting-voucher/examples.json deleted file mode 100644 index 3e51d4982..000000000 --- a/src/strategies/erc3525-vesting-voucher/examples.json +++ /dev/null @@ -1,16 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "erc3525-vesting-voucher", - "params": { - "symbol": "fvSOLV", - "address": "0x4B0dd1aDEdA251ACec75140608bAd663fB0c4cAB", - "decimals": 18 - } - }, - "network": "4", - "addresses": ["0x1a71c8EF63aB6f578b1702a35367cA81c9281A8c"], - "snapshot": 11090903 - } -] diff --git a/src/strategies/erc3525-vesting-voucher/index.ts b/src/strategies/erc3525-vesting-voucher/index.ts deleted file mode 100644 index edf5d5ca0..000000000 --- a/src/strategies/erc3525-vesting-voucher/index.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { BigNumber } from '@ethersproject/bignumber'; -import { hexZeroPad } from '@ethersproject/bytes'; -import { formatUnits } from '@ethersproject/units'; -import { Multicaller } from '../../utils'; -import { claimCoefficient, maturitiesCoefficient } from './utils'; - -export const author = 'buchaoqun'; -export const version = '0.1.3'; - -const abi = [ - 'function getSnapshot(uint256 tokenId_) view returns (uint8 claimType_, uint64 term_, uint256 vestingAmount_, uint256 principal_, uint64[] maturities_, uint32[] percentages_, uint256 availableWithdrawAmount_, string originalInvestor_, bool isValid_)', - 'function balanceOf(address owner) view returns (uint256)', - 'function tokenOfOwnerByIndex(address owner,uint256 index) view returns (uint256)' -]; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - // vesting voucher banlanceOf - const callWalletToCrucibleCount = new Multicaller(network, provider, abi, { - blockTag - }); - for (const walletAddress of addresses) { - callWalletToCrucibleCount.call( - walletAddress, - options.address, - 'balanceOf', - [walletAddress] - ); - } - - // wallet Owner Index - const walletToCrucibleCount: Record = - await callWalletToCrucibleCount.execute(); - - const callWalletToCrucibleAddresses = new Multicaller( - network, - provider, - abi, - { - blockTag - } - ); - for (const [walletAddress, crucibleCount] of Object.entries( - walletToCrucibleCount - )) { - for (let index = 0; index < crucibleCount.toNumber(); index++) { - callWalletToCrucibleAddresses.call( - walletAddress.toString() + '-' + index.toString(), - options.address, - 'tokenOfOwnerByIndex', - [walletAddress, index] - ); - } - } - const walletIDToCrucibleAddresses: Record = - await callWalletToCrucibleAddresses.execute(); - - // voucher snapshot - const callCrucibleToSnapshot = new Multicaller(network, provider, abi, { - blockTag - }); - // walletID: walletAddress-index - for (const [walletID, crucibleAddress] of Object.entries( - walletIDToCrucibleAddresses - )) { - callCrucibleToSnapshot.call(walletID, options.address, 'getSnapshot', [ - hexZeroPad(crucibleAddress.toHexString(), 20) - ]); - } - const walletIDToSnapshot: Record< - string, - Array - > = await callCrucibleToSnapshot.execute(); - - const walletToWeights = {} as Record; - for (const [walletID, snapshot] of Object.entries(walletIDToSnapshot)) { - const address = walletID.split('-')[0]; - - const value = - parseFloat(formatUnits(snapshot[3].toString(), options.decimals)) * - claimCoefficient(snapshot[0]) * - maturitiesCoefficient(snapshot[4]); - walletToWeights[address] = walletToWeights[address] - ? walletToWeights[address] + value - : value; - } - - return Object.fromEntries( - Object.entries(walletToWeights).map(([address, balance]) => [ - address, - balance - ]) - ); -} diff --git a/src/strategies/erc3525-vesting-voucher/utils.ts b/src/strategies/erc3525-vesting-voucher/utils.ts deleted file mode 100644 index 417785e1c..000000000 --- a/src/strategies/erc3525-vesting-voucher/utils.ts +++ /dev/null @@ -1,36 +0,0 @@ -const oneDaySeconds = 86400; - -export const maturitiesCoefficient = (maturities: Array) => { - const nowData = Date.parse(new Date().toString()) / 1000; - const difference = maturities[maturities.length - 1].toNumber() - nowData; - - if (difference <= 0) { - return 1; - } else if (difference > 0 && difference <= 90 * oneDaySeconds) { - return 1.1; - } else if ( - difference > 90 * oneDaySeconds && - difference <= 183 * oneDaySeconds - ) { - return 1.2; - } else if ( - difference > 183 * oneDaySeconds && - difference <= 365 * oneDaySeconds - ) { - return 1.5; - } else { - return 2; - } -}; - -export const claimCoefficient = (claimType: number) => { - if (claimType == 0) { - return 1.2; - } else if (claimType == 1) { - return 2; - } else if (claimType == 2) { - return 1.5; - } else { - return 1; - } -}; diff --git a/src/strategies/esd-delegation/examples.json b/src/strategies/esd-delegation/examples.json deleted file mode 100644 index f45e63fb7..000000000 --- a/src/strategies/esd-delegation/examples.json +++ /dev/null @@ -1,22 +0,0 @@ -[ - { - "name": "Empty Set Dollar", - "strategy": { - "name": "esd-delegation", - "params": { - "uniswap": "0x88ff79eB2Bc5850F27315415da8685282C7610F9", - "rewards": "0x4082D11E506e3250009A991061ACd2176077C88f", - "dao": "0x443d2f2755db5942601fa062cc248aaa153313d3", - "token": "0x36F3FD68E7325a35EB768F1AedaAe9EA0689d723", - "symbol": "ESD", - "decimals": 18 - } - }, - "network": "1", - "addresses": [ - "0x37Ed74A0dA66c0392C4c5901c3b3B97675871FE1", - "0x07C867770C43B1c6b715Aa8AC3A55DfD7f835a82" - ], - "snapshot": "latest" - } -] diff --git a/src/strategies/esd-delegation/index.ts b/src/strategies/esd-delegation/index.ts deleted file mode 100644 index d1837c45a..000000000 --- a/src/strategies/esd-delegation/index.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { strategy as esd } from '../esd'; -import { getDelegations } from '../../utils/delegation'; - -export const author = 'l3wi'; -export const version = '0.1.0'; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const delegations = await getDelegations(space, network, addresses, snapshot); - if (Object.keys(delegations).length === 0) return {}; - - const score = await esd( - space, - network, - provider, - Object.values(delegations).reduce((a: string[], b: string[]) => - a.concat(b) - ), - options, - snapshot - ); - - return Object.fromEntries( - addresses.map((address) => { - const addressScore = delegations[address] - ? delegations[address].reduce((a, b) => a + score[b], 0) - : 0; - return [address, addressScore]; - }) - ); -} diff --git a/src/strategies/esd/README.md b/src/strategies/esd/README.md deleted file mode 100644 index 2bc565197..000000000 --- a/src/strategies/esd/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# ESD Call Strategy - -Allows bonded ESD to be counted towards a valid score. - -## Params - -- `dao` - Address of the DAO proxy address -- `token` - Address of the ESD token -- `Rewards` - Address of the current LP rewards contract -- `uniswap` - Address of the Uniswap pool -- `decimals` - Decimals used by the ESD token - -### Examples - -Can be used instead of the erc20-balance-of strategy, the space config will look like this: - -```JSON -"strategies": [ - { - "name": "esd", - "params": { - "uniswap": "0x88ff79eB2Bc5850F27315415da8685282C7610F9", - "rewards": "0x4082D11E506e3250009A991061ACd2176077C88f", - "dao": "0x443d2f2755db5942601fa062cc248aaa153313d3", - "token": "0x36F3FD68E7325a35EB768F1AedaAe9EA0689d723", - "decimals": 18 - } - } -] \ No newline at end of file diff --git a/src/strategies/esd/examples.json b/src/strategies/esd/examples.json deleted file mode 100644 index be6e0aa9a..000000000 --- a/src/strategies/esd/examples.json +++ /dev/null @@ -1,27 +0,0 @@ -[ - { - "name": "Empty Set Dollar", - "strategy": { - "name": "esd", - "params": { - "uniswap": "0x88ff79eB2Bc5850F27315415da8685282C7610F9", - "rewards": "0x4082D11E506e3250009A991061ACd2176077C88f", - "dao": "0x443d2f2755db5942601fa062cc248aaa153313d3", - "token": "0x36F3FD68E7325a35EB768F1AedaAe9EA0689d723", - "symbol": "ESD", - "decimals": 18 - } - }, - "network": "1", - "addresses": [ - "0x0b7376f2a063c771d460210a4fa8787c9a7379f9", - "0x635b230c3fdf6a466bb6dc3b9b51a8ceb0659b67", - "0x22fa8cc33a42320385cbd3690ed60a021891cb32", - "0xcF63E1C31805254b6fB3Ed7829206c2b2505e3a7", - "0xd5d5a7cb1807364cde0bad51d0a7d758943ab114", - "0x7055ef0557dc6ff56cdf0c36d28b346d40a1b8ed", - "0xd1991b6fd521a3f357d96a15956702ce33342fec" - ], - "snapshot": 11350000 - } -] diff --git a/src/strategies/esd/index.ts b/src/strategies/esd/index.ts deleted file mode 100644 index 6ae697571..000000000 --- a/src/strategies/esd/index.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { formatUnits } from '@ethersproject/units'; -import { multicall } from '../../utils'; - -export const author = 'l3wi'; -export const version = '0.1.0'; - -const abi = [ - { - constant: true, - inputs: [{ internalType: 'address', name: 'account', type: 'address' }], - name: 'balanceOfBonded', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - payable: false, - stateMutability: 'view', - type: 'function' - }, - { - constant: true, - inputs: [{ internalType: 'address', name: '', type: 'address' }], - name: 'balanceOf', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - payable: false, - stateMutability: 'view', - type: 'function' - }, - { - constant: true, - inputs: [], - name: 'totalSupply', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - payable: false, - stateMutability: 'view', - type: 'function' - } -]; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - const daoQuery = addresses.map((address: any) => [ - options.dao, - 'balanceOfBonded', - [address] - ]); - - const lpQuery = addresses.map((address: any) => [ - options.rewards, - 'balanceOfBonded', - [address] - ]); - - const response = await multicall( - network, - provider, - abi, - [ - [options.token, 'balanceOf', [options.uniswap]], - [options.uniswap, 'totalSupply'], - ...daoQuery, - ...lpQuery - ], - { blockTag } - ); - - const uniswapESD = response[0]; - const uniswapTotalSupply = response[1]; - const daoBalances = response.slice(2, addresses.length + 2); - const lpBalances = response.slice( - addresses.length + 2, - addresses.length * 2 + 2 - ); - - return Object.fromEntries( - Array(addresses.length) - .fill('x') - .map((_, i) => [ - addresses[i], - parseFloat( - formatUnits( - uniswapESD[0] - .div(uniswapTotalSupply[0]) - .mul(lpBalances[i][0]) - .add(daoBalances[i][0]) - .toString(), - options.decimals - ) - ) - ]) - ); -} diff --git a/src/strategies/eth-philanthropy/README.md b/src/strategies/eth-philanthropy/README.md deleted file mode 100644 index f0be0baaa..000000000 --- a/src/strategies/eth-philanthropy/README.md +++ /dev/null @@ -1,105 +0,0 @@ -# Contract call strategy - -Enables addresses to increase their score by donating to charity, adding `params.coeff` ETH to their score for every 1 ETH donated. This helps to level the playing field for less wealthy participants and incentivizes altruistic behavior from all participants. - -Implementation of [eth-received](./../eth-received) - -### Currently Included Charities: -- [GiveDirectly](https://www.givedirectly.org/): 0xc7464dbcA260A8faF033460622B23467Df5AEA42 -- [Unsung.org](http://Unsung.org): 0x02a13ED1805624738Cc129370Fee358ea487B0C6 -- [Heifer.org](http://Heifer.org): 0xD3F81260a44A1df7A7269CF66Abd9c7e4f8CdcD1 -- [GraceAid.org.uk](http://GraceAid.org.uk): 0x236dAA98f115caa9991A3894ae387CDc13eaaD1B -- [SENS.org](http://SENS.org): 0x542EFf118023cfF2821b24156a507a513Fe93539 -- [350.org](http://350.org): 0x50990F09d4f0cb864b8e046e7edC749dE410916b -- [EFF.org](http://EFF.org): 0xb189f76323678E094D4996d182A792E52369c005 -- [WikiLeaks](http://WikiLeaks.org): 0xE96E2181F6166A37EA4C04F6E6E2bD672D72Acc1 -- [GiveWell.org](http://GiveWell.org): 0x7cF2eBb5Ca55A8bd671A020F8BDbAF07f60F26C1 -- [CoolEarth.org](http://CoolEarth.org): 0x3c8cB169281196737c493AfFA8F49a9d823bB9c5 -- [Run2Rescue.org](http://Run2Rescue.org): 0xd17bcbFa6De9E3741aa43Ed32e64696F6a9FA996 -- [Archive.org](http://Archive.org): 0xFA8E3920daF271daB92Be9B87d9998DDd94FEF08 -- [Alt.eco](http://alt.eco): 0x5E7ecc1fC819f937fbEe043b40388C0809361ae9 - -## Params - -- `coeff` - (**Optional**, `number`, Default: `100`) Amount to multiply the sum of a voter's ether sent to charity. When used in conjunction with other strategies, this enables the increase or decrease of leverage given to voters who donate. - - -## Examples - -Can be used instead of, or in conjunction with eth-balance strategy. -In this example, the `params.coeff` of `1000` makes a 1 ETH donation equivalent to a 1000 ETH address balance. Thus, giving voters a massive incentive to donate. - -The space config will look like this: - -```JSON -"strategies": [ - { - "name": "Example ETH-Philanthropy Strategy", - "strategy": { - "name": "eth-philanthropy", - "params": { - "coeff": 1000, - "receivingAddresses": [ - "0xc7464dbcA260A8faF033460622B23467Df5AEA42", - "0x02a13ED1805624738Cc129370Fee358ea487B0C6", - "0xD3F81260a44A1df7A7269CF66Abd9c7e4f8CdcD1", - "0x236dAA98f115caa9991A3894ae387CDc13eaaD1B", - "0x542EFf118023cfF2821b24156a507a513Fe93539", - "0x50990F09d4f0cb864b8e046e7edC749dE410916b", - "0xb189f76323678E094D4996d182A792E52369c005", - "0xE96E2181F6166A37EA4C04F6E6E2bD672D72Acc1", - "0x7cF2eBb5Ca55A8bd671A020F8BDbAF07f60F26C1", - "0x3c8cB169281196737c493AfFA8F49a9d823bB9c5", - "0xd17bcbFa6De9E3741aa43Ed32e64696F6a9FA996", - "0xFA8E3920daF271daB92Be9B87d9998DDd94FEF08", - "0x5E7ecc1fC819f937fbEe043b40388C0809361ae9" - ] - } - }, - "network": "1", - "addresses": [ - "0x100fb703c8b84466f79e838835df6fc180aef740", - "0xbcB5f94590904A64e16Acb08D4Fa4b7baFdC8c3A", - "0x0a0249179f559f60496e23e3907e9a3a54aa6537", - "0x6c65fb326e7734ba5508b5d043718288b43b9ed9", - "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", - "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", - "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e" - ], - "snapshot": 11414195 - }, - { - "name": "Example ETH-Balance Strategy", - "strategy": { - "name": "eth-balance", - "params": {} - }, - "network": "1", - "addresses": [ - "0x100fb703c8b84466f79e838835df6fc180aef740", - "0xbcB5f94590904A64e16Acb08D4Fa4b7baFdC8c3A", - "0x0a0249179f559f60496e23e3907e9a3a54aa6537", - "0x6c65fb326e7734ba5508b5d043718288b43b9ed9", - "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", - "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", - "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e" - ], - "snapshot": 11414195 - } -] -``` - -Valid test addresses and snapshot block number: -```typescript -const addresses = [ - "0x100fb703c8b84466f79e838835df6fc180aef740", - "0xbcB5f94590904A64e16Acb08D4Fa4b7baFdC8c3A", - "0x0a0249179f559f60496e23e3907e9a3a54aa6537", - "0x6c65fb326e7734ba5508b5d043718288b43b9ed9", - "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", - "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", - "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e" -]; - -const snapshot = 11414195; -``` diff --git a/src/strategies/eth-philanthropy/examples.json b/src/strategies/eth-philanthropy/examples.json deleted file mode 100644 index 1a2e01d0a..000000000 --- a/src/strategies/eth-philanthropy/examples.json +++ /dev/null @@ -1,24 +0,0 @@ -[ - { - "name": "Example ETH Philanthropy Query", - "strategy": { - "name": "eth-philanthropy", - "params": { - "symbol": "ETH", - "coeff": 50 - } - }, - "network": "1", - "addresses": [ - "0x100fb703c8b84466f79e838835df6fc180aef740", - "0xbcB5f94590904A64e16Acb08D4Fa4b7baFdC8c3A", - "0x0a0249179f559f60496e23e3907e9a3a54aa6537", - "0x6c65fb326e7734ba5508b5d043718288b43b9ed9", - "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", - "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", - "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e", - "0x5E7ecc1fC819f937fbEe043b40388C0809361ae9" - ], - "snapshot": 11486650 - } -] diff --git a/src/strategies/eth-philanthropy/index.ts b/src/strategies/eth-philanthropy/index.ts deleted file mode 100644 index 920f56a71..000000000 --- a/src/strategies/eth-philanthropy/index.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Web3Provider } from '@ethersproject/providers'; -import { strategy as ethReceivedStrategy } from '../eth-received'; - -export const author = 'mccallofthewild'; -export const version = '0.1.0'; - -const ethCharities = [ - ['GiveDirectly', '0xc7464dbcA260A8faF033460622B23467Df5AEA42'], - ['Unsung.org', '0x02a13ED1805624738Cc129370Fee358ea487B0C6'], - ['Heifer.org', '0xD3F81260a44A1df7A7269CF66Abd9c7e4f8CdcD1'], - ['GraceAid.org.uk', '0x236dAA98f115caa9991A3894ae387CDc13eaaD1B'], - ['SENS.org', '0x542EFf118023cfF2821b24156a507a513Fe93539'], - ['350.org', '0x50990F09d4f0cb864b8e046e7edC749dE410916b'], - ['EFF.org', '0xb189f76323678E094D4996d182A792E52369c005'], - ['WikiLeaks', '0xE96E2181F6166A37EA4C04F6E6E2bD672D72Acc1'], - ['GiveWell.org', '0x7cF2eBb5Ca55A8bd671A020F8BDbAF07f60F26C1'], - ['CoolEarth.org', '0x3c8cB169281196737c493AfFA8F49a9d823bB9c5'], - ['Run2Rescue.org', '0xd17bcbFa6De9E3741aa43Ed32e64696F6a9FA996'], - ['Archive.org', '0xFA8E3920daF271daB92Be9B87d9998DDd94FEF08'] -]; - -export async function strategy( - ...args: [string, string, Web3Provider, string[], { coeff?: number }, number] -) { - const [space, network, provider, addresses, options, snapshot] = args; - const { coeff = 100 } = options; - return ethReceivedStrategy( - space, - network, - provider, - addresses, - { - receivingAddresses: ethCharities.map(([, address]) => address), - coeff - }, - snapshot - ); -} diff --git a/src/strategies/eth-received/ElasticSearchTxResult.ts b/src/strategies/eth-received/ElasticSearchTxResult.ts deleted file mode 100644 index 07f0e116a..000000000 --- a/src/strategies/eth-received/ElasticSearchTxResult.ts +++ /dev/null @@ -1,81 +0,0 @@ -export interface ElasticSearchTxResult { - took: number; - timed_out: boolean; - _shards: Shards; - hits: Hits; -} - -export interface Shards { - total: number; - successful: number; - skipped: number; - failed: number; -} - -export interface Hits { - total: Total; - max_score: number; - hits: Hit[]; -} - -export interface Hit { - _index: Index; - _type: Type; - _id: string; - _score: number; - _source: Source; -} - -export enum Index { - The0011EthereumEthereumMainnetTx = '0011-ethereum-ethereum-mainnet-tx' -} - -export interface Source { - blockHash: string; - blockNumber: BlockNumber; - cumulativeGasUsed: BlockNumber; - from: string; - gas: BlockNumber; - gasPrice: BlockNumber; - gasUsed: BlockNumber; - hash: string; - input: string; - logsBloom: string; - nonce: BlockNumber; - r: string; - s: string; - status: boolean; - timestamp: number; - to: string; - publicKey?: string; - transactionIndex: BlockNumber; - standardV?: string; - v: V; - value: Value; -} - -export interface BlockNumber { - raw: string; - num: number; -} - -export enum V { - The0X25 = '0x25', - The0X26 = '0x26' -} - -export interface Value { - raw: string; - padded: string; - eth: number; - num: number; -} - -export enum Type { - Doc = '_doc' -} - -export interface Total { - value: number; - relation: string; -} diff --git a/src/strategies/eth-received/README.md b/src/strategies/eth-received/README.md deleted file mode 100644 index 36e2c5210..000000000 --- a/src/strategies/eth-received/README.md +++ /dev/null @@ -1,90 +0,0 @@ -# Contract call strategy - -Scores addresses by how much ETH they have sent to `params.receivingAddresses`, adding `params.coeff` ETH to their score for every 1 ETH sent. - -This creates a new fundraising opportunity for projects & organizations, levels the playing field for less wealthy participants, and encourages voters to "put their money where their mouth is". - -## Params - -- `receivingAddresses` - (**Required**, `string[]`) Array of addresses to check for ether transactions from voters -- `coeff` - (**Optional**, `number`, Default: `1`) Amount to multiply the sum of a voter's ether sent to `receivingAddresses`. When used in conjunction with other strategies, this enables the increase or decrease of leverage given to voter who send ETH. - - -## Examples - -Can be used instead of, or in conjunction with eth-balance strategy. -In this example, the `params.coeff` of `100` makes a 1 ETH donation equivalent to a 100 ETH address balance. Thus, giving voters a massive incentive to donate. - -The space config will look like this: - -```JSON -"strategies": [ - { - "name": "Example ETH-Received Strategy", - "strategy": { - "name": "eth-received", - "params": { - "coeff": 100, - "receivingAddresses": [ - "0xc7464dbcA260A8faF033460622B23467Df5AEA42", - "0x02a13ED1805624738Cc129370Fee358ea487B0C6", - "0xD3F81260a44A1df7A7269CF66Abd9c7e4f8CdcD1", - "0x236dAA98f115caa9991A3894ae387CDc13eaaD1B", - "0x542EFf118023cfF2821b24156a507a513Fe93539", - "0x50990F09d4f0cb864b8e046e7edC749dE410916b", - "0xb189f76323678E094D4996d182A792E52369c005", - "0xE96E2181F6166A37EA4C04F6E6E2bD672D72Acc1", - "0x7cF2eBb5Ca55A8bd671A020F8BDbAF07f60F26C1", - "0x3c8cB169281196737c493AfFA8F49a9d823bB9c5", - "0xd17bcbFa6De9E3741aa43Ed32e64696F6a9FA996", - "0xFA8E3920daF271daB92Be9B87d9998DDd94FEF08" - ] - } - }, - "network": "1", - "addresses": [ - "0x100fb703c8b84466f79e838835df6fc180aef740", - "0xbcB5f94590904A64e16Acb08D4Fa4b7baFdC8c3A", - "0x0a0249179f559f60496e23e3907e9a3a54aa6537", - "0x6c65fb326e7734ba5508b5d043718288b43b9ed9", - "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", - "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", - "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e" - ], - "snapshot": 11414195 - }, - { - "name": "Example ETH-Balance Strategy", - "strategy": { - "name": "eth-balance", - "params": {} - }, - "network": "1", - "addresses": [ - "0x100fb703c8b84466f79e838835df6fc180aef740", - "0xbcB5f94590904A64e16Acb08D4Fa4b7baFdC8c3A", - "0x0a0249179f559f60496e23e3907e9a3a54aa6537", - "0x6c65fb326e7734ba5508b5d043718288b43b9ed9", - "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", - "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", - "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e" - ], - "snapshot": 11414195 - } -] -``` - -Valid test addresses and snapshot block number: -```typescript -const addresses = [ - "0x100fb703c8b84466f79e838835df6fc180aef740", - "0xbcB5f94590904A64e16Acb08D4Fa4b7baFdC8c3A", - "0x0a0249179f559f60496e23e3907e9a3a54aa6537", - "0x6c65fb326e7734ba5508b5d043718288b43b9ed9", - "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", - "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", - "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e" -]; - -const snapshot = 11414195; -``` diff --git a/src/strategies/eth-received/examples.json b/src/strategies/eth-received/examples.json deleted file mode 100644 index e78a1eb45..000000000 --- a/src/strategies/eth-received/examples.json +++ /dev/null @@ -1,70 +0,0 @@ -[ - { - "name": "Example ETH Received Strategy", - "strategy": { - "name": "eth-received", - "params": { - "symbol": "ETH", - "receivingAddresses": [ - "0xc7464dbcA260A8faF033460622B23467Df5AEA42", - "0x02a13ED1805624738Cc129370Fee358ea487B0C6", - "0xD3F81260a44A1df7A7269CF66Abd9c7e4f8CdcD1", - "0x236dAA98f115caa9991A3894ae387CDc13eaaD1B", - "0x542EFf118023cfF2821b24156a507a513Fe93539", - "0x50990F09d4f0cb864b8e046e7edC749dE410916b", - "0xb189f76323678E094D4996d182A792E52369c005", - "0xE96E2181F6166A37EA4C04F6E6E2bD672D72Acc1", - "0x7cF2eBb5Ca55A8bd671A020F8BDbAF07f60F26C1", - "0x3c8cB169281196737c493AfFA8F49a9d823bB9c5", - "0xd17bcbFa6De9E3741aa43Ed32e64696F6a9FA996", - "0xFA8E3920daF271daB92Be9B87d9998DDd94FEF08" - ] - } - }, - "network": "1", - "addresses": [ - "0x100fb703c8b84466f79e838835df6fc180aef740", - "0xbcB5f94590904A64e16Acb08D4Fa4b7baFdC8c3A", - "0x0a0249179f559f60496e23e3907e9a3a54aa6537", - "0x6c65fb326e7734ba5508b5d043718288b43b9ed9", - "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", - "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", - "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e" - ], - "snapshot": 11486650 - }, - { - "name": "Example ETH Received Query", - "strategy": { - "name": "eth-received", - "params": { - "coeff": 100, - "receivingAddresses": [ - "0xc7464dbcA260A8faF033460622B23467Df5AEA42", - "0x02a13ED1805624738Cc129370Fee358ea487B0C6", - "0xD3F81260a44A1df7A7269CF66Abd9c7e4f8CdcD1", - "0x236dAA98f115caa9991A3894ae387CDc13eaaD1B", - "0x542EFf118023cfF2821b24156a507a513Fe93539", - "0x50990F09d4f0cb864b8e046e7edC749dE410916b", - "0xb189f76323678E094D4996d182A792E52369c005", - "0xE96E2181F6166A37EA4C04F6E6E2bD672D72Acc1", - "0x7cF2eBb5Ca55A8bd671A020F8BDbAF07f60F26C1", - "0x3c8cB169281196737c493AfFA8F49a9d823bB9c5", - "0xd17bcbFa6De9E3741aa43Ed32e64696F6a9FA996", - "0xFA8E3920daF271daB92Be9B87d9998DDd94FEF08" - ] - } - }, - "network": "1", - "addresses": [ - "0x100fb703c8b84466f79e838835df6fc180aef740", - "0xbcB5f94590904A64e16Acb08D4Fa4b7baFdC8c3A", - "0x0a0249179f559f60496e23e3907e9a3a54aa6537", - "0x6c65fb326e7734ba5508b5d043718288b43b9ed9", - "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", - "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", - "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e" - ], - "snapshot": 11486650 - } -] diff --git a/src/strategies/eth-received/index.ts b/src/strategies/eth-received/index.ts deleted file mode 100644 index 76616bc59..000000000 --- a/src/strategies/eth-received/index.ts +++ /dev/null @@ -1,83 +0,0 @@ -import fetch from 'cross-fetch'; -import { Web3Provider } from '@ethersproject/providers'; -import { ElasticSearchTxResult } from './ElasticSearchTxResult'; - -export const author = 'mccallofthewild'; -export const version = '0.1.0'; - -export async function strategy( - ...args: [ - string, - string, - Web3Provider, - string[], - { coeff?: number; receivingAddresses: string[] }, - number - ] -) { - const [, , , addresses, options] = args; - const { coeff = 1, receivingAddresses } = options; - // queries AnyBlock ElasticSearch https://www.anyblockanalytics.com/ - // Account: yidirel126@95ta.com Pass: xU5KKfys76wb633FvGS6 - const charitableTransactions: ElasticSearchTxResult = await fetch( - 'https://api.anyblock.tools/ethereum/ethereum/mainnet/es/tx/search/', - { - method: 'POST', - body: JSON.stringify({ - from: 0, - size: 10000, - query: { - bool: { - must: [ - { - bool: { - should: [ - ...addresses.map((a) => ({ - match: { - from: a - } - })) - ] - } - }, - { - bool: { - should: [ - ...receivingAddresses.map((a) => ({ - match: { - to: a - } - })) - ] - } - } - ] - } - } - }), - headers: { - Authorization: 'Bearer 8c8b3826-afd5-4535-a8be-540562624fbe', - 'Content-Type': 'application/json' - } - } - ) - .then((r) => r.json()) - .catch((e) => { - console.error('Eth-Received AnyBlock ElasticSearch Query Failed:'); - throw e; - }); - - const scores = {}; - for (const address of addresses) { - scores[address] = charitableTransactions.hits.hits - .filter((tx) => { - const validAddress = - tx._source.from.toLowerCase() == address.toLowerCase(); - return validAddress; - }) - .reduce((prev, curr) => { - return prev + curr._source.value.eth * coeff; - }, 0); - } - return scores; -} diff --git a/src/strategies/ethercats-founder-series/examples.json b/src/strategies/ethercats-founder-series/examples.json deleted file mode 100644 index 9efec74a2..000000000 --- a/src/strategies/ethercats-founder-series/examples.json +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "ethercats-founder-series", - "params": { - "symbol": "EtherCat" - } - }, - "network": "1", - "addresses": ["0x0e917dcffb792dbfb36b75afcc1a5d6174ec94e2"], - "snapshot": 14121348 - } -] diff --git a/src/strategies/ethercats-founder-series/index.ts b/src/strategies/ethercats-founder-series/index.ts deleted file mode 100644 index 2a4736594..000000000 --- a/src/strategies/ethercats-founder-series/index.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { subgraphRequest } from '../../utils'; - -export const author = 'woodydeck'; -export const version = '1.0.0'; - -// Constants -const url = { - '1': 'https://gateway.thegraph.com/api/656e05ff867c74eeb11bf0199ff5de86/subgraphs/id/0x7859821024e633c5dc8a4fcf86fc52e7720ce525-1' -}; - -const getPower = (id, value) => { - if (value == 0) return 0; - return value * (parseInt(id.slice(2, 4)) * parseInt(id[4])); -}; - -// Strategy -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const requests = addresses.map((a) => ({ - erc1155Balances: { - __args: { - block: { number: snapshot !== 'latest' ? snapshot : undefined }, - where: { - contract: '0xff3559412c4618af7c6e6f166c74252ff6364456', - account: a.toLowerCase() - } - }, - valueExact: true, - token: { - identifier: true - } - } - })); - - const responses = await Promise.all( - requests.map((request) => subgraphRequest(url[network], request)) - ); - - return Object.fromEntries( - responses.map((response, i) => [ - addresses[i], - response.erc1155Balances?.length > 0 - ? response.erc1155Balances - .map((balance) => { - return getPower( - balance?.token?.identifier || '0', - balance?.valueExact || '0' - ); - }) - .reduce((prev, curr) => prev + curr, 0) - : 0 - ]) - ); -} diff --git a/src/strategies/gin-finance/examples.json b/src/strategies/gin-finance/examples.json deleted file mode 100644 index ff70d8925..000000000 --- a/src/strategies/gin-finance/examples.json +++ /dev/null @@ -1,15 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "gin-finance", - "params": { - "address": "0x66a2a913e447d6b4bf33efbec43aaef87890fbbc", - "symbol": "USDC" - } - }, - "network": "288", - "addresses": ["0xb50edc1F33b0905A9D70A8733712244E8C6E035b"], - "snapshot": 649260 - } -] diff --git a/src/strategies/gin-finance/index.ts b/src/strategies/gin-finance/index.ts deleted file mode 100644 index 168cb3501..000000000 --- a/src/strategies/gin-finance/index.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { getAddress } from '@ethersproject/address'; -import { subgraphRequest } from '../../utils'; - -const GIN_FINANCE_SUBGRAPH_URL = { - '288': 'https://api.thegraph.com/subgraphs/name/gindev2/gin-subgraph' -}; - -export const author = 'perpetuum7'; -export const version = '1.0.0'; - -export async function strategy( - _space: string, - network: string, - _provider, - addresses: string[], - options: { address: string }, - snapshot?: number | string -) { - const params = { - users: { - __args: { - where: { - id_in: addresses.map((address) => address.toLowerCase()) - }, - first: 1000 - }, - id: true, - liquidityPositions: { - __args: { - where: { - liquidityTokenBalance_gt: 0 - } - }, - liquidityTokenBalance: true, - pair: { - id: true, - token0: { - id: true - }, - reserve0: true, - token1: { - id: true - }, - reserve1: true, - totalSupply: true - } - } - } - }; - - if (snapshot !== 'latest') { - // @ts-ignore - params.users.liquidityPositions.__args.block = { number: snapshot }; - } - - const tokenAddress = options.address.toLowerCase(); - const result = await subgraphRequest( - GIN_FINANCE_SUBGRAPH_URL[network], - params - ); - - const score = {}; - - if (result && result.users) { - result.users.forEach((u) => { - u.liquidityPositions - .filter( - (lp) => - lp.pair.token0.id == tokenAddress || - lp.pair.token1.id == tokenAddress - ) - .forEach((lp) => { - const token0perUni = lp.pair.reserve0 / lp.pair.totalSupply; - const token1perUni = lp.pair.reserve1 / lp.pair.totalSupply; - const userScore = - lp.pair.token0.id == tokenAddress - ? token0perUni * lp.liquidityTokenBalance - : token1perUni * lp.liquidityTokenBalance; - - const userAddress = getAddress(u.id); - if (!score[userAddress]) score[userAddress] = 0; - score[userAddress] = score[userAddress] + userScore; - }); - }); - } - - return score || {}; -} diff --git a/src/strategies/giveth-xdai-balance/README.md b/src/strategies/giveth-xdai-balance/README.md deleted file mode 100644 index 6bc76c77b..000000000 --- a/src/strategies/giveth-xdai-balance/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# Giveth xDai balance - -This strategy sums up all the GIV on xDai, including the ones that are staked in Honeyswap pools, Sushiswap pools, and single staked on GIV pool. - -Here is an example of parameters: - -```json -{ - "symbol": "GIV", - "decimals": 18 -} -``` diff --git a/src/strategies/giveth-xdai-balance/examples.json b/src/strategies/giveth-xdai-balance/examples.json deleted file mode 100644 index 8bcc93079..000000000 --- a/src/strategies/giveth-xdai-balance/examples.json +++ /dev/null @@ -1,19 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "giveth-xdai-balance", - "params": { - "symbol": "GIV", - "decimals": 18 - } - }, - "network": "1", - "addresses": [ - "0x839395e20bbb182fa440d08f850e6c7a8f6f0780", - "0x960a16c9070a9bbbb03e1bfd418982636d56d77d", - "0x00d18ca9782be1caef611017c2fbc1a39779a57c" - ], - "snapshot": 14036425 - } -] diff --git a/src/strategies/giveth-xdai-balance/index.ts b/src/strategies/giveth-xdai-balance/index.ts deleted file mode 100644 index 0f8ece58e..000000000 --- a/src/strategies/giveth-xdai-balance/index.ts +++ /dev/null @@ -1,141 +0,0 @@ -import { subgraphRequest } from '../../utils'; -import { BigNumber } from '@ethersproject/bignumber'; -import { getAddress } from '@ethersproject/address'; -import { parseUnits, formatUnits } from '@ethersproject/units'; - -export const author = 'pkretzschmar'; -export const version = '0.1.0'; - -const GIVETH_SUBGRAPH_API = - 'https://api.thegraph.com/subgraphs/name/giveth/giveth-economy-xdai'; -const XDAI_BLOCKS_API = - 'https://api.thegraph.com/subgraphs/name/elkfinance/xdai-blocks'; -const PAIR_IDS = [ - '0x08ea9f608656a4a775ef73f5b187a2f1ae2ae10e', - '0x55ff0cef43f0df88226e9d87d09fa036017f5586' -]; -const PAIR_APIS = [ - 'https://api.thegraph.com/subgraphs/name/1hive/honeyswap-xdai', - 'https://api.thegraph.com/subgraphs/name/sushiswap/xdai-exchange' -]; - -const blockParams = { - blocks: { - __args: { - first: 1, - orderBy: 'timestamp', - orderDirection: 'desc', - where: { - timestamp_lte: '' - } - }, - number: true - } -}; - -const pairParams = { - pair: { - __args: { - id: '' - }, - reserve0: true, - totalSupply: true - } -}; - -const params = { - balances: { - __args: { - orderBy: 'id', - orderDirection: 'asc', - where: { - id_in: [] - } - }, - id: true, - balance: true, - givStaked: true, - honeyswapLp: true, - honeyswapLpStaked: true, - sushiswapLp: true, - sushiSwapLpStaked: true - } -}; - -const formatReserveBalance = (data, decimals) => { - const reserve = parseUnits(data.pair.reserve0, decimals); - const totalSupply = parseUnits(data.pair.totalSupply, decimals); - return { reserve, totalSupply }; -}; - -const calcGivAmount = ( - amountLP: BigNumber, - totalLP: BigNumber, - givBalance: BigNumber -): BigNumber => { - return amountLP.mul(givBalance).div(totalLP); -}; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - const block = await provider.getBlock(blockTag); - blockParams.blocks.__args.where.timestamp_lte = block.timestamp; - const xDaiBlock = await subgraphRequest(XDAI_BLOCKS_API, blockParams); - const blockNumber = Number(xDaiBlock.blocks[0].number); - // @ts-ignore - params.balances.__args.block = { number: blockNumber }; - if (snapshot !== 'latest') { - // @ts-ignore - pairParams.pair.__args.block = { number: blockNumber }; - } - - params.balances.__args.where.id_in = addresses.map((address) => - address.toLowerCase() - ); - - const requests = PAIR_APIS.map((API, index) => { - pairParams.pair.__args.id = PAIR_IDS[index]; - return subgraphRequest(API, pairParams); - }); - requests.push(subgraphRequest(GIVETH_SUBGRAPH_API, params)); - const [hnyData, sushiData, data] = await Promise.all(requests); - - const hnyFormatedData = formatReserveBalance(hnyData, options.decimals); - const sushiFormatedData = formatReserveBalance(sushiData, options.decimals); - const dataBalances = data.balances; - - const score = {}; - dataBalances.map((addressBalance) => { - const { - id, - balance, - givStaked, - honeyswapLp, - honeyswapLpStaked, - sushiswapLp, - sushiSwapLpStaked - } = addressBalance; - const totalGIV = BigNumber.from(balance).add(givStaked); - const hnyGIV = calcGivAmount( - BigNumber.from(honeyswapLp).add(honeyswapLpStaked), - hnyFormatedData.totalSupply, - hnyFormatedData.reserve - ); - const sushiGIV = calcGivAmount( - BigNumber.from(sushiswapLp).add(sushiSwapLpStaked), - sushiFormatedData.totalSupply, - sushiFormatedData.reserve - ); - score[getAddress(id)] = parseFloat( - formatUnits(totalGIV.add(hnyGIV).add(sushiGIV), options.decimals) - ); - }); - return score; -} diff --git a/src/strategies/gysr-pending-rewards/README.md b/src/strategies/gysr-pending-rewards/README.md deleted file mode 100644 index ce3b200ba..000000000 --- a/src/strategies/gysr-pending-rewards/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# GYSR Pending Rewards - -This strategy returns the pending rewards for each user in a specified GYSR pool. It supports the networks the GYSR Pool Info is available. - -Here is an example of parameters: - -```json -{ - // Required - "pool": "0xE48eddbBcA614be5416f20dE57D858562b72479d", - - // Optional - "rewardToken": "0xb521022EeaD7E7eEe95D30BA1A1f0aB657F83a61", - "symbol": "REX" -} -``` diff --git a/src/strategies/gysr-pending-rewards/examples.json b/src/strategies/gysr-pending-rewards/examples.json deleted file mode 100644 index 6d42e5dbc..000000000 --- a/src/strategies/gysr-pending-rewards/examples.json +++ /dev/null @@ -1,21 +0,0 @@ -[ - { - "name": "Example GYSR Pending Rewards query", - "strategy": { - "name": "gysr-pending-rewards", - "params": { - "pool": "0x30c0f65d9b27ebe2cc2a49cbcb4133230b3fb381", - "rewardToken": "0xbEa98c05eEAe2f3bC8c3565Db7551Eb738c8CCAb", - "symbol": "GYSR" - } - }, - "network": 1, - "addresses": [ - "0xc56e357599de4418c3a33ad611130d2b2b36b19a", - "0x3a5a5ed68b3eea83df82fbd3d16b16562e205ffb", - "0x6c2448c22a7947bd4fd886b719618b913cd09538", - "0x30c0f65d9b27ebe2cc2a49cbcb4133230b3fb381" - ], - "snapshot": 15410000 - } -] diff --git a/src/strategies/gysr-pending-rewards/index.ts b/src/strategies/gysr-pending-rewards/index.ts deleted file mode 100644 index 9b4d59b19..000000000 --- a/src/strategies/gysr-pending-rewards/index.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { BigNumberish } from '@ethersproject/bignumber'; -import { formatUnits } from '@ethersproject/units'; -import { multicall, Multicaller } from '../../utils'; - -export const author = 'mitesh-mutha'; -export const version = '0.1.0'; - -const poolInfoAddressForNetwork = { - 1: '0x01356d78c770840166C1654691D19Bd33C52EaAd', - 10: '0x3cAA041d1a0a78d141703C0E95408c1801Ed74dd', - 42: '0x91EB59690526b748FE1046D27BdB1B3dadeaf958', - 137: '0x53590f017d73bAb31A6CbCBF6500A66D92fecFbE' -}; - -const poolInfoABI = [ - 'function rewards(address pool, address addr) external view returns (uint256[])' -]; - -const poolABI = ['function rewardTokens() external view returns (address[])']; - -const tokenABI = ['function decimals() external view returns (uint8)']; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -): Promise> { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - // Network specific pool info contract address - const poolInfoContractAddress = poolInfoAddressForNetwork[network]; - - // Determine which token rewards to count for voting power - let tokenIndex = 0; - - const tokenCallResult = await multicall( - network, - provider, - poolABI, - [[options.pool, 'rewardTokens', []]], - { blockTag } - ); - - const rewardTokens = tokenCallResult[0].map((tokenAddress) => [ - tokenAddress.toString().toLowerCase() - ]); - - if (!(options.rewardToken == null)) { - tokenIndex = Math.max( - rewardTokens.indexOf(options.rewardToken.toLowerCase()), - 0 - ); - } - - // Determine decimals - const rewardTokenAddress = tokenCallResult[0][tokenIndex].toString(); - const decimalCallResult = await multicall( - network, - provider, - tokenABI, - [[rewardTokenAddress, 'decimals', []]], - { blockTag } - ); - const decimals = decimalCallResult[0]; - - // Get the pending rewards for addresses - const multi = new Multicaller(network, provider, poolInfoABI, { blockTag }); - addresses.forEach((address) => - multi.call(address, poolInfoContractAddress, 'rewards', [ - options.pool, - address - ]) - ); - const result: Record = await multi.execute(); - - return Object.fromEntries( - Object.entries(result).map(([address, balances]) => [ - address, - parseFloat(formatUnits(balances[tokenIndex], decimals)) - ]) - ); -} diff --git a/src/strategies/gysr-pending-rewards/schema.json b/src/strategies/gysr-pending-rewards/schema.json deleted file mode 100644 index 468a4eb77..000000000 --- a/src/strategies/gysr-pending-rewards/schema.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$ref": "#/definitions/Strategy", - "definitions": { - "Strategy": { - "title": "Strategy", - "type": "object", - "properties": { - "symbol": { - "type": "string", - "title": "Symbol", - "examples": ["e.g. UNI"], - "maxLength": 16 - }, - "pool": { - "type": "string", - "title": "Pool Address", - "examples": ["e.g. 0xE48eddbBcA614be5416f20dE57D858562b72479d"], - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - }, - "rewardToken": { - "type": "string", - "title": "Reward Token Address", - "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - } - }, - "required": ["pool"], - "additionalProperties": false - } - } -} diff --git a/src/strategies/h2o/README.md b/src/strategies/h2o/README.md index 7fa052053..893c3bb4d 100644 --- a/src/strategies/h2o/README.md +++ b/src/strategies/h2o/README.md @@ -12,6 +12,6 @@ Here is an example of parameters: ```json { "symbol": "OCEAN", - "collateralTypeId": "OCEAN-A", + "collateralTypeId": "OCEAN-A" } ``` diff --git a/src/strategies/hashflow-governance-power/README.md b/src/strategies/hashflow-governance-power/README.md deleted file mode 100644 index 6ff23c17c..000000000 --- a/src/strategies/hashflow-governance-power/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# hashflow-governance-power - -This strategy is used for the Hashflow DAO to consider both held HFT and LP'd HFT equally. - -It was implemented as a result of community proposal [#272](https://gov.hashflow.com/t/allow-hashgang-to-use-their-hft-lp-tokens-to-vote/272/20), which was passed via a [snapshot vote](https://snapshot.org/#/hashflowdao.eth/proposal/0x0fe602a533b10fab93a66b155770ba948ff23209412487ec1ba3c5a4d75357ef). - -It allows users who are LP'ing HFT in public HFT pools to use those for voting. This eliminates the need to withdraw from pools to participate in voting. - -The exact implementation uses the fact that the `payout` field of a pool's `function assetDetails()` call shares how many HFT are claimable in the pool. This can then be combined with the totalSupply of each pool's LP token to determine the HFT value of funds deposited by any given address. - -Here is an example of parameters: - -```json -{ - "hftContract": "0xb3999f658c0391d94a37f7ff328f3fec942bcadc", - "hftPool": "0x5afe266ab4e43c32bad5459fe8df116dd5541222", - "hToken": "0x8a96b94bee6636042f2019c60c43b4f1c8c177a9" -} -``` diff --git a/src/strategies/hashflow-governance-power/examples.json b/src/strategies/hashflow-governance-power/examples.json deleted file mode 100644 index 9220e982e..000000000 --- a/src/strategies/hashflow-governance-power/examples.json +++ /dev/null @@ -1,68 +0,0 @@ -[ - { - "name": "Mainnet query", - "strategy": { - "name": "hashflow-governance-power", - "params": { - "hftContract": "0xb3999f658c0391d94a37f7ff328f3fec942bcadc", - "hftPool": "0x5afe266ab4e43c32bad5459fe8df116dd5541222", - "hToken": "0x8a96b94bee6636042f2019c60c43b4f1c8c177a9" - } - }, - "network": "1", - "addresses": [ - "0x5caf573a688f21bb7a73a5f1cbeac1dfd6b505ca", - "0x5f09807819ca23d2b55d418a1cda9758725b35c1", - "0xb719e6279c5a9b5aa2b7a47f9e0e6453fa405808", - "0xaac0643b2a9f8351113388d935ff0718dae07e56", - "0x5409630192a9adaaa9ffbd46a3c695386be04e9c", - "0xd36ebe8e232955a444b4ab9a9297549c99ff09a9", - "0xee6d0298496153a026678488673a39c6153ab7f6", - "0xcabe8da7ce365392970437c9f4edfb4c89560257", - "0x910c60c049d833a7fd2f5bda310bbea1c5fa3598", - "0x8b5ce16637225516e2af14962407ec5afb8b9b73", - "0x720d2dad9cf67988e5b09d1d0dc4ebe5843cd611", - "0x1bbae2d283f2c14f43147e53d4f1b69601a1eac3", - "0x1e377d026dbb28dff1662927b2cb836b7c9f06d3", - "0xd340c943ae137ea0bab682a286d1af65e4e39a6b", - "0x71311a0e6167efcf28eeab78f87c008d05760b0b", - "0xc4b86bd3d432bd0b55dcd0e4bd3db91e05de2c26" - ], - "snapshot": 16093501 - }, - { - "name": "BSC query", - "strategy": { - "name": "hashflow-governance-power", - "params": { - "hftContract": "0x44ec807ce2f4a6f2737a92e985f318d035883e47", - "hftPool": "0x7286f5be4e531f6ea7660c739108d95aa2fef959", - "hToken": "0x1ddc58822f0071bf6ab973c94a185a97d000d036" - } - }, - "network": "56", - "addresses": [ - "0x884d6fa3a4b349880486ad4d7c833ca968c785d8", - "0xc0b570dc0363b1d3c9714f1060e716696acd4034", - "0xf4a290d914592a7f482fccce09ad73762a5998ca", - "0xdb4d32ca46310b4079fef1d135c88c1d1def32d7", - "0xc479328e6254bf692a3b22f051245069b307647a", - "0x66633cc6b84cd127a0bb84864c1a4ea0172469a6", - "0x1e46348fba3e75fd3b609351adfc22612c20be54", - "0xf41939922947f7c93cfa77364b35c6e85e53aef3", - "0x34f0431bec239c0828fbcf96c32092e5c926df21", - "0x67bcd41adbf12d1ecffd86e17af2b14179b556a3", - "0xf6e1acdb0a18cb397dde6ec0cca024d875e3e6e2", - "0x4d37f2a705377ac4c0827b79a8a4b84267b03ea1", - "0x4e97283bac00e1be24474e0671a1457e55991d11", - "0x9448e95d67fbe5ee576eeddb2adc637bae141e10", - "0xbe7d87e410a5c880f7a8ee83d4ae9d3db26b0d84", - "0x9f9d3b1c793a367310ebe5d159c4599914abdbd5", - "0x7a43dc785ced8554478b2ba2e491347c0826adde", - "0x04d29d747aa0abda9144fc15d1546a1bb959c40a", - "0xbe18f84532d8f7fb6d7919401c0096f3e257db8b", - "0x672c3b982325be86e221fe5d0eb5391ffa9cc8fc" - ], - "snapshot": 23545695 - } -] diff --git a/src/strategies/hashflow-governance-power/index.ts b/src/strategies/hashflow-governance-power/index.ts deleted file mode 100644 index cc53c4be7..000000000 --- a/src/strategies/hashflow-governance-power/index.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { getAddress } from '@ethersproject/address'; -import { BigNumberish } from '@ethersproject/bignumber'; -import { formatUnits } from '@ethersproject/units'; -import { multicall, Multicaller } from '../../utils'; - -export const author = 'mib-hashflow'; -export const version = '0.1.1'; - -const abi = [ - 'function balanceOf(address account) external view returns (uint256)', - 'function assetDetails(address token) external view returns (uint128 withdrawalLimit, uint128 cap, uint128 netPayout, uint128 timestamp, address hToken, address hTokenXChain, bool listed)', - 'function totalSupply() external view returns (uint256)' -]; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -): Promise> { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - const contractData = await multicall( - network, - provider, - abi, - [ - [options.hftPool, 'assetDetails', [options.hftContract]], - [options.hToken, 'totalSupply', []] - ], - { blockTag } - ); - - const netPayout: BigNumberish = contractData[0].netPayout; - const totalSupply: BigNumberish = contractData[1][0]; - - const lpTokenWeight = - parseFloat(formatUnits(netPayout, 18)) / - parseFloat(formatUnits(totalSupply, 18)); - - const hftMulti = new Multicaller(network, provider, abi, { blockTag }); - addresses.forEach((address) => - hftMulti.call(address, options.hftContract, 'balanceOf', [address]) - ); - const hftBalances: Record = await hftMulti.execute(); - - const lpMulti = new Multicaller(network, provider, abi, { blockTag }); - addresses.forEach((address) => - lpMulti.call(address, options.hToken, 'balanceOf', [address]) - ); - const lpBalances: Record = await lpMulti.execute(); - - return Object.fromEntries( - Object.entries(hftBalances).map(([address, balance]) => [ - getAddress(address), - parseFloat(formatUnits(balance, 18)) + - lpTokenWeight * parseFloat(formatUnits(lpBalances[address], 18)) - ]) - ); -} diff --git a/src/strategies/hashflow-governance-power/schema.json b/src/strategies/hashflow-governance-power/schema.json deleted file mode 100644 index 6e5b10b51..000000000 --- a/src/strategies/hashflow-governance-power/schema.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$ref": "#/definitions/Strategy", - "definitions": { - "Strategy": { - "title": "Strategy", - "type": "object", - "properties": { - "hftContract": { - "type": "string", - "title": "HFT Contract address", - "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - }, - "hftPool": { - "type": "string", - "title": "HFT Pool address", - "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - }, - "hToken": { - "type": "string", - "title": "HFT Pool HFT-hToken address", - "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - } - }, - "required": ["hftContract", "hftPool", "hToken"], - "additionalProperties": false - } - } -} diff --git a/src/strategies/hedgey-multi/README.md b/src/strategies/hedgey-multi/README.md deleted file mode 100644 index 42f2440e4..000000000 --- a/src/strategies/hedgey-multi/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# Hedgey strategy - -Calculates voting rights based on the underlying tokens locked in the Hedgey protocol from multiple contracts with a multiplyer - -## Examples - -### Input parameters - -An array of ContractDetails - - - address: The address of the contract - - token: The address of the token that is taken into account for the score - - decimal: The decimal value the token uses - - contractType: Can be NFT for the standard NFT contract or TokenInfusedNFT for the token infused NFT contract - - lockedTokenMultiplier: a simple multiplyer for locked tokens - - lockedTokenMonthlyMultiplier: a multiplier based on the amount of time the tokens will be unlocked for diff --git a/src/strategies/hedgey-multi/examples.json b/src/strategies/hedgey-multi/examples.json deleted file mode 100644 index fca088df0..000000000 --- a/src/strategies/hedgey-multi/examples.json +++ /dev/null @@ -1,27 +0,0 @@ -[ - { - "name": "Example voting based on hedgey token underlying balance from multiple contracts with a multiplyer", - "strategy": { - "name": "hedgey-multi", - "params": { - "contracts": [ - { - "address": "0x4bc8ea84bdc3ebb01d495e5d1605d4f082aeb5d7", - "token": "0xccDE1F2B71573a865d3896eb019C41Bf4BF92e65", - "decimal": 18, - "contractType": "NFT", - "lockedTokenMultiplier": 2, - "lockedTokenMonthlyMultiplier": { - "default": 1, - "1": 1.5, - "2": 2 - } - } - ] - } - }, - "network": "4", - "snapshot": 11452455, - "addresses": ["0x92d9802eFcD0485876DDC13c16cEA67e6aD5EB35"] - } -] diff --git a/src/strategies/hedgey-multi/index.ts b/src/strategies/hedgey-multi/index.ts deleted file mode 100644 index 5e6867ba4..000000000 --- a/src/strategies/hedgey-multi/index.ts +++ /dev/null @@ -1,217 +0,0 @@ -import { BigNumber } from '@ethersproject/bignumber'; -import { Multicaller } from '../../utils'; - -export const author = 'bark4mark'; -export const version = '0.1.0'; - -const MAX_CONTRACTS = 8; - -enum ContractType { - NFT = 'NFT', - TokenInfusedNFT = 'TokenInfusedNFT' -} - -type ContractDetails = { - address: string; - token: string; - decimal: number; - contractType: ContractType; - lockedTokenMultiplier: number; - lockedTokenMonthlyMultiplier: any; -}; - -const abis = { - NFT: [ - 'function balanceOf(address owner) external view returns (uint256 balance)', - 'function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId)', - 'function futures(uint256 index) external view returns (uint256 amount, address token, uint256 unlockDate)', - 'function token() external view returns (address token)' - ], - TokenInfusedNFT: [ - 'function futures(uint256 index) external view returns (uint256 amount, uint256 unlockDate)' - ] -}; - -const compareAddresses = (address1: string, address2: string): boolean => { - if (!address1 || !address2) return false; - return address1.toLowerCase() === address2.toLowerCase(); -}; - -const getMonthDifference = (start: Date, end: Date): number => { - return ( - end.getMonth() - - start.getMonth() + - 12 * (end.getFullYear() - start.getFullYear()) - ); -}; - -export async function strategy( - _space, - network, - provider, - addresses, - options, - snapshot -) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - const contractDetails: ContractDetails[] = options.contracts; - if (contractDetails.length > MAX_CONTRACTS) { - throw new Error(`Max number (${MAX_CONTRACTS}) of contracts exceeded`); - } - const balanceOfMulti = new Multicaller(network, provider, abis.NFT, { - blockTag - }); - - contractDetails.forEach((contractDetail) => { - addresses.forEach((address: string) => { - balanceOfMulti.call( - `${contractDetail.address}/${address}`, - contractDetail.address, - 'balanceOf', - [address] - ); - }); - if (contractDetail.contractType === ContractType.TokenInfusedNFT) { - balanceOfMulti.call( - `${contractDetail.address}/token`, - contractDetail.address, - 'token' - ); - } - }); - - const balanceOfResult = await balanceOfMulti.execute(); - const nftHolderMulti = new Multicaller(network, provider, abis.NFT, { - blockTag - }); - - contractDetails.forEach((contractDetail) => { - addresses.forEach((address: string) => { - const balance = balanceOfResult[`${contractDetail.address}/${address}`]; - for (let index = 0; index < balance; index++) { - nftHolderMulti.call( - `${contractDetail.contractType}/${contractDetail.address}/${address}/${index}`, - contractDetail.address, - 'tokenOfOwnerByIndex', - [address, index] - ); - } - }); - }); - - const nftHolders = await nftHolderMulti.execute(); - - const nftDealsMulti = new Multicaller(network, provider, abis.NFT, { - blockTag - }); - - const tiNFTDealsMulti = new Multicaller( - network, - provider, - abis.TokenInfusedNFT, - { blockTag } - ); - - for (const [path, nftId] of Object.entries(nftHolders)) { - const [contractType, contractAddress, address] = path.split('/'); - switch (contractType) { - case ContractType.NFT: - nftDealsMulti.call( - `${contractAddress}/${address}`, - contractAddress, - 'futures', - [nftId] - ); - break; - case ContractType.TokenInfusedNFT: - tiNFTDealsMulti.call( - `${contractAddress}/${address}`, - contractAddress, - 'futures', - [nftId] - ); - break; - } - } - - const nftDeals = await nftDealsMulti.execute(); - const tiNFTDeals = await tiNFTDealsMulti.execute(); - - const votes = {}; - - for (const [path, deal] of Object.entries(nftDeals)) { - const [contractAddress, address] = path.split('/'); - const contractDetail = contractDetails.find( - (element) => element.address === contractAddress - ); - - if (!contractDetail) continue; - if (!compareAddresses(deal.token, contractDetail.token)) continue; - - const amount = BigNumber.from(deal.amount).div( - BigNumber.from(10).pow(contractDetail.decimal) - ); - - let score = amount.toNumber(); - score = score * contractDetail.lockedTokenMultiplier; - const durationStart = new Date(); - const unlockDate = new Date(deal.unlockDate * 1000); - - const months = getMonthDifference(durationStart, unlockDate); - let monthlyMultiplier = contractDetail.lockedTokenMonthlyMultiplier[months]; - - if (!monthlyMultiplier) - monthlyMultiplier = - contractDetail.lockedTokenMonthlyMultiplier['default']; - - score = score * monthlyMultiplier; - - let existingAmount = votes[address]; - if (existingAmount) { - existingAmount = existingAmount + score; - } else { - votes[address] = score; - } - } - - for (const [path, deal] of Object.entries(tiNFTDeals)) { - const [contractAddress, address] = path.split('/'); - const contractDetail = contractDetails.find( - (element) => element.address === contractAddress - ); - - if (!contractDetail) continue; - - const contractToken = balanceOfResult[`${contractDetail.address}/token`]; - if (!compareAddresses(contractToken, contractDetail.token)) continue; - - const amount = BigNumber.from(deal.amount).div( - BigNumber.from(10).pow(contractDetail.decimal) - ); - - let score = amount.toNumber(); - score = score * contractDetail.lockedTokenMultiplier; - const durationStart = new Date(); - const unlockDate = new Date(deal.unlockDate * 1000); - - const months = getMonthDifference(durationStart, unlockDate); - if (months > 1) { - let monthlyMultiplier = - contractDetail.lockedTokenMonthlyMultiplier[months]; - - if (!monthlyMultiplier) - monthlyMultiplier = - contractDetail.lockedTokenMonthlyMultiplier['default']; - - score = score * monthlyMultiplier; - } - let existingAmount = votes[address]; - if (existingAmount) { - existingAmount = existingAmount + score; - } else { - votes[address] = score; - } - } - - return votes; -} diff --git a/src/strategies/hopr-staking/examples.json b/src/strategies/hopr-staking/examples.json deleted file mode 100644 index 2a88e0253..000000000 --- a/src/strategies/hopr-staking/examples.json +++ /dev/null @@ -1,61 +0,0 @@ -[ - { - "name": "Stakes and unclaimed rewards from HOPR Stake program", - "strategy": { - "name": "hopr-staking", - "params": { - "tokenAddress": "0xf5581dfefd8fb0e4aec526be659cfab1f8c781da", - "symbol": "HOPR" - } - }, - "network": "1", - "addresses": [ - "0x04BBB7eA18EA570aE47d4489991645E4E49bBf37", - "0x2aF80738aC01e7883d11c912dFe8322C129ae5C5", - "0x0bb43EFc1a613658177D8f67CcF9CFFD8B25b906", - "0x53e85186ebF5A7d4BD06324F7b9D8B3623EF0307", - "0x2DCDB99930E279f1e9Ad11F491163051432542A0", - "0x4326990033eCd87A5444383Cf8c715E696301910", - "0xEd6a59A7C1D5a88b7cb5eb877A7A6078A7e801C7", - "0xeFC05B0D0C8bE8D4Cb3a220ef582E9f7E6FBCd00", - "0xC7B169b108c5e75991C520AEA97140534291C81D", - "0x04Be52434EB64aDdF373137310551ac42013677c", - "0xBE8C93a8C18AF63aAB449994AFAc13E71240ccC4", - "0xf813773eBDD4759c1B780d745081f046A5B776fB", - "0x7F26C34Ed10bF66602009231bBFF24f2f84e9270", - "0x4abd7276C53279b3aBFFF2B5D8A47c0AFc84833B", - "0x3e1A12a6019ee26418F22B656926fE38F5e58C5f", - "0x7A27A4D91231aCB3282b410Cc784517B417FA0DA" - ], - "snapshot": 13269966 - }, - { - "name": "Stakes and unclaimed rewards from HOPR Stake program", - "strategy": { - "name": "hopr-staking", - "params": { - "tokenAddress": "0xf5581dfefd8fb0e4aec526be659cfab1f8c781da" - } - }, - "network": "100", - "addresses": [ - "0x04BBB7eA18EA570aE47d4489991645E4E49bBf37", - "0x2aF80738aC01e7883d11c912dFe8322C129ae5C5", - "0x0bb43EFc1a613658177D8f67CcF9CFFD8B25b906", - "0x53e85186ebF5A7d4BD06324F7b9D8B3623EF0307", - "0x2DCDB99930E279f1e9Ad11F491163051432542A0", - "0x4326990033eCd87A5444383Cf8c715E696301910", - "0xEd6a59A7C1D5a88b7cb5eb877A7A6078A7e801C7", - "0xeFC05B0D0C8bE8D4Cb3a220ef582E9f7E6FBCd00", - "0xC7B169b108c5e75991C520AEA97140534291C81D", - "0x04Be52434EB64aDdF373137310551ac42013677c", - "0xBE8C93a8C18AF63aAB449994AFAc13E71240ccC4", - "0xf813773eBDD4759c1B780d745081f046A5B776fB", - "0x7F26C34Ed10bF66602009231bBFF24f2f84e9270", - "0x4abd7276C53279b3aBFFF2B5D8A47c0AFc84833B", - "0x3e1A12a6019ee26418F22B656926fE38F5e58C5f", - "0x7A27A4D91231aCB3282b410Cc784517B417FA0DA" - ], - "snapshot": 18200908 - } -] diff --git a/src/strategies/hopr-staking/index.ts b/src/strategies/hopr-staking/index.ts deleted file mode 100644 index 33f630559..000000000 --- a/src/strategies/hopr-staking/index.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { formatUnits } from '@ethersproject/units'; -import { BigNumber } from '@ethersproject/bignumber'; -import { subgraphRequest } from '../../utils'; - -export const author = 'QYuQianchen'; -export const version = '0.1.0'; - -const XDAI_BLOCK_SUBGRAPH_URL = - 'https://api.thegraph.com/subgraphs/name/1hive/xdai-blocks'; -const HOPR_STAKING_SUBGRAPH_URL = - 'https://api.thegraph.com/subgraphs/name/hoprnet/hopr-staking-program'; -const LIMIT = 1000; // 1000 addresses per query in Subgraph - -async function getXdaiBlockNumber(timestamp: number): Promise { - const query = { - blocks: { - __args: { - first: 1, - orderBy: 'number', - orderDirection: 'desc', - where: { - timestamp_lte: timestamp - } - }, - number: true, - timestamp: true - } - }; - const data = await subgraphRequest(XDAI_BLOCK_SUBGRAPH_URL, query); - return Number(data.blocks[0].number); -} - -async function stakingSubgraphQuery( - addresses: string[], - blockNumber: number -): Promise<{ [propName: string]: BigNumber }> { - const query = { - accounts: { - __args: { - first: LIMIT, - block: { - number: blockNumber - }, - where: { - id_in: addresses.map((adr) => adr.toLowerCase()) - } - }, - id: true, - actualStake: true, - virtualStake: true, - unclaimedRewards: true - } - }; - const data = await subgraphRequest(HOPR_STAKING_SUBGRAPH_URL, query); - // map result (data.accounts) to addresses - const entries = data.accounts.map((d) => [ - d.id, - BigNumber.from(d.actualStake).add( - BigNumber.from(d.virtualStake).add(BigNumber.from(d.unclaimedRewards)) - ) - ]); - return Object.fromEntries(entries); -} - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - const isXdai = network === '100'; // either xDAI or ETH mainnet - const [block] = await Promise.all([provider.getBlock(blockTag)]); - - // get the block number for subgraph query - const subgraphBlock = isXdai - ? block.number - : await getXdaiBlockNumber(block.timestamp); - - // trim addresses to sub of "LIMIT" addresses. - const addressSubsets = Array.apply( - null, - Array(Math.ceil(addresses.length / LIMIT)) - ).map((_e, i) => addresses.slice(i * LIMIT, (i + 1) * LIMIT)); - - const returnedFromSubgraph = await Promise.all( - addressSubsets.map((subset) => stakingSubgraphQuery(subset, subgraphBlock)) - ); - - // get and parse balance from subgraph - const subgraphBalance = Object.assign({}, ...returnedFromSubgraph); - const subgraphScore = addresses.map( - (address) => subgraphBalance[address.toLowerCase()] ?? 0 - ); - - return Object.fromEntries( - addresses.map((adr, i) => [ - adr, - parseFloat(formatUnits(subgraphScore[i], 18)) // subgraph balance - ]) - ); -} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 24c150bc8..3f89c3e34 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -9,11 +9,8 @@ import * as erc20Votes from './erc20-votes'; import * as erc20VotesWithOverride from './erc20-votes-with-override'; import * as antiWhale from './anti-whale'; import * as balancer from './balancer'; -import * as balancerErc20InternalBalanceOf from './balancer-erc20-internal-balance-of'; -import * as sunder from './sunder'; import * as balancerSmartPool from './balancer-smart-pool'; import * as contractCall from './contract-call'; -import * as dextfVaults from './dextf-staked-in-vaults'; import * as dfynFarms from './dfyn-staked-in-farms'; import * as dfynVaults from './dfyn-staked-in-vaults'; import * as vDfynVault from './balance-in-vdfyn-vault'; @@ -35,7 +32,6 @@ import * as erc20BalanceOfTopHolders from './erc20-balance-of-top-holders'; import * as erc20BalanceOfWeighted from './erc20-balance-of-weighted'; import * as ethalendBalanceOf from './ethalend-balance-of'; import * as prepoVesting from './prepo-vesting'; -import * as mintoBalanceAll from './minto-balance-of-all'; import * as erc20BalanceOfIndexed from './erc20-balance-of-indexed'; import * as revest from './revest'; import * as erc20Price from './erc20-price'; @@ -61,22 +57,9 @@ import * as pancake from './pancake'; import * as pancakeProfile from './pancake-profile'; import * as synthetix from './synthetix'; import * as aelinCouncil from './aelin-council'; -import * as synthetixQuadratic from './synthetix-quadratic'; -import * as synthetixQuadraticOne from './synthetix-quadratic_1'; -import * as synthetixQuadraticTwo from './synthetix-quadratic_2'; -import * as synthetixOne from './synthetix_1'; -import * as synthetixNonQuadratic from './synthetix-non-quadratic'; -import * as synthetixNonQuadraticOne from './synthetix-non-quadratic_1'; -import * as synthetixNonQuadraticTwo from './synthetix-non-quadratic_2'; import * as ctoken from './ctoken'; -import * as cream from './cream'; -import * as esd from './esd'; -import * as esdDelegation from './esd-delegation'; import * as stakedUniswap from './staked-uniswap'; -import * as piedao from './piedao'; -import * as ethReceived from './eth-received'; import * as erc20Received from './erc20-received'; -import * as ethPhilanthropy from './eth-philanthropy'; import * as xDaiEasyStaking from './xdai-easy-staking'; import * as xDaiPOSDAOStaking from './xdai-posdao-staking'; import * as xDaiStakeHolders from './xdai-stake-holders'; @@ -84,7 +67,6 @@ import * as xDaiStakeDelegation from './xdai-stake-delegation'; import * as defidollar from './defidollar'; import * as aavegotchi from './aavegotchi'; import * as aavegotchiAgip from './aavegotchi-agip'; -import * as aavegotchiAgip17 from './aavegotchi-agip-17'; import * as mithcash from './mithcash'; import * as dittomoney from './dittomoney'; import * as balancerUnipool from './balancer-unipool'; @@ -103,23 +85,19 @@ import * as ticketValidity from './ticket-validity'; import * as validation from './validation'; import * as opium from './opium'; import * as ocean from './ocean-marketplace'; -import * as ocean_v4 from './ocean-marketplace-v4'; import * as theGraphBalance from './the-graph-balance'; import * as theGraphDelegation from './the-graph-delegation'; import * as theGraphIndexing from './the-graph-indexing'; import * as whitelist from './whitelist'; import * as whitelistWeighted from './whitelist-weighted'; import * as tokenlon from './tokenlon'; -import * as rebased from './rebased'; import * as pobHash from './pob-hash'; -import * as totalAxionShares from './total-axion-shares'; import * as erc1155BalanceOf from './erc1155-balance-of'; import * as erc1155BalanceOfCv from './erc1155-balance-of-cv'; import * as erc1155WithMultiplier from './erc1155-with-multiplier'; import * as compLikeVotes from './comp-like-votes'; import * as governorAlpha from './governor-alpha'; import * as pagination from './pagination'; -import * as rulerStakedToken from './ruler-staked-token'; import * as rulerStakedLP from './ruler-staked-lp'; import * as xcover from './xcover'; import * as niuStaked from './niu-staked'; @@ -136,8 +114,6 @@ import * as erc1155AllBalancesOf from './erc1155-all-balances-of'; import * as trancheStakingLP from './tranche-staking-lp'; import * as masterchefPoolBalance from './masterchef-pool-balance'; import * as masterchefPoolBalancePrice from './masterchef-pool-balance-price'; -import * as avnBalanceOfStaked from './avn-balance-of-staked'; -import * as badgeth from './badgeth'; import * as api from './api'; import * as apiPost from './api-post'; import * as apiV2 from './api-v2'; @@ -146,7 +122,6 @@ import * as molochAll from './moloch-all'; import * as molochLoot from './moloch-loot'; import * as erc721Enumerable from './erc721-enumerable'; import * as erc721WithMultiplier from './erc721-with-multiplier'; -import * as protofiErc721TierWeighted from './protofi-erc721-tier-weighted'; import * as erc721WithTokenId from './erc721-with-tokenid'; import * as erc721WithTokenIdRangeWeights from './erc721-with-tokenid-range-weights'; import * as erc721WithTokenIdRangeWeightsSimple from './erc721-with-tokenid-range-weights-simple'; @@ -158,32 +133,22 @@ import * as erc721 from './erc721'; import * as erc721MultiRegistry from './erc721-multi-registry'; import * as apescape from './apescape'; import * as liftkitchen from './liftkitchen'; -import * as coordinape from './coordinape'; import * as decentralandEstateSize from './decentraland-estate-size'; import * as decentralandWearableRariry from './decentraland-wearable-rarity'; import * as decentralandRentalLessors from './decentraland-rental-lessors'; -import * as iotexBalance from './iotex-balance'; import * as iotexStakedBalance from './iotex-staked-balance'; import * as xrc20BalanceOf from './xrc20-balance-of'; import * as brightid from './brightid'; import * as inverseXINV from './inverse-xinv'; import * as modefi from './modefi'; -import * as modefiStaking from './modefi-staking'; import * as spookyswap from './spookyswap'; -import * as squadzPower from './squadz-power'; import * as glide from './glide'; -import * as goldfinchVotingPower from './goldfinch-voting-power'; -import * as goldfinchMembership from './goldfinch-membership'; import * as rnbwBalance from './rnbw-balance'; import * as celerSgnDelegation from './celer-sgn-delegation'; -import * as balancerDelegation from './balancer-delegation'; import * as infinityProtocolPools from './infinityprotocol-liquidity-pools'; import * as aaveGovernancePower from './aave-governance-power'; import * as cake from './cake'; import * as aks from './aks'; -import * as tomyumswap from './tomyumswap'; -import * as planetFinance from './planet-finance'; -import * as planetFinancev2 from './planet-finance-v2'; import * as impossibleFinance from './impossible-finance'; import * as immutableX from './immutable-x'; import * as ogn from './ogn'; @@ -191,7 +156,6 @@ import * as oolongswap from './oolongswap'; import * as zrxVotingPower from './zrx-voting-power'; import * as tombFinance from './tomb-finance'; import * as trancheStakingSLICE from './tranche-staking-slice'; -import * as unipoolSameToken from './unipool-same-token'; import * as unipoolUniv2Lp from './unipool-univ2-lp'; import * as unipoolXSushi from './unipool-xsushi'; import * as taraxaDelegation from './taraxa-delegation'; @@ -203,11 +167,9 @@ import * as uniswapV3Staking from './uniswap-v3-staking'; import * as l2Deversifi from './l2-deversifi'; import * as vestedDeversifi from './vested-deversifi'; import * as biswap from './biswap'; -import * as cronaswap from './cronaswap'; import * as honeyswap from './honeyswap'; import * as eglVote from './egl-vote'; import * as mcnFarm from './mcn-farm'; -import * as snowswap from './snowswap'; import * as meebitsdao from './meebitsdao'; import * as membership from './membership'; import * as holdsTokens from './holds-tokens'; @@ -219,39 +181,24 @@ import * as hasrock from './has-rock'; import * as flexaCapacityStaking from './flexa-capacity-staking'; import * as sunriseGamingUniv2Lp from './sunrisegaming-univ2-lp'; import * as sunriseGamingStaking from './sunrisegaming-staking'; -import * as sUmamiHolders from './sumami-holders'; import * as singleStakingAutoCompoundBalanceOf from './single-staking-autocompound-balanceof'; import * as singleStakingPoolsBalanceOf from './single-staking-pools-balanceof'; import * as occStakeOf from './occ-stake-of'; -import * as hoprStaking from './hopr-staking'; -import * as hoprStakingS2 from './hopr-staking-s2'; -import * as hoprStakingBySeason from './hopr-staking-by-season'; import * as hoprBridgedBalance from './hopr-bridged-balance'; import * as hoprStakeAndBalanceQV from './hopr-stake-and-balance-qv'; import * as lootCharacterGuilds from './loot-character-guilds'; -import * as swapr from './swapr'; -import * as cyberkongz from './cyberkongz'; -import * as cyberkongzV2 from './cyberkongz-v2'; -import * as cyberkongzV3 from './cyberkongz-v3'; import * as compLikeVotesInclusive from './comp-like-votes-inclusive'; import * as mstable from './mstable'; import * as hashesVoting from './hashes-voting'; -import * as hashflowGovernancePower from './hashflow-governance-power'; import * as hashflowVeHft from './hashflow-vehft'; -import * as podLeader from './pod-leader'; import * as aavegotchiWagmiGuild from './aavegotchi-wagmi-guild'; import * as polisBalance from './polis-balance'; import * as techQuadraticRankedChoice from './tech-quadratic-ranked-choice'; import * as mutantCatsStakersAndHolders from './mutant-cats-stakers-and-holders'; -import * as vaultTokenLpBalance from './vault-token-lp-balance'; -import * as singleStakingVaultBalanceOf from './single-staking-vault-balanceof'; import * as razorVoting from './razor-network-voting'; -import * as svsStaking from './svs-staking'; import * as mcbBalanceFromGraph from './mcb-balance-from-graph'; import * as colonyReputation from './colony-reputation'; -import * as radicleCommunityTokens from './radicle-community-tokens'; import * as digitalaxMonaQuickswap from './digitalax-mona-quickswap'; -import * as digitalaxDecoToMona from './digitalax-deco-to-mona'; import * as digitalaxGenesisContribution from './digitalax-genesis-contribution'; import * as digitalaxLPStakers from './digitalax-lp-stakers'; import * as digitalaxMonaStakersMatic from './digitalax-mona-stakers-matic'; @@ -265,24 +212,17 @@ import * as bscMvb from './bsc-mvb'; import * as coinswap from './coinswap'; import * as dgenesis from './dgenesis'; import * as votePowerAndShare from './vote-power-and-share'; -import * as blockzerolabsCryptonauts from './blockzerolabs-cryptonauts'; import * as math from './math'; import * as pushVotingPower from './push-voting-power'; import * as stakedPSPBalance from './staked-psp-balance'; import * as erc20BalanceOfContractMultiplier from './erc20-balance-of-contract-multiplier'; -import * as agave from './agave'; import * as juicebox from './juicebox'; import * as snetFarmers from './snet-farmers'; import * as snetStakers from './snet-stakers'; import * as snetLiquidityProviders from './snet-liquidity-providers'; -import * as minMaxMcnFarm from './minmax-mcn-farm'; import * as unstackedToadzAndStackedToadzStakers from './unstackedtoadz-and-stackedtoadz-stakers'; -import * as jadeSmrt from './jade-smrt'; import * as oceanDAOBrightID from './ocean-dao-brightid'; -import * as saddleFinance from './saddle-finance'; -import * as saddleFinanceV2 from './saddle-finance-v2'; import * as lydiaGovVault from './lydia-gov-vault'; -import * as xkawaFarm from './xkawa-farm'; import * as darkforestScore from './darkforest-score'; import * as orangeReputationBasedVoting from './orange-reputation-based-voting'; import * as orangeReputationNftBasedVoting from './orange-reputation-nft-based-voting'; @@ -291,13 +231,9 @@ import * as pathBalanceStakedAndLocked from './path-balance-staked-and-locked'; import * as bottoDao from './botto-dao'; import * as genart from './genart'; import * as erc721MultiRegistryWeighted from './erc721-multi-registry-weighted'; -import * as genomesdao from './genomesdao'; -import * as zorro from './zorro'; -import * as voltVotingPower from './volt-voting-power'; import * as balancerPoolid from './balancer-poolid'; import * as stakedBalancer from './staked-balancer'; import * as stakedUniswapModifiable from './staked-uniswap-modifiable'; -import * as givethXdaiBalance from './giveth-xdai-balance'; import * as givethGnosisBalanceV2 from './giveth-gnosis-balance-v2'; import * as givethBalancerBalance from './giveth-balancer-balance'; import * as erc1155BalanceOfIds from './erc1155-balance-of-ids'; @@ -307,7 +243,6 @@ import * as stakersAndHolders from './stakers-and-holders'; import * as banksyDao from './banksy-dao'; import * as spacey2025 from './spacey2025'; import * as sandmanDao from './sandman-dao'; -import * as ethercatsFounderSeries from './ethercats-founder-series'; import * as veBalanceOfAt from './ve-balance-of-at'; import * as veRibbon from './ve-ribbon'; import * as veRibbonVotingPower from './ve-ribbon-voting-power'; @@ -316,7 +251,6 @@ import * as landDaoTiers from './landdao-token-tiers'; import * as defiplaza from './defiplaza'; import * as stakingClaimedUnclaimed from './staking-claimed-unclaimed'; import * as gysrStakingBalance from './gysr-staking-balance'; -import * as gysrPendingRewards from './gysr-pending-rewards'; import * as gysrLPStakingBalance from './gysr-lp-staking-balance'; import * as wanakafarmStaking from './wanakafarm-staking'; import * as starsharks from './starsharks'; @@ -324,21 +258,15 @@ import * as printerFinancial from './printer-financial'; import * as ethercatsFoundersSeries from './ethercats-founders-series'; import * as potion from './potion'; import * as MinotaurMoney from './minotaur-money'; -import * as safetyModuleBptPower from './safety-module-bpt-power'; import * as convFinance from './conv-finance'; import * as sdBoost from './sd-boost'; -import * as capitalDaoStaking from './capitaldao-staking'; -import * as erc20RebaseWrapper from './erc20-rebase-wrapper'; import * as wanakafarmLandIngame from './wanakafarm-land-ingame'; -import * as meebitsDaoDelegation from './meebitsdao-delegation'; import * as starcatchersTopWindow from './starcatchers-top-window'; import * as gno from './gno'; -import * as umaVoting from './uma-voting'; import * as masterchefPoolBalanceNoRewarddebt from './masterchef-pool-balance-no-rewarddebt'; import * as proofOfHumanity from './proof-of-humanity'; import * as samuraiLegendsGeneralsBalance from './samurailegends-generals-balance'; import * as dogsUnchained from './dogs-unchained'; -import * as stakeDAOGovernanceUpdate from './stakedao-governance-update'; import * as umamiVoting from './umami-voting'; import * as liquidityTokenProvide from './liquidity-token-provide'; import * as gamiumVoting from './gamium-voting'; @@ -348,19 +276,13 @@ import * as rowdyRoos from './rowdy-roos'; import * as ethermon721 from './ethermon-erc721'; import * as etherorcsComboBalanceOf from './etherorcs-combo-balanceof'; import * as hedgey from './hedgey'; -import * as hedgeyMulti from './hedgey-multi'; import * as hedgeyDelegate from './hedgey-delegate'; import * as sybilProtection from './sybil-protection'; import * as veBalanceOfAtNFT from './ve-balance-of-at-nft'; import * as genzeesFromSubgraph from './genzees-from-subgraph'; -import * as ginFinance from './gin-finance'; import * as positionGovernancePower from './position-governance-power'; import * as creditLp from './credit-lp'; import * as helix from './helix'; -import * as arrakisFinance from './arrakis-finance'; -import * as auraFinance from './aura-vlaura-vebal'; -import * as auraFinanceWithOverrides from './aura-vlaura-vebal-with-overrides'; -import * as auraBalanceOfVlauraVebal from './aura-balance-of-vlaura-vebal'; import * as auraBalanceOfSingleAsset from './aura-vault-balance-of-single-asset'; import * as rocketpoolNodeOperator from './rocketpool-node-operator'; import * as rocketpoolNodeOperatorv2 from './rocketpool-node-operator-v2'; @@ -368,72 +290,49 @@ import * as rocketpoolNodeOperatorv3 from './rocketpool-node-operator-v3'; import * as earthfundChildDaoStakingBalance from './earthfund-child-dao-staking-balance'; import * as unipilotVaultPilotBalance from './unipilot-vault-pilot-balance'; import * as sdBoostTWAVP from './sd-boost-twavp'; -import * as apeswap from './apeswap'; import * as fortaShares from './forta-shares'; -import * as solvVoucherClaimable from './solv-voucher-claimable'; -import * as h2o from './h2o'; -import * as dopamine from './dopamine'; import * as lrcL2SubgraphBalanceOf from './lrc-l2-subgraph-balance-of'; import * as lrcL2NftBalanceOf from './lrc-l2-nft-balance-of'; import * as lrcLPSubgraphBalanceOf from './lrc-lp-subgraph-balance-of'; -import * as lrcNFTDAOSearch from './lrc-nft-dao-search'; import * as lrcNFTmult from './lrc-nft-search-mult'; -import * as erc3525VestingVoucher from './erc3525-vesting-voucher'; -import * as rariFuse from './rari-fuse'; -import * as selfswap from './selfswap'; -import * as xrookBalanceOfUnderlyingWeighted from './xrook-balance-of-underlying-weighted'; import * as bancorPoolTokenUnderlyingBalance from './bancor-pool-token-underlying-balance'; -import * as orbsNetworkDelegation from './orbs-network-delegation'; import * as balanceOfSubgraph from './balance-of-subgraph'; import * as wagdieSubgraph from './wagdie-subgraph'; import * as erc3525FlexibleVoucher from './erc3525-flexible-voucher'; import * as erc721PairWeights from './erc721-pair-weights'; import * as harmonyStaking from './harmony-staking'; -import * as echelonCachedErc1155Decay from './echelon-cached-erc1155-decay'; import * as orcaPod from './orca-pod'; import * as metropolisPod from './metropolis-pod'; -import * as proxyProtocolErc20BalanceOf from './proxyprotocol-erc20-balance-of'; import * as proxyProtocolErc721BalanceOf from './proxyprotocol-erc721-balance-of'; -import * as proxyProtocolErc1155BalanceOf from './proxyprotocol-erc1155-balance-of'; import * as arrowVesting from './arrow-vesting'; import * as tutellusProtocol from './tutellus-protocol'; import * as fightClub from './fight-club'; import * as tproStaking from './tpro-staking'; import * as safeVested from './safe-vested'; -import * as riskharborUnderwriter from './riskharbor-underwriter'; import * as otterspaceBadges from './otterspace-badges'; import * as syntheticNounsClaimerOwner from './synthetic-nouns-with-claimer'; import * as echelonWalletPrimeAndCachedKey from './echelon-wallet-prime-and-cached-key'; import * as nation3VotesWIthDelegations from './nation3-votes-with-delegations'; import * as nation3CoopPassportWithDelegations from './nation3-passport-coop-with-delegations'; -import * as aavegotchiAgip37WapGhst from './aavegotchi-agip-37-wap-ghst'; -import * as aavegotchiAgip37GltrStakedLp from './aavegotchi-agip-37-gltr-staked-lp'; import * as posichainStaking from './posichain-staking'; import * as posichainTotalBalance from './posichain-total-balance'; import * as erc20TokensPerUni from './erc20-tokens-per-uni'; import * as bancorStandardRewardsUnderlyingBalance from './bancor-standard-rewards-underlying-balance'; import * as sdVoteBoost from './sd-vote-boost'; import * as sdVoteBoostTWAVP from './sd-vote-boost-twavp'; -import * as clqdrBalanceWithLp from './clqdr-balance-with-lp'; import * as ninechroniclesStakedAndDcc from './ninechronicles-staked-and-dcc'; import * as spreadsheet from './spreadsheet'; import * as offchainDelegation from './offchain-delegation'; -import * as dslaParametricStakingServiceCredits from './dsla-parametric-staking-service-credits'; import * as rep3Badges from './rep3-badges'; import * as marsecosystem from './marsecosystem'; import * as ari10StakingLocked from './ari10-staking-locked'; -import * as multichainSerie from './multichain-serie'; -import * as ctsiStaking from './ctsi-staking'; -import * as ctsiStakingPool from './ctsi-staking-pool'; import * as skaleDelegationWeighted from './skale-delegation-weighted'; import * as reliquary from './reliquary'; import * as acrossStakedAcx from './across-staked-acx'; -import * as vstaPoolStaking from './vsta-pool-staking'; import * as lodestarVesting from './lodestar-vesting'; import * as lodestarStakedLp from './lodestar-staked-lp'; import * as jpegdLockedJpegOf from './jpegd-locked-jpeg-of'; import * as litDaoGovernance from './lit-dao-governance'; -import * as babywealthyclub from './babywealthyclub'; import * as battleflyVGFLYAndStakedGFLY from './battlefly-vgfly-and-staked-gfly'; import * as nexonArmyNFT from './nexon-army-nft'; import * as moonbeamFreeBalance from './moonbeam-free-balance'; @@ -442,7 +341,6 @@ import * as pspInSePSP2Balance from './psp-in-sepsp2-balance'; import * as pdnBalancesAndVests from './pdn-balances-and-vests'; 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 stakedDefiBalance from './staked-defi-balance'; import * as degenzooErc721AnimalsWeighted from './degenzoo-erc721-animals-weighted'; @@ -490,27 +388,20 @@ const strategies = { 'recusal-list': recusalList, 'landdao-token-tiers': landDaoTiers, 'giveth-balancer-balance': givethBalancerBalance, - 'giveth-xdai-balance': givethXdaiBalance, 'giveth-gnosis-balance-v2': givethGnosisBalanceV2, 'nouns-rfp-power': nounsPower, - coordinape, 'anti-whale': antiWhale, balancer, - sunder, 'balancer-smart-pool': balancerSmartPool, 'lit-dao-governance': litDaoGovernance, - 'balancer-erc20-internal-balance-of': balancerErc20InternalBalanceOf, 'balance-in-vdfyn-vault': vDfynVault, 'erc20-received': erc20Received, 'contract-call': contractCall, defiplaza: defiplaza, - 'dextf-staked-in-vaults': dextfVaults, 'dfyn-staked-in-farms': dfynFarms, 'dfyn-staked-in-vaults': dfynVaults, 'dps-nft-strategy': dpsNFTStrategy, 'dps-nft-strategy-nova': dpsNFTStrategyNova, - 'eth-received': ethReceived, - 'eth-philanthropy': ethPhilanthropy, 'ens-domains-owned': ensDomainsOwned, 'ens-reverse-record': ensReverseRecord, 'ens-10k-club': ens10kClub, @@ -530,7 +421,6 @@ const strategies = { 'erc20-balance-of-quadratic-delegation': erc20BalanceOfQuadraticDelegation, 'erc20-balance-of-top-holders': erc20BalanceOfTopHolders, 'erc20-balance-of-weighted': erc20BalanceOfWeighted, - 'minto-balance-of-all': mintoBalanceAll, 'erc20-balance-of-indexed': erc20BalanceOfIndexed, 'erc20-price': erc20Price, 'ethalend-balance-of': ethalendBalanceOf, @@ -544,7 +434,6 @@ const strategies = { erc721, 'erc721-enumerable': erc721Enumerable, 'erc721-with-multiplier': erc721WithMultiplier, - 'protofi-erc721-tier-weighted': protofiErc721TierWeighted, 'erc721-with-tokenid': erc721WithTokenId, 'erc721-with-tokenid-range-weights': erc721WithTokenIdRangeWeights, 'erc721-with-tokenid-range-weights-simple': @@ -571,19 +460,8 @@ const strategies = { 'pancake-profile': pancakeProfile, synthetix, 'aelin-council': aelinCouncil, - 'synthetix-quadratic': synthetixQuadratic, - 'synthetix-quadratic_1': synthetixQuadraticOne, - 'synthetix-quadratic_2': synthetixQuadraticTwo, - synthetix_1: synthetixOne, - 'synthetix-non-quadratic': synthetixNonQuadratic, - 'synthetix-non-quadratic_1': synthetixNonQuadraticOne, - 'synthetix-non-quadratic_2': synthetixNonQuadraticTwo, ctoken, - cream, 'staked-uniswap': stakedUniswap, - esd, - 'esd-delegation': esdDelegation, - piedao, 'xdai-easy-staking': xDaiEasyStaking, 'xdai-posdao-staking': xDaiPOSDAOStaking, 'xdai-stake-holders': xDaiStakeHolders, @@ -591,7 +469,6 @@ const strategies = { defidollar, aavegotchi, 'aavegotchi-agip': aavegotchiAgip, - 'aavegotchi-agip-17': aavegotchiAgip17, mithcash, stablexswap, dittomoney, @@ -608,20 +485,16 @@ const strategies = { validation, opium, 'ocean-marketplace': ocean, - 'ocean-marketplace-v4': ocean_v4, 'the-graph-balance': theGraphBalance, 'the-graph-delegation': theGraphDelegation, 'the-graph-indexing': theGraphIndexing, whitelist, 'whitelist-weighted': whitelistWeighted, tokenlon, - rebased, 'pob-hash': pobHash, - 'total-axion-shares': totalAxionShares, 'comp-like-votes': compLikeVotes, 'governor-alpha': governorAlpha, pagination, - 'ruler-staked-token': rulerStakedToken, 'ruler-staked-lp': rulerStakedLP, xcover, 'niu-staked': niuStaked, @@ -639,7 +512,6 @@ const strategies = { 'tranche-staking-lp': trancheStakingLP, 'masterchef-pool-balance': masterchefPoolBalance, 'masterchef-pool-balance-price': masterchefPoolBalancePrice, - 'avn-balance-of-staked': avnBalanceOfStaked, api, 'api-post': apiPost, 'api-v2': apiV2, @@ -656,34 +528,23 @@ const strategies = { brightid, 'inverse-xinv': inverseXINV, modefi, - 'modefi-staking': modefiStaking, - 'iotex-balance': iotexBalance, 'iotex-staked-balance': iotexStakedBalance, 'xrc20-balance-of': xrc20BalanceOf, spookyswap, - 'squadz-power': squadzPower, glide, - 'goldfinch-voting-power': goldfinchVotingPower, - 'goldfinch-membership': goldfinchMembership, 'rnbw-balance': rnbwBalance, 'celer-sgn-delegation': celerSgnDelegation, - 'balancer-delegation': balancerDelegation, 'infinityprotocol-liquidity-pools': infinityProtocolPools, 'aave-governance-power': aaveGovernancePower, cake, aks, - tomyumswap, - 'planet-finance': planetFinance, - 'planet-finance-v2': planetFinancev2, ogn, oolongswap, 'impossible-finance': impossibleFinance, 'immutable-x': immutableX, - badgeth, 'zrx-voting-power': zrxVotingPower, 'tomb-finance': tombFinance, 'tranche-staking-slice': trancheStakingSLICE, - 'unipool-same-token': unipoolSameToken, 'unipool-univ2-lp': unipoolUniv2Lp, 'unipool-xsushi': unipoolXSushi, 'taraxa-delegation': taraxaDelegation, @@ -695,11 +556,9 @@ const strategies = { 'l2-deversifi': l2Deversifi, 'vested-deversifi': vestedDeversifi, biswap, - cronaswap, honeyswap, 'egl-vote': eglVote, 'mcn-farm': mcnFarm, - snowswap, meebitsdao, 'crucible-erc20-balance-of': crucibleERC20BalanceOf, 'erc20-token-and-lp-weighted': erc20TokenAndLpWeighted, @@ -711,40 +570,26 @@ const strategies = { 'sunrisegaming-staking': sunriseGamingStaking, 'single-staking-autocompound-balanceof': singleStakingAutoCompoundBalanceOf, 'single-staking-pools-balanceof': singleStakingPoolsBalanceOf, - 'hopr-staking': hoprStaking, - 'hopr-staking-s2': hoprStakingS2, - 'hopr-staking-by-season': hoprStakingBySeason, 'hopr-stake-and-balance-qv': hoprStakeAndBalanceQV, 'hopr-bridged-balance': hoprBridgedBalance, 'occ-stake-of': occStakeOf, - swapr, 'holds-tokens': holdsTokens, 'loot-character-guilds': lootCharacterGuilds, - cyberkongz: cyberkongz, - 'cyberkongz-v2': cyberkongzV2, - 'cyberkongz-v3': cyberkongzV3, 'comp-like-votes-inclusive': compLikeVotesInclusive, mstable, 'hashes-voting': hashesVoting, - 'hashflow-governance-power': hashflowGovernancePower, 'hashflow-vehft': hashflowVeHft, - 'pod-leader': podLeader, 'aavegotchi-wagmi-guild': aavegotchiWagmiGuild, 'polis-balance': polisBalance, - 'vault-token-lp-balance': vaultTokenLpBalance, - 'single-staking-vault-balanceof': singleStakingVaultBalanceOf, 'mutant-cats-stakers-and-holders': mutantCatsStakersAndHolders, 'razor-network-voting': razorVoting, - 'svs-staking': svsStaking, 'mcb-balance-from-graph': mcbBalanceFromGraph, - 'radicle-community-tokens': radicleCommunityTokens, - 'digitalax-mona-quickswap': digitalaxMonaQuickswap, - 'digitalax-deco-to-mona': digitalaxDecoToMona, 'digitalax-genesis-contribution': digitalaxGenesisContribution, 'digitalax-lp-stakers': digitalaxLPStakers, 'digitalax-mona-stakers-matic': digitalaxMonaStakersMatic, 'digitalax-lp-stakers-matic': digitalaxLPStakersMatic, 'colony-reputation': colonyReputation, + 'digitalax-mona-quickswap': digitalaxMonaQuickswap, 'galaxy-nft-with-score': galaxyNftWithScore, 'galxe-loyalty-points': galxeLoyaltyPoints, 'gatenet-total-staked': gatenetTotalStaked, @@ -755,37 +600,26 @@ const strategies = { coinswap, dgenesis, 'vote-power-and-share': votePowerAndShare, - 'blockzerolabs-cryptonauts': blockzerolabsCryptonauts, math, 'push-voting-power': pushVotingPower, 'staked-psp-balance': stakedPSPBalance, 'erc20-balance-of-contract-multiplier': erc20BalanceOfContractMultiplier, - agave, juicebox, 'snet-farmers': snetFarmers, 'snet-stakers': snetStakers, 'snet-liquidity-providers': snetLiquidityProviders, - 'minmax-mcn-farm': minMaxMcnFarm, 'unstackedtoadz-and-stackedtoadz-stakers': unstackedToadzAndStackedToadzStakers, - 'jade-smrt': jadeSmrt, 'ocean-dao-brightid': oceanDAOBrightID, - 'saddle-finance': saddleFinance, - 'saddle-finance-v2': saddleFinanceV2, membership: membership, 'lydia-gov-vault': lydiaGovVault, - 'xkawa-farm': xkawaFarm, 'darkforest-score': darkforestScore, 'orange-reputation-based-voting': orangeReputationBasedVoting, 'orange-reputation-nft-based-voting': orangeReputationNftBasedVoting, 'squid-dao': squidDao, 'botto-dao': bottoDao, genart, - genomesdao, 'path-balance-staked-and-locked': pathBalanceStakedAndLocked, - 'sumami-holders': sUmamiHolders, - zorro, - 'volt-voting-power': voltVotingPower, 'balancer-poolid': balancerPoolid, 'staked-balancer': stakedBalancer, 'staked-uniswap-modifiable': stakedUniswapModifiable, @@ -796,7 +630,6 @@ const strategies = { 'banksy-dao': banksyDao, spacey2025: spacey2025, 'sandman-dao': sandmanDao, - 'ethercats-founder-series': ethercatsFounderSeries, 've-balance-of-at': veBalanceOfAt, 've-ribbon': veRibbon, 've-ribbon-voting-power': veRibbonVotingPower, @@ -804,49 +637,36 @@ const strategies = { revest: revest, 'staking-claimed-unclaimed': stakingClaimedUnclaimed, 'gysr-staking-balance': gysrStakingBalance, - 'gysr-pending-rewards': gysrPendingRewards, 'gysr-lp-staking-balance': gysrLPStakingBalance, 'wanakafarm-staking': wanakafarmStaking, starsharks, 'printer-financial': printerFinancial, 'ethercats-founders-series': ethercatsFoundersSeries, potion, - 'safety-module-bpt-power': safetyModuleBptPower, 'minotaur-money': MinotaurMoney, 'conv-finance': convFinance, 'sd-boost': sdBoost, - 'capitaldao-staking': capitalDaoStaking, - 'erc20-rebase-wrapper': erc20RebaseWrapper, 'wanakafarm-land-ingame': wanakafarmLandIngame, - 'meebitsdao-delegation': meebitsDaoDelegation, 'starcatchers-top-window': starcatchersTopWindow, gno: gno, 'gno-vote-weight': gno, - 'uma-voting': umaVoting, 'masterchef-pool-balance-no-rewarddebt': masterchefPoolBalanceNoRewarddebt, 'proof-of-humanity': proofOfHumanity, 'sybil-protection': sybilProtection, 'samurailegends-generals-balance': samuraiLegendsGeneralsBalance, 'dogs-unchained': dogsUnchained, - 'stakedao-governance-update': stakeDAOGovernanceUpdate, 'umami-voting': umamiVoting, 'liquidity-token-provide': liquidityTokenProvide, 'gamium-voting': gamiumVoting, 'citydao-square-root': citydaoSquareRoot, 'rowdy-roos': rowdyRoos, hedgey, - 'hedgey-multi': hedgeyMulti, 'hedgey-delegate': hedgeyDelegate, 've-balance-of-at-nft': veBalanceOfAtNFT, 'genzees-from-subgraph': genzeesFromSubgraph, - 'gin-finance': ginFinance, 'position-governance-power': positionGovernancePower, 'credit-lp': creditLp, helix, - 'arrakis-finance': arrakisFinance, - 'aura-vlaura-vebal': auraFinance, - 'aura-vlaura-vebal-with-overrides': auraFinanceWithOverrides, - 'aura-balance-of-vlaura-vebal': auraBalanceOfVlauraVebal, 'aura-vault-balance-of-single-asset': auraBalanceOfSingleAsset, 'rocketpool-node-operator': rocketpoolNodeOperator, 'rocketpool-node-operator-v2': rocketpoolNodeOperatorv2, @@ -854,34 +674,21 @@ const strategies = { 'earthfund-child-dao-staking-balance': earthfundChildDaoStakingBalance, 'sd-boost-twavp': sdBoostTWAVP, 'unipilot-vault-pilot-balance': unipilotVaultPilotBalance, - 'solv-voucher-claimable': solvVoucherClaimable, 'balance-of-with-linear-vesting-power': balanceOfWithLinearVestingPower, 'linear-vesting-power': linearVestingPower, - apeswap, - h2o, - dopamine, 'lrc-l2-subgraph-balance-of': lrcL2SubgraphBalanceOf, 'lrc-l2-nft-balance-of': lrcL2NftBalanceOf, 'lrc-lp-subgraph-balance-of': lrcLPSubgraphBalanceOf, - 'lrc-nft-dao-search': lrcNFTDAOSearch, 'lrc-nft-search-mult': lrcNFTmult, - 'rari-fuse': rariFuse, 'bancor-pool-token-underlying-balance': bancorPoolTokenUnderlyingBalance, - selfswap, - 'erc3525-vesting-voucher': erc3525VestingVoucher, - 'xrook-balance-of-underlying-weighted': xrookBalanceOfUnderlyingWeighted, - 'orbs-network-delegation': orbsNetworkDelegation, 'balance-of-subgraph': balanceOfSubgraph, 'wagdie-subgraph': wagdieSubgraph, 'erc721-pair-weights': erc721PairWeights, 'harmony-staking': harmonyStaking, - 'echelon-cached-erc1155-decay': echelonCachedErc1155Decay, 'erc3525-flexible-voucher': erc3525FlexibleVoucher, 'orca-pod': orcaPod, 'metropolis-pod': metropolisPod, - 'proxyprotocol-erc20-balance-of': proxyProtocolErc20BalanceOf, 'proxyprotocol-erc721-balance-of': proxyProtocolErc721BalanceOf, - 'proxyprotocol-erc1155-balance-of': proxyProtocolErc1155BalanceOf, 'posichain-staking': posichainStaking, 'posichain-total-balance': posichainTotalBalance, 'arrow-vesting': arrowVesting, @@ -889,38 +696,27 @@ const strategies = { 'fight-club': fightClub, 'tpro-staking': tproStaking, 'safe-vested': safeVested, - 'riskharbor-underwriter': riskharborUnderwriter, 'otterspace-badges': otterspaceBadges, 'synthetic-nouns-with-claimer': syntheticNounsClaimerOwner, 'echelon-wallet-prime-and-cached-key': echelonWalletPrimeAndCachedKey, 'nation3-votes-with-delegations': nation3VotesWIthDelegations, 'nation3-passport-coop-with-delegations': nation3CoopPassportWithDelegations, - 'aavegotchi-agip-37-wap-ghst': aavegotchiAgip37WapGhst, - 'aavegotchi-agip-37-gltr-staked-lp': aavegotchiAgip37GltrStakedLp, 'erc20-tokens-per-uni': erc20TokensPerUni, 'bancor-standard-rewards-underlying-balance': bancorStandardRewardsUnderlyingBalance, 'sd-vote-boost': sdVoteBoost, 'sd-vote-boost-twavp': sdVoteBoostTWAVP, - 'clqdr-balance-with-lp': clqdrBalanceWithLp, spreadsheet, 'offchain-delegation': offchainDelegation, 'ninechronicles-staked-and-dcc': ninechroniclesStakedAndDcc, - 'dsla-parametric-staking-service-credits': - dslaParametricStakingServiceCredits, 'rep3-badges': rep3Badges, marsecosystem, 'ari10-staking-locked': ari10StakingLocked, - 'multichain-serie': multichainSerie, - 'ctsi-staking': ctsiStaking, - 'ctsi-staking-pool': ctsiStakingPool, 'skale-delegation-weighted': skaleDelegationWeighted, reliquary, - 'vsta-pool-staking': vstaPoolStaking, 'jpegd-locked-jpeg-of': jpegdLockedJpegOf, 'lodestar-vesting': lodestarVesting, 'lodestar-staked-lp': lodestarStakedLp, - babywealthyclub, 'battlefly-vgfly-and-staked-gfly': battleflyVGFLYAndStakedGFLY, 'nexon-army-nft': nexonArmyNFT, 'moonbeam-free-balance': moonbeamFreeBalance, @@ -928,8 +724,6 @@ const strategies = { 'psp-in-sepsp2-balance': pspInSePSP2Balance, 'pdn-balances-and-vests': pdnBalancesAndVests, 'lqty-proxy-stakers': lqtyProxyStakers, - 'echelon-wallet-prime-and-cached-key-gated': - echelonWalletPrimeAndCachedKeyGated, 'rdnt-capital-voting': rdntCapitalVoting, 'staked-defi-balance': stakedDefiBalance, 'degenzoo-erc721-animals-weighted': degenzooErc721AnimalsWeighted, diff --git a/src/strategies/iotex-balance/examples.json b/src/strategies/iotex-balance/examples.json deleted file mode 100644 index 7fa6bbe80..000000000 --- a/src/strategies/iotex-balance/examples.json +++ /dev/null @@ -1,19 +0,0 @@ -[ - { - "name": "iotex balance query", - "strategy": { - "name": "iotex-balance", - "params": { - "address": "0x1904BFcb93EdC9BF961Eead2e5c0de81dCc1D37D", - "symbol": "IOTX", - "decimals": 18 - } - }, - "network": "4689", - "addresses": [ - "0x515c2c35c3ec82c30affc5ec06da9a30ef008741", - "0xa00744882684c3e4747faefd68d283ea44099d03" - ], - "snapshot": 13000000 - } -] diff --git a/src/strategies/iotex-balance/index.ts b/src/strategies/iotex-balance/index.ts deleted file mode 100644 index 0ecf21b25..000000000 --- a/src/strategies/iotex-balance/index.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { strategy as EthBalanceStrategy } from '../eth-balance'; -import fetch from 'cross-fetch'; -interface ApiReturn { - balance: string[]; -} - -export const author = 'iotexproject'; -export const version = '0.0.2'; - -const testNetUrl = 'https://analyser-api.testnet.iotex.io'; -const mainNetUrl = 'https://analyser-api.iotex.io'; - -function getUrl(network) { - return network == 4689 ? mainNetUrl : testNetUrl; -} - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - if (blockTag == 'latest') - return EthBalanceStrategy( - space, - network, - provider, - addresses, - options, - snapshot - ); - - const apiUrl = getUrl(network); - const response = await fetch( - `${apiUrl}/api.AccountService.IotexBalanceByHeight`, - { - method: 'POST', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - address: addresses, - height: snapshot - }) - } - ); - - const ret: ApiReturn = await response.json(); - return Object.fromEntries( - ret.balance.map((v, i) => [addresses[i], parseFloat(v)]) - ); -} diff --git a/src/strategies/jade-smrt/README.md b/src/strategies/jade-smrt/README.md deleted file mode 100644 index 0126da0f3..000000000 --- a/src/strategies/jade-smrt/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# jade-smrt - -This is a strategy for counting: -- JADE and sJADE token held on BSC -- SMRT and SMRTR token held on Avalanche c-chain (including the ones in -the SMRTR/AVAX pool), which are then weighted by the price_SMRT/price_JADE -and price_SMRTR/price_JADE \ No newline at end of file diff --git a/src/strategies/jade-smrt/examples.json b/src/strategies/jade-smrt/examples.json deleted file mode 100644 index 87af5aa7a..000000000 --- a/src/strategies/jade-smrt/examples.json +++ /dev/null @@ -1,73 +0,0 @@ -[ - { - "name": "Jade-Smrt multichain voting", - "strategy": { - "name": "jade-smrt", - "params": { - "symbol": "jade-smrt", - - "JADE": { - "network": "56", - "address": "0x7ad7242A99F21aa543F9650A56D141C57e4F6081", - "decimals": 9 - }, - - "SJADE": { - "network": "56", - "address": "0x94CEA04C51E7d3EC0a4A97Ac0C3B3c9254c2aD41", - "decimals": 9 - }, - - "JADELP": { - "network": "56", - "address": "0x46503d91D7a41FCbDC250E84ceE9D457d082D7b4", - "decimals": 18 - }, - - "SMRTR": { - "network": "43114", - "address": "0x6D923f688C7FF287dc3A5943CAeefc994F97b290", - "decimals": 18 - }, - - "SMRT": { - "network": "43114", - "address": "0xCC2f1d827b18321254223dF4e84dE399D9Ff116c", - "decimals": 18 - }, - - "SMRTLP": { - "network": "43114", - "address": "0xf070843Ba9ed0ab85B0d15f9E8D67A5A8E073254", - "decimals": 18 - }, - - "SMRTRLP": { - "network": "43114", - "address": "0x7b7617c7b2236d7871741783cae8bcc222c2e05d", - "decimals": 18 - }, - - "avaxGraph": "https://api.thegraph.com/subgraphs/name/elkfinance/avax-blocks", - - "startBlocks": { - "56": 12858840, - "43114": 7639389 - } - } - }, - - "network": "56", - "addresses": [ - "0x422Cb45F4DCB3f798B53835F8671288D424d881F", - "0x0E916175eFa7633b5703cb9c50A99602e6c65530", - "0xbDe951E26aae4F39e20628724f58293A4E6457D4", - "0xA932857fA2Dbf18A8EeB50e359E99EDD40E27F7f", - "0xe0d7069685AF2F940D60685d93673Ee1141473C4", - "0xB0354be8EDD26d154dCf10BE3c47C88Ee6150DDB", - "0x20c204adad9C991ED35ce2778e705439227EA406", - "0x7AaCE7fb8CD4CEC3588F4a0b0A0DBdd470b20FbD" - ], - "snapshot": 13350104 - } -] diff --git a/src/strategies/jade-smrt/index.ts b/src/strategies/jade-smrt/index.ts deleted file mode 100644 index 8596b4c53..000000000 --- a/src/strategies/jade-smrt/index.ts +++ /dev/null @@ -1,170 +0,0 @@ -import { subgraphRequest } from '../../utils'; -import { Multicaller, getProvider } from '../../utils'; -import { formatUnits } from '@ethersproject/units'; - -export const author = 'drgorillamd'; -export const version = '1.0.0'; - -const abi = [ - 'function balanceOf(address account) external view returns (uint256)', - 'function totalSupply() external view returns (uint256)' -]; - -const BUSD = '0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56'; -const WAVAX = '0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7'; -const USDC = '0xA7D7079b0FEaD91F3e65f86E8915Cb59c1a4C664'; -const WAVAXUSDC = '0xA389f9430876455C36478DeEa9769B7Ca4E3DDB1'; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - const block = await provider.getBlock(blockTag); - const timestamp = block.timestamp; - const avaxBlockTag = await getAvaxBlockTag(timestamp, options); - - // BSC balances: - const multiBsc = new Multicaller(network, provider, abi, { blockTag }); - addresses.forEach((address: string) => { - multiBsc.call(address + '-jade', options.JADE.address, 'balanceOf', [ - address - ]); - multiBsc.call(address + '-sjade', options.SJADE.address, 'balanceOf', [ - address - ]); - }); - - // BUSD per JADE spot - pick CAREFULLY the block height, it is NOT a twap - // as a twap would require 2 additionnal multicalls (and therefore be above the Snapshot 5 calls limit) - multiBsc.call('jadeLPBalance', options.JADE.address, 'balanceOf', [ - options.JADELP.address - ]); // jade balance in jade-busd pool - multiBsc.call('busdLPBalance', BUSD, 'balanceOf', [options.JADELP.address]); // BUSD balance in jade-busd pool - - // Avax balances: - const multiAvax = new Multicaller('43114', getProvider('43114'), abi, { - blockTag: avaxBlockTag - }); - addresses.forEach((address: string) => { - multiAvax.call(address + '-smrt', options.SMRT.address, 'balanceOf', [ - address - ]); - multiAvax.call(address + '-smrtR', options.SMRTR.address, 'balanceOf', [ - address - ]); - multiAvax.call(address + '-smrtRLp', options.SMRTRLP.address, 'balanceOf', [ - address - ]); - }); - - // WAVAX per SMRT spot - multiAvax.call('smrtLPBalance', options.SMRT.address, 'balanceOf', [ - options.SMRTLP.address - ]); // SMRT in SMRT/WAVAX pool balance - multiAvax.call('wavaxSmrtLPBalance', WAVAX, 'balanceOf', [ - options.SMRTLP.address - ]); // wavax in SMRT/WAVAX pool balance - - // WAVAX per SMRTR spot - multiAvax.call('smrtRLPBalance', options.SMRTR.address, 'balanceOf', [ - options.SMRTRLP.address - ]); - multiAvax.call('wavaxSmrtRLPBalance', WAVAX, 'balanceOf', [ - options.SMRTRLP.address - ]); // SMRT SMRT/WAVAX pool balance - - // USD per WAVAX spot - multiAvax.call('UsdLPBalance', USDC, 'balanceOf', [WAVAXUSDC]); // SMRT SMRT/WAVAX pool balance - multiAvax.call('wavaxUsdLPBalance', WAVAX, 'balanceOf', [WAVAXUSDC]); // SMRT SMRT/WAVAX pool balance - - // Avax SMRTR/WAVAX pool: LP token total supply - multiAvax.call('smrtRLPSupply', options.SMRTRLP.address, 'totalSupply', []); - - let resBsc: Record | number = { 0: 0 }, - resAvax: - | [number, number, number, Record, Record] - | number = [0, 0, 0, { 0: 0 }, { 0: 0 }]; - - [resBsc, resAvax] = await Promise.all([ - multiBsc.execute(), - multiAvax.execute() - ]); - - // All prices in USDish (BUSD or USDC.e) - const jadePrice: number = - parseFloat(formatUnits(resBsc['busdLPBalance'], 18)) / - parseFloat(formatUnits(resBsc['jadeLPBalance'], 9)); - const wavaxPrice: number = - parseFloat(formatUnits(resAvax['UsdLPBalance'], 6)) / - parseFloat(formatUnits(resAvax['wavaxUsdLPBalance'], 18)); - const smrtPrice: number = - wavaxPrice / - (parseFloat(formatUnits(resAvax['smrtLPBalance'], 18)) / - parseFloat(formatUnits(resAvax['wavaxSmrtLPBalance'], 18))); - const smrtRPrice: number = - wavaxPrice / - (parseFloat(formatUnits(resAvax['smrtRLPBalance'], 18)) / - parseFloat(formatUnits(resAvax['wavaxSmrtRLPBalance'], 18))); - const smrtRLPBalance: number = parseFloat( - formatUnits(resAvax['smrtRLPBalance'], 18) - ); - const smrtRLPSupply: number = parseFloat( - formatUnits(resAvax['smrtRLPSupply'], 18) - ); - - return Object.fromEntries( - addresses.map((adr: string) => { - let bal = parseFloat( - formatUnits(resBsc[adr + '-jade'], options.JADE.decimals) - ); - bal += parseFloat( - formatUnits(resBsc[adr + '-sjade'], options.SJADE.decimals) - ); - - // SMRT balance * SMRT price/JADE price: - const parsedSmrt = parseFloat( - formatUnits(resAvax[adr + '-smrt'], options.SMRT.decimals) - ); - bal += (parsedSmrt * smrtPrice) / jadePrice; - - // SMRTR balance * SMRTR price/JADE price: - const parsedSrmtr = parseFloat( - formatUnits(resAvax[adr + '-smrtR'], options.SMRTR.decimals) - ); - bal += (parsedSrmtr * smrtRPrice) / jadePrice; - - // LP token held * smrtr pool balance / LP token total supply: - const LPHeld = - (parseFloat(formatUnits(resAvax[adr + '-smrtRLp'], 18)) * - smrtRLPBalance) / - smrtRLPSupply; - bal += (LPHeld * smrtRPrice) / jadePrice; - - return [adr, bal]; - }) - ); -} - -async function getAvaxBlockTag(timestamp: number, options): Promise { - const query = { - blocks: { - __args: { - first: 1, - orderBy: 'number', - orderDirection: 'desc', - where: { - timestamp_lte: timestamp - } - }, - number: true, - timestamp: true - } - }; - const data = await subgraphRequest(options.avaxGraph, query); - return Number(data.blocks[0].number); -} diff --git a/src/strategies/lrc-nft-dao-search/README.md b/src/strategies/lrc-nft-dao-search/README.md deleted file mode 100644 index f7112f189..000000000 --- a/src/strategies/lrc-nft-dao-search/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# lrc-nft-dao-search - -This is an improvement of karamorf's lrc-l2-nft-balance of Snapshot voting strategy by raecaug(system32). -The extended functionality allows space owners to(alongside all of lrc-l2-nft-balance-of's functionality) specify individual nft ids within a token contract with the nft_ids option. -This option is not needed, and if excluded the query will search for all nfts minted under that token contract address. -No other behavior has been changed. - - -Strategy to read account balances for NFTs (72 or 1155) from LoopringV2 subgraph. Assumes we only want tokens minted by a specific account id. - -Here is an example of parameters: - -```json -{ - "graph": "https://api.thegraph.com/subgraphs/name/juanmardefago/loopring36", - "minter_account_id": "74447", - "tokens": ["token (Collection contract address) to include"], - "nft_ids": ["nftIDs, unique to every nft, even those under the same token contract"], - "blacklisted_account_ids": ["38482"], - "blacklisted_nft_ids": ["... nft id's to exclude ..."] -} -``` - -Use explorer.loopring.io to look up addresses and find account id's. - -Account id `38482` maps to `0x000000000000000000000000000000000000dead` and is used for burning tokens. - -to note: either the `minter_account_id` or the `tokens` parameter must be provided for this query to work. You do not need to specify both, just one of them. diff --git a/src/strategies/lrc-nft-dao-search/examples.json b/src/strategies/lrc-nft-dao-search/examples.json deleted file mode 100644 index a944db039..000000000 --- a/src/strategies/lrc-nft-dao-search/examples.json +++ /dev/null @@ -1,21 +0,0 @@ -[ - { - "name": "LoopringDAOSearch", - "strategy": { - "name": "lrc-nft-dao-search", - "params": { - "graph": "https://api.thegraph.com/subgraphs/name/juanmardefago/loopring36", - "minter_account_id": "157510", - "tokens": ["0xb6d91e38e4ac53c9f8952c6c6b1c7aee66c8b6f0"], - "nft_ids": [ - "0x1e31297dd163ca44a5fad74de4ffbebf1ba11d46e1b448b0e105449d827fb264" - ], - "blacklisted_account_ids": [""], - "blacklisted_nft_ids": [""] - } - }, - "network": "1", - "addresses": ["0xeE253D3fCC30787a1E58570E355010d0b9C33B60"], - "snapshot": 15677787 - } -] diff --git a/src/strategies/lrc-nft-dao-search/index.ts b/src/strategies/lrc-nft-dao-search/index.ts deleted file mode 100644 index a18cba427..000000000 --- a/src/strategies/lrc-nft-dao-search/index.ts +++ /dev/null @@ -1,126 +0,0 @@ -// Original code by Karamorf, upgraded by Raecaug(system32) -// Allows querys of Loopring L2 accounts & balances by specifying a nft minter, token contract address(and optionally specifying individual ids to white/blacklist) - -import { subgraphRequest } from '../../utils'; -export const author = 'raecaug'; -export const version = '0.1.2'; - -const LIMIT = 1000; - -function makeQuery( - snapshot, // This is an Ethereum block # or defaults to 'latest' - minter, // This is referred to as account # or account id on the Loopring L2 block explorer - tokens, // NFT collection contract addresses, also referred to as 'token address' - skip, // Used to skip response lines in requests - blacklisted_account_ids, // Ditto properties of 'minter' - blacklisted_nft_ids, // This is the nft id, which is unique for every nft ever minted, allows distinction between nfts in a collection at the chain level - nft_ids // Ditto properties of blacklisted version -) { - const query: any = { - // Query constructor, builds request with params from snapshot space settings - accountNFTSlots: { - __args: { - where: { - nft_: { - id_not_in: blacklisted_nft_ids, // Excluding blacklisted nft ids - nftID_in: nft_ids // Including uniquely specified nft ids - }, - account_not_in: blacklisted_account_ids // Excluding blacklisted account ids - }, - first: LIMIT, - skip: skip - }, - account: { address: true }, - balance: true - } - }; - - if (minter && minter !== '') { - //Check to ensure minter id is specified and not blank - query.accountNFTSlots.__args.where.nft_.minter = minter; - } - - if (tokens && tokens.length > 0) { - //Check to ensure at least 1 token to search for is specified - query.accountNFTSlots.__args.where.nft_.token_in = tokens; - } - - if (snapshot !== 'latest') { - // If the snapshot date is manually specified, overwrite the 'latest' block, strict inequality check operand used - query.accountNFTSlots.__args = { - ...query.accountNFTSlots.__args, - block: { - number: snapshot - } - }; - } - - return query; -} - -export async function strategy( // *****Logical execution begins here; args passed in by Snapshot settings***** - space, - network, - provider, - addresses, - options, - snapshot -): Promise> { - let blacklisted_account_ids = options.blacklisted_account_ids; - let blacklisted_nft_ids = options.blacklisted_nft_ids; - - let nft_ids = options.nft_ids; // Unique NFT ids, distinguishable from 1155 token contracts - - const balances = {}; // Initialization - let skip = 0; - let response_size = 0; - - if (!blacklisted_account_ids || blacklisted_account_ids.length === 0) { - // If no blacklisted accts specified, set to empty - blacklisted_account_ids = ['']; - } - - if (!blacklisted_nft_ids || blacklisted_nft_ids.length === 0) { - // If no unique nft_ids specified, set to empty - blacklisted_nft_ids = ['']; - } - - if (!nft_ids || nft_ids.length === 0) { - // If no unique nft_ids specified, set to empty - nft_ids = ['']; - } - - do { - // Transmit query and await results - const response = await subgraphRequest( - // Constructs response variable from subgraph query function - options.graph, // Parameter 1, options specified - makeQuery( - // Query constructor(defined above) called, results are the second parameter - snapshot, - options.minter_account_id, - options.tokens, - skip, - blacklisted_account_ids, - blacklisted_nft_ids, - nft_ids - ) - ); - - response.accountNFTSlots.forEach((slot) => { - // Checking against each accountNFTSlot element - if (!balances.hasOwnProperty(slot.account.address)) { - balances[slot.account.address] = 0; // If nothing returned, set this accounts balance to 0 - } - balances[slot.account.address] += parseInt(slot.balance); // Otherwise, a bigint is returned, parse it and store in balances array - }); - response_size = response.accountNFTSlots.length; // Value is set to 0 on loop entry, updated here, will break loop for anything other than 1000 - skip += response_size; - } while (response_size == LIMIT); - - const scores = Object.fromEntries( - addresses.map((address) => [address, balances[address.toLowerCase()]]) // Map returned addresses and balances as scores array - ); - - return scores; // Returns addresses and balances to Snapshot -} diff --git a/src/strategies/minmax-mcn-farm/README.md b/src/strategies/minmax-mcn-farm/README.md deleted file mode 100644 index f48af959d..000000000 --- a/src/strategies/minmax-mcn-farm/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# minmax-mcn-farm - -This strategy returns the total amount of user-owned MAX tokens rewards, including the token in wallet, staked token and pending rewards held by the farm contract. - -## Examples - -Rhe space config will look like this: - -```JSON -{ - "tokenAddress": "0xe45d95a66cfF6aB5E9b796CF5A36F0669AF3Ec98", - "lpAddress": "0x88137f2a610693e975b17d7cf940bf014cf0f325", - "stakingAddress": "0xf3a640eeb661cdf78f1817314123e8bbd12e191f" -} -``` diff --git a/src/strategies/minmax-mcn-farm/examples.json b/src/strategies/minmax-mcn-farm/examples.json deleted file mode 100644 index 6c46be2f7..000000000 --- a/src/strategies/minmax-mcn-farm/examples.json +++ /dev/null @@ -1,24 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "minmax-mcn-farm", - "params": { - "tokenAddress": "0xe45d95a66cfF6aB5E9b796CF5A36F0669AF3Ec98", - "symbol": "MAX", - "decimals": "18", - "lpAddress": "0x88137f2a610693e975b17d7cf940bf014cf0f325", - "stakingAddress": "0xf3a640eeb661cdf78f1817314123e8bbd12e191f" - } - }, - "network": "4689", - "addresses": [ - "0x207dCfFf0bF605e892d7b036617FfF1A9B7a3038", - "0x1c4922142585881d24a0374a26368224974ba730", - "0x9125b2457479964540a0557e3b010681317b635e", - "0x226f272a2635523b9d50a8d2b481ced204b4d9c2", - "0x2a4aa0c965e7903b230036169803d00c886c0d11" - ], - "snapshot": 14629883 - } -] diff --git a/src/strategies/minmax-mcn-farm/index.ts b/src/strategies/minmax-mcn-farm/index.ts deleted file mode 100644 index 420da0604..000000000 --- a/src/strategies/minmax-mcn-farm/index.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { multicall } from '../../utils'; - -export const author = 'LeifuChen'; -export const version = '0.1.0'; - -const FARM_ADDRESS = '0xf3a640eeb661cdf78f1817314123e8bbd12e191f'; -const MAX_ADDRESS = '0xe45d95a66cff6ab5e9b796cf5a36f0669af3ec98'; -const MAX_LP_ADDRESS = '0x88137f2a610693e975b17d7cf940bf014cf0f325'; - -const abi = [ - 'function totalSupply() view returns (uint256)', - 'function balanceOf(address account) view returns (uint256)', - 'function getUser(address _lpToken, address _account) view returns (tuple(uint256 amount, uint256[] rewardsWriteoffs) user, uint256[] rewards)' -]; - -export async function strategy( - space, - network, - provider, - addresses: string[], - options, - snapshot -) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - const lpAddress = options.lpAddress || MAX_LP_ADDRESS; - const tokenAddress = options.tokenAddress || MAX_ADDRESS; - const farmAddress = options.stakingAddress || FARM_ADDRESS; - const pools = [ - '0x88137F2a610693E975b17D7Cf940BF014CF0f325', // BUSD_MAX => MAX token in LP - '0xC35257624b01932e521bc5D9dc07e4F9ed21ED28', // minmaxB3 - '0x14D66e676b978255C719B2771c657ACc418Bb9Fa', // minmaxE4 - '0xdFf5DC9d8dAC189324452D54e2df19d2Bdba78CE', // minmaxM3 - '0x425C2c686f12d61ECD4dFD1170214E3BEFEbBe33' // minmaxUSDT - ]; - - const flatten = (arr) => [].concat.apply([], arr); - const product = (...sets) => { - return sets.reduce( - (acc, set) => flatten(acc.map((x) => set.map((y) => [...x, y]))), - [[]] - ); - }; - const params = product(pools, addresses); - const res = await multicall( - network, - provider, - abi, - [ - [lpAddress, 'totalSupply', []], - [tokenAddress, 'balanceOf', [lpAddress]] - ] - .concat(addresses.map((p) => [lpAddress, 'balanceOf', [p]])) - .concat(addresses.map((p) => [tokenAddress, 'balanceOf', [p]])) - .concat(params.map((p) => [farmAddress, 'getUser', p])), - { blockTag } - ); - - const values = {}; - Object.values(addresses).forEach((address: string) => (values[address] = 0)); - - // MAX token in user's wallet - const walletInfo = res.slice(2 + addresses.length, 2 + addresses.length * 2); - for (let i = 0; i < addresses.length; i++) { - values[addresses[i]] += walletInfo[i] / 10 ** 18; - } - - // MAX token in pendingRewards - const poolInfo = res.slice(2 + addresses.length * 2); - poolInfo.forEach(({ 1: reward }, i) => { - values[addresses[i % addresses.length]] += reward / 10 ** 18; - }); - - // MAX token in MAX_BUSD LP (MCN Farm) - const [totalSupply] = res[0]; - const [tokenBalanceInLP] = res[1]; - const tokensPerLP = tokenBalanceInLP / totalSupply; - const lpInfo = res.slice(2 + addresses.length * 2, 2 + addresses.length * 3); - lpInfo.forEach(({ 0: userInfo }, i) => { - values[addresses[i % addresses.length]] += - (userInfo[0] / 10 ** 18) * tokensPerLP; - }); - - // MAX token in MAX_BUSD LP (User Wallet) - const lpInWallet = res.slice(2, 2 + addresses.length); - for (let i = 0; i < addresses.length; i++) { - values[addresses[i]] += (lpInWallet[i] / 10 ** 18) * tokensPerLP; - } - - return values; -} diff --git a/src/strategies/minto-balance-of-all/README.md b/src/strategies/minto-balance-of-all/README.md deleted file mode 100644 index be2fd8de1..000000000 --- a/src/strategies/minto-balance-of-all/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# minto-balance-of-all - -This is the minto strategy, it returns sum the balances of the voters from minto erc20, minto staking, minto staking. - -Here is an example of parameters: - -```json -{ - "address": "0x410a56541bD912F9B60943fcB344f1E3D6F09567", - "symbol": "BTCMT", - "decimals": 18, - "stakingAddress": "0x78ae303182FCA96A4629A78Ee13235e6525EbcFb", - "autoStakingAddress": "0xE751ffdC2a684EEbcaB9Dc95fEe05c083F963Bf1" -} -``` diff --git a/src/strategies/minto-balance-of-all/examples.json b/src/strategies/minto-balance-of-all/examples.json deleted file mode 100644 index 2d63f741f..000000000 --- a/src/strategies/minto-balance-of-all/examples.json +++ /dev/null @@ -1,36 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "minto-balance-of-all", - "params": { - "address": "0x410a56541bD912F9B60943fcB344f1E3D6F09567", - "symbol": "BTCMT", - "decimals": 18, - "stakingAddress": "0x78ae303182FCA96A4629A78Ee13235e6525EbcFb", - "autoStakingAddress": "0xE751ffdC2a684EEbcaB9Dc95fEe05c083F963Bf1" - } - }, - "network": "128", - "addresses": [ - "0x05903a958710ec752dd4a25dd3157ccee9d6c92e", - "0x03bb74c32acb025effab4d31e579d3751363c216", - "0x0369a66d5d25734a9aef4689546a809888fe5bfe", - "0x0743a7eb79cf4b478ba0bba22bdf2f11bc8ad5de", - "0x00ce049d0624a087473a4bd5078ac90ad25175e8", - "0x01f3a3962668df7799429ae827df59bc32a5d761", - "0x020ce48bb83cd6cb1483149ed7a6d2bca4526c84", - "0x0235ac7285d4ad1a5261904539e4862c13a830af", - "0x0369a66d5d25734a9aef4689546a809888fe5bfe", - "0x03bb74c32acb025effab4d31e579d3751363c216", - "0x05903a958710ec752dd4a25dd3157ccee9d6c92e", - "0x0636b47164ea3099c6fc39c52a3f4b7b7ecaa03b", - "0x0686b62cd088715dcb690e6514aaeca229bbac07", - "0x34db5451844371226c7737137f9cdf30638733f2", - "0xe2096f4a5d1ea4501e27ffafc1e910e35a2c200a", - "0xf4ad32a268d49f72e7bd1b89e2a63d89ac5e8b62", - "0x0dC14192333A736a3caDfBD3f9f883106584614A" - ], - "snapshot": 12883023 - } -] diff --git a/src/strategies/minto-balance-of-all/index.ts b/src/strategies/minto-balance-of-all/index.ts deleted file mode 100644 index 009f367b5..000000000 --- a/src/strategies/minto-balance-of-all/index.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { formatUnits } from '@ethersproject/units'; -import { Multicaller } from '../../utils'; - -export const author = 'btcmt-minto'; -export const version = '0.1.0'; - -const abi = [ - 'function balanceOfSum(address account) external view returns (uint256)' -]; - -const stakingAbi = [ - 'function userStakes(address account) external view returns (uint256, uint256, uint256, uint256, uint256, uint256, uint256)' -]; - -const autoStakingAbi = [ - 'function userStake(address account) external view returns (uint256, uint256, uint256)' -]; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -): Promise> { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - const multi = new Multicaller(network, provider, abi, { blockTag }); - - const multiStaking = new Multicaller(network, provider, stakingAbi, { - blockTag - }); - const multiAutoStaking = new Multicaller(network, provider, autoStakingAbi, { - blockTag - }); - - addresses.forEach((address) => { - multi.call(address, options.address, 'balanceOfSum', [address]); - multiStaking.call(address, options.stakingAddress, 'userStakes', [address]); - multiAutoStaking.call(address, options.autoStakingAddress, 'userStake', [ - address - ]); - }); - - const [result, resultStaking, resultAutoStaking] = await Promise.all([ - multi.execute(), - multiStaking.execute(), - multiAutoStaking.execute() - ]); - - return Object.fromEntries( - addresses.map((address) => { - const sum = - parseFloat(formatUnits(result[address], options.decimals)) + - parseFloat(formatUnits(resultStaking[address][1], options.decimals)) + - parseFloat( - formatUnits(resultAutoStaking[address][0], options.decimals) - ); - return [address, sum]; - }) - ); -} diff --git a/src/strategies/multichain-serie/examples.json b/src/strategies/multichain-serie/examples.json deleted file mode 100644 index 70aa3639e..000000000 --- a/src/strategies/multichain-serie/examples.json +++ /dev/null @@ -1,36 +0,0 @@ -[ - { - "name": "Multichain serie", - "strategy": { - "name": "multichain-serie", - "params": { - "symbol": "MULTI", - "strategies": [ - { - "name": "erc20-balance-of", - "network": "137", - "params": { - "address": "0xB9638272aD6998708de56BBC0A290a1dE534a578", - "decimals": 18 - } - }, - { - "name": "erc20-balance-of", - "network": "56", - "params": { - "address": "0x0e37d70b51ffa2b98b4d34a5712c5291115464e3", - "decimals": 18 - } - } - ] - } - }, - "network": "1", - "addresses": [ - "0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5", - "0x9feab70f3c4a944b97b7565bac4991df5b7a69ff", - "0xaca39b187352d9805deced6e73a3d72abf86e7a0" - ], - "snapshot": 13035566 - } -] diff --git a/src/strategies/multichain-serie/index.ts b/src/strategies/multichain-serie/index.ts deleted file mode 100644 index 98b3d9982..000000000 --- a/src/strategies/multichain-serie/index.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { getProvider, getSnapshots } from '../../utils'; -import strategies from '..'; - -export const author = 'kesar'; -export const version = '1.1.0'; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const results: any = []; - const blocks = await getSnapshots( - network, - snapshot, - provider, - options.strategies.map((s) => s.network || network) - ); - - for (const strategy of options.strategies) { - // If snapshot is taken before a network is activated then ignore its strategies - if ( - options.startBlocks && - blocks[strategy.network] < options.startBlocks[strategy.network] - ) { - continue; - } - - results.push( - await strategies[strategy.name].strategy( - space, - strategy.network, - getProvider(strategy.network), - addresses, - strategy.params, - blocks[strategy.network] - ) - ); - } - - return results.reduce((finalResults: any, strategyResult: any) => { - for (const [address, value] of Object.entries(strategyResult)) { - if (!finalResults[address]) { - finalResults[address] = 0; - } - finalResults[address] += value; - } - return finalResults; - }, {}); -} diff --git a/src/strategies/ocean-marketplace-v4/README.md b/src/strategies/ocean-marketplace-v4/README.md deleted file mode 100644 index 71121343b..000000000 --- a/src/strategies/ocean-marketplace-v4/README.md +++ /dev/null @@ -1,51 +0,0 @@ -# Ocean marketplace v4 - -```version 0.1``` - -This strategy gives score aka votes to the liquidity providers on the [Ocean marketplace v4](https://market.oceanprotocol.com). This means that LP participants can vote for OceanDAO grants via Snapshot without removing their liquidity. - -## Solution description - -The solution pulls the needed data from all Ocean Protocol subgraphs using the following path: -```https://subgraph.{network}.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph``` - -This strategy is designed to give voting scores only to marketplace liquidity providers by calculating their individual pool shares. - -The remaining vote count comes from other strategies configured in [OceanDAO Snapshot Page](https://vote.oceanprotocol.com/#/). - -For v4, we only look at pools w/ OCEAN as the basetoken, and pools that have been proprely initialized. We then attributes votes to LP'ers like this: -``` -user_votes = user_pool_shares * (total_Ocean_in_the_pool / total_number_of_pool_shares) -``` -This is done for all pools and the votes for the users are added up. - -To extend or run this strategy please use the setup described [here](https://docs.snapshot.page/strategies). - -## v3 vs. v4 differences -- In v4 we have to check if the pool basetoken is Ocean. Only Ocean tokens will obtain voting power. -- In v4, pools.datatoken.holderCount is always 0 as datatokens are consumed as soon as they are purchased -- In v4, pools.isFinalized checks if the pool has been properly setup. In v3 the equivalent was pools.active - -## Ocean ERC20 Addresses -You need to submit the ERC20 Ocean tokenAddress via the stratgy parameters. These [can be found here](https://github.com/oceanprotocol/contracts/blob/v4main/addresses/address.json) - -Addresses by network: -``` -'1': '0x967da4048cD07aB37855c090aAF366e4ce1b9F48', //mainnet -'3': '0x5e8DCB2AfA23844bcc311B00Ad1A0C30025aADE9', //ropsten -'42': '0x8967bcf84170c91b0d24d4302c2376283b0b3a07', //rinkeby -'56': '0xDCe07662CA8EbC241316a15B611c89711414Dd1a', //bsc -'137': '0x282d8efCe846A88B159800bd4130ad77443Fa1A1', //poly -'246': '0x593122AAE80A6Fc3183b2AC0c4ab3336dEbeE528', //ewt -'1285': '0x99C409E5f62E4bd2AC142f17caFb6810B8F0BAAE', //movr -'1287': '0xF6410bf5d773C7a41ebFf972f38e7463FA242477', //glmr -'80001': '0xd8992Ed72C445c35Cb4A2be468568Ed1079357c8' //mumbai -``` - -## How to Test -(1) Remove comments around debug logs. -(2) Enable code block inside `index.ts` that verifies expected results. -``` -if (options.expectedResults) { -``` -(3) Use the regular testing functionality `yarn test -strategy=ocean-marktplace-v4` diff --git a/src/strategies/ocean-marketplace-v4/examples.json b/src/strategies/ocean-marketplace-v4/examples.json deleted file mode 100644 index d4986c397..000000000 --- a/src/strategies/ocean-marketplace-v4/examples.json +++ /dev/null @@ -1,94 +0,0 @@ -[ - { - "name": "ERC-20 OCEAN staked in mainnet v4 marketplace via subgraph", - "strategy": { - "name": "ocean-marketplace-v4", - "params": { - "address": "0x967da4048cD07aB37855c090aAF366e4ce1b9F48", - "expectedResults": { - "scores": { - "0x7842Fa3B2d87Ff1cd52C4152382f7C4B3406E5A6": 250, - "0x99840Df5Cb42faBE0Feb8811Aaa4BC99cA6C84e0": 200, - "0x903322C7E45A60d7c8C3EA236c5beA9Af86310c7": 50 - } - } - } - }, - "network": "1", - "addresses": [ - "0x7842Fa3B2d87Ff1cd52C4152382f7C4B3406E5A6", - "0x99840Df5Cb42faBE0Feb8811Aaa4BC99cA6C84e0", - "0x903322C7E45A60d7c8C3EA236c5beA9Af86310c7" - ], - "snapshot": 15006609 - }, - { - "name": "ERC-20 OCEAN staked in polygon v4 marketplace via subgraph", - "strategy": { - "name": "ocean-marketplace-v4", - "params": { - "address": "0x282d8efCe846A88B159800bd4130ad77443Fa1A1", - "expectedResults": { - "scores": { - "0x3EFDD8f728c8e774aB81D14d0B2F07a8238960f4": 10762.326857765422, - "0xbbd33AFa85539fa65cc08A2e61a001876D2f13FE": 5752.362504190221, - "0x0363F3C31076a64b85Ceb69a28f958A7c1181CEe": 1750, - "0xC5320Dc3956484662cF3FE3B9355AEA93729783D": 778.6503526737412 - } - } - } - }, - "network": "137", - "addresses": [ - "0x3EFDD8f728c8e774aB81D14d0B2F07a8238960f4", - "0xbbd33AFa85539fa65cc08A2e61a001876D2f13FE", - "0x0363F3C31076a64b85Ceb69a28f958A7c1181CEe", - "0xC5320Dc3956484662cF3FE3B9355AEA93729783D" - ], - "snapshot": 29358635 - }, - { - "name": "ERC-20 OCEAN staked in EWT v4 marketplace via subgraph", - "strategy": { - "name": "ocean-marketplace-v4", - "params": { - "address": "0x593122AAE80A6Fc3183b2AC0c4ab3336dEbeE528", - "expectedResults": { - "scores": { - "0x159924ca0F47D6F704B97E29099b89e518A17B5E": 3489.1235163210085, - "0x4F20e69E7bA5aB2Fb2ae25A1d17C93fE5307faA9": 500.45061032028195 - } - } - } - }, - "network": "246", - "addresses": [ - "0x159924ca0F47D6F704B97E29099b89e518A17B5E", - "0x4F20e69E7bA5aB2Fb2ae25A1d17C93fE5307faA9" - ], - "snapshot": 18788160 - }, - { - "name": "ERC-20 OCEAN staked in MOVR v4 marketplace via subgraph", - "strategy": { - "name": "ocean-marketplace-v4", - "params": { - "address": "0x99C409E5f62E4bd2AC142f17caFb6810B8F0BAAE", - "expectedResults": { - "scores": { - "0xc97fa83746aDe91b0eeB16cb51326a0A980Af7c3": 200, - "0x99840Df5Cb42faBE0Feb8811Aaa4BC99cA6C84e0": 200, - "0xFcd3DfCc1E793D4D03fB4ffFf2B7Eb5A20FCfe4E": 0 - } - } - } - }, - "network": "1285", - "addresses": [ - "0xc97fa83746aDe91b0eeB16cb51326a0A980Af7c3", - "0x99840Df5Cb42faBE0Feb8811Aaa4BC99cA6C84e0", - "0xFcd3DfCc1E793D4D03fB4ffFf2B7Eb5A20FCfe4E" - ], - "snapshot": 2150228 - } -] diff --git a/src/strategies/ocean-marketplace-v4/index.ts b/src/strategies/ocean-marketplace-v4/index.ts deleted file mode 100644 index b86da3220..000000000 --- a/src/strategies/ocean-marketplace-v4/index.ts +++ /dev/null @@ -1,171 +0,0 @@ -import { getAddress } from '@ethersproject/address'; -import { subgraphRequest } from '../../utils'; -import { formatUnits, parseUnits } from '@ethersproject/units'; -import { BigNumber } from '@ethersproject/bignumber'; -// import { verifyResultsLength, verifyResults } from './oceanUtils'; - -export const author = 'oceanprotocol'; -export const version = '0.1.0'; - -const OCEAN_ERC20_DECIMALS = 18; -const OCEAN_SUBGRAPH_URL = { - '1': 'https://v4.subgraph.mainnet.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph', - '3': 'https://v4.subgraph.ropsten.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph', - '42': 'https://v4.subgraph.rinkeby.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph', - '56': 'https://v4.subgraph.bsc.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph', - '137': - 'https://v4.subgraph.polygon.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph', - '246': - 'https://v4.subgraph.energyweb.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph', - '1285': - 'https://v4.subgraph.moonriver.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph', - '1287': - 'https://v4.subgraph.moonbase.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph', - '80001': - 'https://v4.subgraph.mumbai.oceanprotocol.com/subgraphs/name/oceanprotocol/ocean-subgraph' -}; - -// Returns a BigDecimal as a BigNumber with 10^decimals extra zeros -export function bdToBn(bd, decimals) { - let bn; - const splitDecimal = bd.split('.'); - - if (splitDecimal.length > 1) { - bn = `${splitDecimal[0]}.${splitDecimal[1].slice( - 0, - decimals - splitDecimal[0].length - 1 - )}`; - } else { - bn = `${splitDecimal[0]}`; - } - - const bn2 = parseUnits(bn, decimals); - return bn2; -} - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const oceanToken = options.address.toLowerCase(); - const params = { - pools: { - __args: { - where: { - baseToken_in: [oceanToken] - }, - first: 1000, - orderBy: 'baseTokenLiquidity', - orderDirection: 'desc' - }, - isFinalized: true, - totalShares: true, - baseTokenLiquidity: true, - shares: { - __args: { - where: { - user_in: addresses.map((address) => address.toLowerCase()) - }, - orderBy: 'shares', - orderDirection: 'desc' - }, - user: { - id: true - }, - shares: true - }, - datatoken: { - holderCount: true - } - } - }; - - if (snapshot !== 'latest') { - // @ts-ignore - params.pools.__args.block = { number: +snapshot }; - } - - // Retrieve the top 1000 pools - const graphResults = await subgraphRequest( - OCEAN_SUBGRAPH_URL[network], - params - ); - - // Get total votes, for ALL addresses, inside top 1000 pools, with a minimum of 0.0001 shares - const score = {}; - const userAddresses: string[] = []; - const return_score = {}; - - // console.log( - // `graph results for network: ${network} at snapshot: ${snapshot}` - // ); - // console.log('results: ', graphResults); - - if (graphResults && graphResults.pools) { - graphResults.pools.forEach((pool) => { - if (pool.isFinalized) { - pool.shares.map((share) => { - const userAddress = getAddress(share.user.id); - // const shares = share.shares; - // console.log( - // `High Level - User address: ${userAddress} user poolShares: ${shares} baseTokenLiquidity: ${pool.baseTokenLiquidity} poolTotalShares: ${pool.totalShares}` - // ); - if (!userAddresses.includes(userAddress)) - userAddresses.push(userAddress); - if (!score[userAddress]) score[userAddress] = BigNumber.from(0); - const userShare = - share.shares * (pool.baseTokenLiquidity / pool.totalShares); - if (userShare > 0.0001) { - score[userAddress] = score[userAddress].add( - bdToBn(userShare.toString(), OCEAN_ERC20_DECIMALS) - ); - } - }); - } - }); - - // We then sum total votes, per user address - userAddresses.forEach((address) => { - const parsedSum = parseFloat( - formatUnits(score[address], OCEAN_ERC20_DECIMALS) - ); - return_score[address] = parsedSum * 2; //this resolves the 50% discrepancy due to 50/50 OCEAN/DT LP - - // console.log(`Score for address: ${address} is: ${return_score[address]}`); - }); - } - - // We then filter only the addresses expected - const results = Object.fromEntries( - Object.entries(return_score).filter(([k]) => addresses.indexOf(k) >= 0) - ); - - // Test validation: Update examples.json w/ expectedResults to reflect LPs @ blockHeight - // Success criteria: Address scores and length, must match expectedResults. Order not validated. - // From GRT's graphUtils.ts => verifyResults => Scores need to match expectedResults. - // npm run test --strategy=ocean-marketplace | grep -E 'SUCCESS|ERROR' - // if (options.expectedResults) { - // const expectedResults = {}; - // Object.keys(options.expectedResults.scores).forEach(function (key) { - // expectedResults[key] = results[key]; - // }); - // - // verifyResults( - // JSON.stringify(expectedResults), - // JSON.stringify(options.expectedResults.scores), - // 'Scores' - // ); - // - // verifyResultsLength( - // Object.keys(expectedResults).length, - // Object.keys(options.expectedResults.scores).length, - // 'Scores' - // ); - // } - - return results || {}; -} diff --git a/src/strategies/ocean-marketplace-v4/oceanUtils.ts b/src/strategies/ocean-marketplace-v4/oceanUtils.ts deleted file mode 100644 index be3b22095..000000000 --- a/src/strategies/ocean-marketplace-v4/oceanUtils.ts +++ /dev/null @@ -1,31 +0,0 @@ -export function verifyResultsLength( - result: number, - expectedResults: number, - type: string -): void { - if (result === expectedResults) { - console.log( - `>>> SUCCESS: ${type} result:[${result}] match expected results:[${expectedResults}] - length` - ); - } else { - console.error( - `>>> ERROR: ${type} result:[${result}] do not match expected results:[${expectedResults}] - length` - ); - } -} - -export function verifyResults( - result: string, - expectedResults: string, - type: string -): void { - if (result === expectedResults) { - console.log( - `>>> SUCCESS: ${type} result:[${result}] match expected results:[${expectedResults}]` - ); - } else { - console.error( - `>>> ERROR: ${type} result:[${result}] do not match expected results:[${expectedResults}]` - ); - } -} diff --git a/src/strategies/piedao/examples.json b/src/strategies/piedao/examples.json deleted file mode 100644 index 40b626a10..000000000 --- a/src/strategies/piedao/examples.json +++ /dev/null @@ -1,23 +0,0 @@ -[ - { - "name": "piedao", - "strategy": { - "name": "piedao", - "params": { - "symbol": "PIE", - "BPT": "0xFAE2809935233d4BfE8a56c2355c4A2e7d1fFf1A", - "doughv1": "0x5f5e9ed11344dadc3a08688e5f17e23f6a99bf81", - "doughv2": "0xad32A8e6220741182940c5aBF610bDE99E737b2D", - "stakedDough": "0xB9a4Bca06F14A982fcD14907D31DFACaDC8ff88E", - "eDOUGH": "0x63cbd1858bd79de1a06c3c26462db360b834912d", - "decimals": 18 - } - }, - "network": "1", - "addresses": [ - "0x66827bcd635f2bb1779d68c46aeb16541bca6ba8", - "0x635b230c3fdf6a466bb6dc3b9b51a8ceb0659b67" - ], - "snapshot": 11350000 - } -] diff --git a/src/strategies/piedao/index.ts b/src/strategies/piedao/index.ts deleted file mode 100644 index 8c4bdc1b9..000000000 --- a/src/strategies/piedao/index.ts +++ /dev/null @@ -1,136 +0,0 @@ -import { formatUnits } from '@ethersproject/units'; -import { multicall } from '../../utils'; - -export const author = 'alexintosh'; -export const version = '0.0.1'; - -const abi = [ - { - constant: true, - inputs: [ - { - internalType: 'address', - name: 'account', - type: 'address' - } - ], - name: 'balanceOf', - outputs: [ - { - internalType: 'uint256', - name: '', - type: 'uint256' - } - ], - payable: false, - stateMutability: 'view', - type: 'function' - }, - { - constant: true, - inputs: [], - name: 'totalSupply', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - payable: false, - stateMutability: 'view', - type: 'function' - } -]; - -const chunk = (arr, size) => - Array.from({ length: Math.ceil(arr.length / size) }, (v, i) => - arr.slice(i * size, i * size + size) - ); - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - const doughv1Query = addresses.map((address: any) => [ - options.doughv1, - 'balanceOf', - [address] - ]); - - const doughv2Query = addresses.map((address: any) => [ - options.doughv2, - 'balanceOf', - [address] - ]); - - const eDOUGHQuery = addresses.map((address: any) => [ - options.eDOUGH, - 'balanceOf', - [address] - ]); - - const stakedDoughQuery = addresses.map((address: any) => [ - options.stakedDough, - 'balanceOf', - [address] - ]); - - const lpDoughQuery = addresses.map((address: any) => [ - options.BPT, - 'balanceOf', - [address] - ]); - - const response = await multicall( - network, - provider, - abi, - [ - [options.doughv2, 'balanceOf', [options.BPT]], - [options.BPT, 'totalSupply'], - ...doughv1Query, - ...doughv2Query, - ...eDOUGHQuery, - ...stakedDoughQuery, - ...lpDoughQuery - ], - { blockTag } - ); - - const doughv2BPT = response[0]; - const doughv2BptTotalSupply = response[1]; - const responseClean = response.slice(2, response.length); - - const chunks = chunk(responseClean, addresses.length); - const doughv1Balances = chunks[0]; - const doughv2Balances = chunks[1]; - const eDOUGHBalances = chunks[2]; - const stakedDoughBalances = chunks[3]; - const lpDoughBalances = chunks[4]; - - return Object.fromEntries( - Array(addresses.length) - .fill('x') - .map((_, i) => [ - addresses[i], - parseFloat( - formatUnits( - doughv2BPT[0] - .mul(stakedDoughBalances[i][0]) - .div(doughv2BptTotalSupply[0]) - .add( - doughv2BPT[0] - .mul(lpDoughBalances[i][0]) - .div(doughv2BptTotalSupply[0]) - ) - .add(doughv1Balances[i][0]) - .add(doughv2Balances[i][0]) - .add(eDOUGHBalances[i][0]) - .toString(), - options.decimals - ) - ) - ]) - ); -} diff --git a/src/strategies/planet-finance/examples.json b/src/strategies/planet-finance/examples.json deleted file mode 100644 index a1d317dc5..000000000 --- a/src/strategies/planet-finance/examples.json +++ /dev/null @@ -1,16 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "planet-finance", - "params": { - "address": "0x72B7D61E8fC8cF971960DD9cfA59B8C829D91991", - "symbol": "AQUA", - "decimals": 18 - } - }, - "network": "56", - "addresses": ["0x3BDaDCbF17e24B2157d920E25407FF8cd4f5F54C"], - "snapshot": 13267571 - } -] diff --git a/src/strategies/planet-finance/index.ts b/src/strategies/planet-finance/index.ts deleted file mode 100644 index 6b3e0c189..000000000 --- a/src/strategies/planet-finance/index.ts +++ /dev/null @@ -1,221 +0,0 @@ -import { formatUnits } from '@ethersproject/units'; -import { multicall } from '../../utils'; -import { Multicaller } from '../../utils'; -import { strategy as erc20BalanceOfStrategy } from '../erc20-balance-of'; - -export const author = 'planet-finance'; -export const version = '0.0.1'; - -const planetFinanceFarmAbi = [ - 'function poolInfo(uint256) returns (address want,uint256 allocPoint,uint256 lastRewardBlock,uint256 accAQUAPerShare,address strat)', - 'function stakedWantTokens(uint256 _pid, address _user) returns (uint256)' -]; - -const bep20Abi: any = [ - 'function totalSupply() view returns (uint256)', - 'function balanceOf(address) view returns (uint256)' -]; - -const aquaAutoCompAbi = [ - 'function balanceOf() view returns (uint256)', - 'function totalShares() view returns (uint256)', - 'function userInfo(address) view returns (uint256 shares, uint256 lastDepositedTime , uint256 cakeAtLastUserAction , uint256 lastUserActionTime)' -]; - -const aquaLendingAbi = [ - 'function getAccountSnapshot(address) view returns (uint256,uint256,uint256,uint256)' -]; - -const planetFinanceFarmContractAddress = - '0x0ac58Fd25f334975b1B61732CF79564b6200A933'; - -const gammaFarmAddress = '0xB87F7016585510505478D1d160BDf76c1f41b53d'; - -const aquaAutoCompPoolAddress = '0x8A53dAdF2564d030b41dB1c04fB3c4998dC1326e'; - -const aquaAddress = '0x72B7D61E8fC8cF971960DD9cfA59B8C829D91991'; - -const aquaBnbLpTokenAddress = '0x03028D2F8B275695A1c6AFB69A4765e3666e36d9'; - -const aquaGammaLpTokenAddress = '0xcCaF3fcE9f2D7A7031e049EcC65c0C0Cc331EE0D'; - -const aquaLendingAddress = '0xb7eD4A5AF620B52022fb26035C565277035d4FD7'; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - const erc20Multi = new Multicaller(network, provider, bep20Abi, { - blockTag - }); - - const autoCompMulti = new Multicaller(network, provider, aquaAutoCompAbi, { - blockTag - }); - - // returns user's aqua balance ofr their address - let score: any = erc20BalanceOfStrategy( - space, - network, - provider, - addresses, - options, - snapshot - ); - - // returns user's aqua balance in aqua only vault - let usersAquaVaultBalances: any = multicall( - network, - provider, - planetFinanceFarmAbi, - addresses.map((address: any) => [ - planetFinanceFarmContractAddress, - 'stakedWantTokens', - ['1', address] - ]), - { blockTag } - ); - - //returns user's shares in aqua auto comp vault - let usersAquaAutoCompVaultBalances: any = multicall( - network, - provider, - aquaAutoCompAbi, - addresses.map((address: any) => [ - aquaAutoCompPoolAddress, - 'userInfo', - [address] - ]), - { blockTag } - ); - - // returns user's aqua balance in aqua-bnb vault - let usersAquaGammaVaultBalances: any = multicall( - network, - provider, - planetFinanceFarmAbi, - addresses.map((address: any) => [ - gammaFarmAddress, - 'stakedWantTokens', - ['0', address] - ]), - { blockTag } - ); - - // returns user's aqua balance in aqua-bnb vault - let usersNewAquaBnbVaultBalances: any = multicall( - network, - provider, - planetFinanceFarmAbi, - addresses.map((address: any) => [ - gammaFarmAddress, - 'stakedWantTokens', - ['1', address] - ]), - { blockTag } - ); - - //AQUA LENDING - let usersAquaInLending: any = multicall( - network, - provider, - aquaLendingAbi, - addresses.map((address: any) => [ - aquaLendingAddress, - 'getAccountSnapshot', - [address] - ]), - { blockTag } - ); - - const result = await Promise.all([ - score, - usersAquaVaultBalances, - usersAquaAutoCompVaultBalances, - usersAquaGammaVaultBalances, - usersNewAquaBnbVaultBalances, - usersAquaInLending - ]); - - score = result[0]; - usersAquaVaultBalances = result[1]; - usersAquaAutoCompVaultBalances = result[2]; - usersAquaGammaVaultBalances = result[3]; - usersNewAquaBnbVaultBalances = result[4]; - usersAquaInLending = result[5]; - - //AQUA-BNB - erc20Multi.call('aquaBnbTotalSupply', aquaBnbLpTokenAddress, 'totalSupply'); - - erc20Multi.call('aquaBnbAquaBal', aquaAddress, 'balanceOf', [ - aquaBnbLpTokenAddress - ]); - - //AQUA-GAMMA - erc20Multi.call( - 'aquaGammaTotalSupply', - aquaGammaLpTokenAddress, - 'totalSupply' - ); - - erc20Multi.call('aquaGammaAquaBal', aquaAddress, 'balanceOf', [ - aquaGammaLpTokenAddress - ]); - - const erc20Result = await erc20Multi.execute(); - - const totalSupply = erc20Result.aquaBnbTotalSupply.toString(); - - const contractAquaBalance = erc20Result.aquaBnbAquaBal.toString(); - - const totalSupplyAquaGamma = erc20Result.aquaGammaTotalSupply.toString(); - - const aquaGammaContractAquaBalance = erc20Result.aquaGammaAquaBal.toString(); - - //AQUA AUTO COMPOUNDING - autoCompMulti.call('aquaBalance', aquaAutoCompPoolAddress, 'balanceOf'); - autoCompMulti.call('totalShares', aquaAutoCompPoolAddress, 'totalShares'); - - const autoCompResult = await autoCompMulti.execute(); - - let aquaBalance = autoCompResult.aquaBalance.toString(); - aquaBalance = parseFloat(formatUnits(aquaBalance, 18)); - - let totalShares = autoCompResult.totalShares.toString(); - totalShares = parseFloat(formatUnits(totalShares, 18)); - - return Object.fromEntries( - Object.entries(score).map((address: any, index) => [ - address[0], - - address[1] + - parseFloat(formatUnits(usersAquaVaultBalances[index].toString(), 18)) + - (parseFloat( - formatUnits(usersNewAquaBnbVaultBalances[index].toString(), 18) - ) / - parseFloat(formatUnits(totalSupply, 18))) * - parseFloat(formatUnits(contractAquaBalance, 18)) + - (parseFloat( - formatUnits(usersAquaGammaVaultBalances[index].toString(), 18) - ) / - parseFloat(formatUnits(totalSupplyAquaGamma, 18))) * - parseFloat(formatUnits(aquaGammaContractAquaBalance, 18)) + - (parseFloat( - formatUnits( - usersAquaAutoCompVaultBalances[index]['shares'].toString(), - 18 - ) - ) / - totalShares) * - aquaBalance + - parseFloat(formatUnits(usersAquaInLending[index]['1'], 18)) * - parseFloat(formatUnits(usersAquaInLending[index]['3'], 18)) - ]) - ); -} diff --git a/src/strategies/pod-leader/README.md b/src/strategies/pod-leader/README.md deleted file mode 100644 index 0ac193924..000000000 --- a/src/strategies/pod-leader/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# PodLeader pool balance - -Calculates the balance of either a uniswap pair in a Yield Yak/Pod leader style farm, or the amount of each individual token in that LP which is deposited into the farm. For example, if an LP pair has 100 token1 and 200 token2, one can isolate token2 for snapshot votes. One can also give weights to each of these tokens when combined with other strategies. - -## Accepted options: - -- chefAddress: Masterchef contract address -- pid: Mastechef pool id (starting with zero) - -- uniPairAddress: Address of a uniswap pair (or a sushi pair or any other with the same interface) - - If the uniPairAddress option is provided, converts staked LP token balance to base token balance - (based on the pair total supply and base token reserve) - - If uniPairAddress is null or undefined, returns staked token balance of the pool - -- tokenAddress: Address of a token for single token Pools. - - if the uniPairAddress is provided the tokenAddress is ignored. - -- weight: Integer multiplier of the result (for combining strategies with different weights, totally optional) -- weightDecimals: Integer value of number of decimal places to apply to the final result - -- token0.address: Address of the uniPair token 0. If defined, the strategy will return the result for the token0. - -- token0.weight: Integer multiplier of the result for token0 -- token0.weightDecimals: Integer value of number of decimal places to apply to the result of token0 - -- token1.address: Address of the uniPair token 1. If defined, the strategy will return the result for the token1. - -- token1.weight: Integer multiplier of the result for token1 -- token1.weightDecimal: Integer value of number of decimal places to apply to the result of token1 - - -- log: Boolean flag to enable or disable logging to the console (used for debugging purposes during development) - - - -Check the examples.json file for how to use the options. diff --git a/src/strategies/pod-leader/examples.json b/src/strategies/pod-leader/examples.json deleted file mode 100644 index 67d0c6578..000000000 --- a/src/strategies/pod-leader/examples.json +++ /dev/null @@ -1,63 +0,0 @@ -[ - { - "name": "Example query - Count of tokens in single token Pool", - "strategy": { - "name": "pod-leader", - "params": { - "symbol": "STAKE", - "chefAddress": "0x111E1E97435b57467E79d4930acc4B7EB3d478ad", - "uniPairAddress": "0x73e6CB72a79dEa7ed75EF5eD6f8cFf86C9128eF5", - "token0": { - "address": "0x8B1d98A91F853218ddbb066F20b8c63E782e2430", - "weight": 1, - "weightDecimals": 0 - }, - "pid": "2", - "weight": 1, - "weightDecimals": 0 - } - }, - "network": "43114", - "addresses": ["0x9F8A5B35f5508071cf2304A670EAB0803F3737aa"], - "snapshot": 5475221 - }, - { - "name": "Example query - Count of tokens in single token Pool", - "strategy": { - "name": "pod-leader", - "params": { - "chefAddress": "0x111E1E97435b57467E79d4930acc4B7EB3d478ad", - "uniPairAddress": "0x1a9bd67c82c0e8e47c3ad2fa772fcb9b7a831a37", - "token1": { - "address": "0x8B1d98A91F853218ddbb066F20b8c63E782e2430", - "weight": 1, - "weightDecimals": 0 - }, - "pid": "0", - "weight": 1, - "weightDecimals": 0 - } - }, - "network": "43114", - "addresses": ["0x9F8A5B35f5508071cf2304A670EAB0803F3737aa"], - "snapshot": 5475221 - }, - - { - "name": "Example query - Tokens in single token Pool", - "strategy": { - "name": "pod-leader", - "params": { - "chefAddress": "0xA3654801Ba6FB21d5A984F9a857441395dDeccFb", - "tokenAddress": "0x8B1d98A91F853218ddbb066F20b8c63E782e2430", - "pid": "0", - "weight": 1, - "weightDecimals": 0, - "decimals": 0 - } - }, - "network": "43114", - "addresses": ["0x9F8A5B35f5508071cf2304A670EAB0803F3737aa"], - "snapshot": 5475221 - } -] diff --git a/src/strategies/pod-leader/index.ts b/src/strategies/pod-leader/index.ts deleted file mode 100644 index 4b448e509..000000000 --- a/src/strategies/pod-leader/index.ts +++ /dev/null @@ -1,343 +0,0 @@ -import { formatUnits } from '@ethersproject/units'; -import { multicall } from '../../utils'; -import { BigNumber } from '@ethersproject/bignumber'; - -export const author = 'ursamaritimus'; -export const version = '0.3.0'; - -/* - * PodLeader pool balance. Accepted options: - * - chefAddress: Masterchef contract address - * - pid: Mastechef pool id (starting with zero) - * - * - uniPairAddress: Address of a uniswap pair (or a sushi pair or any other with the same interface) - * - If the uniPairAddress option is provided, converts staked LP token balance to base token balance - * (based on the pair total supply and base token reserve) - * - If uniPairAddress is null or undefined, returns staked token balance of the pool - * - * - tokenAddress: Address of a token for single token Pools. - * - if the uniPairAddress is provided the tokenAddress is ignored. - * - * - weight: Integer multiplier of the result (for combining strategies with different weights, totally optional) - * - weightDecimals: Integer value of number of decimal places to apply to the final result - * - * - token0.address: Address of the uniPair token 0. If defined, the strategy will return the result for the token0. - * - * - token0.weight: Integer multiplier of the result for token0 - * - token0.weightDecimals: Integer value of number of decimal places to apply to the result of token0 - * - * - token1.address: Address of the uniPair token 1. If defined, the strategy will return the result for the token1. - * - * - token1,weight: Integer multiplier of the result for token1 - * - token1.weightDecimal: Integer value of number of decimal places to apply to the result of token1 - * - * - * - log: Boolean flag to enable or disable logging to the console (used for debugging purposes during development) - * - - * - * Check the examples.json file for how to use the options. - */ - -const abi = [ - 'function userInfo(uint256, address) view returns (uint256 amount, uint256 rewardTokenDebt)', - 'function totalSupply() view returns (uint256)', - 'function getReserves() view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast)', - 'function token0() view returns (address)', - 'function token1() view returns (address)', - 'function decimals() view returns (uint8)' -]; - -let log: string[] = []; -let _options; - -const getUserInfoCalls = (addresses: any[]) => { - const result: any[] = []; - - for (const address of addresses) { - result.push([_options.chefAddress, 'userInfo', [_options.pid, address]]); - } - - return result; -}; - -const getTokenCalls = () => { - const result: any[] = []; - - if (_options.uniPairAddress != null) { - result.push([_options.uniPairAddress, 'totalSupply', []]); - result.push([_options.uniPairAddress, 'getReserves', []]); - result.push([_options.uniPairAddress, 'token0', []]); - result.push([_options.uniPairAddress, 'token1', []]); - result.push([_options.uniPairAddress, 'decimals', []]); - - if (_options.token0?.address != null) { - result.push([_options.token0.address, 'decimals', []]); - } - - if (_options.token1?.address != null) { - result.push([_options.token1.address, 'decimals', []]); - } - } else if (_options.tokenAddress != null) { - result.push([_options.tokenAddress, 'decimals', []]); - } - - return result; -}; - -function arrayChunk(arr: T[], chunkSize: number): T[][] { - const result: T[][] = []; - - for (let i = 0, j = arr.length; i < j; i += chunkSize) { - result.push(arr.slice(i, i + chunkSize)); - } - - return result; -} - -async function processValues( - values: any[], - tokenValues: any[], - network: any, - provider: any, - blockTag: string | number -) { - log.push(`values = ${JSON.stringify(values, undefined, 2)}`); - log.push(`tokenValues = ${JSON.stringify(tokenValues, undefined, 2)}`); - printLog(); - - const poolStaked = values[0][0] as BigNumber; - const weight = BigNumber.from(_options.weight || 1); - const weightDecimals = BigNumber.from(10).pow( - BigNumber.from(_options.weightDecimals || 0) - ); - - let result = 0; - - if (_options.uniPairAddress == null) { - log.push(`poolStaked = ${poolStaked}`); - - if (_options.tokenAddress != null) { - const tokenDecimals = BigNumber.from(10).pow( - BigNumber.from(tokenValues[0][0]) - ); - - log.push(`tokenDecimals = ${tokenDecimals}`); - log.push(`decimals = ${_options.decimals}`); - printLog(); - - result = toFloat(poolStaked.div(tokenDecimals), _options.decimals); - } else { - printLog(); - result = toFloat(poolStaked, _options.decimals); - } - } else { - const uniTotalSupply = tokenValues[0][0]; - const uniReserve0 = tokenValues[1][0]; - const uniReserve1 = tokenValues[1][1]; - const uniPairDecimalsIndex: any = - _options.uniPairAddress != null ? 4 : null; - const uniPairDecimalsCount = tokenValues[uniPairDecimalsIndex][0]; - const uniPairDecimals = - uniPairDecimalsIndex != null - ? BigNumber.from(10).pow(BigNumber.from(uniPairDecimalsCount || 0)) - : BigNumber.from(1); - - const token0Address = tokenValues[2][0]; - const useToken0 = - _options.token0?.address != null && - _options.token0.address.toString().toLowerCase() == - token0Address?.toString().toLowerCase(); - - log.push(`useToken0 = ${useToken0}`); - - if (useToken0) { - const token0DecimalsIndex = 5; - - log.push(`token0DecimalsIndex = ${token0DecimalsIndex}`); - log.push(`tokenValues = ${JSON.stringify(tokenValues, undefined, 2)}`); - printLog(); - - result += await GetTokenValue( - network, - provider, - blockTag, - uniTotalSupply, - uniReserve0, - uniPairDecimals, - poolStaked, - tokenValues, - token0Address, - token0DecimalsIndex, - _options.token0?.weight, - _options.token0?.weightDecimals - ); - } - - const token1Address = tokenValues[3][0]; - const useToken1 = - _options.token1?.address != null && - _options.token1.address.toString().toLowerCase() == - token1Address?.toString().toLowerCase(); - - log.push(`useToken1 = ${useToken1}`); - - if (useToken1) { - const token1DecimalsIndex = _options.token0?.address != null ? 6 : 5; - - log.push(`token1DecimalsIndex = ${token1DecimalsIndex}`); - log.push(`tokenValues = ${JSON.stringify(tokenValues, undefined, 2)}`); - printLog(); - - result += await GetTokenValue( - network, - provider, - blockTag, - uniTotalSupply, - uniReserve1, - uniPairDecimals, - poolStaked, - tokenValues, - token1Address, - token1DecimalsIndex, - _options.token1?.weight, - _options.token1?.WeightDecimals - ); - } - - if (!useToken0 && !useToken1) { - log.push(`poolStaked = ${poolStaked}`); - log.push(`uniPairDecimals = ${uniPairDecimals}`); - printLog(); - - const tokenCount = poolStaked.toNumber() / 10 ** uniPairDecimalsCount; - - log.push(`tokenCount = ${tokenCount}`); - - result = tokenCount / 10 ** (_options.decimals || 0); - } - } - - log.push(`result = ${result}`); - printLog(); - - result *= weight.toNumber() / weightDecimals.toNumber(); - - log.push(`weight = ${weight}`); - log.push(`weightDecimals = ${weightDecimals}`); - log.push(`result = ${result}`); - printLog(); - - return result; -} - -function toFloat(value: BigNumber, decimals: any): number { - const decimalsResult = decimals === 0 ? 0 : decimals || 18; - - log.push(`toFloat value = ${value}`); - log.push(`toFloat decimals = ${decimals}`); - log.push(`toFloat decimalsResult = ${decimalsResult}`); - printLog(); - - return parseFloat(formatUnits(value.toString(), decimalsResult)); -} - -async function GetTokenValue( - network: any, - provider: any, - blockTag: string | number, - uniTotalSupply: any, - uniReserve: any, - uniPairDecimals: BigNumber, - poolStaked: BigNumber, - tokenValues: any[], - tokenAddress: any, - tokenDecimalsIndex: any, - tokenWeight: any, - tokenWeightDecimals: any -) { - const weightDecimals = BigNumber.from(10).pow( - BigNumber.from(tokenWeightDecimals || 0) - ); - const weight = BigNumber.from(tokenWeight || 1); - const tokensPerLp = uniReserve.mul(uniPairDecimals).div(uniTotalSupply); - - const tokenDecimals = - tokenDecimalsIndex != null - ? BigNumber.from(10).pow( - BigNumber.from(tokenValues[tokenDecimalsIndex][0] || 0) - ) - : BigNumber.from(1); - log.push(`tokenAddress = ${tokenAddress}`); - log.push(`tokenDecimals = ${tokenDecimals}`); - log.push(`poolStaked = ${poolStaked}`); - log.push(`uniReserve = ${uniReserve}`); - log.push(`uniPairDecimals = ${uniPairDecimals}`); - log.push(`uniTotalSupply = ${uniTotalSupply}`); - log.push(`tokensPerLp = ${tokensPerLp}`); - log.push(`tokenWeight = ${weight}`); - log.push(`tokenWeightDecimals = ${weightDecimals}`); - - printLog(); - - const tokenCount = poolStaked - .mul(tokensPerLp) - .div(tokenDecimals) - .mul(weight) - .div(weightDecimals); - - log.push(`tokenCount = ${tokenCount}`); - - return toFloat(tokenCount, _options.decimals); -} - -function printLog() { - if (_options.log || false) { - console.debug(log); - log = []; - } -} - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - _options = options; - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - const userInfoCalls = getUserInfoCalls(addresses); - const tokenCalls = getTokenCalls(); - const entries = new Map(); - - const userInfoResponse = await multicall( - network, - provider, - abi, - userInfoCalls, - { blockTag } - ); - - const userInfoChunks = arrayChunk(userInfoResponse, 1); - - const tokenResponse = await multicall(network, provider, abi, tokenCalls, { - blockTag - }); - - for (let i = 0; i < userInfoChunks.length; i++) { - const value = userInfoChunks[i]; - const score = await processValues( - value, - tokenResponse, - network, - provider, - blockTag - ); - - entries.set(addresses[i], score); - } - - return Object.fromEntries(entries); -} diff --git a/src/strategies/protofi-erc721-tier-weighted/README.md b/src/strategies/protofi-erc721-tier-weighted/README.md deleted file mode 100644 index ac298c140..000000000 --- a/src/strategies/protofi-erc721-tier-weighted/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# protofi-erc721-tier-weighted - -This strategy returns the voting power of a wallet given by the sum of the NFT token owned, weighted by the tier of the NFT. Works specifically for Protofi NFTs. -With the parameter "countUsed" you decide if taking into account used NFTs as voting power. - -Here is an example of parameters: - -```json -{ - "address": "0x1aDB6f30561116B4283169DdD1Ca16ed2A34355A", - "symbol": "PNFT", - "tierToWeight": [10,20,30,40,50], - "countUsed": true -} -``` diff --git a/src/strategies/protofi-erc721-tier-weighted/examples.json b/src/strategies/protofi-erc721-tier-weighted/examples.json deleted file mode 100644 index baab1db4b..000000000 --- a/src/strategies/protofi-erc721-tier-weighted/examples.json +++ /dev/null @@ -1,23 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "protofi-erc721-tier-weighted", - "params": { - "address": "0x1aDB6f30561116B4283169DdD1Ca16ed2A34355A", - "symbol": "PNFT", - "tierToWeight": [10, 20, 30, 40, 50], - "countUsed": false - } - }, - "network": "250", - "addresses": [ - "0x5bF13Edc7De3E95029ffDC0C65C193E9bBEBcead", - "0x6f3064d973C08Dd9c88D43080549F474E5827d71", - "0x7751f0B8CfbC18b8931Ae54E234F908014D6D46d", - "0x346F59ac0aF2C85DB1250322b2beD4eEb4c61313", - "0x8a347ec3cB809D9a53d2B8d74e23f08d908e19dc" - ], - "snapshot": 31508266 - } -] diff --git a/src/strategies/protofi-erc721-tier-weighted/index.ts b/src/strategies/protofi-erc721-tier-weighted/index.ts deleted file mode 100644 index de84fa575..000000000 --- a/src/strategies/protofi-erc721-tier-weighted/index.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { Multicaller } from '../../utils'; -import { BigNumber } from '@ethersproject/bignumber'; - -export const author = 'theothercrypto'; -export const version = '0.1.0'; - -const abi = [ - 'function balanceOf(address account) external view returns (uint256)', - 'function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256)', - 'function tokenTier(uint256 index) external view returns (uint256)', - 'function tokenUsed(uint256 _id) public view virtual returns (bool)' -]; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - // First, get the balance of the token - const callWalletToBalanceOf = new Multicaller(network, provider, abi, { - blockTag - }); - for (const walletAddress of addresses) { - callWalletToBalanceOf.call(walletAddress, options.address, 'balanceOf', [ - walletAddress - ]); - } - const walletToBalanceOf: Record = - await callWalletToBalanceOf.execute(); - - // Second, get the tokenId's for each token - const callWalletToAddresses = new Multicaller(network, provider, abi, { - blockTag - }); - for (const [walletAddress, count] of Object.entries(walletToBalanceOf)) { - for (let index = 0; index < count.toNumber(); index++) { - callWalletToAddresses.call( - walletAddress.toString() + '-' + index.toString(), - options.address, - 'tokenOfOwnerByIndex', - [walletAddress, index] - ); - } - } - const walletIDToAddresses: Record = - await callWalletToAddresses.execute(); - - // Third, given the tokenIds for each token - const callWalletToTiers = new Multicaller(network, provider, abi, { - blockTag - }); - for (const [walletAddress, tokenId] of Object.entries(walletIDToAddresses)) { - callWalletToTiers.call( - walletAddress.toString() + '-' + tokenId.toString(), - options.address, - 'tokenTier', - [tokenId] - ); - } - - const walletIDToTiers: Record = - await callWalletToTiers.execute(); - - // Third, given the tokenIds for each token get if the token is used - const callWalletToUsed = new Multicaller(network, provider, abi, { - blockTag - }); - for (const [walletAddress, tokenId] of Object.entries(walletIDToAddresses)) { - callWalletToUsed.call( - walletAddress.toString() + '-' + tokenId.toString(), - options.address, - 'tokenUsed', - [tokenId] - ); - } - const walletIDToUsed: Record = - await callWalletToUsed.execute(); - - // Ultimately, sum the weights for each tokenId and assign votes based on the - // strategy parameters - const walletToLpBalance = {} as Record; - for (const [walletID, tokenTier] of Object.entries(walletIDToTiers)) { - const address = walletID.split('-')[0]; - const used = walletIDToUsed[walletID]; - if (!options.countUsed && used) { - // Its used and - continue; - } - - // Voting power given by the tier of NFTs owned - const tokenIdValue = options.tierToWeight[tokenTier - 1]; - - walletToLpBalance[address] = walletToLpBalance[address] - ? walletToLpBalance[address].add(BigNumber.from(tokenIdValue)) - : BigNumber.from(tokenIdValue); - } - - return Object.fromEntries( - Object.entries(walletToLpBalance).map(([address, balance]) => [ - address, - balance.toNumber() - ]) - ); -} diff --git a/src/strategies/proxyprotocol-erc1155-balance-of/README.md b/src/strategies/proxyprotocol-erc1155-balance-of/README.md deleted file mode 100644 index af84210fc..000000000 --- a/src/strategies/proxyprotocol-erc1155-balance-of/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Proxy ERC1155 - -This allows for a Proxy wallet to map to multiple wallets owned by the user. - -You would use the exact same parameters as erc1155-balance-of, but the signing wallet is now the proxy wallet. diff --git a/src/strategies/proxyprotocol-erc1155-balance-of/examples.json b/src/strategies/proxyprotocol-erc1155-balance-of/examples.json deleted file mode 100644 index dd62f2028..000000000 --- a/src/strategies/proxyprotocol-erc1155-balance-of/examples.json +++ /dev/null @@ -1,20 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "proxyprotocol-erc1155-balance-of", - "params": { - "symbol": "ADI", - "address": "0x28472a58a490c5e09a238847f66a68a47cc76f0f", - "tokenId": "1", - "decimals": 0 - } - }, - "network": "1", - "addresses": [ - "0x346f1c338b38ef9cf18964695dd68e9956ca5d37", - "0xa164591f695b11e1c6b77925e326e20754521200" - ], - "snapshot": 15304592 - } -] diff --git a/src/strategies/proxyprotocol-erc1155-balance-of/index.ts b/src/strategies/proxyprotocol-erc1155-balance-of/index.ts deleted file mode 100644 index 38a211f6c..000000000 --- a/src/strategies/proxyprotocol-erc1155-balance-of/index.ts +++ /dev/null @@ -1,60 +0,0 @@ -import fetch from 'cross-fetch'; -import { strategy as erc1155BalanceOfStrategy } from '../erc1155-balance-of'; - -export const author = 'rawrjustin'; -export const version = '0.1.0'; - -const calculateVotingPower = (inputAddresses, addressScores, walletMap) => { - const userVotingPower = {}; - inputAddresses.forEach((input) => { - let count = 0.0; - walletMap[input.toLowerCase()].forEach((address) => { - count += addressScores[address]; - }); - userVotingPower[input] = count; - }); - return userVotingPower; -}; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - // Get the wallet mapping from proxy wallets to actual wallets - const url = 'https://api.proxychat.xyz/external/v0/getProxyWalletMappings'; - const params = { - proxyAddresses: addresses - }; - const apiResponse = await fetch(url, { - method: 'POST', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json' - }, - body: JSON.stringify(params) - }); - const data = await apiResponse.json(); - - // Flatten the wallet mapping so it's an array of real wallets to query for tokens - const arrayOfProxyWallets = Object.keys(data).map(function (key) { - return data[key]; - }); - const flattenedWalletAddresses = [].concat.apply([], arrayOfProxyWallets); - - // Query for token holdings - const addressScores = await erc1155BalanceOfStrategy( - space, - network, - provider, - flattenedWalletAddresses, - options, - snapshot - ); - - // Calculate the voting power across all wallets and map it back to original Proxy wallets. - return calculateVotingPower(addresses, addressScores, data); -} diff --git a/src/strategies/proxyprotocol-erc20-balance-of/README.md b/src/strategies/proxyprotocol-erc20-balance-of/README.md deleted file mode 100644 index 12ea50a13..000000000 --- a/src/strategies/proxyprotocol-erc20-balance-of/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Proxy ERC-20 - -This allows for a Proxy wallet to map to multiple wallets owned by the user. - -You would use the exact same parameters as erc20-balance-of, but the signing wallet is now the proxy wallet. diff --git a/src/strategies/proxyprotocol-erc20-balance-of/examples.json b/src/strategies/proxyprotocol-erc20-balance-of/examples.json deleted file mode 100644 index 89db17a96..000000000 --- a/src/strategies/proxyprotocol-erc20-balance-of/examples.json +++ /dev/null @@ -1,19 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "proxyprotocol-erc20-balance-of", - "params": { - "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "symbol": "WETH", - "decimals": 18 - } - }, - "network": "1", - "addresses": [ - "0x346f1c338b38ef9cf18964695dd68e9956ca5d37", - "0xa164591f695b11e1c6b77925e326e20754521200" - ], - "snapshot": 15304592 - } -] diff --git a/src/strategies/proxyprotocol-erc20-balance-of/index.ts b/src/strategies/proxyprotocol-erc20-balance-of/index.ts deleted file mode 100644 index ba3fabe34..000000000 --- a/src/strategies/proxyprotocol-erc20-balance-of/index.ts +++ /dev/null @@ -1,60 +0,0 @@ -import fetch from 'cross-fetch'; -import { strategy as erc20BalanceOfStrategy } from '../erc20-balance-of'; - -export const author = 'rawrjustin'; -export const version = '0.1.0'; - -const calculateVotingPower = (inputAddresses, addressScores, walletMap) => { - const userVotingPower = {}; - inputAddresses.forEach((input) => { - let count = 0.0; - walletMap[input.toLowerCase()].forEach((address) => { - count += addressScores[address]; - }); - userVotingPower[input] = count; - }); - return userVotingPower; -}; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -): Promise> { - // Get the wallet mapping from proxy wallets to actual wallets - const url = 'https://api.proxychat.xyz/external/v0/getProxyWalletMappings'; - const params = { - proxyAddresses: addresses - }; - const response = await fetch(url, { - method: 'POST', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json' - }, - body: JSON.stringify(params) - }); - const data = await response.json(); - - // Flatten the wallet mapping so it's an array of real wallets to query for tokens - const arrayOfProxyWallets = Object.keys(data).map(function (key) { - return data[key]; - }); - const flattenedWalletAddresses = [].concat.apply([], arrayOfProxyWallets); - - // Query for token holdings - const addressScores = await erc20BalanceOfStrategy( - space, - network, - provider, - flattenedWalletAddresses, - options, - snapshot - ); - - // Calculate the voting power across all wallets and map it back to original Proxy wallets. - return calculateVotingPower(addresses, addressScores, data); -} diff --git a/src/strategies/proxyprotocol-erc20-balance-of/schema.json b/src/strategies/proxyprotocol-erc20-balance-of/schema.json deleted file mode 100644 index 2113da8b8..000000000 --- a/src/strategies/proxyprotocol-erc20-balance-of/schema.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$ref": "#/definitions/Strategy", - "definitions": { - "Strategy": { - "title": "Strategy", - "type": "object", - "properties": { - "symbol": { - "type": "string", - "title": "Symbol", - "examples": ["e.g. UNI"], - "maxLength": 16 - }, - "address": { - "type": "string", - "title": "Contract address", - "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - }, - "decimals": { - "type": "number", - "title": "Decimals", - "examples": ["e.g. 18"] - } - }, - "required": ["address", "decimals"], - "additionalProperties": false - } - } -} diff --git a/src/strategies/radicle-community-tokens/README.md b/src/strategies/radicle-community-tokens/README.md deleted file mode 100644 index 7b7209670..000000000 --- a/src/strategies/radicle-community-tokens/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# radicle-community-tokens - -This strategy is used to calculate voting power from the Radicle funding subgraph with the entity NFT and field `amtPerSec`. Each voter can have multiple NFTs, each with specific `amtPerSec`. The voters' voting power would be the sum of all the `amtPerSec`. If a fundingProject `id` is provided the summation is done only over NFTs of that project. - -Here is an example of parameters: - -```json -{ - "symbol": "DAI", - "decimals": 18, - "fundingProject": "0x488fc5d6e43259f87f816556a7ab99dc78cfbab6" -} -``` diff --git a/src/strategies/radicle-community-tokens/examples.json b/src/strategies/radicle-community-tokens/examples.json deleted file mode 100644 index 0ddc2f6c3..000000000 --- a/src/strategies/radicle-community-tokens/examples.json +++ /dev/null @@ -1,19 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "radicle-community-tokens", - "params": { - "symbol": "DAI", - "decimals": 18, - "fundingProject": "0x488fc5d6e43259f87f816556a7ab99dc78cfbab6" - } - }, - "network": "4", - "addresses": [ - "0xeCa823848221a1DA310E1a711E19D82F43101B07", - "0xb5bb9A125c2F67F1F2cd9d8992955bb209490aFE" - ], - "snapshot": 9601000 - } -] diff --git a/src/strategies/radicle-community-tokens/index.ts b/src/strategies/radicle-community-tokens/index.ts deleted file mode 100644 index d3aedb53c..000000000 --- a/src/strategies/radicle-community-tokens/index.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { BigNumber } from '@ethersproject/bignumber'; -import { formatUnits } from '@ethersproject/units'; -import { getAddress } from '@ethersproject/address'; -import { subgraphRequest } from '../../utils'; - -const FUNDING_SUBGRAPH_URL = { - '4': 'https://api.studio.thegraph.com/query/9578/funding-subgraph-v5/v0.0.1' // Rinkeby testnet -}; - -export const author = 'AmirSarraf'; -export const version = '0.1.0'; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -): Promise> { - let params = {}; - const fundingProject = options.fundingProject; - const mainField: string = fundingProject ? 'fundingProjects' : 'nfts'; - - if (fundingProject) { - // parameters to query nfts belonging to the provided addresses in a certain fundingProject - params = { - fundingProjects: { - __args: { - id: fundingProject.toLowerCase() - }, - id: true, - nfts: { - __args: { - where: { - nftReceiver_in: addresses.map((address) => address.toLowerCase()) - } - }, - amtPerSec: true, - nftReceiver: true - } - } - }; - } else { - // parameters to query nfts belonging to the provided addresses - params = { - nfts: { - __args: { - where: { - nftReceiver_in: addresses.map((address) => address.toLowerCase()) - }, - first: 1000 - }, - amtPerSec: true, - nftReceiver: true - } - }; - } - - if (snapshot !== 'latest') { - // @ts-ignore - params[mainField].__args.block = { number: snapshot }; - } - - let result = await subgraphRequest(FUNDING_SUBGRAPH_URL[network], params); - result = fundingProject - ? result?.fundingProjects?.find((proj) => proj.id == fundingProject) //double checking id - : result; - - const score: Record = {}; - if (result && result.nfts) { - result.nfts.forEach((nft) => { - const userAddress = getAddress(nft.nftReceiver); - const userScore = nft.amtPerSec; - if (!score[userAddress]) score[userAddress] = BigNumber.from(0); - score[userAddress] = score[userAddress].add(BigNumber.from(userScore)); - }); - } - - return Object.fromEntries( - Object.entries(score).map(([address, balance]) => [ - address, - parseFloat(formatUnits(balance.toString(), options.decimals)) - ]) - ); -} diff --git a/src/strategies/rebased/examples.json b/src/strategies/rebased/examples.json deleted file mode 100644 index bfc39d664..000000000 --- a/src/strategies/rebased/examples.json +++ /dev/null @@ -1,24 +0,0 @@ -[ - { - "name": "Rebased", - "strategy": { - "name": "rebased", - "params": { - "symbol": "REB", - "uniswap": "0x54f5f952cca8888227276581F26978F99FDBa64E", - "sharePool": "0x574D80f005B9f5a26e6D4E0bcbD379EABD7edEb0", - "token": "0x87f5f9ebe40786d49d35e1b5997b07ccaa8adbff", - "decimals": 18 - } - }, - "network": "1", - "addresses": [ - "0xde389fb34f54bec6d09bd98152a69be15c43163f", - "0xbe80fd79e26ce0a605e5d2803e876f1b009d70cc", - "0x55c307cbe54a1c1c105838a9d0fd60b75d7ff951", - "0x01BaD7E976d59CE92295Dbacd5da7fc06FE05412", - "0x64be824f732312490224a67537d49b8580068abf" - ], - "snapshot": 11941425 - } -] diff --git a/src/strategies/rebased/index.ts b/src/strategies/rebased/index.ts deleted file mode 100644 index 97923be5e..000000000 --- a/src/strategies/rebased/index.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { formatUnits, parseUnits } from '@ethersproject/units'; -import { Multicaller } from '../../utils'; - -export const author = 'codingsh'; -export const version = '0.1.0'; - -const abi = [ - { - constant: true, - inputs: [ - { - internalType: 'address', - name: '', - type: 'address' - } - ], - name: 'balanceOf', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - payable: false, - stateMutability: 'view', - type: 'function' - }, - { - inputs: [], - name: 'totalSupply', - outputs: [ - { - internalType: 'uint256', - name: '', - type: 'uint256' - } - ], - stateMutability: 'view', - type: 'function' - }, - { - constant: true, - inputs: [ - { - internalType: 'address', - name: 'addr', - type: 'address' - } - ], - name: 'totalStakedFor', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - payable: false, - stateMutability: 'view', - type: 'function' - } -]; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - const multi = new Multicaller(network, provider, abi, { blockTag }); - - multi.call('uniswapBalance', options.token, 'balanceOf', [options.uniswap]); - multi.call('uniswapTotalSupply', options.uniswap, 'totalSupply'); - addresses.forEach((address) => { - multi.call( - `scores.${address}.totalStaked`, - options.sharePool, - 'totalStakedFor', - [address] - ); - multi.call(`scores.${address}.uniswap`, options.uniswap, 'balanceOf', [ - address - ]); - multi.call(`scores.${address}.balance`, options.token, 'balanceOf', [ - address - ]); - }); - - const result = await multi.execute(); - const rebasedPerLP = result.uniswapBalance; - - return Object.fromEntries( - Array(addresses.length) - .fill('') - .map((_, i) => { - const lpBalances = result.scores[addresses[i]].uniswap; - const stakedLpBalances = result.scores[addresses[i]].totalStaked; - const tokenBalances = result.scores[addresses[i]].balance; - const lpBalance = lpBalances.add(stakedLpBalances); - const rebasedLpBalance = lpBalance - .add(tokenBalances) - .mul(rebasedPerLP) - .div(parseUnits('1', 18)); - return [ - addresses[i], - parseFloat(formatUnits(rebasedLpBalance, options.decimals)) - ]; - }) - ); -} diff --git a/src/strategies/riskharbor-underwriter/README.md b/src/strategies/riskharbor-underwriter/README.md deleted file mode 100644 index ebd323100..000000000 --- a/src/strategies/riskharbor-underwriter/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# riskharbor-underwriter - -This strategy allows underwriters in a given Risk Harbor vault to vote based on the shares issued to them across their various positions in that vault. This strategy works by querying the vault's subgraph to compute how many shares each user holds and divides that amount by the decimals in the underwriting asset. - -```json -{ - "SUBGRAPH_URL": "https://api.thegraph.com/subgraphs/name/some-protocol/v1-protocol", - "VAULT_ADDR": "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984" -} -``` diff --git a/src/strategies/riskharbor-underwriter/examples.json b/src/strategies/riskharbor-underwriter/examples.json deleted file mode 100644 index 154fe0f76..000000000 --- a/src/strategies/riskharbor-underwriter/examples.json +++ /dev/null @@ -1,22 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "riskharbor-underwriter", - "params": { - "SUBGRAPH_URL": "https://api.thegraph.com/subgraphs/name/risk-harbor/v2-arbitrum", - "VAULT_ADDR": "0xbcA81A2118982182d897845571BE950aE94C619c" - } - }, - "network": "42161", - "addresses": [ - "0xD4D4e905d7F1Eb095769fAce2C2bE516865E4981", - "0xd401c5B54A079420C6C7D9405faFc9a10CD8a4ed", - "0x010dab3779810cf08ac213b9efa915821bb43e26", - "0x0dcdd4f4a70ebb2eaffd5a01bd6cacde14dae4f0", - "0xfc9bffa77c2b725add71f4ad88bbe228d5601eb3", - "0xc2e63f57958d5ad5ced8fc18a7b763d9c8327237" - ], - "snapshot": 22260293 - } -] diff --git a/src/strategies/riskharbor-underwriter/index.ts b/src/strategies/riskharbor-underwriter/index.ts deleted file mode 100644 index a615a771f..000000000 --- a/src/strategies/riskharbor-underwriter/index.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { getAddress } from '@ethersproject/address'; -import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; -import { formatUnits } from '@ethersproject/units'; -import { subgraphRequest } from '../../utils'; - -export const author = 'dewpe'; -export const version = '0.1.1'; - -export async function strategy( - _space, - _network, - _provider, - addresses, - options, - snapshot -): Promise> { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - const positionsQuery = { - underwriterPositions: { - __args: { - where: { - shares_not: '0', - vault: options.VAULT_ADDR.toLowerCase(), - user_in: addresses.map((addr: string) => addr.toLowerCase()) - }, - block: blockTag != 'latest' ? { number: blockTag } : null, - first: 1000 - }, - shares: true, - user: { - id: true - } - } - }; - - const decimalsQuery = { - vault: { - __args: { - id: options.VAULT_ADDR.toLowerCase(), - block: blockTag != 'latest' ? { number: blockTag } : null - }, - underwritingToken: { - decimals: true - } - } - }; - - const decimals = (await subgraphRequest(options.SUBGRAPH_URL, decimalsQuery)) - .vault.underwritingToken.decimals; - - const positions = ( - await subgraphRequest(options.SUBGRAPH_URL, positionsQuery) - ).underwriterPositions; - - // Go through each position and reduce it down to the form: - // userAddr: balance - const agUserBals: Record = {}; - positions.forEach((position) => { - const shares = BigNumber.from(position.shares); - if (shares.isZero()) return; - // If key already has a value, then increase it - if (agUserBals[position.user.id]) { - agUserBals[position.user.id] = ( - agUserBals[position.user.id] as BigNumber - ).add(shares); - } else { - agUserBals[position.user.id] = shares; - } - }); - - return Object.fromEntries( - Object.entries(agUserBals).map(([address, balance]) => [ - getAddress(address), - // Divide each bal by 1eDecimals - parseFloat(formatUnits(balance, decimals)) - ]) - ); -} diff --git a/src/strategies/riskharbor-underwriter/schema.json b/src/strategies/riskharbor-underwriter/schema.json deleted file mode 100644 index 78f56d803..000000000 --- a/src/strategies/riskharbor-underwriter/schema.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$ref": "#/definitions/Strategy", - "definitions": { - "Strategy": { - "title": "Strategy", - "type": "object", - "properties": { - "SUBGRAPH_URL": { - "type": "string", - "title": "Subgraph url", - "examples": [ - "https://api.thegraph.com/subgraphs/name/some-protocol/v1-protocol" - ] - }, - "VAULT_ADDR": { - "type": "string", - "title": "Vault address", - "examples": ["e.g. 0xbcA81A2118982182d897845571BE950aE94C619c"], - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - } - }, - "required": ["SUBGRAPH_URL", "VAULT_ADDR"], - "additionalProperties": false - } - } -} diff --git a/src/strategies/ruler-staked-token/README.md b/src/strategies/ruler-staked-token/README.md deleted file mode 100644 index 493bd5251..000000000 --- a/src/strategies/ruler-staked-token/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# ruler-staked-token - -This strategy returns the balance of a specific ERC20 token staked in a ruler-style contract. - -Here is an example of parameters: - -```json -{ - "tokenAddress": "0x2aECCB42482cc64E087b6D2e5Da39f5A7A7001f8", - "stakingAddress": "0x3423c8Af3a95D9FEE7Ec06c4e0E905D4fd559F89", - "symbol": "RULER", - "decimals": 18 -} -``` diff --git a/src/strategies/ruler-staked-token/examples.json b/src/strategies/ruler-staked-token/examples.json deleted file mode 100644 index 3045a5202..000000000 --- a/src/strategies/ruler-staked-token/examples.json +++ /dev/null @@ -1,22 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "ruler-staked-token", - "params": { - "tokenAddress": "0xb1EECFea192907fC4bF9c4CE99aC07186075FC51", - "stakingAddress": "0x3423c8Af3a95D9FEE7Ec06c4e0E905D4fd559F89", - "symbol": "RULER-WETH SLP", - "decimals": 18 - } - }, - "network": "1", - "addresses": [ - "0x0291eb432CB4a2613a7415018933E3Db45Bcd769", - "0x7DE2bF548eaAd49588eB334696d7C2d4443C0575", - "0xBDbFdf3e82fC9d2bE1352e252aB1Ce2287fC2122", - "0x17EA85484cD4E97bE63fC02F20a196EDEAa937a9" - ], - "snapshot": 12777196 - } -] diff --git a/src/strategies/ruler-staked-token/index.ts b/src/strategies/ruler-staked-token/index.ts deleted file mode 100644 index 35aa25da4..000000000 --- a/src/strategies/ruler-staked-token/index.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { formatUnits } from '@ethersproject/units'; -import { multicall } from '../../utils'; - -export const author = 'drop-out-dev'; -export const version = '0.1.0'; - -const abi = [ - { - inputs: [ - { internalType: 'address', name: '_lpToken', type: 'address' }, - { internalType: 'address', name: '_account', type: 'address' } - ], - name: 'getUser', - outputs: [ - { - components: [ - { internalType: 'uint256', name: 'amount', type: 'uint256' }, - { - internalType: 'uint256[]', - name: 'rewardsWriteoffs', - type: 'uint256[]' - } - ], - internalType: 'struct IBonusRewards.User', - name: '', - type: 'tuple' - }, - { internalType: 'uint256[]', name: '', type: 'uint256[]' } - ], - stateMutability: 'view', - type: 'function' - } -]; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - const response = await multicall( - network, - provider, - abi, - addresses.map((address: any) => [ - options.stakingAddress, - 'getUser', - [options.tokenAddress, address] - ]), - { blockTag } - ); - return Object.fromEntries( - response.map(([userInfo], i) => [ - addresses[i], - parseFloat(formatUnits(userInfo.amount, options.decimals)) - ]) - ); -} diff --git a/src/strategies/saddle-finance-v2/README.md b/src/strategies/saddle-finance-v2/README.md deleted file mode 100644 index d9ba0d12e..000000000 --- a/src/strategies/saddle-finance-v2/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Saddle Finance Governance Strategy - -Custom strategy which includes unclaimed SDL tokens in the user's wallet, retroactive drop and team/advisor/investor vesting contracts. diff --git a/src/strategies/saddle-finance-v2/examples.json b/src/strategies/saddle-finance-v2/examples.json deleted file mode 100644 index 22ae6a208..000000000 --- a/src/strategies/saddle-finance-v2/examples.json +++ /dev/null @@ -1,20 +0,0 @@ -[ - { - "name": "Saddle Finance", - "strategy": { - "name": "saddle-finance", - "params": { - "symbol": "SDL" - } - }, - "network": "1", - "addresses": [ - "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B", - "0x664f45ed5084abcf2f8e1a95e320b06cc700591b", - "0xf4a0e9ad90f441670016742c8977f79553ee8ee8", - "0x243fFB6d39aD73327242D08329b8273B81ed0Ab0", - "0xcb10d759caaa8ec12a4d2e59f9d55018dd8b1c9a" - ], - "snapshot": 13754897 - } -] diff --git a/src/strategies/saddle-finance-v2/index.ts b/src/strategies/saddle-finance-v2/index.ts deleted file mode 100644 index a68252422..000000000 --- a/src/strategies/saddle-finance-v2/index.ts +++ /dev/null @@ -1,153 +0,0 @@ -import fetch from 'cross-fetch'; -import { formatUnits } from '@ethersproject/units'; -import { multicall } from '../../utils'; -import { vestingContractAddrs } from './vestingContractAddrs'; - -export const author = 'saddle-finance'; -export const version = '0.1.0'; - -const SDLTokenAddress = '0xf1Dc500FdE233A4055e25e5BbF516372BC4F6871'; -const RetroRewardsContract = '0x5DCA270671935cf3dF78bd8373C22BE250198a03'; - -const abi = [ - 'function balanceOf(address) external view returns (uint256)', - 'function beneficiary() external view returns (address)', - 'function vestings(address) external view returns (bool isVerified, uint120 totalAmount, uint120 released)', - 'function vestedAmount() public view returns (uint256)' -]; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - const remappedMerkleDataRes = await fetch( - 'https://gateway.pinata.cloud/ipfs/QmV73GEaijyiBFHu1vRdZBFffoCHaXYWG5SpurbEgr4VK6', - { - method: 'GET', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json' - } - } - ); - const remappedMerkleData = await remappedMerkleDataRes.json(); - - const userWalletBalanceResponse = multicall( - network, - provider, - abi, - addresses.map((address: any) => [ - SDLTokenAddress, - 'balanceOf', - [address.toLowerCase()] - ]), - { blockTag } - ); - - const beneficiaries = multicall( - network, - provider, - abi, - vestingContractAddrs.map((vestingContractAddress: any) => [ - vestingContractAddress.toLowerCase(), - 'beneficiary' - ]), - { blockTag } - ); - - const vestedAndUnclaimedAmountRes = multicall( - network, - provider, - abi, - vestingContractAddrs.map((vestingContractAddress: any) => [ - vestingContractAddress.toLowerCase(), - 'vestedAmount' - ]), - { blockTag } - ); - - const retroAddrs = Object.keys(remappedMerkleData); - - const userVestingsRes = multicall( - network, - provider, - abi, - retroAddrs.map((retroAddr: any) => [ - RetroRewardsContract, - 'vestings', - [retroAddr.toLowerCase()] - ]), - { blockTag } - ); - - const balances = await Promise.all([ - userWalletBalanceResponse, - vestedAndUnclaimedAmountRes, - beneficiaries, - userVestingsRes - ]); - - const retroUserBalances = {}; - retroAddrs.forEach((addr, i) => { - const userVesting = balances[3][i]; - if (userVesting?.isVerified) { - retroUserBalances[addr.toLowerCase()] = parseFloat( - formatUnits( - userVesting.totalAmount.sub(userVesting.released).toString(), - 18 - ) - ); - } else { - retroUserBalances[addr.toLowerCase()] = parseFloat( - formatUnits(remappedMerkleData[addr].amount, 18) - ); - } - }); - - const mappedBeneficiariesToUnclaimedAmount = balances[2].reduce( - (acc, addr, i) => ({ - ...acc, - [addr]: parseFloat(formatUnits(balances[1][i][0].toString(), 18)) - }), - {} - ); - - const userWalletBalances = balances[0].map((amount, i) => { - return [ - addresses[i].toLowerCase(), - parseFloat(formatUnits(amount.toString(), 18)) - ]; - }); - - const userTotal = {}; - // loop through user, investor/advisor/team-member, and airdrop wallets to calculate total. - userWalletBalances.forEach(([address, amount]) => { - const addr = address.toLowerCase(); - if (userTotal[addr]) userTotal[addr] += amount; - else userTotal[addr] = amount; - }); - for (const [address, amount] of Object.entries(retroUserBalances)) { - const addr = address.toLowerCase(); - if (userTotal[addr]) userTotal[addr] += amount; - else userTotal[addr] = amount; - } - for (const [address, amount] of Object.entries( - mappedBeneficiariesToUnclaimedAmount - )) { - const addr = address.toLowerCase(); - if (userTotal[addr]) userTotal[addr] += amount; - else userTotal[addr] = amount; - } - - const finalUserBalances = Object.fromEntries( - addresses.map((addr) => [addr, userTotal[addr.toLowerCase()]]) - ); - - return finalUserBalances; -} diff --git a/src/strategies/saddle-finance-v2/vestingContractAddrs.ts b/src/strategies/saddle-finance-v2/vestingContractAddrs.ts deleted file mode 100644 index 5034e7a78..000000000 --- a/src/strategies/saddle-finance-v2/vestingContractAddrs.ts +++ /dev/null @@ -1,74 +0,0 @@ -export const vestingContractAddrs = [ - '0x5dfbceea7a5f6556356c7a66d2a43332755d68a5', - '0xa440423cc4731909d21cda5b80cdf4a0e998a046', - '0x1e82992cd3f1f495827b545fa1d0845316c3404d', - '0xafc5d02588035124273291e35cacc11ce4249295', - '0xd17c31796d3cb41d9d211904780320c4be286172', - '0x85f99b73d0edd9cdb3462c94ebe4c5758684bdf1', - '0x92ff688d17504ff04f6551150ff34de61cf6f772', - '0x3f2763cace9b48f0cdbe84e049b5695ce3cf7d7e', - '0xb960fafebb589ca3500eb9350eea503548bccfc2', - '0xc7b2f1a2d0838370f88a2fd5c2e3f64d8af89a18', - '0x85c77d06f326381390b619ef202fe8fb9ce40679', - '0xcdec570c3eff689d97eaf3ad9eb31993dcf04f51', - '0xeed792fda7bd79398d4f3cc28f02bb65bfb7700f', - '0x878a65846a37b8cb117662bfdda596ed99b50f0d', - '0x5f4d8017ab0b5476a7177b2f1200f1ccf23f396d', - '0x8e0b95b6040188ac4a51da2eaf11ef93cc9af89f', - '0xa382a5427b387a8ea419d7259496d5b5d8930d43', - '0xcd57f671c59e32af35258c19ed112bac6c5db48b', - '0xf8264afe6483e7149ad9bc9d27759e37ce03f0ed', - '0x32b58b1bc7d10d5313b87b4e45c17d9cd342dcf6', - '0x7024716497d385ad9e5762a17e5d91893af5a47b', - '0xb8196a14c3318eb39518bc1977b99ea000e02f66', - '0xfdc134499b7de70ee88f4594761b8f6acf9c64a0', - '0xf5d69f455474f1f78654b08138178622dc20651a', - '0x64cac463ac033534bdbc94b9da06193b95cf779f', - '0x2a611277d378b475ba7bad5d601a94d19f6a5eb3', - '0x12ce3e43d2d6d793f2af61ff8e8ae7df88704b32', - '0xb5c81597f982dedf7452aecfe9ea0d2317d0a6cb', - '0x3ce780be5cfa346f60d1919451ec0dc9df316a12', - '0xa5a5f2cdefbbec9b107032edaa737c0b947acc9c', - '0xf1dfa2b7331f31317d15d74121485068589e0d8d', - '0x8a81e676d2f32c9cbaa0f5ea48d36ef7172eda97', - '0x94fcefc941ef42510e166746c9a8ab8fe4933cbc', - '0xb6fa5b81f6898b9acfa2d5af352b3ae25105028b', - '0x6672fbe9793970fd762ed7a48cbae81db7bb0a5e', - '0x7a1c42297c00823736fd91e3d0f2cc7ca848e98e', - '0xc896e23a786b51a55fe0c2d5091faa4bf2ee0896', - '0xa0e5ca644b026377f8f280e35438bf8acb0b5790', - '0x5c17b22a49ac26305d9a001fdc41733e59d868d0', - '0xdf239a0397c4f1d39b4cf414a1a06aa0f3797fba', - '0x76cb506fc99c10000145796b7e5e00d91b06829b', - '0x338179f237eecc39d3c0ad1a776ad02b1bf3761a', - '0xe1aeca359b91eadcd9934b3584b39fefff4c3b16', - '0xcfb49d2b349d389c41e5f915d1250e36a4eb42ca', - '0xee08c493a458876520813b256e9688eaede6a91a', - '0xdddf8b5c211fd97967eda1b7ad6330b9066bdee4', - '0x971b5eda88a400974556ac82d37389de8f140543', - '0xd6c29b1a8106584dc21ac3db4f4863e3caa47a60', - '0x5412a79e9cae0bad06bd9dd33f97ae2e196519e1', - '0x3e5f69698628b92e0a47f9c2c9e14ab892216096', - '0xe68319e9389554af7fe3f7ed41ff1901632634b6', - '0x493ecf1ece448ee83f72098cff0e196fb2948cb9', - '0x3d2ab86da84b2496168e5cf841d42a4ac27511d3', - '0x3bbfb974fc85286ca6db8162c312459a92f3e302', - '0xfde9512c0c4d7b092674229a42ab4aea5f743da1', - '0x597e475a5ddd90b3eb2135ac47319bd866f685d8', - '0xb39c77901054766662b77e3269d3b622e7cacab4', - '0x0622927ecf00406d48d05c39134bcd53ed396cb4', - '0xdcae005fcf34cf3e2b12b662dded94d0f7bf2977', - '0xdc0e9a031e9fc09681495a5ae5912954cbd858e4', - '0xbe3e1228d471fc747d7a4c68823910153ee552a5', - '0x45545bd03ccb1cd84d3c8f000a7d6c709d84720d', - '0x1ac13ff6e1bbca5b49c3f12468689289fb93c388', - '0x3cfd17f9cf57164ed64b91d25f72c2c6dfaeab48', - '0xaf8094420749b0131200b8e85f5018688261f110', - '0x039827df17ae5449b31162ec579bbbbe72300188', - '0xc7b3dbc8424a11255cf895c2916f24e0063dcdc3', - '0x2f246c27ed9f4839dff70233ce250a3f6024f484', - '0xa663ae21db74048e50401f542703e0802a3afeb9', - '0xf8b70d8cf29ee045acc5623ebe61037b33228fd1', - '0x5c85b43468da23f86016f508f14ca927bfd8a737', - '0x41092b4ecf2c4db719ec5ab67dbd0c66f095ee97' -]; diff --git a/src/strategies/saddle-finance/README.md b/src/strategies/saddle-finance/README.md deleted file mode 100644 index d9ba0d12e..000000000 --- a/src/strategies/saddle-finance/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Saddle Finance Governance Strategy - -Custom strategy which includes unclaimed SDL tokens in the user's wallet, retroactive drop and team/advisor/investor vesting contracts. diff --git a/src/strategies/saddle-finance/examples.json b/src/strategies/saddle-finance/examples.json deleted file mode 100644 index 22ae6a208..000000000 --- a/src/strategies/saddle-finance/examples.json +++ /dev/null @@ -1,20 +0,0 @@ -[ - { - "name": "Saddle Finance", - "strategy": { - "name": "saddle-finance", - "params": { - "symbol": "SDL" - } - }, - "network": "1", - "addresses": [ - "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B", - "0x664f45ed5084abcf2f8e1a95e320b06cc700591b", - "0xf4a0e9ad90f441670016742c8977f79553ee8ee8", - "0x243fFB6d39aD73327242D08329b8273B81ed0Ab0", - "0xcb10d759caaa8ec12a4d2e59f9d55018dd8b1c9a" - ], - "snapshot": 13754897 - } -] diff --git a/src/strategies/saddle-finance/index.ts b/src/strategies/saddle-finance/index.ts deleted file mode 100644 index 44a22533a..000000000 --- a/src/strategies/saddle-finance/index.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { formatUnits } from '@ethersproject/units'; -import { multicall } from '../../utils'; -import fetch from 'cross-fetch'; -import { vestingContractAddrs } from './vestingContractAddrs'; - -export const author = 'saddle-finance'; -export const version = '0.1.0'; - -const SDLTokenAddress = '0xf1Dc500FdE233A4055e25e5BbF516372BC4F6871'; -const RetroRewardsContract = '0x5DCA270671935cf3dF78bd8373C22BE250198a03'; - -const abi = [ - 'function balanceOf(address) external view returns (uint256)', - 'function beneficiary() external view returns (address)', - 'function vestings(address) external view returns (bool isVerified, uint120 totalAmount, uint120 released)' -]; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - const remappedMerkleDataRes = await fetch( - 'https://gateway.pinata.cloud/ipfs/QmV73GEaijyiBFHu1vRdZBFffoCHaXYWG5SpurbEgr4VK6', - { - method: 'GET', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json' - } - } - ); - const remappedMerkleData = await remappedMerkleDataRes.json(); - - const userWalletBalanceResponse = multicall( - network, - provider, - abi, - addresses.map((address: any) => [ - SDLTokenAddress, - 'balanceOf', - [address.toLowerCase()] - ]), - { blockTag } - ); - - const vestingAddrsBalanceRes = multicall( - network, - provider, - abi, - vestingContractAddrs.map((vestingContractAddress: any) => [ - SDLTokenAddress, - 'balanceOf', - [vestingContractAddress.toLowerCase()] - ]), - { blockTag } - ); - - const beneficiaries = multicall( - network, - provider, - abi, - vestingContractAddrs.map((vestingContractAddress: any) => [ - vestingContractAddress.toLowerCase(), - 'beneficiary' - ]), - { blockTag } - ); - - const retroAddrs = Object.keys(remappedMerkleData); - - const userVestingsRes = multicall( - network, - provider, - abi, - retroAddrs.map((retroAddr: any) => [ - RetroRewardsContract, - 'vestings', - [retroAddr.toLowerCase()] - ]), - { blockTag } - ); - - const balances = await Promise.all([ - userWalletBalanceResponse, - vestingAddrsBalanceRes, - beneficiaries, - userVestingsRes - ]); - - const retroUserBalances = {}; - retroAddrs.forEach((addr, i) => { - const userVesting = balances[3][i]; - if (userVesting?.isVerified) { - retroUserBalances[addr.toLowerCase()] = parseFloat( - formatUnits( - userVesting.totalAmount.sub(userVesting.released).toString(), - 18 - ) - ); - } else { - retroUserBalances[addr.toLowerCase()] = parseFloat( - formatUnits(remappedMerkleData[addr].amount, 18) - ); - } - }); - - const mappedBeneficiariesToVestingContract = balances[2].reduce( - (acc, addr, i) => ({ - ...acc, - [addr]: parseFloat(formatUnits(balances[1][i][0].toString(), 18)) - }), - {} - ); - - const userWalletBalances = balances[0].map((amount, i) => { - return [ - addresses[i].toLowerCase(), - parseFloat(formatUnits(amount.toString(), 18)) - ]; - }); - - const userTotal = {}; - // loop through user, investor/advisor/team-member, and airdrop wallets to calculate total. - userWalletBalances.forEach(([address, amount]) => { - const addr = address.toLowerCase(); - if (userTotal[addr]) userTotal[addr] += amount; - else userTotal[addr] = amount; - }); - for (const [address, amount] of Object.entries(retroUserBalances)) { - const addr = address.toLowerCase(); - if (userTotal[addr]) userTotal[addr] += amount; - else userTotal[addr] = amount; - } - for (const [address, amount] of Object.entries( - mappedBeneficiariesToVestingContract - )) { - const addr = address.toLowerCase(); - if (userTotal[addr]) userTotal[addr] += amount; - else userTotal[addr] = amount; - } - - const finalUserBalances = Object.fromEntries( - addresses.map((addr) => [addr, userTotal[addr.toLowerCase()]]) - ); - - return finalUserBalances; -} diff --git a/src/strategies/saddle-finance/vestingContractAddrs.ts b/src/strategies/saddle-finance/vestingContractAddrs.ts deleted file mode 100644 index 5034e7a78..000000000 --- a/src/strategies/saddle-finance/vestingContractAddrs.ts +++ /dev/null @@ -1,74 +0,0 @@ -export const vestingContractAddrs = [ - '0x5dfbceea7a5f6556356c7a66d2a43332755d68a5', - '0xa440423cc4731909d21cda5b80cdf4a0e998a046', - '0x1e82992cd3f1f495827b545fa1d0845316c3404d', - '0xafc5d02588035124273291e35cacc11ce4249295', - '0xd17c31796d3cb41d9d211904780320c4be286172', - '0x85f99b73d0edd9cdb3462c94ebe4c5758684bdf1', - '0x92ff688d17504ff04f6551150ff34de61cf6f772', - '0x3f2763cace9b48f0cdbe84e049b5695ce3cf7d7e', - '0xb960fafebb589ca3500eb9350eea503548bccfc2', - '0xc7b2f1a2d0838370f88a2fd5c2e3f64d8af89a18', - '0x85c77d06f326381390b619ef202fe8fb9ce40679', - '0xcdec570c3eff689d97eaf3ad9eb31993dcf04f51', - '0xeed792fda7bd79398d4f3cc28f02bb65bfb7700f', - '0x878a65846a37b8cb117662bfdda596ed99b50f0d', - '0x5f4d8017ab0b5476a7177b2f1200f1ccf23f396d', - '0x8e0b95b6040188ac4a51da2eaf11ef93cc9af89f', - '0xa382a5427b387a8ea419d7259496d5b5d8930d43', - '0xcd57f671c59e32af35258c19ed112bac6c5db48b', - '0xf8264afe6483e7149ad9bc9d27759e37ce03f0ed', - '0x32b58b1bc7d10d5313b87b4e45c17d9cd342dcf6', - '0x7024716497d385ad9e5762a17e5d91893af5a47b', - '0xb8196a14c3318eb39518bc1977b99ea000e02f66', - '0xfdc134499b7de70ee88f4594761b8f6acf9c64a0', - '0xf5d69f455474f1f78654b08138178622dc20651a', - '0x64cac463ac033534bdbc94b9da06193b95cf779f', - '0x2a611277d378b475ba7bad5d601a94d19f6a5eb3', - '0x12ce3e43d2d6d793f2af61ff8e8ae7df88704b32', - '0xb5c81597f982dedf7452aecfe9ea0d2317d0a6cb', - '0x3ce780be5cfa346f60d1919451ec0dc9df316a12', - '0xa5a5f2cdefbbec9b107032edaa737c0b947acc9c', - '0xf1dfa2b7331f31317d15d74121485068589e0d8d', - '0x8a81e676d2f32c9cbaa0f5ea48d36ef7172eda97', - '0x94fcefc941ef42510e166746c9a8ab8fe4933cbc', - '0xb6fa5b81f6898b9acfa2d5af352b3ae25105028b', - '0x6672fbe9793970fd762ed7a48cbae81db7bb0a5e', - '0x7a1c42297c00823736fd91e3d0f2cc7ca848e98e', - '0xc896e23a786b51a55fe0c2d5091faa4bf2ee0896', - '0xa0e5ca644b026377f8f280e35438bf8acb0b5790', - '0x5c17b22a49ac26305d9a001fdc41733e59d868d0', - '0xdf239a0397c4f1d39b4cf414a1a06aa0f3797fba', - '0x76cb506fc99c10000145796b7e5e00d91b06829b', - '0x338179f237eecc39d3c0ad1a776ad02b1bf3761a', - '0xe1aeca359b91eadcd9934b3584b39fefff4c3b16', - '0xcfb49d2b349d389c41e5f915d1250e36a4eb42ca', - '0xee08c493a458876520813b256e9688eaede6a91a', - '0xdddf8b5c211fd97967eda1b7ad6330b9066bdee4', - '0x971b5eda88a400974556ac82d37389de8f140543', - '0xd6c29b1a8106584dc21ac3db4f4863e3caa47a60', - '0x5412a79e9cae0bad06bd9dd33f97ae2e196519e1', - '0x3e5f69698628b92e0a47f9c2c9e14ab892216096', - '0xe68319e9389554af7fe3f7ed41ff1901632634b6', - '0x493ecf1ece448ee83f72098cff0e196fb2948cb9', - '0x3d2ab86da84b2496168e5cf841d42a4ac27511d3', - '0x3bbfb974fc85286ca6db8162c312459a92f3e302', - '0xfde9512c0c4d7b092674229a42ab4aea5f743da1', - '0x597e475a5ddd90b3eb2135ac47319bd866f685d8', - '0xb39c77901054766662b77e3269d3b622e7cacab4', - '0x0622927ecf00406d48d05c39134bcd53ed396cb4', - '0xdcae005fcf34cf3e2b12b662dded94d0f7bf2977', - '0xdc0e9a031e9fc09681495a5ae5912954cbd858e4', - '0xbe3e1228d471fc747d7a4c68823910153ee552a5', - '0x45545bd03ccb1cd84d3c8f000a7d6c709d84720d', - '0x1ac13ff6e1bbca5b49c3f12468689289fb93c388', - '0x3cfd17f9cf57164ed64b91d25f72c2c6dfaeab48', - '0xaf8094420749b0131200b8e85f5018688261f110', - '0x039827df17ae5449b31162ec579bbbbe72300188', - '0xc7b3dbc8424a11255cf895c2916f24e0063dcdc3', - '0x2f246c27ed9f4839dff70233ce250a3f6024f484', - '0xa663ae21db74048e50401f542703e0802a3afeb9', - '0xf8b70d8cf29ee045acc5623ebe61037b33228fd1', - '0x5c85b43468da23f86016f508f14ca927bfd8a737', - '0x41092b4ecf2c4db719ec5ab67dbd0c66f095ee97' -]; diff --git a/src/strategies/safe-vested/examples.json b/src/strategies/safe-vested/examples.json old mode 100755 new mode 100644 diff --git a/src/strategies/safe-vested/index.ts b/src/strategies/safe-vested/index.ts old mode 100755 new mode 100644 diff --git a/src/strategies/safety-module-bpt-power/README.md b/src/strategies/safety-module-bpt-power/README.md deleted file mode 100644 index eafa910a9..000000000 --- a/src/strategies/safety-module-bpt-power/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# staked-psp-balance - -This strategy computes the voting power of a staker relative to one token involved in a Aave like safety module that accepts arbitrary balancer LP token as staked token. -It uses balancer-pool-id strategy. - -To simplify async flow, it requires to pass couple of parameters: -- balancer pool id -- safety module (address, decimals) -- voting token (address, decimals) - - -This strategy works under 2 different regimes: - -1/ if voting_token matches reward_token of safety module --> count for staked tokens and unclaimed rewards - -2/ else --> count for staked tokens only \ No newline at end of file diff --git a/src/strategies/safety-module-bpt-power/examples.json b/src/strategies/safety-module-bpt-power/examples.json deleted file mode 100644 index a562035d7..000000000 --- a/src/strategies/safety-module-bpt-power/examples.json +++ /dev/null @@ -1,37 +0,0 @@ -[ - { - "name": "Example safety module bpt query", - "strategy": { - "name": "safety-module-bpt-power", - "params": { - "symbol": "PSP", - "balancerPoolId": "0xcb0e14e96f2cefa8550ad8e4aea344f211e5061d00020000000000000000011a", - "safetyModule": { - "address": "0xC8DC2Ec5f5e02bE8b37A8444a1931F02374A17ab", - "decimals": 18 - }, - "votingToken": { - "address": "0xcAfE001067cDEF266AfB7Eb5A286dCFD277f3dE5", - "decimals": 18 - } - } - }, - "network": "1", - "addresses": [ - "0x0ddc793680ff4f5793849c8c6992be1695cbe72a", - "0x9c0d72f2ac26420cb7eeb155bf401b672840e87b", - "0x7494eb2916cad8649f4f91eb1db6e20be605dad6", - "0xb7b65acf585c29070b9926c089fcfa1eb9983d3d", - "0x9824697f7c12cabada9b57842060931c48dea969", - "0x5b52e503c9e1440b47991bc0a64599c1c916084c", - "0x3ce06981bc523f950e3df346878216365b24b6fe", - "0xf2078c58d6c38c893af4e40d7b09843ec3b7d26c", - "0xcff61382e659603046358f86a119efd127d5bb48", - "0x8f60501dE5b9b01F9EAf1214dbE1924aA97F7fd0", - "0x9B8e8dD9151260c21CB6D7cc59067cd8DF306D58", - "0x17ea92D6FfbAA1c7F6B117c1E9D0c88ABdc8b84C", - "0x38C0039247A31F3939baE65e953612125cB88268" - ], - "snapshot": 14215928 - } -] diff --git a/src/strategies/safety-module-bpt-power/index.ts b/src/strategies/safety-module-bpt-power/index.ts deleted file mode 100644 index 4cbc5ea8f..000000000 --- a/src/strategies/safety-module-bpt-power/index.ts +++ /dev/null @@ -1,227 +0,0 @@ -import { strategy as balancerPoolIdStrategy } from '../balancer-poolid'; -import { BigNumberish } from '@ethersproject/bignumber'; -import { Multicaller } from '../../utils'; -import { formatUnits } from '@ethersproject/units'; - -export const author = 'mwamedacen'; -export const version = '0.1.0'; - -interface Options { - balancerPoolId: string; - safetyModule: { - address: string; - decimals: number; - }; - votingToken: { - address: string; - decimals: number; - }; -} - -type FetchSafetyModuleScoreOutput = Promise; - -async function fetchSafetyModuleScore( - space: string, - network: string, - provider, - addresses: string[], - options: Options, - snapshot: number -): FetchSafetyModuleScoreOutput { - const scores = await balancerPoolIdStrategy( - space, - network, - provider, - [options.safetyModule.address], - { - poolId: options.balancerPoolId, - token: options.votingToken.address - }, - snapshot - ); - - return parseFloat(scores[options.safetyModule.address]); -} - -const SafetyModuleMinABI = [ - 'function totalSupply() external view returns (uint256)', - 'function STAKED_TOKEN() external view returns (address)', - 'function REWARD_TOKEN() external view returns (address)', - 'function decimals() view returns (uint8)', - 'function balanceOf(address account) external view returns (uint256)', - 'function getTotalRewardsBalance(address staker) view returns (uint256)' -]; - -const TOTAL_SUPPLY_ATTR = 'totalSupply'; -const STAKED_TOKEN_ATTR = 'stakedToken'; -const REWARD_TOKEN_ATTR = 'rewardToken'; -const BALANCE_OF_ATTR = 'balanceOf'; -const REWARDS_OF_ATTR = 'totalRewardsBalance'; - -type FetchAccountsSafetyModuleStakesAndRewardsOuput = Promise<{ - [address: string]: { - [BALANCE_OF_ATTR]: BigNumberish; - [REWARD_TOKEN_ATTR]: BigNumberish; - }; -}>; - -async function fetchAccountsSafetyModuleStakesAndRewards( - space: string, - network: string, - provider, - addresses: string[], - options: Options, - snapshot: number -): FetchAccountsSafetyModuleStakesAndRewardsOuput { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - const multi = new Multicaller(network, provider, SafetyModuleMinABI, { - blockTag - }); - - addresses.forEach((address) => { - multi.call( - `${BALANCE_OF_ATTR}_${address}`, - options.safetyModule.address, - 'balanceOf', - [address] - ); - multi.call( - `${REWARDS_OF_ATTR}_${address}`, - options.safetyModule.address, - 'getTotalRewardsBalance', - [address] - ); - }); - - const result: Record = await multi.execute(); - - return Object.entries(result).reduce((acc, [key, value]) => { - const [attr, addr] = key.split('_'); - - if (!acc[addr]) { - acc[addr] = {}; - } - - acc[addr][attr] = value; - - return acc; - }, {}); -} - -type FetchSafetyModuleGlobalStateOutput = Promise<{ - [TOTAL_SUPPLY_ATTR]: BigNumberish; - [REWARD_TOKEN_ATTR]: string; - [STAKED_TOKEN_ATTR]: string; -}>; - -async function fetchSafetyModuleGlobalState( - space: string, - network: string, - provider, - addresses: string[], - options: Options, - snapshot: number -): FetchSafetyModuleGlobalStateOutput { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - const multi = new Multicaller(network, provider, SafetyModuleMinABI, { - blockTag - }); - - multi.call(STAKED_TOKEN_ATTR, options.safetyModule.address, 'STAKED_TOKEN'); - multi.call(REWARD_TOKEN_ATTR, options.safetyModule.address, 'REWARD_TOKEN'); - multi.call(TOTAL_SUPPLY_ATTR, options.safetyModule.address, 'totalSupply'); - - const result: { - [STAKED_TOKEN_ATTR]: string; - [REWARD_TOKEN_ATTR]: string; - [TOTAL_SUPPLY_ATTR]: BigNumberish; - } = await multi.execute(); - - return result; -} - -export async function strategy( - space: string, - network: string, - provider, - addresses: string[], - options: Options, - snapshot: number -) { - const [safetyModuleScore, accountsStakesAndRewards, safetyModuleGlobalState] = - await Promise.all( - [ - fetchSafetyModuleScore, - fetchAccountsSafetyModuleStakesAndRewards, - fetchSafetyModuleGlobalState - ].map((fn) => - fn(space, network, provider, addresses, options, snapshot) - ) as [ - FetchSafetyModuleScoreOutput, - FetchAccountsSafetyModuleStakesAndRewardsOuput, - FetchSafetyModuleGlobalStateOutput - ] - ); - - const safetyModuleStakedToken = safetyModuleGlobalState[STAKED_TOKEN_ATTR]; - - if ( - safetyModuleStakedToken.toLowerCase() !== - options.balancerPoolId.substring(0, 42).toLowerCase() - ) { - throw new Error( - `safety-module-bpt-power, safety module's staken token ${safetyModuleStakedToken} doesn't match balancer pool ${options.balancerPoolId}` - ); - } - - const safetyModuleRewardsToken = safetyModuleGlobalState[REWARD_TOKEN_ATTR]; - - const votingAndRewardTokenMatching = - safetyModuleRewardsToken.toLowerCase() === - options.votingToken.address.toLowerCase(); - - const safetyModuleTotalSupply = parseFloat( - formatUnits( - safetyModuleGlobalState[TOTAL_SUPPLY_ATTR], - options.safetyModule.decimals - ) - ); - - const scores = Object.fromEntries( - Object.entries(accountsStakesAndRewards).map( - ([address, accountStakesAndRewards]) => { - const accountSafetyModuleBalance = parseFloat( - formatUnits( - accountStakesAndRewards[BALANCE_OF_ATTR], - options.safetyModule.decimals - ) - ); - - const accountSharePercent = - accountSafetyModuleBalance / safetyModuleTotalSupply; - - const accountStakedScore = accountSharePercent * safetyModuleScore; - - if (!votingAndRewardTokenMatching) { - return [address, accountStakedScore]; - } - - const accountRewardsScore = parseFloat( - formatUnits( - accountStakesAndRewards[REWARDS_OF_ATTR], - options.votingToken.decimals - ) - ); - - const accountStakedAndRewardsScore = - accountStakedScore + accountRewardsScore; - - return [address, accountStakedAndRewardsScore]; - } - ) - ); - - return scores; -} diff --git a/src/strategies/safety-module-bpt-power/schema.json b/src/strategies/safety-module-bpt-power/schema.json deleted file mode 100644 index 565093bc9..000000000 --- a/src/strategies/safety-module-bpt-power/schema.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$ref": "#/definitions/Strategy", - "definitions": { - "Strategy": { - "title": "Strategy", - "type": "object", - "properties": { - "symbol": { - "type": "string", - "title": "Symbol", - "examples": ["e.g. PSP"], - "maxLength": 16 - }, - "balancerPoolId": { - "type": "string", - "title": "BalancerPoolId", - "examples": [ - "e.g. 0xcb0e14e96f2cefa8550ad8e4aea344f211e5061d00020000000000000000011a" - ], - "pattern": "^0x[a-fA-F0-9]{64}$", - "minLength": 66, - "maxLength": 66 - }, - "safetyModule": { - "type": "object", - "title": "SafetyModule", - "properties": { - "address": { - "type": "string", - "title": "Address", - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - }, - "decimals": { - "type": "number", - "title": "Decimals", - "examples": ["e.g. 18"] - } - } - }, - "votingToken": { - "type": "object", - "title": "VotingToken", - "properties": { - "address": { - "type": "string", - "title": "Address", - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - }, - "decimals": { - "type": "number", - "title": "Decimals", - "examples": ["e.g. 18"] - } - } - } - }, - "required": ["balancerPoolId", "safetyModule", "votingToken"], - "additionalProperties": false - } - } -} diff --git a/src/strategies/selfswap/README.md b/src/strategies/selfswap/README.md deleted file mode 100644 index 42c764887..000000000 --- a/src/strategies/selfswap/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# selfswap - -Fetches [SELF](https://bscscan.com/address/0x7a364484303b38bce7b0ab60a20da8f2f4370129) balance from the following sources: - -- Wallet -- SELF-BNB LP Farm -- SELF Pool -- SELF Vault -- Pools that were active at the time of the snapshot diff --git a/src/strategies/selfswap/examples.json b/src/strategies/selfswap/examples.json deleted file mode 100644 index 82b20d8c5..000000000 --- a/src/strategies/selfswap/examples.json +++ /dev/null @@ -1,19 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "selfswap", - "params": { - "symbol": "SELF" - } - }, - "network": "56", - "addresses": [ - "0x26e82CB17cfd4ef12096f38f3ba0DAD6ea5B5035", - "0x21fF20E7e1B820020415707298b92299CF0951fE", - "0x2b3D1D31ac5C053cf89a92EE9c94dbF3774D6366", - "0x273e3fD65450032a44AC6CA36F6551D74A459B6A" - ], - "snapshot": 16308675 - } -] diff --git a/src/strategies/selfswap/index.ts b/src/strategies/selfswap/index.ts deleted file mode 100644 index 76531aa09..000000000 --- a/src/strategies/selfswap/index.ts +++ /dev/null @@ -1,224 +0,0 @@ -import { strategy as erc20BalanceOfStrategy } from '../erc20-balance-of'; -import { strategy as masterChefPoolBalanceStrategy } from '../masterchef-pool-balance'; -import { formatEther } from '@ethersproject/units'; -import { Zero, WeiPerEther } from '@ethersproject/constants'; -import { BigNumber } from '@ethersproject/bignumber'; -import { subgraphRequest, Multicaller } from '../../utils'; - -const chunk = (arr, size) => - Array.from({ length: Math.ceil(arr.length / size) }, (v, i) => - arr.slice(i * size, i * size + size) - ); - -const PAGE_SIZE = 1000; - -export const author = 'Cr3k'; -export const version = '0.0.1'; - -const SELF_ADDRESS = '0x7a364484303b38bce7b0ab60a20da8f2f4370129'; -const SELF_VAULT_ADDRESS = '0xeb4f1307DE7DF263E8e54d083fE7db1e281e710D'; -const SELF_BNB_LP_ADDRESS = '0x9C6FF656A563Ec9057460D8a400E2AC7c2AE0a1C'; - -const MASTER_CHEF_ADDRESS = { - v1: '0x3d03d12F95Bdc4509804f9Bcee4139b7789DC516' -}; - -const vaultAbi = [ - 'function getPricePerFullShare() view returns (uint256)', - 'function userInfo(address) view returns (uint256 shares, uint256 lastDepositedTime, uint256 selfAtLastUserAction, uint256 lastUserActionTime)' -]; - -const smartChefUrl = 'https://api.thegraph.com/subgraphs/name/cr3k/smartchef'; - -async function getPools(provider, snapshot: any) { - let blockNumber = snapshot; - if (blockNumber === 'latest') { - blockNumber = await provider.getBlockNumber(); - } - - const params = { - smartChefs: { - __args: { - where: { - stakeToken: SELF_ADDRESS.toLowerCase(), - endBlock_gte: blockNumber, - startBlock_lt: blockNumber - } - }, - id: true - } - }; - - const pools = await subgraphRequest(smartChefUrl, params); - - return pools.smartChefs; -} - -async function getSmartChefStakedSELFAmount( - snapshot: any, - poolAddresses: string[], - addresses: string[] -) { - const addressChunks = chunk(addresses, 1500); - let results: any[] = []; - - for (const addressChunk of addressChunks) { - const params = { - users: { - __args: { - where: { - pool_in: poolAddresses.map((addr) => addr.toLowerCase()), - address_in: addressChunk.map((addr) => addr.toLowerCase()), - stakeAmount_gt: '0' - }, - first: PAGE_SIZE - }, - address: true, - stakeAmount: true - } - }; - - let page = 0; - let triedBlockNumber = false; - - while (true) { - // @ts-ignore - params.users.__args.skip = page * PAGE_SIZE; - if (snapshot !== 'latest' && !triedBlockNumber) { - // @ts-ignore - params.users.__args.block = { number: snapshot }; - } else { - // @ts-ignore - delete params.users.__args.block; - } - let result; - try { - result = await subgraphRequest(smartChefUrl, params); - } catch (error) { - if (!triedBlockNumber) { - triedBlockNumber = true; - continue; - } else { - throw error; - } - } - if (!Array.isArray(result.users) && !triedBlockNumber) { - triedBlockNumber = true; - continue; - } - results = results.concat(result.users); - page++; - if (result.users.length < PAGE_SIZE) break; - } - } - - return results.reduce>((acc, user) => { - if (acc[user.address]) { - acc[user.address] = (acc[user.address] as BigNumber).add( - user.stakeAmount - ); - } else { - acc[user.address] = BigNumber.from(user.stakeAmount); - } - return acc; - }, {}); -} - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const pools = await getPools(provider, snapshot); - - const userPoolBalance = await getSmartChefStakedSELFAmount( - snapshot, - pools.map((p) => p.id), - addresses - ); - - const blockTag = snapshot; - - const erc20Balance = await erc20BalanceOfStrategy( - space, - network, - provider, - addresses, - { - address: SELF_ADDRESS, - symbol: 'SELF', - decimals: 18 - }, - snapshot - ); - - const selfBnbLpBalance = await masterChefPoolBalanceStrategy( - space, - network, - provider, - addresses, - { - chefAddress: MASTER_CHEF_ADDRESS.v1, - uniPairAddress: SELF_BNB_LP_ADDRESS, - pid: '251', - symbol: 'SELF-BNB LP', - tokenIndex: 0 - }, - snapshot - ); - - const selfVaultBalance = await getVaultBalance( - network, - provider, - addresses, - blockTag - ); - - return Object.fromEntries( - addresses.map((address) => [ - address, - erc20Balance[address] + - selfBnbLpBalance[address] + - parseFloat( - formatEther( - (userPoolBalance[address.toLowerCase()] || Zero).add( - selfVaultBalance[address] || Zero - ) - ) - ) - ]) - ); -} - -async function getVaultBalance(network, provider, addresses, blockTag) { - const vaultMulti = new Multicaller(network, provider, vaultAbi, { blockTag }); - - vaultMulti.call( - SELF_VAULT_ADDRESS, - SELF_VAULT_ADDRESS, - 'getPricePerFullShare' - ); - - addresses.forEach((address) => - vaultMulti.call( - `${SELF_VAULT_ADDRESS}-${address}`, - SELF_VAULT_ADDRESS, - 'userInfo', - [address] - ) - ); - - const vaultMultiRes = await vaultMulti.execute(); - - return Object.fromEntries( - addresses.map((address) => [ - address, - (vaultMultiRes[SELF_VAULT_ADDRESS] || Zero) - .mul(vaultMultiRes[`${SELF_VAULT_ADDRESS}-${address}`]?.shares || Zero) - .div(WeiPerEther) - ]) - ); -} diff --git a/src/strategies/single-staking-vault-balanceof/README.md b/src/strategies/single-staking-vault-balanceof/README.md deleted file mode 100644 index a7c2d76da..000000000 --- a/src/strategies/single-staking-vault-balanceof/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# single-staking-vault-balanceof - -Used for fetching the staked token balance in a single staking vault - -The only parameter is the vault address. The vault must -have the function call `wantLockedTotal(address)` which should -return the amount of tokens in the vault. - -```json -{ - "vaultAddress": "0xA68E643e1942fA8635776b718F6EeD5cEF2a3F15" -} -``` diff --git a/src/strategies/single-staking-vault-balanceof/examples.json b/src/strategies/single-staking-vault-balanceof/examples.json deleted file mode 100644 index 5a4bbb5e6..000000000 --- a/src/strategies/single-staking-vault-balanceof/examples.json +++ /dev/null @@ -1,20 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "single-staking-vault-balanceof", - "params": { - "symbol": "STAKE", - "vaultAddress": "0xA68E643e1942fA8635776b718F6EeD5cEF2a3F15" - } - }, - "network": "1666600000", - "addresses": [ - "0xD20B976584bF506BAf5cC604D1f0A1B8D07138dA", - "0x4ff9B7C1424b9E4375BbbDF3357a318412c02E0c", - "0x57B7713c0E013cfbEC0E4C6c8B264dAf7598ebA9", - "0xB989B490F9899a5AD56a4255A3C84457040B59dc" - ], - "snapshot": 18263021 - } -] diff --git a/src/strategies/single-staking-vault-balanceof/index.ts b/src/strategies/single-staking-vault-balanceof/index.ts deleted file mode 100644 index 729c3b7a4..000000000 --- a/src/strategies/single-staking-vault-balanceof/index.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { formatUnits } from '@ethersproject/units'; -import { multicall } from '../../utils'; - -export const author = 'foxthefarmer'; -export const version = '0.0.1'; - -const vaultAbi = ['function wantLockedTotal(address) view returns (uint256)']; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - const vaultBalancesCalls: any = multicall( - network, - provider, - vaultAbi, - addresses.map((address: any) => [ - options.vaultAddress, - 'wantLockedTotal', - [address] - ]), - { blockTag } - ); - - const vaultBalances = await Promise.all([vaultBalancesCalls]); - - return Object.fromEntries( - Object.entries(addresses).map((address: any, index) => [ - address[1], - parseFloat(formatUnits(vaultBalances[0][index].toString(), 18)) - ]) - ); -} diff --git a/src/strategies/snowswap/README.md b/src/strategies/snowswap/README.md deleted file mode 100644 index 8a83fd7c6..000000000 --- a/src/strategies/snowswap/README.md +++ /dev/null @@ -1,12 +0,0 @@ -Snowswap - -Checks for the number of SNOW's staked in Frosty’s pool (https://etherscan.io/address/0x7d2c8b58032844f222e2c80219975805dce1921c) and adds it to the balance of the voters FLAME ERC20 token - -Here is an example of parameters: - -{ - "address": "0xfe9A29aB92522D14Fc65880d817214261D8479AE", - "symbol": "SNOW", - "decimals": 18, - "snowStakingAddress": "0x7d2c8b58032844f222e2c80219975805dce1921c" -} diff --git a/src/strategies/snowswap/examples.json b/src/strategies/snowswap/examples.json deleted file mode 100644 index 2b75c2774..000000000 --- a/src/strategies/snowswap/examples.json +++ /dev/null @@ -1,20 +0,0 @@ -[ - { - "name": "Snowswap", - "strategy": { - "name": "snowswap", - "params": { - "address": "0xfe9A29aB92522D14Fc65880d817214261D8479AE", - "symbol": "SNOW", - "decimals": 18, - "snowStakingAddress": "0x7d2c8b58032844f222e2c80219975805dce1921c" - } - }, - "network": "1", - "addresses": [ - "0x109763295D1636D6b311ab690c63e2A7A4606bC7", - "0x7d2c8b58032844f222e2c80219975805dce1921c" - ], - "snapshot": 13087619 - } -] diff --git a/src/strategies/snowswap/index.ts b/src/strategies/snowswap/index.ts deleted file mode 100644 index bcccaa601..000000000 --- a/src/strategies/snowswap/index.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { BigNumberish } from '@ethersproject/bignumber'; -import { formatUnits } from '@ethersproject/units'; -import { Multicaller } from '../../utils'; -import { strategy as erc20BalanceOfStrategy } from '../erc20-balance-of'; - -export const author = 'jairsnowswap'; -export const version = '0.1.0'; - -const stakedAbi = [ - 'function balanceOf(address account) external view returns (uint256)' -]; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - const { snowStakingAddress, decimals } = options; - - const snowBalances = await erc20BalanceOfStrategy( - space, - network, - provider, - addresses, - options, - snapshot - ); - - const stakedTokenBalances = new Multicaller(network, provider, stakedAbi, { - blockTag - }); - - addresses.forEach((address: string) => - stakedTokenBalances.call(address, snowStakingAddress, 'balanceOf', [ - address - ]) - ); - const result: Record = - await stakedTokenBalances.execute(); - - return Object.fromEntries( - Object.entries(result).map(([address, output]) => [ - address, - parseFloat(formatUnits(output, decimals)) + snowBalances[address] - ]) - ); -} diff --git a/src/strategies/solv-voucher-claimable/README.md b/src/strategies/solv-voucher-claimable/README.md deleted file mode 100644 index 04e7da0c6..000000000 --- a/src/strategies/solv-voucher-claimable/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# solv-voucher-claimable - -This strategy is to let owners of [Solv vesting vouchers](https://solv.finance/) vote with the voting power equal to their claimable token amount in the voucher at the time of the snapshot. - -This can be combined with `erc20-balance-of` strategy to give the voting power of "amount held in wallet" + "amount available in the vesting voucher". - -The parameters are the `address` of the vesting voucher contract and the `symbol` of the underlying token. Here is an example of parameters: - -```json -{ - "address": "0x522f8fe415e08b600b8bd6c1db74a1b696845d0d", - "symbol": "PDT" -} -``` diff --git a/src/strategies/solv-voucher-claimable/examples.json b/src/strategies/solv-voucher-claimable/examples.json deleted file mode 100644 index 95c270dba..000000000 --- a/src/strategies/solv-voucher-claimable/examples.json +++ /dev/null @@ -1,42 +0,0 @@ -[ - { - "name": "PDT Vesting Voucher Claimable Amounts", - "strategy": { - "name": "solv-voucher-claimable", - "params": { - "address": "0x522f8fe415e08b600b8bd6c1db74a1b696845d0d", - "symbol": "PDT" - } - }, - "network": "1", - "addresses": [ - "0x0d5f507074db8ead56f5875219dbf1ff73bcd429", - "0xf96225d26fa257b200420696092e02cc141cf3d8", - "0xd3be4499f28ef91a6b6dd5ab6beb0588039d72ba", - "0x661c3a6db7241f2a7b3b1c1d73fe98198d089fc2", - "0xceeab2af38e6b086cdce120c49f93b65f0b92b76", - "0xc40fc1c553737b2aa8572fdb036986510219f233" - ], - "snapshot": 14955800 - }, - { - "name": "VERA Vesting Voucher Claimable Amounts", - "strategy": { - "name": "solv-voucher-claimable", - "params": { - "address": "0x928b35660f8388042d871e82eb40234901461354", - "symbol": "VERA" - } - }, - "network": 56, - "addresses": [ - "0x0d5f507074db8ead56f5875219dbf1ff73bcd429", - "0xf96225d26fa257b200420696092e02cc141cf3d8", - "0xd3be4499f28ef91a6b6dd5ab6beb0588039d72ba", - "0x661c3a6db7241f2a7b3b1c1d73fe98198d089fc2", - "0xceeab2af38e6b086cdce120c49f93b65f0b92b76", - "0xc40fc1c553737b2aa8572fdb036986510219f233" - ], - "snapshot": 19287600 - } -] diff --git a/src/strategies/solv-voucher-claimable/index.ts b/src/strategies/solv-voucher-claimable/index.ts deleted file mode 100644 index 32fb035c3..000000000 --- a/src/strategies/solv-voucher-claimable/index.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { BigNumber, FixedNumber } from '@ethersproject/bignumber'; -import { Multicaller } from '../../utils'; - -export const author = 'mitesh-mutha'; -export const version = '0.1.0'; - -const abi = [ - 'function balanceOf(address account) external view returns (uint256)', - 'function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256)', - 'function tokenURI(uint256 tokenId) external view returns (string)' -]; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -): Promise> { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - // Fetch the balanceOf the addresses i.e. how many vouchers do they hold? - const balanceOfMulti = new Multicaller(network, provider, abi, { blockTag }); - addresses.forEach((address) => - balanceOfMulti.call(address, options.address, 'balanceOf', [address]) - ); - const ownedCounts: Record = await balanceOfMulti.execute(); - - // Fetch the voucher token IDs held for each address - const tokenIdsMulti = new Multicaller(network, provider, abi, { blockTag }); - addresses.map((address) => { - let ownedCount = ownedCounts[address]; - while (ownedCount.gt(0)) { - const index = ownedCount.sub(1); - tokenIdsMulti.call( - `${address}-${index.toString()}`, - options.address, - 'tokenOfOwnerByIndex', - [address, index.toNumber()] - ); - ownedCount = index; - } - }); - const ownerTokenIds: Record = await tokenIdsMulti.execute(); - - // Fetch the voucher data for each voucher held by an address among the address - const tokenURIMulti = new Multicaller(network, provider, abi, { blockTag }); - Object.entries(ownerTokenIds).map(([addressWithIndex, tokenId]) => { - tokenURIMulti.call(`${addressWithIndex}`, options.address, `tokenURI`, [ - tokenId - ]); - }); - const ownerTokenURIs: Record = await tokenURIMulti.execute(); - - // Go through the list of results and sum up claimable values - const claimableVotingPower: Record = {}; - Object.entries(ownerTokenURIs).map(([addressWithIndex, tokenURI]) => { - const address = addressWithIndex.split('-')[0]; - if (tokenURI.split(',')[0] == 'data:application/json') { - const tokenData = JSON.parse(tokenURI.slice(22)); - const claimableAmount = tokenData['properties']['claimableAmount']; - if (!claimableVotingPower[address]) - claimableVotingPower[address] = FixedNumber.from(0); - claimableVotingPower[address] = claimableVotingPower[address].addUnsafe( - FixedNumber.fromString(claimableAmount) - ); - } - }); - - // Return the computed values - return Object.fromEntries( - Object.entries(claimableVotingPower).map(([address, votingPower]) => [ - address, - votingPower.toUnsafeFloat() - ]) - ); -} diff --git a/src/strategies/solv-voucher-claimable/schema.json b/src/strategies/solv-voucher-claimable/schema.json deleted file mode 100644 index 7d01484de..000000000 --- a/src/strategies/solv-voucher-claimable/schema.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$ref": "#/definitions/Strategy", - "definitions": { - "Strategy": { - "title": "Strategy", - "type": "object", - "properties": { - "symbol": { - "type": "string", - "title": "Underlying Token Symbol", - "examples": ["e.g. UNI"], - "maxLength": 16 - }, - "address": { - "type": "string", - "title": "Vesting Voucher Contract address", - "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - } - }, - "required": ["address"], - "additionalProperties": false - } - } -} diff --git a/src/strategies/squadz-power/README.md b/src/strategies/squadz-power/README.md deleted file mode 100644 index 295cd2668..000000000 --- a/src/strategies/squadz-power/README.md +++ /dev/null @@ -1,15 +0,0 @@ -Strategy for using the "power" stat of Squadz collections for voting power. - -Power factors in: -- if an address has a currently active membership -- how many memberships an address has been minted total - -Parameters should look like: -``` -{ - "symbol": "SQDZ", // the token symbol for your collection - "collectionAddress": "0xd5746787be995887c59eff90611778b9cb67f0db", // the address for your collection -} -``` - -RARE: If your collection was forked onto the Squadz engine (see heyshell.xyz), you will also need to include the `forkNumber` in the parameters object. \ No newline at end of file diff --git a/src/strategies/squadz-power/examples.json b/src/strategies/squadz-power/examples.json deleted file mode 100644 index f27dbe1a6..000000000 --- a/src/strategies/squadz-power/examples.json +++ /dev/null @@ -1,36 +0,0 @@ -[ - { - "name": "Example squadz-power query goerli", - "strategy": { - "name": "squadz-power", - "params": { - "symbol": "SQDZ", - "collectionAddress": "0xd5746787be995887c59eff90611778b9cb67f0db" - } - }, - "network": "5", - "addresses": [ - "0x4171160db0e7e2c75a4973b7523b437c010dd9d4", - "0xd50fc49ff389558d23a76cf246da147ff53d8df8" - ], - "snapshot": 6679906 - }, - { - "name": "Example squadz-power query polygon", - "strategy": { - "name": "squadz-power", - "params": { - "symbol": "SQDZ", - "collectionAddress": "0xe56a303d9494bc55bd4ea570af6fb69efbd1aa63" - } - }, - "network": "137", - "addresses": [ - "0xd50fc49ff389558d23a76cf246da147ff53d8df8", - "0xc8d61fe5db0ef7b4512ce4d086c9c1c3f091fb75", - "0x4171160db0e7e2c75a4973b7523b437c010dd9d4", - "0x57421dea5152997c5ca37c3c6a5891c2c0217078" - ], - "snapshot": 26893958 - } -] diff --git a/src/strategies/squadz-power/index.ts b/src/strategies/squadz-power/index.ts deleted file mode 100644 index 7b388de98..000000000 --- a/src/strategies/squadz-power/index.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { multicall } from '../../utils'; - -export const author = 'EzraWeller'; -export const version = '0.0.1'; - -const engineAddresses: { [network: string]: string } = { - '5': '0x7beaa4e60e0faab603e99813f0f2330704b53086', - '80001': '0x39235b78626d8fa4ef6a81ba5616c58708ba4ea5', - '137': '0xb4a1a96ffa514b295b9a0de127288ec7d09e4e7c', - '4': '0xbeea7483aef24502a27eb7a35aad55280f8e2ebc' -}; - -const engineAbi = [ - 'function getMemberInfo(address, uint256, address) view returns (uint256, uint256, uint256, bool, bool, uint256, uint256)' -]; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - if (!Object.keys(engineAddresses).includes(network)) - throw new Error( - 'Invalid network:' + network + 'not in' + Object.keys(engineAddresses) - ); - - const engineAddress = engineAddresses[network]; - const forkNumber = options.forkNumber ?? 0; - - const response = await multicall( - network, - provider, - engineAbi, - addresses.map((member) => [ - engineAddress, - 'getMemberInfo', - [options.collectionAddress, forkNumber, member] - ]), - { blockTag } - ); - - return Object.fromEntries( - response.map((value, i) => [addresses[i], parseInt(value[5])]) - ); -} diff --git a/src/strategies/stakedao-governance-update/README.md b/src/strategies/stakedao-governance-update/README.md deleted file mode 100644 index 1fd27719d..000000000 --- a/src/strategies/stakedao-governance-update/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# stakedao-governance-update - -This strategy is used by StakeDAO to vote for the governance on the protocol. -Here is an example of parameters: - -```json -{ - "SDT_ETHEREUM": "0x73968b9a57c6E53d41345FD57a6E6ae27d6CDB2F", - "SDT_POLYGON": "0x361A5a4993493cE00f61C32d4EcCA5512b82CE90", - "SDT_RARI_ETHEREUM": "0x1066AB47a342152C564AF62D179aA4B659a11F7d", - "xSDT_RARI_ETHEREUM": "0x806323188117b73315fC9EB3FAa3a48A8D080376", - "veSDT_ETHEREUM": "0x0C30476f66034E11782938DF8e4384970B6c9e8a", - "network_ETHEREUM": "1", - "network_POLYGON": "137", - "symbol": "sdToken", - "decimals": 18 -} -``` diff --git a/src/strategies/stakedao-governance-update/examples.json b/src/strategies/stakedao-governance-update/examples.json deleted file mode 100644 index 9c5fb5100..000000000 --- a/src/strategies/stakedao-governance-update/examples.json +++ /dev/null @@ -1,26 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "stakedao-governance-update", - "params": { - "SDT_ETHEREUM": "0x73968b9a57c6E53d41345FD57a6E6ae27d6CDB2F", - "SDT_POLYGON": "0x361A5a4993493cE00f61C32d4EcCA5512b82CE90", - "SDT_RARI_ETHEREUM": "0x1066AB47a342152C564AF62D179aA4B659a11F7d", - "xSDT_RARI_ETHEREUM": "0x806323188117b73315fC9EB3FAa3a48A8D080376", - "veSDT_ETHEREUM": "0x0C30476f66034E11782938DF8e4384970B6c9e8a", - "network_ETHEREUM": "1", - "network_POLYGON": "137", - "symbol": "sdToken", - "decimals": 18 - } - }, - "network": "1", - "addresses": [ - "0x983ec6d045713d1b87f110a7edab9fc7996eefc0", - "0x6d75ffbffd1e63e5072f0ffbf6c4eefa16043967", - "0xbd2471B4150619a42093fFBA3a7AF35335ceC5B6" - ], - "snapshot": 14316000 - } -] diff --git a/src/strategies/stakedao-governance-update/index.ts b/src/strategies/stakedao-governance-update/index.ts deleted file mode 100644 index 49f137783..000000000 --- a/src/strategies/stakedao-governance-update/index.ts +++ /dev/null @@ -1,135 +0,0 @@ -import { multicall } from '../../utils'; -import { getProvider } from '../../utils'; - -export const author = 'clement-ux'; -export const version = '0.0.1'; - -const abi = [ - 'function balanceOf(address account) external view returns (uint256)', - 'function totalSupply() external view returns (uint256)', - 'function locked(address arg0) external view returns (int128,uint256)' -]; - -const F = 4; // veSDT vote multiplicator - -const chunk = (arr, size) => - Array.from({ length: Math.ceil(arr.length / size) }, (v, i) => - arr.slice(i * size, i * size + size) - ); -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -): Promise> { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - // *** Query *** // - - // Ethereum Side - const SDT_Query_ETH = addresses.map((address: any) => [ - options.SDT_ETHEREUM, - 'balanceOf', - [address] - ]); - - const SDT_Locked_Query_ETH = addresses.map((address: any) => [ - options.veSDT_ETHEREUM, - 'locked', - [address] - ]); - const veSDT_Query_ETH = addresses.map((address: any) => [ - options.veSDT_ETHEREUM, - 'balanceOf', - [address] - ]); - - const SDT_RARI_Query_ETH = addresses.map((address: any) => [ - options.SDT_RARI_ETHEREUM, - 'balanceOf', - [address] - ]); - const xSDT_RARI_Query_ETH = addresses.map((address: any) => [ - options.xSDT_RARI_ETHEREUM, - 'balanceOf', - [address] - ]); - // Polygon Side - const SDT_Query_POLYGON = addresses.map((address: any) => [ - options.SDT_POLYGON, - 'balanceOf', - [address] - ]); - - // *** Response *** // - const responseETH = await multicall( - options.network_ETHEREUM, - getProvider(options.network_ETHEREUM), - abi, - [ - ...SDT_Query_ETH, - ...SDT_Locked_Query_ETH, - ...SDT_RARI_Query_ETH, - ...xSDT_RARI_Query_ETH, - ...veSDT_Query_ETH - ], - { - blockTag - } - ); - const responsePOLYGON = await multicall( - options.network_POLYGON, - getProvider(options.network_POLYGON), - abi, - [...SDT_Query_POLYGON], - { - blockTag - } - ); - - const responseCleanETH = responseETH.slice(0, responseETH.length); - const responseCleanPOLYGON = responsePOLYGON.slice(0, responsePOLYGON.length); - const chunksETH = chunk(responseCleanETH, addresses.length); - const chunksPOLY = chunk(responseCleanPOLYGON, addresses.length); - - const SDT_ETH = chunksETH[0]; - const SDTLocked_ETH = chunksETH[1]; - const fSDT = chunksETH[2]; - const fxSDT = chunksETH[3]; - const veSDT = chunksETH[4]; - const SDT_POLY = chunksPOLY[0]; - - return Object.fromEntries( - Array(addresses.length) - .fill('x') - .map((_, i) => { - const SDT_ETHi = SDT_ETH[i][0]; - const SDTLocked_ETHi = SDTLocked_ETH[i][0]; - const veSDTi = veSDT[i][0]; - const fSDTi = fSDT[i][0]; - const fxSDTi = fxSDT[i][0]; - const SDT_POLYi = SDT_POLY[i][0]; - - // Print statements - //console.log(`==================${addresses[i]}==================\n`); - //console.log(`${SDT_ETHi / 10 ** 18} SDT_ETH`); - //console.log(`${SDTLocked_ETHi / 10 ** 18} SDTLocked_ETH`); - //console.log(`${veSDTi / 10 ** 18} veSDT`); - //console.log(`${fSDTi / 10 ** 18} fSDT`); - //console.log(`${fxSDTi / 10 ** 18} fxSDT`); - //console.log(`${SDT_POLYi / 10 ** 18} SDT_POLY`); - - return [ - addresses[i], - SDT_ETHi.add(SDTLocked_ETHi) - .add(veSDTi.mul(F)) - .add(fSDTi) - .add(fxSDTi) - .add(SDT_POLYi) / - 10 ** 18 - ]; - }) - ); -} diff --git a/src/strategies/sumami-holders/README.md b/src/strategies/sumami-holders/README.md deleted file mode 100644 index 40fc546a8..000000000 --- a/src/strategies/sumami-holders/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# Contract call strategy - -Allows the tokens locked in marinate contract to be used to calculate voter scores. - -## Examples - -Can be used instead of the erc20-balance-of strategy, the space config will look like this: - -```JSON -{ - "address": "0xe6d557d416ff5640235119369c7e26AA18a906D7", - "marinateLevels": [0, 1, 2, 3], - "symbol": "sUMAMI", - "marinateAddress": "0x190a6b6E8e4D9B8324E1F97127c588C5b082d94b", - "decimals": 9 -} diff --git a/src/strategies/sumami-holders/examples.json b/src/strategies/sumami-holders/examples.json deleted file mode 100644 index 57093d9c2..000000000 --- a/src/strategies/sumami-holders/examples.json +++ /dev/null @@ -1,37 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "sumami-holders", - "params": { - "address": "0xe6d557d416ff5640235119369c7e26AA18a906D7", - "marinateLevels": [0, 1, 2, 3], - "symbol": "sUMAMI", - "marinateAddress": "0x190a6b6E8e4D9B8324E1F97127c588C5b082d94b", - "decimals": 9 - } - }, - "network": "42161", - "addresses": [ - "0x541D67bEdBfe820b4E58712bf032C7250548D733", - "0x93615705c74bfd7d7c0b0d9cfd5d04ee00d90471", - "0xb9d24761ebb3e3a88b8cf20e77f56ccf026a2044", - "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", - "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e", - "0x1d5E65a087eBc3d03a294412E46CE5D6882969f4", - "0x1f254336E5c46639A851b9CfC165697150a6c327", - "0x2ec3F80BeDA63Ede96BA20375032CDD3aAfb3030", - "0x4AcBcA6BE2f8D2540bBF4CA77E45dA0A4a095Fa2", - "0x4F3D348a6D09837Ae7961B1E0cEe2cc118cec777", - "0x6D7f23A509E212Ba7773EC1b2505d1A134f54fbe", - "0x07a1f6fc89223c5ebD4e4ddaE89Ac97629856A0f", - "0x8d5F05270da470e015b67Ab5042BDbE2D2FEFB48", - "0xb2273e70eda1cb2e16bdfd7a15c031d12400f7ca", - "0x8f60501dE5b9b01F9EAf1214dbE1924aA97F7fd0", - "0x9B8e8dD9151260c21CB6D7cc59067cd8DF306D58", - "0x17ea92D6FfbAA1c7F6B117c1E9D0c88ABdc8b84C", - "0x9a32b1a10504489f9b88106acec79c672630158c" - ], - "snapshot": 4178460 - } -] diff --git a/src/strategies/sumami-holders/index.ts b/src/strategies/sumami-holders/index.ts deleted file mode 100644 index 0c8226da4..000000000 --- a/src/strategies/sumami-holders/index.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { formatUnits } from '@ethersproject/units'; -import { multicall } from '../../utils'; -import { strategy as erc20BalanceOfStrategy } from '../erc20-balance-of'; - -export const author = 'arugulo'; -export const version = '0.1.0'; - -// Merged ABI for sUMAMI and Marinate contracts -const abi = [ - 'function balanceOf(address account) view returns (uint256)', - 'function stakedBalance(address account, uint32 level) view returns (uint256)' -]; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - if (options.marinateLevels.length > 4) { - return []; - } - const sUmamiBalances = await erc20BalanceOfStrategy( - space, - network, - provider, - addresses, - options, - snapshot - ); - - const marinateBalances = await Promise.all( - options.marinateLevels.map((level: number) => - multicall( - network, - provider, - abi, - addresses.map((address: any) => [ - options.marinateAddress, - 'stakedBalance', - [address, level], - { blockTag } - ]), - { blockTag } - ) - ) - ); - - const totalMarinateBalances = marinateBalances.reduce( - //@ts-ignore - (prev: any, cur: any) => - cur.map( - (balance, idx) => - (prev[idx] || 0) + - parseFloat(formatUnits(balance.toString(), options.decimals)) - ), - [] - ); - - return Object.fromEntries( - Object.entries(sUmamiBalances).map((address, index) => [ - address[0], - //@ts-ignore - address[1] + totalMarinateBalances[index] - ]) - ); -} diff --git a/src/strategies/sunder/examples.json b/src/strategies/sunder/examples.json deleted file mode 100644 index 3827e91e5..000000000 --- a/src/strategies/sunder/examples.json +++ /dev/null @@ -1,20 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "sunder", - "params": { - "token": "0xaF5A2E9E0BCf9Ec3bf447F511F8Ac028F5959077", - "symbol": "sudner (token)", - "decimals": 18, - "balanceOfAdds": "0x20a183539DF9dE2223991329FE68d5cCc5c8C0D8" - } - }, - "network": "42", - "addresses": [ - "0x02Ec1090D59cbAA9D58EAeBb3328dF56A6dEd2D3", - "0x714AfdEB0c24127ec03149005AD59F80bbFD71d7" - ], - "snapshot": 26570329 - } -] diff --git a/src/strategies/sunder/index.ts b/src/strategies/sunder/index.ts deleted file mode 100644 index 4a5501e4a..000000000 --- a/src/strategies/sunder/index.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { BigNumberish } from '@ethersproject/bignumber'; -import { formatUnits } from '@ethersproject/units'; -import { Multicaller } from '../../utils'; - -export const author = 'krotos-arch'; -export const version = '0.0.1'; - -const abi = [ - 'function balanceOfDToken(address _token, address _account) public returns (uint256 _balance)' -]; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -): Promise> { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - const multi = new Multicaller(network, provider, abi, { blockTag }); - addresses.forEach((address) => - multi.call(address, options.balanceOfAdds, 'balanceOfDToken', [ - options.token, - address - ]) - ); - const result: Record = await multi.execute(); - - return Object.fromEntries( - Object.entries(result).map(([address, balance]) => [ - address, - parseFloat(formatUnits(balance, options.decimals)) - ]) - ); -} diff --git a/src/strategies/svs-staking/examples.json b/src/strategies/svs-staking/examples.json deleted file mode 100644 index 27cea55ea..000000000 --- a/src/strategies/svs-staking/examples.json +++ /dev/null @@ -1,23 +0,0 @@ -[ - { - "name": "SVS stakers and holders", - "strategy": { - "name": "svs-staking", - "params": { - "symbol": "SVS", - "decimals": 0, - "tokenAddress": "0x219B8aB790dECC32444a6600971c7C3718252539", - "stakingAddress": "0x12753244901f9E612A471c15C7E5336e813D2e0B" - } - }, - "network": "1", - "addresses": [ - "0x24d19f100ba142543a863fc2294b188e35ab55b9", - "0xC0d6d28811df8466E4BAC33CfC9Ed6e745900a07", - "0xFdA9F18221d14F5FAD1ff8a0dbA92A716Ba8144D", - "0x43522a5abA7c0FEad84b6614C208B5162A1b4ADF", - "0xcA50e4211B330295212FF9C1160F5DF3E0Ccd9D8" - ], - "snapshot": 13449843 - } -] diff --git a/src/strategies/svs-staking/index.ts b/src/strategies/svs-staking/index.ts deleted file mode 100644 index 480b014e5..000000000 --- a/src/strategies/svs-staking/index.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { formatUnits } from '@ethersproject/units'; -import { multicall } from '../../utils'; - -export const author = 'fsjuhl'; -export const version = '0.1.0'; - -const stakingAbi = [ - 'function getVampsBuried(address burier) view returns (uint256[])' -]; - -const tokenAbi = ['function balanceOf(address owner) view returns (uint256)']; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - const stakersResponse = await multicall( - network, - provider, - stakingAbi, - addresses.map((address: any) => [ - options.stakingAddress, - 'getVampsBuried', - [address] - ]), - { blockTag } - ); - - const holdersResponse = await multicall( - network, - provider, - tokenAbi, - addresses.map((address: any) => [ - options.tokenAddress, - 'balanceOf', - [address] - ]), - { blockTag } - ); - - return Object.fromEntries( - stakersResponse.map((value, i) => [ - addresses[i], - value[0].length + - parseFloat( - formatUnits(holdersResponse[i][0].toString(), options.decimals) - ) - ]) - ); -} diff --git a/src/strategies/swapr/README.md b/src/strategies/swapr/README.md deleted file mode 100644 index 4d486c7b2..000000000 --- a/src/strategies/swapr/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Swapr - -This strategy returns balances of the underlying token in Swapr pairs (including the liquidity staked on the farming campaigns offered by the platform). - -Here is an example of parameters: - -```json -{ - "address": "0xdE903E2712288A1dA82942DDdF2c20529565aC30" -} -``` - -- _address_ - the underlying token diff --git a/src/strategies/swapr/commons.ts b/src/strategies/swapr/commons.ts deleted file mode 100644 index b2b64f6ff..000000000 --- a/src/strategies/swapr/commons.ts +++ /dev/null @@ -1,15 +0,0 @@ -export const SWAPR_SUBGRAPH_URL = { - '1': 'https://api.thegraph.com/subgraphs/name/luzzif/swapr-mainnet-v2', - '100': 'https://api.thegraph.com/subgraphs/name/luzzif/swapr-xdai-v2', - '42161': - 'https://api.thegraph.com/subgraphs/name/luzzif/swapr-arbitrum-one-v2' -}; - -export const mergeBalanceMaps = ( - outputMap: { [address: string]: number }, - inputMap: { [address: string]: number } -) => { - Object.entries(inputMap).forEach(([account, balance]) => { - outputMap[account] = (outputMap[account] || 0) + balance; - }); -}; diff --git a/src/strategies/swapr/examples.json b/src/strategies/swapr/examples.json deleted file mode 100644 index ef6992687..000000000 --- a/src/strategies/swapr/examples.json +++ /dev/null @@ -1,15 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "swapr", - "params": { - "symbol": "SWPR", - "address": "0xdE903E2712288A1dA82942DDdF2c20529565aC30" - } - }, - "network": "42161", - "addresses": ["0xa5A29f81EEE450eC189b2F8B4562af1785595D69"], - "snapshot": 2867713 - } -] diff --git a/src/strategies/swapr/index.ts b/src/strategies/swapr/index.ts deleted file mode 100644 index bf4ae8cfb..000000000 --- a/src/strategies/swapr/index.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { getSwaprLiquidityProvidersBalance } from './swapr-lps'; -import { strategy as erc20BalanceOfStartegy } from '../erc20-balance-of'; -import { mergeBalanceMaps } from './commons'; -import { getAddress } from '@ethersproject/address'; - -export const author = 'luzzif'; -export const version = '0.1.0'; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const lpData = await getSwaprLiquidityProvidersBalance( - network, - addresses, - options, - snapshot - ); - - let i = 0; - const PAGE_SIZE = 250; - let rawErc20HoldersData: { [address: string]: number } = {}; - while (true) { - const pageData = await erc20BalanceOfStartegy( - space, - network, - provider, - addresses.slice(PAGE_SIZE * i, PAGE_SIZE * i + PAGE_SIZE), - options, - snapshot - ); - rawErc20HoldersData = { ...rawErc20HoldersData, ...pageData }; - if (Object.keys(pageData).length < PAGE_SIZE) break; - i++; - } - - // make sure the addresses have the correct casing before - // merging the balance maps - const erc20HoldersData = Object.entries(rawErc20HoldersData).reduce( - (accumulator, [address, balance]) => { - accumulator[getAddress(address)] = balance; - return accumulator; - }, - {} - ); - - const score: { [address: string]: number } = {}; - mergeBalanceMaps(score, lpData); - mergeBalanceMaps(score, erc20HoldersData); - return score; -} diff --git a/src/strategies/swapr/swapr-lps.ts b/src/strategies/swapr/swapr-lps.ts deleted file mode 100644 index 2ccf51dba..000000000 --- a/src/strategies/swapr/swapr-lps.ts +++ /dev/null @@ -1,211 +0,0 @@ -import { Decimal } from 'decimal.js-light'; -import { getAddress } from '@ethersproject/address'; -import { mergeBalanceMaps, SWAPR_SUBGRAPH_URL } from './commons'; -import { subgraphRequest } from '../../utils'; - -interface StandardLiquidityPosition { - id: string; - user: { id: string }; - liquidityTokenBalance: string; - pair: { - totalSupply: string; - reserve0: string; - reserve1: string; - }; -} - -interface StakedLiquidityPosition { - id: string; - user: { id: string }; - stakedAmount: string; - targetedPair: { - totalSupply: string; - reserve0: string; - reserve1: string; - }; -} - -const mergeStandardAndStakedPositions = ( - standardPositions: StandardLiquidityPosition[], - stakedPositions: StakedLiquidityPosition[] -) => { - return stakedPositions.reduce( - (accumulator: StandardLiquidityPosition[], stakedPosition) => { - const index = accumulator.findIndex( - (p) => p.user.id.toLowerCase() === stakedPosition.user.id.toLowerCase() - ); - if (index >= 0) - accumulator[index].liquidityTokenBalance = new Decimal( - accumulator[index].liquidityTokenBalance - ) - .plus(stakedPosition.stakedAmount) - .toString(); - else - accumulator.push({ - ...stakedPosition, - pair: stakedPosition.targetedPair, - liquidityTokenBalance: stakedPosition.stakedAmount - }); - return accumulator; - }, - standardPositions - ); -}; - -const getPositions = async ( - network, - addresses, - options, - snapshot -): Promise<{ - positionsByToken0: StandardLiquidityPosition[]; - positionsByToken1: StandardLiquidityPosition[]; -}> => { - const wantedTokenAddress = options.address; - const swaprSubgraphUrl = SWAPR_SUBGRAPH_URL[network]; - - const [token0Query, token1Query] = ['token0', 'token1'].map((key) => ({ - pairs: { - __args: { - where: { - [key]: wantedTokenAddress.toLowerCase() - }, - first: 1000 - }, - id: true - } - })); - if (snapshot !== 'latest') { - // @ts-ignore - token0Query.pairs.__args.block = { number: snapshot }; - // @ts-ignore - token1Query.pairs.__args.block = { number: snapshot }; - } - const swprPairsByToken0 = await subgraphRequest( - swaprSubgraphUrl, - token0Query - ); - const swprPairsByToken1 = await subgraphRequest( - swaprSubgraphUrl, - token1Query - ); - - const [liquidityPositionsByToken0Query, liquidityPositionsByToken1Query] = [ - swprPairsByToken0, - swprPairsByToken1 - ].map((wrappedPairs) => ({ - liquidityPositions: { - __args: { - where: { - user_in: addresses.map((address) => address.toLowerCase()), - pair_in: wrappedPairs.pairs.map((pair) => pair.id), - liquidityTokenBalance_gt: 0 - }, - first: 1000 - }, - user: { - id: true - }, - liquidityTokenBalance: true, - pair: { - totalSupply: true, - reserve0: true, - reserve1: true - } - } - })); - const liquidityPositionsByToken0 = await subgraphRequest( - swaprSubgraphUrl, - liquidityPositionsByToken0Query - ); - const liquidityPositionsByToken1 = await subgraphRequest( - swaprSubgraphUrl, - liquidityPositionsByToken1Query - ); - - const [ - liquidityMiningPositionsByToken0Query, - liquidityMiningPositionsByToken1Query - ] = [swprPairsByToken0, swprPairsByToken1].map((wrappedPairs) => ({ - liquidityMiningPositions: { - __args: { - where: { - user_in: addresses.map((address) => address.toLowerCase()), - targetedPair_in: wrappedPairs.pairs.map((pair) => pair.id), - stakedAmount_gt: 0 - }, - first: 1000 - }, - user: { - id: true - }, - stakedAmount: true, - targetedPair: { - totalSupply: true, - reserve0: true, - reserve1: true - } - } - })); - - const liquidityMiningPositionsByToken0 = await subgraphRequest( - swaprSubgraphUrl, - liquidityMiningPositionsByToken0Query - ); - const liquidityMiningPositionsByToken1 = await subgraphRequest( - swaprSubgraphUrl, - liquidityMiningPositionsByToken1Query - ); - - return { - positionsByToken0: mergeStandardAndStakedPositions( - liquidityPositionsByToken0.liquidityPositions, - liquidityMiningPositionsByToken0.liquidityMiningPositions - ), - positionsByToken1: mergeStandardAndStakedPositions( - liquidityPositionsByToken1.liquidityPositions, - liquidityMiningPositionsByToken1.liquidityMiningPositions - ) - }; -}; - -const lpDataToBalanceMap = ( - positions: StandardLiquidityPosition[], - useToken0Data: boolean -) => { - return positions.reduce( - (accumulator: { [address: string]: number }, position) => { - const userLpTokenBalance = new Decimal(position.liquidityTokenBalance); - const pairTotalSupply = new Decimal(position.pair.totalSupply); - const userPoolPercentage = userLpTokenBalance.dividedBy(pairTotalSupply); - const userHolding = new Decimal( - useToken0Data ? position.pair.reserve0 : position.pair.reserve1 - ).mul(userPoolPercentage); - const userAddress = getAddress(position.user.id); - accumulator[userAddress] = - (accumulator[userAddress] || 0) + userHolding.toNumber(); - return accumulator; - }, - {} - ); -}; - -export const getSwaprLiquidityProvidersBalance = async ( - network, - addresses, - options, - snapshot -): Promise<{ - [address: string]: number; -}> => { - const { positionsByToken0, positionsByToken1 } = await getPositions( - network, - addresses, - options, - snapshot - ); - const balanceMap: { [address: string]: number } = {}; - mergeBalanceMaps(balanceMap, lpDataToBalanceMap(positionsByToken0, true)); - mergeBalanceMaps(balanceMap, lpDataToBalanceMap(positionsByToken1, false)); - return balanceMap; -}; diff --git a/src/strategies/synthetix-non-quadratic/README.md b/src/strategies/synthetix-non-quadratic/README.md deleted file mode 100644 index 5aaf2215f..000000000 --- a/src/strategies/synthetix-non-quadratic/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# Non-Quadratic Debt Percentage Strategy - -Calculates the weighting of voters, based on their debt percentage in the previous fee period. - -## Examples - -Can be used instead of the erc20-balance-of strategy, the space config will look like this: - -```JSON -{ - "strategies": [ - ["synthetix-non-quadratic"] - ] -} -``` diff --git a/src/strategies/synthetix-non-quadratic/examples.json b/src/strategies/synthetix-non-quadratic/examples.json deleted file mode 100644 index 937bf7e13..000000000 --- a/src/strategies/synthetix-non-quadratic/examples.json +++ /dev/null @@ -1,24 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "synthetix-non-quadratic", - "params": { - "address": "0x023c66b7e13d30a3c46aa433fd2829763d5817c5", - "symbol": "WD" - } - }, - "network": "1", - "addresses": [ - "0x78b037B39704e88a82DD23CFBE1f57f6AeF8EBC5", - "0x0bc3668d2AaFa53eD5E5134bA13ec74ea195D000", - "0xcAc59F91E4536Bc0E79aB816a5cD54e89f10433C", - "0x6dc88B231Cd04Dd1b1e525161162993F47140006", - "0x935D2fD458fdf41B6F7B62471f593797866a3Ce6", - "0x24e445fe7708Bf4bC2ae8d4df1694C98Af8BDE4F", - "0x49be88f0fcc3a8393a59d3688480d7d253c37d2a", - "0x27Cc4d6bc95b55a3a981BF1F1c7261CDa7bB0931" - ], - "snapshot": 13228907 - } -] diff --git a/src/strategies/synthetix-non-quadratic/index.ts b/src/strategies/synthetix-non-quadratic/index.ts deleted file mode 100644 index 0d42dd088..000000000 --- a/src/strategies/synthetix-non-quadratic/index.ts +++ /dev/null @@ -1,184 +0,0 @@ -import { getAddress } from '@ethersproject/address'; -import { BigNumber } from '@ethersproject/bignumber'; -import { Contract } from '@ethersproject/contracts'; -import { Provider } from '@ethersproject/providers'; -import { - subgraphRequest - // ipfsGet -} from '../../utils'; -import { - DebtCacheABI, - debtL1, - debtL2, - returnGraphParams, - SNXHoldersResult, - SynthetixStateABI -} from '../synthetix/helper'; - -export const author = 'andytcf'; -export const version = '1.0.0'; - -const MED_PRECISE_UNIT = 1e18; - -// @TODO: check if most-up-to-date version (using https://contracts.synthetix.io/SynthetixState) -const SynthetixStateContractAddress = - '0x4b9Ca5607f1fF8019c1C6A3c2f0CC8de622D5B82'; -// @TODO: check if most-up-to-date version (using http://contracts.synthetix.io/DebtCache) -const DebtCacheContractAddress = '0xe92B4c7428152052B0930c81F4c687a5F1A12292'; - -const defaultGraphs = { - '1': 'https://api.thegraph.com/subgraphs/name/killerbyte/synthetix', - '10': 'https://api.thegraph.com/subgraphs/name/synthetixio-team/optimism-issuance' -}; - -// @TODO: update with the latest ovm snapshot -// const ovmSnapshotJSON = 'QmNwvhq4By1Mownjycg7bWSXqbJWMVyAWRZ1K4mjxuvGXg'; - -const loadLastDebtLedgerEntry = async ( - provider: Provider, - snapshot: number | string -) => { - const contract = new Contract( - SynthetixStateContractAddress, - SynthetixStateABI, - provider - ); - - const lastDebtLedgerEntry = await contract.lastDebtLedgerEntry({ - blockTag: snapshot - }); - - return BigNumber.from(lastDebtLedgerEntry); -}; - -const loadL1TotalDebt = async ( - provider: Provider, - snapshot: number | string -) => { - const contract = new Contract( - DebtCacheContractAddress, - DebtCacheABI, - provider - ); - - const currentDebtObject = await contract.currentDebt({ - blockTag: snapshot - }); - - return Number(currentDebtObject.debt) / MED_PRECISE_UNIT; -}; - -export async function strategy( - _space, - _network, - _provider, - _addresses, - _, - snapshot -) { - const score = {}; - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - /* Global Constants */ - - const totalL1Debt = await loadL1TotalDebt(_provider, snapshot); // (high-precision 1e18) - const lastDebtLedgerEntry = await loadLastDebtLedgerEntry( - _provider, - snapshot - ); - - /* EDIT THESE FOR OVM */ - - // @TODO update the currentDebt for the snapshot from (https://contracts.synthetix.io/ovm/DebtCache) - const totalL2Debt = 22617610; - // @TODO update the lastDebtLedgerEntry from (https://contracts.synthetix.io/ovm/SynthetixState) - const lastDebtLedgerEntryL2 = 20222730523217499684984991; - // @TODO update the comparison between OVM:ETH c-ratios at the time of snapshot - const normalisedL2CRatio = 600 / 450; - // @TODO update the L2 block number to use - const L2BlockNumber = 1770186; - - const scaledTotalL2Debt = totalL2Debt * normalisedL2CRatio; - - /* --------------- */ - - /* Using the subgraph, we get the relevant L1 calculations */ - - const l1Results = (await subgraphRequest( - defaultGraphs[1], - returnGraphParams(blockTag, _addresses) - )) as SNXHoldersResult; - - if (l1Results && l1Results.snxholders) { - for (let i = 0; i < l1Results.snxholders.length; i++) { - const holder = l1Results.snxholders[i]; - const vote = await debtL1( - holder.initialDebtOwnership, - holder.debtEntryAtIndex, - totalL1Debt, - scaledTotalL2Debt, - lastDebtLedgerEntry, - false - ); - score[getAddress(holder.id)] = vote; - } - } - - /* Using the subgraph, we get the relevant L2 calculations */ - - const l2Results = (await subgraphRequest( - defaultGraphs[10], - returnGraphParams(L2BlockNumber, _addresses) - )) as SNXHoldersResult; - - // @notice fallback for when subgraph is down - /* - const OVMSnapshot = await ipfsGet('gateway.pinata.cloud', ovmSnapshotJSON); - const array = Object.assign( - {}, - ...OVMSnapshot.data.snxholders.map((key) => ({ - [getAddress(key.id)]: { - initialDebtOwnership: key.initialDebtOwnership, - debtEntryAtIndex: key.debtEntryAtIndex - } - })) - ); - for (let k = 0; k < _addresses.length; k++) { - const address = _addresses[k]; - if (array[getAddress(address)]) { - score[getAddress(address)] += await quadraticWeightedVoteL2( - array[getAddress(address)].initialDebtOwnership, - array[getAddress(address)].debtEntryAtIndex, - totalL1Debt, - scaledTotalL2Debt, - lastDebtLedgerEntryL2 - ); - } else { - continue; - } - } - */ - - if (l2Results && l2Results.snxholders) { - for (let i = 0; i < l2Results.snxholders.length; i++) { - const holder = l2Results.snxholders[i]; - - const vote = await debtL2( - holder.initialDebtOwnership, - holder.debtEntryAtIndex, - totalL1Debt, - scaledTotalL2Debt, - lastDebtLedgerEntryL2, - false - ); - - if (score[getAddress(holder.id)]) { - score[getAddress(holder.id)] += vote; - } else { - score[getAddress(holder.id)] = vote; - } - } - } - - return score || {}; -} diff --git a/src/strategies/synthetix-non-quadratic_2/README.md b/src/strategies/synthetix-non-quadratic_2/README.md deleted file mode 100644 index 1d849ec83..000000000 --- a/src/strategies/synthetix-non-quadratic_2/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# Non-Quadratic Debt Percentage Strategy - -Calculates the weighting of voters, based on their debt percentage in the previous fee period. - -## Examples - -Can be used instead of the erc20-balance-of strategy, the space config will look like this: - -```JSON -{ - "strategies": [ - ["synthetix-non-quadratic_2"] - ] -} -``` diff --git a/src/strategies/synthetix-non-quadratic_2/examples.json b/src/strategies/synthetix-non-quadratic_2/examples.json deleted file mode 100644 index c18fd6915..000000000 --- a/src/strategies/synthetix-non-quadratic_2/examples.json +++ /dev/null @@ -1,27 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "synthetix-non-quadratic_2", - "params": { - "address": "0x023c66b7e13d30a3c46aa433fd2829763d5817c5", - "symbol": "WD", - "totalL2Debt": 40201854, - "lastDebtLedgerEntryL2": 10909822163955610660349890, - "L2BlockNumber": 4750287 - } - }, - "network": "1", - "addresses": [ - "0x78b037B39704e88a82DD23CFBE1f57f6AeF8EBC5", - "0x0bc3668d2AaFa53eD5E5134bA13ec74ea195D000", - "0xcAc59F91E4536Bc0E79aB816a5cD54e89f10433C", - "0x6dc88B231Cd04Dd1b1e525161162993F47140006", - "0x935D2fD458fdf41B6F7B62471f593797866a3Ce6", - "0x24e445fe7708Bf4bC2ae8d4df1694C98Af8BDE4F", - "0x49be88f0fcc3a8393a59d3688480d7d253c37d2a", - "0x27Cc4d6bc95b55a3a981BF1F1c7261CDa7bB0931" - ], - "snapshot": 14443440 - } -] diff --git a/src/strategies/synthetix-non-quadratic_2/index.ts b/src/strategies/synthetix-non-quadratic_2/index.ts deleted file mode 100644 index bcc5609fc..000000000 --- a/src/strategies/synthetix-non-quadratic_2/index.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { getAddress } from '@ethersproject/address'; -import { BigNumber } from '@ethersproject/bignumber'; -import { Contract } from '@ethersproject/contracts'; -import { Provider } from '@ethersproject/providers'; -import { subgraphRequest } from '../../utils'; -import { - DebtCacheABI, - debtL1, - debtL2, - returnGraphParams, - SNXHoldersResult, - SynthetixStateABI -} from '../synthetix/helper'; - -export const author = 'andytcf'; -export const version = '1.0.0'; - -const MED_PRECISE_UNIT = 1e18; - -// @TODO: check if most-up-to-date version (using https://contracts.synthetix.io/SynthetixState) -const SynthetixStateContractAddress = - '0x4b9Ca5607f1fF8019c1C6A3c2f0CC8de622D5B82'; -// @TODO: check if most-up-to-date version (using http://contracts.synthetix.io/DebtCache) -const DebtCacheContractAddress = '0x1620Aa736939597891C1940CF0d28b82566F9390'; - -const defaultGraphs = { - '1': 'https://api.thegraph.com/subgraphs/name/synthetixio-team/synthetix', - '10': 'https://api.thegraph.com/subgraphs/name/synthetixio-team/optimism-main' -}; - -const loadLastDebtLedgerEntry = async ( - provider: Provider, - snapshot: number | string -) => { - const contract = new Contract( - SynthetixStateContractAddress, - SynthetixStateABI, - provider - ); - - const lastDebtLedgerEntry = await contract.lastDebtLedgerEntry({ - blockTag: snapshot - }); - - return BigNumber.from(lastDebtLedgerEntry); -}; - -const loadL1TotalDebt = async ( - provider: Provider, - snapshot: number | string -) => { - const contract = new Contract( - DebtCacheContractAddress, - DebtCacheABI, - provider - ); - - const currentDebtObject = await contract.currentDebt({ - blockTag: snapshot - }); - - return Number(currentDebtObject.debt) / MED_PRECISE_UNIT; -}; - -export async function strategy( - _space, - _network, - _provider, - _addresses, - _options, - snapshot -) { - const score = {}; - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - /* Global Constants */ - - const totalL1Debt = await loadL1TotalDebt(_provider, snapshot); // (high-precision 1e18) - const lastDebtLedgerEntry = await loadLastDebtLedgerEntry( - _provider, - snapshot - ); - - /* EDIT THESE FOR OVM */ - - // @TODO update the currentDebt for the snapshot from (https://contracts.synthetix.io/ovm/DebtCache) - // const totalL2Debt = 40201854; - const totalL2Debt = _options.totalL2Debt; - // @TODO update the lastDebtLedgerEntry from (https://contracts.synthetix.io/ovm/SynthetixState) - // const lastDebtLedgerEntryL2 = 10909822163955610660349890; - const lastDebtLedgerEntryL2 = _options.lastDebtLedgerEntryL2; - // @TODO update the comparison between OVM:ETH c-ratios at the time of snapshot - const normalisedL2CRatio = 500 / 400; - // @TODO update the L2 block number to use - // const L2BlockNumber = 4750287; - const L2BlockNumber = _options.L2BlockNumber; - - const scaledTotalL2Debt = totalL2Debt * normalisedL2CRatio; - - /* --------------- */ - - /* Using the subgraph, we get the relevant L1 calculations */ - - const l1Results = (await subgraphRequest( - defaultGraphs[1], - returnGraphParams(blockTag, _addresses) - )) as SNXHoldersResult; - - if (l1Results && l1Results.snxholders) { - for (let i = 0; i < l1Results.snxholders.length; i++) { - const holder = l1Results.snxholders[i]; - const vote = await debtL1( - holder.initialDebtOwnership, - holder.debtEntryAtIndex, - totalL1Debt, - scaledTotalL2Debt, - lastDebtLedgerEntry, - false - ); - score[getAddress(holder.id)] = vote; - } - } - - /* Using the subgraph, we get the relevant L2 calculations */ - - const l2Results = (await subgraphRequest( - defaultGraphs[10], - returnGraphParams(L2BlockNumber, _addresses) - )) as SNXHoldersResult; - - if (l2Results && l2Results.snxholders) { - for (let i = 0; i < l2Results.snxholders.length; i++) { - const holder = l2Results.snxholders[i]; - - const vote = await debtL2( - holder.initialDebtOwnership, - holder.debtEntryAtIndex, - totalL1Debt, - scaledTotalL2Debt, - lastDebtLedgerEntryL2, - false - ); - - if (score[getAddress(holder.id)]) { - score[getAddress(holder.id)] += vote; - } else { - score[getAddress(holder.id)] = vote; - } - } - } - - return score || {}; -} diff --git a/src/strategies/synthetix-quadratic_2/README.md b/src/strategies/synthetix-quadratic_2/README.md deleted file mode 100644 index d80b9dd4b..000000000 --- a/src/strategies/synthetix-quadratic_2/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# Quadratic Debt Percentage Strategy - -Calculates the quadratic weighting of voters, based on their debt percentage in the previous fee period. - -## Examples - -Can be used instead of the erc20-balance-of strategy, the space config will look like this: - -```JSON -{ - "strategies": [ - ["synthetix-quadratic_2"] - ] -} -``` diff --git a/src/strategies/synthetix-quadratic_2/examples.json b/src/strategies/synthetix-quadratic_2/examples.json deleted file mode 100644 index ea890a6cc..000000000 --- a/src/strategies/synthetix-quadratic_2/examples.json +++ /dev/null @@ -1,27 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "synthetix-quadratic_2", - "params": { - "address": "0x023c66b7e13d30a3c46aa433fd2829763d5817c5", - "symbol": "WD", - "totalL2Debt": 40201854, - "lastDebtLedgerEntryL2": 10909822163955610660349890, - "L2BlockNumber": 4750287 - } - }, - "network": "1", - "addresses": [ - "0x78b037B39704e88a82DD23CFBE1f57f6AeF8EBC5", - "0x0bc3668d2AaFa53eD5E5134bA13ec74ea195D000", - "0xcAc59F91E4536Bc0E79aB816a5cD54e89f10433C", - "0x6dc88B231Cd04Dd1b1e525161162993F47140006", - "0x935D2fD458fdf41B6F7B62471f593797866a3Ce6", - "0x24e445fe7708Bf4bC2ae8d4df1694C98Af8BDE4F", - "0x49be88f0fcc3a8393a59d3688480d7d253c37d2a", - "0x27Cc4d6bc95b55a3a981BF1F1c7261CDa7bB0931" - ], - "snapshot": 14443440 - } -] diff --git a/src/strategies/synthetix-quadratic_2/index.ts b/src/strategies/synthetix-quadratic_2/index.ts deleted file mode 100644 index 8f030c1ac..000000000 --- a/src/strategies/synthetix-quadratic_2/index.ts +++ /dev/null @@ -1,151 +0,0 @@ -import { getAddress } from '@ethersproject/address'; -import { BigNumber } from '@ethersproject/bignumber'; -import { Contract } from '@ethersproject/contracts'; -import { Provider } from '@ethersproject/providers'; -import { subgraphRequest } from '../../utils'; -import { - DebtCacheABI, - debtL1, - debtL2, - returnGraphParams, - SNXHoldersResult, - SynthetixStateABI -} from '../synthetix/helper'; - -export const author = 'andytcf'; -export const version = '1.0.0'; - -const MED_PRECISE_UNIT = 1e18; - -// @TODO: check if most-up-to-date version (using https://contracts.synthetix.io/SynthetixState) -const SynthetixStateContractAddress = - '0x4b9Ca5607f1fF8019c1C6A3c2f0CC8de622D5B82'; -// @TODO: check if most-up-to-date version (using http://contracts.synthetix.io/DebtCache) -const DebtCacheContractAddress = '0x1620Aa736939597891C1940CF0d28b82566F9390'; - -const defaultGraphs = { - '1': 'https://api.thegraph.com/subgraphs/name/synthetixio-team/synthetix', - '10': 'https://api.thegraph.com/subgraphs/name/synthetixio-team/optimism-main' -}; - -const loadLastDebtLedgerEntry = async ( - provider: Provider, - snapshot: number | string -) => { - const contract = new Contract( - SynthetixStateContractAddress, - SynthetixStateABI, - provider - ); - - const lastDebtLedgerEntry = await contract.lastDebtLedgerEntry({ - blockTag: snapshot - }); - - return BigNumber.from(lastDebtLedgerEntry); -}; - -const loadL1TotalDebt = async ( - provider: Provider, - snapshot: number | string -) => { - const contract = new Contract( - DebtCacheContractAddress, - DebtCacheABI, - provider - ); - - const currentDebtObject = await contract.currentDebt({ - blockTag: snapshot - }); - - return Number(currentDebtObject.debt) / MED_PRECISE_UNIT; -}; - -export async function strategy( - _space, - _network, - _provider, - _addresses, - _options, - snapshot -) { - const score = {}; - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - /* Global Constants */ - - const totalL1Debt = await loadL1TotalDebt(_provider, snapshot); // (high-precision 1e18) - const lastDebtLedgerEntry = await loadLastDebtLedgerEntry( - _provider, - snapshot - ); - - // @TODO update the currentDebt for the snapshot from (https://contracts.synthetix.io/ovm/DebtCache) - // const totalL2Debt = 40201854; - const totalL2Debt = _options.totalL2Debt; - // @TODO update the lastDebtLedgerEntry from (https://contracts.synthetix.io/ovm/SynthetixState) - // const lastDebtLedgerEntryL2 = 10909822163955610660349890; - const lastDebtLedgerEntryL2 = _options.lastDebtLedgerEntryL2; - // @TODO update the comparison between OVM:ETH c-ratios at the time of snapshot - const normalisedL2CRatio = 500 / 400; - // @TODO update the L2 block number to use - // const L2BlockNumber = 4750287; - const L2BlockNumber = _options.L2BlockNumber; - - const scaledTotalL2Debt = totalL2Debt * normalisedL2CRatio; - - /* --------------- */ - - /* Using the subgraph, we get the relevant L1 calculations */ - - const l1Results = (await subgraphRequest( - defaultGraphs[1], - returnGraphParams(blockTag, _addresses) - )) as SNXHoldersResult; - - if (l1Results && l1Results.snxholders) { - for (let i = 0; i < l1Results.snxholders.length; i++) { - const holder = l1Results.snxholders[i]; - const vote = await debtL1( - holder.initialDebtOwnership, - holder.debtEntryAtIndex, - totalL1Debt, - scaledTotalL2Debt, - lastDebtLedgerEntry, - true - ); - score[getAddress(holder.id)] = vote; - } - } - - /* Using the subgraph, we get the relevant L2 calculations */ - - const l2Results = (await subgraphRequest( - defaultGraphs[10], - returnGraphParams(L2BlockNumber, _addresses) - )) as SNXHoldersResult; - - if (l2Results && l2Results.snxholders) { - for (let i = 0; i < l2Results.snxholders.length; i++) { - const holder = l2Results.snxholders[i]; - - const vote = await debtL2( - holder.initialDebtOwnership, - holder.debtEntryAtIndex, - totalL1Debt, - scaledTotalL2Debt, - lastDebtLedgerEntryL2, - true - ); - - if (score[getAddress(holder.id)]) { - score[getAddress(holder.id)] += vote; - } else { - score[getAddress(holder.id)] = vote; - } - } - } - - return score || {}; -} diff --git a/src/strategies/tomyumswap/README.md b/src/strategies/tomyumswap/README.md deleted file mode 100644 index 132af0c87..000000000 --- a/src/strategies/tomyumswap/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Contract Call Strategy - -Fetches [TOMYUM](https://bscscan.com/address/0xa8777a7855cc5e5d4994d890eaad369050a9ff47) balance from the following sources: - -- Wallet -- TOMYUM-BNB LP Farm -- TOMYUM Pool -- TOMYUM Vault -- Pools that were active at the time of the snapshot diff --git a/src/strategies/tomyumswap/examples.json b/src/strategies/tomyumswap/examples.json deleted file mode 100644 index c9bce8660..000000000 --- a/src/strategies/tomyumswap/examples.json +++ /dev/null @@ -1,17 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "tomyumswap", - "params": { - "symbol": "TOMYUM" - } - }, - "network": "56", - "addresses": [ - "0xF677b8EF72C34f63c43f47C30612B1A3Ec1b622F", - "0xd7eAd7DD37EFf97531beA958a58282Fa6D3a31A5" - ], - "snapshot": 7151302 - } -] diff --git a/src/strategies/tomyumswap/index.ts b/src/strategies/tomyumswap/index.ts deleted file mode 100644 index 3d77ee008..000000000 --- a/src/strategies/tomyumswap/index.ts +++ /dev/null @@ -1,132 +0,0 @@ -import fetch from 'cross-fetch'; -import { subgraphRequest } from '../../utils'; - -export const author = 'tomyumswap'; -export const version = '0.0.1'; - -type VotingResponse = { - verificationHash: string; - block: number; - tomYumBalance: string; - tomYumVaultBalance: string; - tomYumPoolBalance: string; - tomYumBnbLpBalance: string; - poolsBalance: string; - total: string; -}; - -const MINIMUM_VOTING_POWER = 0.01; -const SMART_CHEF_URL = - 'https://api.thegraph.com/subgraphs/name/tomyumswap/smartchef'; -const VOTING_API_URL = 'http://voting-api.tomyumswap.com/api/'; - -/** - * Fetches voting power of one address - */ -// const fetchVotingPower = async ( -// address: string, -// block: number, -// poolAddresses: string[] -// ): Promise => { -// const response = await fetch(`${VOTING_API_URL}power`, { -// method: 'POST', -// headers: { -// 'Content-Type': 'application/json' -// }, -// body: JSON.stringify({ -// block, -// address, -// poolAddresses -// }) -// }); - -// const payload = await response.json(); -// return payload.data; -// }; - -/** - * Fetches voting power of multiple addresses - */ -const fetchVotingPowerMultiple = async ( - addresses: string[], - block: number, - poolAddresses: string[] -): Promise => { - const response = await fetch(`${VOTING_API_URL}powerV2`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - block, - addresses, - poolAddresses - }) - }); - - const payload = await response.json(); - - return payload.data; -}; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const blockTag = - typeof snapshot === 'number' ? snapshot : await provider.getBlockNumber(); - - const params = { - smartChefs: { - __args: { - where: { - startBlock_lte: blockTag, - endBlock_gte: blockTag - }, - first: 1000, - orderBy: 'block', - orderDirection: 'desc' - }, - id: true, - startBlock: true, - endBlock: true - } - }; - - const results = await subgraphRequest(SMART_CHEF_URL, params); - - if (!results) { - return; - } - - try { - const poolAddresses = results.smartChefs.map((pool) => pool.id); - const votingPowerResult = await fetchVotingPowerMultiple( - addresses, - blockTag, - poolAddresses - ); - - const calculatedPower = votingPowerResult.reduce( - (accum, response, index) => { - const address = addresses[index]; - const total = parseFloat(response.total); - - return { - ...accum[index], - [address]: - total <= MINIMUM_VOTING_POWER ? MINIMUM_VOTING_POWER : total - }; - }, - {} - ); - - return calculatedPower; - } catch { - return []; - } -} diff --git a/src/strategies/uma-voting/README.md b/src/strategies/uma-voting/README.md deleted file mode 100644 index 45cd408a6..000000000 --- a/src/strategies/uma-voting/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# uma-voting strategy - -This strategy returns the UMA balance of the voting wallet for the hot wallet. - -Here is an example of parameters: - -## Example - -```JSON -[ - { - "name": "Example query", - "strategy": { - "name": "uma-voting", - "params": { - "address": "0x04Fa0d235C4abf4BcF4787aF4CF447DE572eF828", - "votingFactoryAddress": "0xDE7c02aD2b925587Bd16724810f994a2948c4a38", - "symbol": "UMA", - "decimals": 18 - } - }, - "network": "1", - "addresses": [ - "0x6888ff4be3262f3232e1c022de731680a16ddda7", - "0x66b5409f52d23ef87bdbfaa7312f8d790755fe13", - "0xedd049c56b804bcdbf7e704cc312491e3d50485a", - "0x18a31db2ecc0c27ee445266337b144f60810c228", - "0xacd3dc5c6f9cb967b5e1f719001e85039b0c976f", - "0x3d88456277e32d62575267c3564b72387c3f21f7", - "0xdf815836fe1457f7e2c0c3d2348e94190a37c687", - "0x515978b57fc91b6a845dc64574b151c7ed3bc2a7", - "0x8a6800c753ed8ed19e0df473a97a7a94b2cecf54", - "0x1fdef3d3c7984a945008c253caa6cf380fddb16f", - "0x82b6a4ebc3904b7aabd4e85510045eff0d43a6bd", - "0x50e453636f153ded412eca1ecc3e520a206b3496", - "0x336b9de28d67d692c31df93a9b8630b2fa50d88f", - "0x2cf6988d57d0df95d3ff37cdfbfe0520f15c860f", - "0x644a7ff3cdff23c3f10f25807a40fa48aff34885", - "0xfd8355b24ab8815ca2d76d1e495dc29b4330241f", - "0xc00667d8b00f35b3565a5c4458dff1cd718e3527" - ], - "snapshot": 14515308 - } -] - -``` diff --git a/src/strategies/uma-voting/examples.json b/src/strategies/uma-voting/examples.json deleted file mode 100644 index 02bdafc92..000000000 --- a/src/strategies/uma-voting/examples.json +++ /dev/null @@ -1,56 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "uma-voting", - "params": { - "address": "0x04Fa0d235C4abf4BcF4787aF4CF447DE572eF828", - "votingFactoryAddress": "0xDE7c02aD2b925587Bd16724810f994a2948c4a38", - "symbol": "UMA", - "decimals": 18 - } - }, - "network": "1", - "addresses": [ - "0x9a8f92a830a5cb89a3816e3d267cb7791c16b04d", - "0x691c39fdd4f89db2d885324a2b5cef00fbf8caa3", - "0xfb9e5f5874565a6ef8fcf1debc4975501331a8ca", - "0x075ad09e2b27be785c863d756096d0aebcf13118", - "0x644a7ff3cdff23c3f10f25807a40fa48aff34885", - "0xfd8355b24ab8815ca2d76d1e495dc29b4330241f", - "0x1398fc0793d8b67744bfde4a4ff338c69bba753b", - "0xc3d26aa4954816330c5ffc9bb2d46acbceaff130", - "0x9e3a4ed4eea5c27a5e82a32e90482a4827a4ae80", - "0xdcf99ba641c98e37df8ea31188ad7e7fa5501b09", - "0x3b271e8f1409e8e90c484d3591143bd7e1d2a177", - "0x112eae3093451187c8b945fb601c6df34bdc8105", - "0xfdf7f859807d1dc73873640759b2706822802529", - "0x4b070c428ddbb49524abf2d4be4998c1e3b6f3a5", - "0x8d4f93e9962f3392e4c9d10c08f2f1c757f95866", - "0x49e0cdd718d330e5a27856256236b4e56a76d3fb", - "0xabbcf7b0735e4eb152fd13fa02691cc046fac0bd", - "0xc00667d8b00f35b3565a5c4458dff1cd718e3527", - "0x11efc2638184a0382bf1bb29c4047c6111f8f3c7", - "0x7cac2ab1cf9dc459ca88a85d72ac94de2691f1e5", - "0xb0903a62f5ca7a215aa67232ba691cb801decd5b", - "0xbca0fd352dce62fa1b7c7f9fa8f0c1de7fef09d9", - "0x6888ff4be3262f3232e1c022de731680a16ddda7", - "0x66b5409f52d23ef87bdbfaa7312f8d790755fe13", - "0xedd049c56b804bcdbf7e704cc312491e3d50485a", - "0x18a31db2ecc0c27ee445266337b144f60810c228", - "0xacd3dc5c6f9cb967b5e1f719001e85039b0c976f", - "0x718648c8c531f91b528a7757dd2be813c3940608", - "0x3d88456277e32d62575267c3564b72387c3f21f7", - "0xdf815836fe1457f7e2c0c3d2348e94190a37c687", - "0x515978b57fc91b6a845dc64574b151c7ed3bc2a7", - "0x8a6800c753ed8ed19e0df473a97a7a94b2cecf54", - "0x1fdef3d3c7984a945008c253caa6cf380fddb16f", - "0x82b6a4ebc3904b7aabd4e85510045eff0d43a6bd", - "0x50e453636f153ded412eca1ecc3e520a206b3496", - "0x969397c71eb51f7fdcf6527db4d97871b05d6f63", - "0x336b9de28d67d692c31df93a9b8630b2fa50d88f", - "0x2cf6988d57d0df95d3ff37cdfbfe0520f15c860f" - ], - "snapshot": 14515308 - } -] diff --git a/src/strategies/uma-voting/index.ts b/src/strategies/uma-voting/index.ts deleted file mode 100644 index c3bf58280..000000000 --- a/src/strategies/uma-voting/index.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { formatUnits } from '@ethersproject/units'; -import { multicall } from '../../utils'; - -export const author = 'abg4'; -export const version = '0.1.0'; - -const abi = [ - 'function balanceOf(address account) external view returns (uint256)', - 'function designatedVotingContracts(address) view returns (address)' -]; - -function getArgs(options, address: string) { - const args: Array = options.args || ['%{address}']; - return args.map((arg) => - typeof arg === 'string' ? arg.replace(/%{address}/g, address) : arg - ); -} - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - const votingAddress = await multicall( - network, - provider, - abi, - addresses.map((address: any) => [ - options.votingFactoryAddress, - 'designatedVotingContracts', - getArgs(options, address) - ]), - { blockTag } - ); - - const response = await multicall( - network, - provider, - abi, - votingAddress.map((address: any) => [ - options.address, - 'balanceOf', - getArgs(options, address) - ]), - { blockTag } - ); - - return Object.fromEntries( - response.map((value, i) => [ - addresses[i], - parseFloat( - formatUnits( - options?.output ? value[options.output].toString() : value.toString(), - options.decimals - ) - ) - ]) - ); -} diff --git a/src/strategies/vault-token-lp-balance/README.md b/src/strategies/vault-token-lp-balance/README.md deleted file mode 100644 index b895c988c..000000000 --- a/src/strategies/vault-token-lp-balance/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# vault-token-lp-balance - -This strategy computes the amount of a token -in a vault lp pool. The vault must use the function `stakedWantTokens(pid, user)`. - -You must supply the token, vault address, lp address, and pid of the pool -in the vault chef. Here is an example of the params: - -```json -{ - "tokenAddress": "0x0159ED2E06DDCD46a25E74eb8e159Ce666B28687", - "tokenDecimals": 18, - "vaultChefAddress": "0x2914646E782Cc36297c6639734892927B3b6Fe56", - "pid": 8, - "lpAddress": "0xE2E34C07754C4CAb2b6D585C06D418628f8ba553" -} -``` diff --git a/src/strategies/vault-token-lp-balance/examples.json b/src/strategies/vault-token-lp-balance/examples.json deleted file mode 100644 index dc3be1918..000000000 --- a/src/strategies/vault-token-lp-balance/examples.json +++ /dev/null @@ -1,24 +0,0 @@ -[ - { - "name": "Vault Token in LP balance", - "strategy": { - "name": "vault-token-lp-balance", - "params": { - "tokenAddress": "0x0159ED2E06DDCD46a25E74eb8e159Ce666B28687", - "symbol": "FOX", - "tokenDecimals": 18, - "vaultChefAddress": "0x2914646E782Cc36297c6639734892927B3b6Fe56", - "pid": 8, - "lpAddress": "0xE2E34C07754C4CAb2b6D585C06D418628f8ba553" - } - }, - "network": "1666600000", - "addresses": [ - "0xD20B976584bF506BAf5cC604D1f0A1B8D07138dA", - "0x4ff9B7C1424b9E4375BbbDF3357a318412c02E0c", - "0x57B7713c0E013cfbEC0E4C6c8B264dAf7598ebA9", - "0xBfA58c2516cB64C7f6E19c0B3690158C38E4d0f7" - ], - "snapshot": 18263021 - } -] diff --git a/src/strategies/vault-token-lp-balance/index.ts b/src/strategies/vault-token-lp-balance/index.ts deleted file mode 100644 index 870b6b3f3..000000000 --- a/src/strategies/vault-token-lp-balance/index.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { formatUnits } from '@ethersproject/units'; -import { multicall, Multicaller } from '../../utils'; - -export const author = 'foxthefarmer'; -export const version = '0.0.1'; - -const vaultAbi = [ - 'function poolInfo(uint256) returns (address want,uint256 allocPoint,uint256 lastRewardBlock,uint256 accAQUAPerShare,address strat)', - 'function stakedWantTokens(uint256 _pid, address _user) returns (uint256)' -]; - -const bep20Abi: any = [ - 'function totalSupply() view returns (uint256)', - 'function balanceOf(address) view returns (uint256)' -]; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - const erc20Multi = new Multicaller(network, provider, bep20Abi, { - blockTag - }); - erc20Multi.call('lpTotalSupply', options.lpAddress, 'totalSupply'); - erc20Multi.call('lpTokenBalance', options.tokenAddress, 'balanceOf', [ - options.lpAddress - ]); - - const erc20Result = await erc20Multi.execute(); - - const tokenPerLp = - parseFloat(erc20Result.lpTokenBalance.toString()) / - parseFloat(erc20Result.lpTotalSupply.toString()); - - const userVaultLpBalanceCalls = multicall( - network, - provider, - vaultAbi, - addresses.map((address: any) => [ - options.vaultChefAddress, - 'stakedWantTokens', - [options.pid, address] - ]), - { blockTag } - ); - - const vaultBalances = await Promise.all([userVaultLpBalanceCalls]); - - return Object.fromEntries( - Object.entries(addresses).map((address: any, index) => [ - address[1], - parseFloat(formatUnits(vaultBalances[0][index].toString(), 18)) * - tokenPerLp - ]) - ); -} diff --git a/src/strategies/volt-voting-power/README.md b/src/strategies/volt-voting-power/README.md index ff14e35d9..2e825dee0 100644 --- a/src/strategies/volt-voting-power/README.md +++ b/src/strategies/volt-voting-power/README.md @@ -1,5 +1,5 @@ # Voting shares of VOLT token stakers and holders - + This strategy computes users shares of volt token (erc-20) in an lp pool. The strategy calculates user votes using this formula : user's volt balance + staked volt balance + User LP share mapped volt balance @@ -11,9 +11,9 @@ You must supply the voltwap token address, symbol, decimals, network id, swap su "symbol": "VOLT", "tokenDecimals": 18, "lpTokenAddress": "0x1071392e4cdf7c01d433b87be92beb1f8fd663a8", - "voltAddress":"0x8df95e66cb0ef38f91d2776da3c921768982fba0", - "network":"82", - "swapSubgraph":"https://graph-meter.voltswap.finance/subgraphs/name/meterio/uniswap-v2-subgraph", - "stakingSubgraph":"https://graph-meter.voltswap.finance/subgraphs/name/meter/geyser-v2" + "voltAddress": "0x8df95e66cb0ef38f91d2776da3c921768982fba0", + "network": "82", + "swapSubgraph": "https://graph-meter.voltswap.finance/subgraphs/name/meterio/uniswap-v2-subgraph", + "stakingSubgraph": "https://graph-meter.voltswap.finance/subgraphs/name/meter/geyser-v2" } ``` diff --git a/src/strategies/vsta-pool-staking/README.md b/src/strategies/vsta-pool-staking/README.md deleted file mode 100644 index 189242083..000000000 --- a/src/strategies/vsta-pool-staking/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# vsta-pool-staking - -This strategy returns voters underlying VSTA token balance for lping and staking to our reward farms - -## Params - -- `symbol` - (**Optional**, `string`) Symbol of ERC20 token -- `decimals` - (**Required**, `number`) Decimal precision for ERC20 token -- `balancerVaultAddress` - (**Required**, `string`) Address of Balancer Vault to get token balances of LPs -- `poolAddress` - (**Required**, `string`) Address of VSTA-TOKEN lp token -- `poolId` - (**Required**, `string`) Balancer pool ID of VSTA-TOKEN lp -- `farmAddress` - (**Required**, `string`) Vesta farm address -- `vstaAddress` - (**Required**, `string`) Vesta token address - -Here is an example of parameters: - -```json -{ - "balancerVaultAddress": "0xBA12222222228d8Ba445958a75a0704d566BF2C8", - "poolAddress": "0xC61ff48f94D801c1ceFaCE0289085197B5ec44F0", - "poolId": "0xc61ff48f94d801c1ceface0289085197b5ec44f000020000000000000000004d", - "farmAddress": "0x65207da01293C692a37f59D1D9b1624F0f21177c", - "vstaAddress": "0xa684cd057951541187f288294a1e1C2646aA2d24", - "symbol": "VSTA", - "decimals": 18 -} -``` diff --git a/src/strategies/vsta-pool-staking/examples.json b/src/strategies/vsta-pool-staking/examples.json deleted file mode 100644 index 8f74a71b5..000000000 --- a/src/strategies/vsta-pool-staking/examples.json +++ /dev/null @@ -1,24 +0,0 @@ -[ - { - "name": "VSTA pool staking strategy", - "strategy": { - "name": "vsta-pool-staking", - "params": { - "balancerVaultAddress": "0xBA12222222228d8Ba445958a75a0704d566BF2C8", - "poolAddress": "0xC61ff48f94D801c1ceFaCE0289085197B5ec44F0", - "poolId": "0xc61ff48f94d801c1ceface0289085197b5ec44f000020000000000000000004d", - "farmAddress": "0x65207da01293C692a37f59D1D9b1624F0f21177c", - "vstaAddress": "0xa684cd057951541187f288294a1e1C2646aA2d24", - "symbol": "VSTA", - "decimals": 18 - } - }, - "network": "42161", - "addresses": [ - "0x88684f6abb5dcd4d3195cc2c714dd79de5a76999", - "0x126824925a67f98dca1eb9d92d78d51c99f3a427", - "0x7a16e350ab5929a40cd9a6f51957d5a45a6e361b" - ], - "snapshot": 44025597 - } -] diff --git a/src/strategies/vsta-pool-staking/index.ts b/src/strategies/vsta-pool-staking/index.ts deleted file mode 100644 index c4e3ca9f1..000000000 --- a/src/strategies/vsta-pool-staking/index.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { formatUnits } from '@ethersproject/units'; -import { getAddress } from '@ethersproject/address'; -import { Multicaller } from '../../utils'; - -export const author = 'shinitakunai'; -export const version = '0.1.0'; - -const abi = [ - 'function getPoolTokens(bytes32 poolId) external view returns (address[], uint256[], uint256)', - 'function totalSupply() external view returns (uint256)', - 'function balances(address owner) external view returns (uint256)' -]; - -export async function strategy( - _space, - network, - provider, - addresses, - options, - snapshot -): Promise> { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - const multi = new Multicaller(network, provider, abi, { blockTag }); - multi.call('poolTokens', options.balancerVaultAddress, 'getPoolTokens', [ - options.poolId - ]); - multi.call('lpTokenTotalSupply', options.poolAddress, 'totalSupply', []); - addresses.forEach((address) => - multi.call(`userBalances.${address}`, options.farmAddress, 'balances', [ - address - ]) - ); - - const { - poolTokens: [tokens, balances], - lpTokenTotalSupply, - userBalances - } = await multi.execute(); - - const vstaIndex = tokens.findIndex( - (address) => address.toLowerCase() === options.vstaAddress.toLowerCase() - ); - - const vstaPerLp = balances[vstaIndex].div(lpTokenTotalSupply); - - const result = Object.fromEntries( - Object.entries(userBalances).map(([address, lpBalance]) => [ - getAddress(address), - parseFloat(formatUnits(vstaPerLp.mul(lpBalance), options.decimals)) - ]) - ); - - return result; -} diff --git a/src/strategies/vsta-pool-staking/schema.json b/src/strategies/vsta-pool-staking/schema.json deleted file mode 100644 index a2d73368c..000000000 --- a/src/strategies/vsta-pool-staking/schema.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$ref": "#/definitions/Strategy", - "definitions": { - "Strategy": { - "title": "Strategy", - "type": "object", - "properties": { - "symbol": { - "type": "string", - "title": "symbol", - "examples": ["e.g. VSTA"], - "maxLength": 16 - }, - "decimals": { - "type": "number", - "title": "decimals", - "examples": ["e.g. 18"] - }, - "balancerVaultAddress": { - "type": "string", - "title": "balancerVaultAddress", - "examples": ["e.g. 0x2d94AA3e47d9D5024503Ca8491fcE9A2fB4DA198"], - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - }, - "poolAddress": { - "type": "string", - "title": "poolAddress", - "examples": ["e.g. 0x472D0B0DDFE0BC02C27928b8BcbD67E65D07d48a"], - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - }, - "poolId": { - "type": "string", - "title": "poolId", - "examples": [ - "e.g. 0xc61ff48f94d801c1ceface0289085197b5ec44f000020000000000000000004d" - ], - "pattern": "^0x[a-fA-F0-9]{64}$", - "minLength": 66, - "maxLength": 66 - }, - "farmAddress": { - "type": "string", - "title": "farmAddress", - "examples": ["e.g. 0x472D0B0DDFE0BC02C27928b8BcbD67E65D07d48a"], - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - }, - "vstaAddress": { - "type": "string", - "title": "vstaAddress", - "examples": ["e.g. 0x472D0B0DDFE0BC02C27928b8BcbD67E65D07d48a"], - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - } - }, - "required": [ - "decimals", - "balancerVaultAddress", - "poolAddress", - "farmAddress", - "vstaAddress" - ], - "additionalProperties": false - } - } -} diff --git a/src/strategies/xkawa-farm/README.md b/src/strategies/xkawa-farm/README.md deleted file mode 100644 index 1975565f8..000000000 --- a/src/strategies/xkawa-farm/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# xkawa-farm - -Returns voting power based on xKawa token held and stacked in the xKawa Single-side farm, as well as associated pending xKawa reward \ No newline at end of file diff --git a/src/strategies/xkawa-farm/examples.json b/src/strategies/xkawa-farm/examples.json deleted file mode 100644 index bf8e8684b..000000000 --- a/src/strategies/xkawa-farm/examples.json +++ /dev/null @@ -1,21 +0,0 @@ -[ - { - "name": "xKAWA farm balance", - "strategy": { - "name": "xkawa-farm", - "params": { - "farm": "0xC68844Cd3BA9d3Ad88F2cC278213F64b8C0bCddf", - "token": "0xdC386452F9FFDa7F0d2940e5c60Dc0F9469b1097", - "LPxKawa": "0x876692166cAC59506Eac1DB7f01B120F5Da98A50", - "symbol": "xKAWA", - "decimals": 18 - } - }, - "network": "1", - "addresses": [ - "0x41a1b36fdef3df142d5116e52d6e72c02b904fda", - "0x7766ef005ec1b38a8472831e2f0631b12c811a5f" - ], - "snapshot": 13677274 - } -] diff --git a/src/strategies/xkawa-farm/index.ts b/src/strategies/xkawa-farm/index.ts deleted file mode 100644 index d580f2bfc..000000000 --- a/src/strategies/xkawa-farm/index.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { BigNumberish, BigNumber } from '@ethersproject/bignumber'; -import { formatUnits } from '@ethersproject/units'; -import { Multicaller } from '../../utils'; - -export const author = 'drgorillamd'; -export const version = '1.0.0'; - -const abi = [ - 'function userInfo(address,uint256) external view returns(uint256 amount,uint256,uint256,uint256)', - 'function balanceOf(address) external view returns(uint256)', - 'function getReserves() external view returns(uint112,uint112 reserve1,uint32)', - 'function totalSupply() external view returns(uint256)' -]; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -): Promise> { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - const multi = new Multicaller(network, provider, abi, { blockTag }); - - addresses.forEach((address) => { - multi.call(address + '-staked', options.farm, 'userInfo', [address, '1']); // .amount: uint - multi.call(address + '-balance', options.token, 'balanceOf', [address]); // uint - multi.call(address + '-LPstaked', options.farm, 'userInfo', [address, '3']); // .amount: uint - }); - - // xKawa is token1 - multi.call('reserves', options.LPxKawa, 'getReserves', []); // .reserve1: uint - multi.call('totalSupplyLP', options.LPxKawa, 'totalSupply', []); // uint - - const result: Record = await multi.execute(); - - return Object.fromEntries( - addresses.map((adr) => { - let bal = result[adr + '-staked']['amount']; - bal = bal.add(result[adr + '-balance']); - - bal = bal.add( - BigNumber.from(result[adr + '-LPstaked']['amount']) - .mul(result['reserves']['reserve1']) - .div(result['totalSupplyLP']) - ); - - return [adr, parseFloat(formatUnits(bal, options.decimals))]; - }) - ); -} diff --git a/src/strategies/xrook-balance-of-underlying-weighted/examples.json b/src/strategies/xrook-balance-of-underlying-weighted/examples.json deleted file mode 100644 index fb4e85a6d..000000000 --- a/src/strategies/xrook-balance-of-underlying-weighted/examples.json +++ /dev/null @@ -1,37 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "xrook-balance-of-underlying-weighted", - "params": { - "symbol": "xROOK", - "address": "0x8aC32F0a635a0896a8428A9c31fBf1AB06ecf489", - "decimals": 18, - "weight": 1.2, - "underlyingTokenAddress": "0xfA5047c9c78B8877af97BDcb85Db743fD7313d4a", - "liquidityPoolAddress": "0x4F868C1aa37fCf307ab38D215382e88FCA6275E2" - } - }, - "network": "1", - "addresses": [ - "0x759a159D78342340EbACffB027c05910c093f430", - "0x2D21170928854F7Da6dC4b1C89dcb95BBc948338", - "0x722f531740937fc21A2FaC7648670C7f2872A1c7", - "0xA1ebb64d1f19D36A31221fFAd19747EF573Cd5A4", - "0x698EE32575dc58DDC0dd2e8B80d2EaB8Af1E94e1", - "0xBE6DcFDf4F1bf2ec0d3dEbD894a02a0765af6D69", - "0xFe4C4A27BeD5E9113480C84A177068F7421A1Eb7", - "0x0054D2575820cf60F5B6D350fb8d3d352BB3B6FD", - "0x4A9A3815060C3Bd08fb4d44C9e74513874771b0C", - "0x99BcEa6bB0403927fB3c038163478D5b42082Fd9", - "0x04b92e3b5De16Dc7e307ea4CEBc5d7dabaE1894F", - "0xe41eeB9ab53Ab208fD57A5E10dFC2FeE464Ca216", - "0x51F13C84b49B64ba6B1615e7D91b11066908BF3C", - "0x2ee8D80de1c389f1254e94bc44D2d1Bc391eD402", - "0x7453019b806919563EaC33870Fe5f8e5154fdF38", - "0x0B72513E73BB60375a4329FABF9BA16f861C0f12", - "0x9a82d59f46913913808bFE905F6157F967AAa28E" - ], - "snapshot": 15039737 - } -] diff --git a/src/strategies/xrook-balance-of-underlying-weighted/index.ts b/src/strategies/xrook-balance-of-underlying-weighted/index.ts deleted file mode 100644 index ccd613306..000000000 --- a/src/strategies/xrook-balance-of-underlying-weighted/index.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { call } from '../../utils'; -import { formatUnits } from '@ethersproject/units'; -import { strategy as erc20BalanceOfStrategy } from '../erc20-balance-of'; - -export const author = 'TudorSante'; -export const version = '1.0.0'; - -const erc20ABI = [ - 'function balanceOf(address account) external view returns (uint256)', - 'function totalSupply() external view returns (uint256)' -]; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -) { - const score = await erc20BalanceOfStrategy( - space, - network, - provider, - addresses, - options, - snapshot - ); - - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - - const xROOKTotalSupply = await call( - provider, - erc20ABI, - [options.address, 'totalSupply', []], - { blockTag } - ).then((res) => parseFloat(formatUnits(res, options.decimals))); - - const liquidityPoolBalance = await call( - provider, - erc20ABI, - [ - options.underlyingTokenAddress, - 'balanceOf', - [options.liquidityPoolAddress] - ], - { blockTag } - ).then((res) => parseFloat(formatUnits(res, options.decimals))); - - const underlyingValue = liquidityPoolBalance / xROOKTotalSupply; - - return Object.fromEntries( - Object.entries(score).map((res: any) => [ - res[0], - res[1] * options.weight * underlyingValue - ]) - ); -} diff --git a/src/strategies/zorro/README.md b/src/strategies/zorro/README.md deleted file mode 100644 index e333b4df7..000000000 --- a/src/strategies/zorro/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# Zorro Proof of Personhood - -This strategy distributes voting power democratically using the Zorro Proof of Personhood protocol (https://zorro.xyz). - -- The voting power of an address is `0` if they have not been proven as a unique person within your Snapshot space. If they are proven unique, then their voting power is given by the `power` parameter (which defaults to `1`). - -- No matter how many Ethereum addresses someone creates, Zorro aims to make it so only one of them can receive a non-zero voting power from this strategy for a given `purposeIdentifier` (which defaults to your space's ENS name). - -## Example options parameters - -#### Minimal example - -```json -{ - "symbol": "VOTES" -} -``` - -In the above example, `purposeIdentifier` defaults to your space's ens name (e.g. `yourdao.eth`), and `power` defaults to `1`. - -#### options - -```json -{ - "symbol": "VOTES", - "purposeIdentifier": "YourDaoName", - "power": 1000 -} -``` - -## Customization - -If you want a proof-of-personhood strategy customized for your purposes, just email ted@suzman.net and I'll be happy to help. diff --git a/src/strategies/zorro/examples.json b/src/strategies/zorro/examples.json deleted file mode 100644 index 0b7d654c4..000000000 --- a/src/strategies/zorro/examples.json +++ /dev/null @@ -1,31 +0,0 @@ -[ - { - "name": "Example query", - "strategy": { - "name": "zorro", - "params": { - "purposeIdentifier": "roboteddy.eth", - "symbol": "VOTES", - "power": 1 - } - }, - "network": "1", - "addresses": [ - "0xa478c2975ab1ea89e8196811f51a7b7ade33eb11", - "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", - "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", - "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", - "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e", - "0x1d5E65a087eBc3d03a294412E46CE5D6882969f4", - "0x1f254336E5c46639A851b9CfC165697150a6c327", - "0x2ec3F80BeDA63Ede96BA20375032CDD3aAfb3030", - "0x4AcBcA6BE2f8D2540bBF4CA77E45dA0A4a095Fa2", - "0x4F3D348a6D09837Ae7961B1E0cEe2cc118cec777", - "0x6D7f23A509E212Ba7773EC1b2505d1A134f54fbe", - "0x07a1f6fc89223c5ebD4e4ddaE89Ac97629856A0f", - "0x33fA82CC7AB518Aae0f2Caee754E78d08A0cB190", - "0x8d07D225a769b7Af3A923481E1FdF49180e6A265" - ], - "snapshot": 13891032 - } -] diff --git a/src/strategies/zorro/index.ts b/src/strategies/zorro/index.ts deleted file mode 100644 index 35465e7b6..000000000 --- a/src/strategies/zorro/index.ts +++ /dev/null @@ -1,36 +0,0 @@ -import fetch from 'cross-fetch'; - -export const author = 'zorro-project'; -export const version = '0.1.0'; - -const API_URL = 'http://api.zorro.xyz'; - -export async function strategy( - space, - network, - provider, - addresses, - options, - snapshot -): Promise> { - const response = await fetch(API_URL + '/getVerifiedExternalAddresses', { - method: 'POST', - headers: { Accept: 'application/json', 'Content-Type': 'application/json' }, - body: JSON.stringify({ - purposeIdentifier: options.purposeIdentifier || space, - externalAddresses: addresses, - snapshot - }) - }); - const { verifiedExternalAddresses } = await response.json(); - const lookup = Object.fromEntries( - verifiedExternalAddresses.map((addr) => [addr.toLowerCase(), true]) - ); - const power = options.power || 1; - return Object.fromEntries( - addresses.map((address) => [ - address, - lookup[address.toLowerCase()] ? power : 0 - ]) - ); -} diff --git a/src/strategies/zorro/schema.json b/src/strategies/zorro/schema.json deleted file mode 100644 index a887206d2..000000000 --- a/src/strategies/zorro/schema.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$ref": "#/definitions/Strategy", - "definitions": { - "Strategy": { - "title": "Strategy", - "type": "object", - "properties": { - "symbol": { - "type": "string", - "title": "Symbol", - "examples": ["e.g. VOTES"], - "maxLength": 16 - }, - "purposeIdentifier": { - "type": "string", - "title": "Purpose identifier (defaults to snapshot space ens)", - "examples": ["e.g. YourDaoName"] - }, - "power": { - "type": "number", - "title": "Voting power per verified person (defaults to 1)", - "examples": ["e.g. 1000"] - } - }, - "required": [], - "additionalProperties": false - } - } -} From 23c57b14efe715f4f0247c2c011a60c74075d0d5 Mon Sep 17 00:00:00 2001 From: jtakalai Date: Thu, 30 Nov 2023 18:41:29 +0200 Subject: [PATCH 565/815] [streamr] Add Streamr snapshot strategy (#1365) * [streamr] feat: added Streamr strategy * [streamr] feat: add Operator value to direct DATA balance Operator value is the DATA tokens that are staked through the Operator contract that the token holder controls. This means they participate in the Streamr Network and their DATA tokens are hard at work. Add those tokens to the idle DATA tokens 1:1 to get the total voting power. --- src/strategies/index.ts | 4 +- src/strategies/streamr/README.md | 18 +++++++ src/strategies/streamr/examples.json | 36 ++++++++++++++ src/strategies/streamr/index.ts | 71 ++++++++++++++++++++++++++++ src/strategies/streamr/schema.json | 30 ++++++++++++ 5 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 src/strategies/streamr/README.md create mode 100644 src/strategies/streamr/examples.json create mode 100644 src/strategies/streamr/index.ts create mode 100644 src/strategies/streamr/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 3f89c3e34..769e7bf8a 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -376,6 +376,7 @@ import * as bubblegumKids from './bubblegum-kids'; import * as clipperStakedSail from './clipper-staked-sail'; import * as plearn from './plearn'; import * as snote from './snote'; +import * as streamr from './streamr'; const strategies = { 'cap-voting-power': capVotingPower, @@ -758,7 +759,8 @@ const strategies = { 'bubblegum-kids': bubblegumKids, 'clipper-staked-sail': clipperStakedSail, plearn, - snote + snote, + streamr }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/streamr/README.md b/src/strategies/streamr/README.md new file mode 100644 index 000000000..861a0d8e1 --- /dev/null +++ b/src/strategies/streamr/README.md @@ -0,0 +1,18 @@ +# Streamr snapshot strategy + +The Streamr Network is a peer-to-peer network for publishing and subscribing to data in real-time. Applications use it for decentralized messaging, for example sharing data across applications or broadcasting real-time state changes to large audiences. The decentralized nature of the system makes the data transport scalable, robust, secure, tamper proof, and censorship resistant. + +Operators are the node running "miners" in the Streamr Network. They run Streamr nodes, subscribe to streams, and stake DATA in the Sponsorship contract(s) of those streams. When they subscribe, they help making that stream more robust. In return, they receive DATA tokens from the Sponsorship contract, in proportion to their stake. + +This is why part of the Operators' DATA tokens are staked in Sponsorships (through an Operator contract that they control). Only a small portion of DATA is expected to be in the Streamr Network participants' wallets, the rest is staked or delegated into the Streamr Network. + +'''The point of the Streamr snapshot strategy''' is to allocate voting power not only according to DATA token holding (as in the plain erc-20-balance-of strategy), but also counting in the DATA tokens the token holders control via staking and delegation (NOTE: at first, only implemented for stakers. Counting delegated DATA may be added later). + +## Parameters + +```json +{ + "tokenAddress": "0x3a9A81d576d83FF21f26f325066054540720fC34", + "operatorFactoryAddress": "0x935734e66729b69260543Cf6e5EfeB42AC962183" +} +``` diff --git a/src/strategies/streamr/examples.json b/src/strategies/streamr/examples.json new file mode 100644 index 000000000..7e0c62765 --- /dev/null +++ b/src/strategies/streamr/examples.json @@ -0,0 +1,36 @@ +[ + { + "name": "Streamr", + "strategy": { + "name": "streamr", + "params": { + "tokenAddress": "0x3a9A81d576d83FF21f26f325066054540720fC34", + "operatorFactoryAddress": "0x935734e66729b69260543Cf6e5EfeB42AC962183" + } + }, + "network": "137", + "addresses": [ + "0xD6c2bF543491337D81eC9b7d96CFbC04fCB3F4a0", + "0x2112a4b0F6500Bc0c1AebbAb547eaAB6862acC57", + "0x488c0Ba58dAc039fAA30D91DdF86CD75B7Dbe4cD", + "0x013B3576Ef573b7D1eD82Fc4C08bb9dB24EBFa4f", + "0xAd6A86cC6F6e1169292e7bf325564e0B9AC812A7", + "0x9bC7F7Aa4b4395391089dA8588fFb0842b5483A6", + "0xab034dCE46BC70Fd1A032f883B46f6d2BC18DD1a", + "0xB20C20ba1B94A2Fb746091c8D83937Ee35644251", + "0x02fdB03705ed8F92fB8C5073990FC5D4d169FAF8", + "0xc65394747cCCFc5e5DED39da191Bc1C3f9FDB3a2", + "0x5015C1654D8829d549EE976e462bD8B7adE847C5", + "0x6Fc263FF819609E5F4c3d5b8D742Fa94B8a3fEaD", + "0xA39E67290f89dC2419d5F6bf7fE8cc448A80CD1A", + "0x8d1BEc0692cbFC14CC53af1f0D1aBFFC79DBC04f", + "0x02880624Bb0743E3144e8943E29Fd1DDe66cF72c", + "0x8da1A015bb11BcC718CF1f49804282Fa5dBA75C7", + "0x444d26eC73DBaC8d78299597135dA5C0234BafA1", + "0x2594664714882D47aC207b4C46751649d886Bdf8", + "0x41c00f648E781742A5C2CB83B34a05D11D833C4D", + "0x40f076d4AbE73Be1eB21B862A578cDd583910556" + ], + "snapshot": 50305259 + } +] diff --git a/src/strategies/streamr/index.ts b/src/strategies/streamr/index.ts new file mode 100644 index 000000000..d29822e6d --- /dev/null +++ b/src/strategies/streamr/index.ts @@ -0,0 +1,71 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import { formatEther } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'streamr-dev'; +export const version = '0.1.1'; + +const ADDRESS_ZERO = '0x0000000000000000000000000000000000000000'; + +const abi = [ + 'function balanceOf(address account) external view returns (uint256)', // in DATA token + 'function operators(address owner) external view returns (address)', // in OperatorFactory, returns operator contract address + 'function valueWithoutEarnings() external view returns (uint)' // in Operator contract +]; + +type Balances = { + tokens: BigNumber; + staked?: BigNumber; +}; + +export async function strategy( + space, + network, + provider, + addresses: string[], + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + // find the Operator contract deployed by the DATA token holder, will return ADDRESS_ZERO if not found + const getContractOf = new Multicaller(network, provider, abi, { blockTag }); + for (const tokenHolder of addresses) { + getContractOf.call( + tokenHolder, + options.operatorFactoryAddress, + 'operators', + [tokenHolder] + ); + } + const contractOf: Record = await getContractOf.execute(); + + // get both the "cash in hand", and DATA tokens staked through the Operator contract (Operator value) + const getBalances = new Multicaller(network, provider, abi, { blockTag }); + for (const tokenHolder of addresses) { + getBalances.call( + `${tokenHolder}.tokens`, + options.tokenAddress, + 'balanceOf', + [tokenHolder] + ); + if (contractOf[tokenHolder] != ADDRESS_ZERO) { + getBalances.call( + `${tokenHolder}.staked`, + contractOf[tokenHolder], + 'valueWithoutEarnings', + [] + ); + } + } + const balances: Record = await getBalances.execute(); + + return Object.fromEntries( + Object.entries(balances).map( + ([address, { tokens, staked = BigNumber.from(0) }]) => [ + address, + parseFloat(formatEther(tokens.add(staked))) + ] + ) + ); +} diff --git a/src/strategies/streamr/schema.json b/src/strategies/streamr/schema.json new file mode 100644 index 000000000..781cc5ac2 --- /dev/null +++ b/src/strategies/streamr/schema.json @@ -0,0 +1,30 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "tokenAddress": { + "type": "string", + "title": "DATA token address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "operatorFactoryAddress": { + "type": "string", + "title": "OperatorFactory address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } + }, + "required": ["tokenAddress", "operatorFactoryAddress"], + "additionalProperties": false + } + } +} From 8d83db8aebec88279f2905cf082d95b1876b1479 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Fri, 1 Dec 2023 14:17:25 +0530 Subject: [PATCH 566/815] fix: Add back missing strategies (#1366) --- src/strategies/index.ts | 58 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 769e7bf8a..d0e9c2281 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -377,6 +377,34 @@ import * as clipperStakedSail from './clipper-staked-sail'; import * as plearn from './plearn'; import * as snote from './snote'; import * as streamr from './streamr'; +import * as aavegotchiAgip17 from './aavegotchi-agip-17'; +import * as aavegotchiAgip37GltrStakedLp from './aavegotchi-agip-37-gltr-staked-lp'; +import * as aavegotchiAgip37WapGhst from './aavegotchi-agip-37-wap-ghst'; +import * as agave from './agave'; +import * as arrakisFinance from './arrakis-finance'; +import * as ctsiStakingPool from './ctsi-staking-pool'; +import * as cyberkongzV2 from './cyberkongz-v2'; +import * as dextfStakedInVaults from './dextf-staked-in-vaults'; +import * as genomesdao from './genomesdao'; +import * as goldfinchMembership from './goldfinch-membership'; +import * as goldfinchVotingPower from './goldfinch-voting-power'; +import * as h2o from './h2o'; +import * as hoprStakingBySeason from './hopr-staking-by-season'; +import * as hoprStakingS2 from './hopr-staking-s2'; +import * as ilv from './ilv'; +import * as meebitsdaoDelegation from './meebitsdao-delegation'; +import * as modefiStaking from './modefi-staking'; +import * as orbsNetworkDelegation from './orbs-network-delegation'; +import * as planetFinanceV2 from './planet-finance-v2'; +import * as rariFuse from './rari-fuse'; +import * as synthetixNonQuadratic_1 from './synthetix-non-quadratic_1'; +import * as synthetixQuadratic from './synthetix-quadratic'; +import * as synthetixQuadratic_1 from './synthetix-quadratic_1'; +import * as synthetix_1 from './synthetix_1'; +import * as totalAxionShares from './total-axion-shares'; +import * as unipoolSameToken from './unipool-same-token'; +import * as voltVotingPower from './volt-voting-power'; +import * as xdaiStakersAndHolders from './xdai-stakers-and-holders'; const strategies = { 'cap-voting-power': capVotingPower, @@ -760,7 +788,35 @@ const strategies = { 'clipper-staked-sail': clipperStakedSail, plearn, snote, - streamr + streamr, + 'aavegotchi-agip-17': aavegotchiAgip17, + 'aavegotchi-agip-37-gltr-staked-lp': aavegotchiAgip37GltrStakedLp, + 'aavegotchi-agip-37-wap-ghst': aavegotchiAgip37WapGhst, + agave, + 'arrakis-finance': arrakisFinance, + 'ctsi-staking-pool': ctsiStakingPool, + 'cyberkongz-v2': cyberkongzV2, + 'dextf-staked-in-vaults': dextfStakedInVaults, + genomesdao, + 'goldfinch-membership': goldfinchMembership, + 'goldfinch-voting-power': goldfinchVotingPower, + h2o, + 'hopr-staking-by-season': hoprStakingBySeason, + 'hopr-staking-s2': hoprStakingS2, + ilv, + 'meebitsdao-delegation': meebitsdaoDelegation, + 'modefi-staking': modefiStaking, + 'orbs-network-delegation': orbsNetworkDelegation, + 'planet-finance-v2': planetFinanceV2, + 'rari-fuse': rariFuse, + 'synthetix-non-quadratic_1': synthetixNonQuadratic_1, + 'synthetix-quadratic': synthetixQuadratic, + 'synthetix-quadratic_1': synthetixQuadratic_1, + synthetix_1, + 'total-axion-shares': totalAxionShares, + 'unipool-same-token': unipoolSameToken, + 'volt-voting-power': voltVotingPower, + 'xdai-stakers-and-holders': xdaiStakersAndHolders }; Object.keys(strategies).forEach(function (strategyName) { From b68c2913ff62a745e88aab2147049e9e44136304 Mon Sep 17 00:00:00 2001 From: gershido <81111572+gershido@users.noreply.github.com> Date: Mon, 4 Dec 2023 09:05:40 +0200 Subject: [PATCH 567/815] [hats-protocol-hat-id] Fix hats-protocol-hat-id strategy (#1367) * fix hat id conversion and use only multicall * Update index.ts --------- Co-authored-by: Chaitanya --- src/strategies/hats-protocol-hat-id/index.ts | 104 ++++--------------- 1 file changed, 22 insertions(+), 82 deletions(-) diff --git a/src/strategies/hats-protocol-hat-id/index.ts b/src/strategies/hats-protocol-hat-id/index.ts index a494a0588..8943aba8a 100644 --- a/src/strategies/hats-protocol-hat-id/index.ts +++ b/src/strategies/hats-protocol-hat-id/index.ts @@ -1,31 +1,13 @@ -import { subgraphRequest } from '../../utils'; +import { BigNumberish, BigNumber } from '@ethersproject/bignumber'; import { getAddress } from '@ethersproject/address'; +import { Multicaller } from '../../utils'; export const author = 'hotmanics'; export const version = '1.0.0'; -async function subgraphRequestHats(url, snapshot, hatIp) { - const hatHex = HatIpToHex(hatIp); - - const params = { - hat: { - __args: { - id: hatHex - }, - id: true, - wearers: { - id: true - } - } - }; - - if (snapshot !== 'latest') { - // @ts-ignore - params.hat.__args.block = { number: snapshot }; - } - const result = await subgraphRequest(url, params); - return result; -} +const abi = [ + 'function isWearerOfHat(address _user, uint256 _hatId) view returns (bool isWearer)' +]; export async function strategy( space, @@ -35,67 +17,24 @@ export async function strategy( options, snapshot ): Promise> { - let result; - - switch (network) { - case '1': - result = await subgraphRequestHats( - 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-ethereum', - snapshot, - options.hatId - ); - break; - case '10': - result = await subgraphRequestHats( - 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-optimism', - snapshot, - options.hatId - ); - break; - case '5': - result = await subgraphRequestHats( - 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-goerli', - snapshot, - options.hatId - ); - break; - case '137': - result = await subgraphRequestHats( - 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-polygon', - snapshot, - options.hatId - ); - break; - case '100': - result = await subgraphRequestHats( - 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-gnosis-chain', - snapshot, - options.hatId - ); - break; - case '42161': - result = await subgraphRequestHats( - 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-arbitrum', - snapshot, - options.hatId - ); - break; - } + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - const myObj = {}; + const hatId = BigNumber.from(HatIpToHex(options.hatId)); - addresses.forEach((address) => { - myObj[address] = 0; + const multi = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => + multi.call(address, options.address, 'isWearerOfHat', [address, hatId]) + ); + const result: Record = await multi.execute(); - for (let i = 0; i < result.hat.wearers.length; i++) { - if (address === getAddress(result.hat.wearers[i].id)) { - myObj[address] = 1; - break; - } - } - }); + const res = Object.fromEntries( + Object.entries(result).map(([address, isWearer]) => [ + getAddress(address), + isWearer ? 1 : 0 + ]) + ); - return myObj; + return res; } function HatIpToHex(hatIp) { @@ -125,12 +64,13 @@ function HatIpToHex(hatIp) { const hex = sections[i].toString(16); if (i === 0) { - constructedResult += hex.padStart(10 - hex.length, '0'); + constructedResult += hex.padStart(8, '0'); } else { - constructedResult += hex.padStart(5 - hex.length, '0'); + constructedResult += hex.padStart(4, '0'); } } constructedResult = constructedResult.padEnd(66, '0'); + return constructedResult; } From 9603642da1e88b0c72f66e5289e16c5f7f707ceb Mon Sep 17 00:00:00 2001 From: gershido <81111572+gershido@users.noreply.github.com> Date: Mon, 4 Dec 2023 19:52:13 +0200 Subject: [PATCH 568/815] fix hats-protocol-hat-ids strategy (#1368) --- src/strategies/hats-protocol-hat-ids/index.ts | 226 ++---------------- 1 file changed, 25 insertions(+), 201 deletions(-) diff --git a/src/strategies/hats-protocol-hat-ids/index.ts b/src/strategies/hats-protocol-hat-ids/index.ts index 9ccb9372f..7491141d8 100644 --- a/src/strategies/hats-protocol-hat-ids/index.ts +++ b/src/strategies/hats-protocol-hat-ids/index.ts @@ -1,7 +1,6 @@ -import { subgraphRequest } from '../../utils'; +import { BigNumber } from '@ethersproject/bignumber'; import { getAddress } from '@ethersproject/address'; -import { StaticJsonRpcProvider } from '@ethersproject/providers'; -import { multicall } from '../../utils'; +import { Multicaller } from '../../utils'; export const author = 'hotmanics'; export const version = '1.0.0'; @@ -10,32 +9,6 @@ const abi = [ 'function isWearerOfHat(address _user, uint256 _hatId) external view returns (bool isWearer)' ]; -async function subgraphRequestHats({ url, snapshot, treeIp }) { - const treeHex = treeIdDecimalToHex(treeIp); - - const params = { - tree: { - __args: { - id: treeHex - }, - id: true, - hats: { - id: true, - wearers: { - id: true - } - } - } - }; - - if (snapshot !== 'latest') { - // @ts-ignore - params.tree.__args.block = { number: snapshot }; - } - const result = await subgraphRequest(url, params); - return result; -} - export async function strategy( space, network, @@ -46,126 +19,33 @@ export async function strategy( ): Promise> { const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - //This strategy currently enforces that all hatIds passed in are from the same tree. - for (let i = 0; i < options.hatIds.length; i++) { - const lhs = treeIpFromIp(options.hatIds[i]); - - for (let j = 0; j < options.hatIds.length; j++) { - const rhs = treeIpFromIp(options.hatIds[j]); - if (lhs !== rhs) { - throw Error('You can only use hats from the same tree!'); - } - } - } - - //all hatIds are assumed to be from the same tree, set selectedTree to any, and continue. - const selectedTree = treeIpFromIp(options.hatIds[0]); - - const request = { - url: getActiveNetworkSubgraphURL(network), - snapshot, - treeIp: selectedTree - }; - - const result = await subgraphRequestHats(request); - - const validHats: any[] = []; - - for (let j = 0; j < options.hatIds.length; j++) { - for (let i = 0; i < result.tree.hats.length; i++) { - const hatIpHex = HatIpToHex(options.hatIds[j]); - - if (hatIpHex === result.tree.hats[i].id) { - validHats.push(result.tree.hats[i]); - break; - } - } - } - - let wearersInAddresses = []; - - addresses.forEach((address) => { - const wearer = checkIfExists(address, validHats); - wearersInAddresses = wearersInAddresses.concat(wearer); - }); + const hatIds = options.hatIds.map((hatId) => + BigNumber.from(HatIpToHex(hatId)) + ); const multi = new Multicaller(network, provider, abi, { blockTag }); - - wearersInAddresses.forEach((wearer) => { - multi.call(wearer.address, options.address, 'isWearerOfHat', [ - wearer.address, - wearer.hat - ]); - }); - - const multiResult = await multi.execute(); - - const myObj = {}; - - wearersInAddresses.forEach((wearer) => { - myObj[wearer.address] = 0; - for (const result of multiResult) { - if (wearer.address === result.address) { - myObj[wearer.address] = 1; - break; - } - } + addresses.forEach((address) => { + hatIds.forEach((hatId) => { + multi.call(`${address}.${hatId}`, options.address, 'isWearerOfHat', [ + address, + hatId + ]); + }); }); - return myObj; -} - -function getActiveNetworkSubgraphURL(network) { - let url; + const multicallResult: Record< + string, + Record + > = await multi.execute(); - switch (network) { - case '1': - url = - 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-ethereum'; - break; - case '10': - url = - 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-optimism'; - break; - case '5': - url = - 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-goerli'; - break; - case '137': - url = - 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-polygon'; - break; - case '100': - url = - 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-gnosis-chain'; - break; - case '42161': - url = - 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-arbitrum'; - break; - } - - return url; -} - -function checkIfExists(address, hats) { - const addressWithHats = []; - hats.forEach((hat) => { - hat.wearers.forEach((wearer) => { - if (getAddress(wearer.id) === address) { - const addressWithHat = { - address: getAddress(wearer.id), - hat: BigInt(hat.id) - }; - addressWithHats.push(addressWithHat); - } - }); - }); - return addressWithHats; -} + const res = Object.fromEntries( + Object.entries(multicallResult).map(([address, isWearerPerHat]) => [ + getAddress(address), + Object.values(isWearerPerHat).includes(true) ? 1 : 0 + ]) + ); -function treeIdDecimalToHex(treeId: number): string { - return '0x' + treeId.toString(16).padStart(8, '0'); + return res; } function HatIpToHex(hatIp) { @@ -195,68 +75,12 @@ function HatIpToHex(hatIp) { const hex = sections[i].toString(16); if (i === 0) { - constructedResult += hex.padStart(10 - hex.length, '0'); + constructedResult += hex.padStart(8, '0'); } else { - constructedResult += hex.padStart(5 - hex.length, '0'); + constructedResult += hex.padStart(4, '0'); } } constructedResult = constructedResult.padEnd(66, '0'); return constructedResult; } - -function treeIpFromIp(hatIp) { - let treeIp; - - if (hatIp.indexOf('.') === -1) treeIp = hatIp; - else treeIp = hatIp.substring(0, hatIp.indexOf('.')); - - return Number(treeIp); -} - -class Multicaller { - public network: string; - public provider: StaticJsonRpcProvider; - public abi: any[]; - public options: any = {}; - public calls: any[] = []; - public paths: any[] = []; - - constructor( - network: string, - provider: StaticJsonRpcProvider, - abi: any[], - options? - ) { - this.network = network; - this.provider = provider; - this.abi = abi; - this.options = options || {}; - } - - call(path, address, fn, params?): Multicaller { - this.calls.push([address, fn, params]); - this.paths.push(path); - return this; - } - - async execute(): Promise { - const obj = []; - const result = await multicall( - this.network, - this.provider, - this.abi, - this.calls, - this.options - ); - result.forEach((r, i) => { - obj.push({ - address: this.paths[i], - value: r - }); - }); - this.calls = []; - this.paths = []; - return obj; - } -} From 79320ac0afc518f2d06ab617f54eb445aaeed371 Mon Sep 17 00:00:00 2001 From: 0xButterfield <100517047+0xButterfield@users.noreply.github.com> Date: Fri, 8 Dec 2023 12:49:22 +0100 Subject: [PATCH 569/815] feat: delegation-with-cap (#1369) Co-authored-by: Chaitanya --- src/strategies/delegation-with-cap/README.md | 30 ++++++++ .../delegation-with-cap/examples.json | 30 ++++++++ src/strategies/delegation-with-cap/index.ts | 69 +++++++++++++++++++ src/strategies/index.ts | 2 + 4 files changed, 131 insertions(+) create mode 100644 src/strategies/delegation-with-cap/README.md create mode 100644 src/strategies/delegation-with-cap/examples.json create mode 100644 src/strategies/delegation-with-cap/index.ts diff --git a/src/strategies/delegation-with-cap/README.md b/src/strategies/delegation-with-cap/README.md new file mode 100644 index 000000000..88a59ed79 --- /dev/null +++ b/src/strategies/delegation-with-cap/README.md @@ -0,0 +1,30 @@ +# delegation-with-cap + +This strategy is based on the [delegation](https://github.com/snapshot-labs/snapshot-strategies/tree/master/src/strategies/delegation) strategy, with an additional `capPercentage` parameter that caps the voting power of any address to a percentage of the total votes. + +| Param Name | Description | +|----------------------------|-----------------------------------------------------------------------------------------| +| strategies | list of sub strategies to calculate voting power based on delegation | +| capPercentage | Maximum voting power for any address as a percentage of total votes | +| delegationSpace (optional) | Get delegations of a particular space (by default it take delegations of current space) | + +Here is an example of parameters: + +```json +{ + "symbol": "veBAL (delegated)", + "strategies": [ + { + "name": "erc20-balance-of", + "params": { + "symbol": "veBAL", + "address": "0xC128a9954e6c874eA3d62ce62B468bA073093F25", + "decimals": 18 + } + } + ], + "delegationSpace": "balancer.eth", + "capPercentage": 30 +} + +``` diff --git a/src/strategies/delegation-with-cap/examples.json b/src/strategies/delegation-with-cap/examples.json new file mode 100644 index 000000000..89442defa --- /dev/null +++ b/src/strategies/delegation-with-cap/examples.json @@ -0,0 +1,30 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "delegation-with-cap", + "params": { + "symbol": "veBAL (delegated)", + "strategies": [ + { + "name": "erc20-balance-of", + "params": { + "symbol": "veBAL", + "address": "0xC128a9954e6c874eA3d62ce62B468bA073093F25", + "decimals": 18 + } + } + ], + "delegationSpace": "balancer.eth", + "capPercentage": 30 + } + }, + "network": "1", + "addresses": [ + "0xAD9992f3631028CEF19e6D6C31e822C5bc2442CC", + "0x512fce9B07Ce64590849115EE6B32fd40eC0f5F3", + "0x9f74662aD05840Ba35d111930501c617920dD68e" + ], + "snapshot": 17834154 + } +] diff --git a/src/strategies/delegation-with-cap/index.ts b/src/strategies/delegation-with-cap/index.ts new file mode 100644 index 000000000..a0f2975f1 --- /dev/null +++ b/src/strategies/delegation-with-cap/index.ts @@ -0,0 +1,69 @@ +import { getDelegations } from '../../utils/delegation'; +import { getScoresDirect } from '../../utils'; + +export const author = 'bonustrack'; +export const version = '0.1.0'; +export const dependOnOtherAddress = true; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const invalidStrategies = [ + '{"name":"erc20-balance-of","params":{"symbol":"HOP","address":"0xed8Bdb5895B8B7f9Fdb3C087628FD8410E853D48","decimals":18}}' //https://snapshot.org/#/hop.eth/proposal/0x603f0f6e54c7be8d5db7e16ae7145e6df4b439b8aac49654cdfd6b0c03eb6492 + ]; + + if ( + options.strategies.some((s) => + invalidStrategies.includes(JSON.stringify(s)) + ) + ) + return {}; + const delegationSpace = options.delegationSpace || space; + const delegations = await getDelegations( + delegationSpace, + network, + addresses, + snapshot + ); + if (Object.keys(delegations).length === 0) return {}; + + const scores = ( + await getScoresDirect( + space, + options.strategies, + network, + provider, + Object.values(delegations).reduce((a: string[], b: string[]) => + a.concat(b) + ), + snapshot + ) + ).filter((score) => Object.keys(score).length !== 0); + + const addressScores = Object.fromEntries( + addresses.map((address) => { + const addressScore = delegations[address] + ? delegations[address].reduce( + (a, b) => a + scores.reduce((x, y) => (y[b] ? x + y[b] : x), 0), + 0 + ) + : 0; + return [address, addressScore]; + }) + ); + + const totalScore = Object.values(addressScores).reduce((a, b) => a + b, 0); + const maxScore = (options.capPercentage * totalScore) / 100; + + return Object.fromEntries( + Object.entries(addressScores).map(([address, addressScore]) => [ + address, + Math.min(addressScore, maxScore) + ]) + ); +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index d0e9c2281..d9b454d1c 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -77,6 +77,7 @@ import * as stakedKeep from './staked-keep'; import * as stakedDaomaker from './staked-daomaker'; import * as typhoon from './typhoon'; import * as delegation from './delegation'; +import * as delegationWithCap from './delegation-with-cap'; import * as delegationWithOverrides from './delegation-with-overrides'; import * as withDelegation from './with-delegation'; import * as ticket from './ticket'; @@ -506,6 +507,7 @@ const strategies = { 'balancer-unipool': balancerUnipool, typhoon, delegation, + 'delegation-with-cap': delegationWithCap, 'delegation-with-overrides': delegationWithOverrides, 'with-delegation': withDelegation, ticket, From dad4d14de99e06bf15362797987a8a1799143949 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 8 Dec 2023 17:28:41 +0530 Subject: [PATCH 570/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.9.6 (#1371) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 623867b84..050160ea4 100755 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.9.5", + "@snapshot-labs/snapshot.js": "^0.9.6", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index f26d1d88b..cf6dae5cc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.9.5": - version "0.9.5" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.9.5.tgz#2fe0f12b0d913d43121a2fb23e99ac160a3cd41f" - integrity sha512-+Vqn+kms+Yw2pa87cSSp0aIKoJim6wiuUVxl0DIZ2e4yWe8YGZGbJuLXMgozZhwMRVtjW3QX9sHE7lyI1cjMpg== +"@snapshot-labs/snapshot.js@^0.9.6": + version "0.9.6" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.9.6.tgz#749b7df2f0b377231bf47faf9cc64088ff9156c1" + integrity sha512-xO4H9p+to/17hYSbsQpiG29+iEzQf00wRzG+G+Cx/+0/KxkyMoGQhZuZqm9zxYHjtmCBiEY6dITbu38A/n0lmA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From b7727ef81a7111bf567f809666f86d264c5c4d1e Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Fri, 8 Dec 2023 22:57:36 +0530 Subject: [PATCH 571/815] Change author for delegation-with-cap --- src/strategies/delegation-with-cap/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategies/delegation-with-cap/index.ts b/src/strategies/delegation-with-cap/index.ts index a0f2975f1..9dc2bceaa 100644 --- a/src/strategies/delegation-with-cap/index.ts +++ b/src/strategies/delegation-with-cap/index.ts @@ -1,7 +1,7 @@ import { getDelegations } from '../../utils/delegation'; import { getScoresDirect } from '../../utils'; -export const author = 'bonustrack'; +export const author = '0xButterfield'; export const version = '0.1.0'; export const dependOnOtherAddress = true; From 22b8c270d2bead1f1461345593b9361e7a85fb7d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 13 Dec 2023 10:35:05 +0530 Subject: [PATCH 572/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.9.7 (#1372) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 050160ea4..451933fee 100755 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.9.6", + "@snapshot-labs/snapshot.js": "^0.9.7", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index cf6dae5cc..5dd3124b3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.9.6": - version "0.9.6" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.9.6.tgz#749b7df2f0b377231bf47faf9cc64088ff9156c1" - integrity sha512-xO4H9p+to/17hYSbsQpiG29+iEzQf00wRzG+G+Cx/+0/KxkyMoGQhZuZqm9zxYHjtmCBiEY6dITbu38A/n0lmA== +"@snapshot-labs/snapshot.js@^0.9.7": + version "0.9.7" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.9.7.tgz#f384d6c085a64c808eaab077995a3e023526ded7" + integrity sha512-TFXNkJ33yY3+nPt2ZWDif/QcSmggfIyi/Cyo2N16xQ1ZNJvEwTjHuHPdX6chP4X0vqtsDn+RU6CtuHYibwWOUA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From ddda8e9e1f2614be2e5a69a333d75901021418b7 Mon Sep 17 00:00:00 2001 From: ChefJoJo <94336009+chef-jojo@users.noreply.github.com> Date: Fri, 15 Dec 2023 21:53:13 +0800 Subject: [PATCH 573/815] [cake] Update cake strategy for only veCake (#1364) * Update cake strategy for only veCake * use proxy address * Update block * Update block --- src/strategies/cake/examples.json | 15 +++++------ src/strategies/cake/index.ts | 42 ++++++++++++++++++++++++++++--- 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/src/strategies/cake/examples.json b/src/strategies/cake/examples.json index ea44a6127..9a243885a 100644 --- a/src/strategies/cake/examples.json +++ b/src/strategies/cake/examples.json @@ -9,15 +9,15 @@ }, "network": "56", "addresses": [ - "0x8b017905DC96B38f817473dc885F84D4C76bC113", - "0x21fF20E7e1B820020415707298b92299CF0951fE", - "0xa7A01B93B889ff0639d5ec02914A77529924a46F", - "0x68e0c606036CAcb83D1755ca31f79630468F044e" + "0x4385c3ca394021a9411B925C94b23a89a3814Ed5", + "0x5B7A2dd16767dD598BA6a432c5c93D167477fB99", + "0x5224F9c440589b2D96F74ac9BA65C648260A4480", + "0xcD8efe4072A489DAB0f662FbA328ECc755E7A66f" ], - "snapshot": 16308675 + "snapshot": 34337773 }, { - "name": "Example query - before 16300686 snapshot", + "name": "Example query - before 34337773 snapshot", "strategy": { "name": "cake", "params": { @@ -28,8 +28,9 @@ "addresses": [ "0x8b017905DC96B38f817473dc885F84D4C76bC113", "0x21fF20E7e1B820020415707298b92299CF0951fE", + "0xa7A01B93B889ff0639d5ec02914A77529924a46F", "0x68e0c606036CAcb83D1755ca31f79630468F044e" ], - "snapshot": 15204010 + "snapshot": 16308675 } ] diff --git a/src/strategies/cake/index.ts b/src/strategies/cake/index.ts index 497928e99..68d51ff29 100644 --- a/src/strategies/cake/index.ts +++ b/src/strategies/cake/index.ts @@ -36,6 +36,8 @@ const onChainVotingPower = { } }; +const veCakeBlockNumber = 34371669; + const abi = [ 'function getVotingPowerWithoutPool(address _user) view returns (uint256)' ]; @@ -142,6 +144,31 @@ async function getSmartChefStakedCakeAmount( }, {}); } +async function veCakeStrategy(addresses, network, provider, blockTag, options) { + let callData = addresses.map((address: any) => [ + onChainVotingPower.v1.address, + 'getVotingPowerWithoutPool', + [address.toLowerCase()] + ]); + + callData = [...chunk(callData, options.max || 400)]; + + const response: any[] = []; + for (const call of callData) { + const multiRes = await multicall(network, provider, abi, call, { + blockTag + }); + response.push(...multiRes); + } + + return Object.fromEntries( + response.map((value, i) => [ + addresses[i], + parseFloat(formatEther(value.toString())) + ]) + ); +} + export async function strategy( space, network, @@ -150,6 +177,15 @@ export async function strategy( options, snapshot ) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + if ( + blockTag === 'latest' || + (typeof blockTag === 'number' && blockTag >= veCakeBlockNumber) + ) { + return veCakeStrategy(addresses, network, provider, blockTag, options); + } + const pools = await getPools(provider, snapshot); const userPoolBalance = await getSmartChefStakedCakeAmount( @@ -158,11 +194,9 @@ export async function strategy( addresses ); - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; if ( - blockTag === 'latest' || - (typeof blockTag === 'number' && - blockTag >= onChainVotingPower.v0.blockNumber) + typeof blockTag === 'number' && + blockTag >= onChainVotingPower.v0.blockNumber ) { let callData = addresses.map((address: any) => [ typeof blockTag === 'number' && From d4eca95b85c122f52954f3409bcfcbff79f163fc Mon Sep 17 00:00:00 2001 From: 0xButterfield <100517047+0xButterfield@users.noreply.github.com> Date: Sun, 17 Dec 2023 12:50:41 +0100 Subject: [PATCH 574/815] fix: delegation-with-cap (#1374) - Ensure the `delegation-with-cap` strategy caps votes against the total supply, not total cast votes Co-authored-by: Chaitanya --- src/strategies/delegation-with-cap/README.md | 6 +++++- src/strategies/delegation-with-cap/examples.json | 4 +++- src/strategies/delegation-with-cap/index.ts | 11 ++++++++--- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/strategies/delegation-with-cap/README.md b/src/strategies/delegation-with-cap/README.md index 88a59ed79..354213c84 100644 --- a/src/strategies/delegation-with-cap/README.md +++ b/src/strategies/delegation-with-cap/README.md @@ -1,11 +1,13 @@ # delegation-with-cap -This strategy is based on the [delegation](https://github.com/snapshot-labs/snapshot-strategies/tree/master/src/strategies/delegation) strategy, with an additional `capPercentage` parameter that caps the voting power of any address to a percentage of the total votes. +This strategy is based on the [delegation](https://github.com/snapshot-labs/snapshot-strategies/tree/master/src/strategies/delegation) strategy, with an additional `capPercentage` parameter that caps the voting power of any address to a percentage of the total supply, along with `address` and `decimals` parameters to get the total supply that the voting power should be capped against. | Param Name | Description | |----------------------------|-----------------------------------------------------------------------------------------| | strategies | list of sub strategies to calculate voting power based on delegation | | capPercentage | Maximum voting power for any address as a percentage of total votes | +| address | Address of the token contract used to cap total supply against | +| decimals | Decimals of the token contract used to cap total supply against | | delegationSpace (optional) | Get delegations of a particular space (by default it take delegations of current space) | Here is an example of parameters: @@ -13,6 +15,8 @@ Here is an example of parameters: ```json { "symbol": "veBAL (delegated)", + "address": "0xC128a9954e6c874eA3d62ce62B468bA073093F25", + "decimals": 18, "strategies": [ { "name": "erc20-balance-of", diff --git a/src/strategies/delegation-with-cap/examples.json b/src/strategies/delegation-with-cap/examples.json index 89442defa..8f554a491 100644 --- a/src/strategies/delegation-with-cap/examples.json +++ b/src/strategies/delegation-with-cap/examples.json @@ -5,6 +5,8 @@ "name": "delegation-with-cap", "params": { "symbol": "veBAL (delegated)", + "address": "0xC128a9954e6c874eA3d62ce62B468bA073093F25", + "decimals": 18, "strategies": [ { "name": "erc20-balance-of", @@ -16,7 +18,7 @@ } ], "delegationSpace": "balancer.eth", - "capPercentage": 30 + "capPercentage": 10 } }, "network": "1", diff --git a/src/strategies/delegation-with-cap/index.ts b/src/strategies/delegation-with-cap/index.ts index 9dc2bceaa..daa31413c 100644 --- a/src/strategies/delegation-with-cap/index.ts +++ b/src/strategies/delegation-with-cap/index.ts @@ -1,5 +1,5 @@ import { getDelegations } from '../../utils/delegation'; -import { getScoresDirect } from '../../utils'; +import { call, getScoresDirect } from '../../utils'; export const author = '0xButterfield'; export const version = '0.1.0'; @@ -57,8 +57,13 @@ export async function strategy( }) ); - const totalScore = Object.values(addressScores).reduce((a, b) => a + b, 0); - const maxScore = (options.capPercentage * totalScore) / 100; + const totalSupply = await call( + provider, + ['function totalSupply() public view returns (uint256)'], + [options.address, 'totalSupply'] + ).then((res) => Number(res.toString()) / 10 ** options.decimals); + + const maxScore = (options.capPercentage * totalSupply) / 100; return Object.fromEntries( Object.entries(addressScores).map(([address, addressScore]) => [ From 215c357e4f4c0406e6329ed08d3b390a8bf37a01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Espen=20H=C3=B8jsgaard?= Date: Sun, 17 Dec 2023 12:59:34 +0100 Subject: [PATCH 575/815] [station-score-if-badge, station-constant-if-badge, mangrove-station-qv-scaled-to-mgv] Update ERC-6551 ABI (#1373) * [station-score-if-badge, station-constant-if-badge, mangrove-station-qv-scaled-to-mgv] Update ERC-6551 ABI The ordering of the ERC-6551 'account' function parameters has changed and the 'salt' is now a bytes32 instead of a uint256. This commit updates the station-score-if-badge and its dependents station-constant-if-badge and mangrove-station-qv-scaled-to-mgv accordingly. * chore: Fix linting error --- .../examples.json | 27 +++++++++---------- .../index.ts | 2 +- .../schema.json | 10 ++++--- .../station-constant-if-badge/examples.json | 23 ++++++++-------- .../station-constant-if-badge/index.ts | 2 +- .../station-constant-if-badge/schema.json | 10 ++++--- .../station-score-if-badge/examples.json | 25 +++++++++-------- .../station-score-if-badge/index.ts | 10 +++---- .../station-score-if-badge/schema.json | 10 ++++--- 9 files changed, 64 insertions(+), 55 deletions(-) diff --git a/src/strategies/mangrove-station-qv-scaled-to-mgv/examples.json b/src/strategies/mangrove-station-qv-scaled-to-mgv/examples.json index 425f88e26..dbe07b91b 100644 --- a/src/strategies/mangrove-station-qv-scaled-to-mgv/examples.json +++ b/src/strategies/mangrove-station-qv-scaled-to-mgv/examples.json @@ -4,26 +4,25 @@ "strategy": { "name": "mangrove-station-qv-scaled-to-mgv", "params": { - "membershipERC721": "0xd71c8619209cc95a81f8d9ba4fd704d9eff3ddd6", - "badgesERC1155": "0xd775e55e314164cce7f71f9f70fc905c907fc65e", + "membershipERC721": "0x33dbde2e093b7cf8446d9ac0de79220d42423501", + "badgesERC1155": "0xd1502a7659eaad60278ae3ef27edea849504f4da", "activeBadgeId": 1, - "activityScoreERC20": "0x30D602cBfe96FC2C83fF31Bdf79d48De65f80733", + "activityScoreERC20": "0x5f120453dfd0c55f55370d1f718089ae0fcf6387", "activityScoreDecimals": 18, - "erc6551Registry": "0x02101dfB77FDE026414827Fdc604ddAF224F0921", - "erc6551Implementation": "0x2d25602551487c3f3354dd80d76d54383a243358", - "erc6551Salt": 0, - "dssVestAddress": "0xc67A1EB2BD5794C070cC555fD4533CF8E28E7162", + "erc6551Registry": "0x000000006551c19487814612e58FE06813775758", + "erc6551Implementation": "0x509b531c8e979c85375370c0ba92ac44173c2d12", + "erc6551Salt": "0x0000000000000000000000000000000000000000000000000000000000000000", + "dssVestAddress": "0x370F850180FDDCdc521Ed11900a7a27D08B2d402", "dssVestDecimals": 18 } }, - "network": "5", + "network": "1", "addresses": [ - "0x4D7f3AEA074C6e8136C7e81ff8Af8BccdA3a7d89", - "0x4B977dC5bF15eC7FB9B2062CA15092B99d13b8F1", - "0xf78E7a442ea032a4D30FBA984c16a73Af5C915a0", - "0xAa01DeC5307CF17F20881A3286dcaA062578cea7", - "0xCD252d6AB26b7363E75d7451029C0f0729783AcE" + "0x5A8CA059a7e185ad01695136dbe5A721D4e053D6", + "0x1ba671ce4718d76D42609affbB567Bf1E71E0852", + "0x008B1FFe244bF31896C833bFf4Ad9009E7A0f4Eb", + "0x1b515D521dd0CBA174Bee666ED8f42449C8cA8bb" ], - "snapshot": 9855099 + "snapshot": 18779365 } ] diff --git a/src/strategies/mangrove-station-qv-scaled-to-mgv/index.ts b/src/strategies/mangrove-station-qv-scaled-to-mgv/index.ts index f78089700..059666c00 100644 --- a/src/strategies/mangrove-station-qv-scaled-to-mgv/index.ts +++ b/src/strategies/mangrove-station-qv-scaled-to-mgv/index.ts @@ -6,7 +6,7 @@ import { import { getAllVestings } from '../dss-vest-unpaid'; export const author = 'espendk'; -export const version = '1.0.0'; +export const version = '1.0.1'; export async function strategy( space, diff --git a/src/strategies/mangrove-station-qv-scaled-to-mgv/schema.json b/src/strategies/mangrove-station-qv-scaled-to-mgv/schema.json index 690760156..fa70a4561 100644 --- a/src/strategies/mangrove-station-qv-scaled-to-mgv/schema.json +++ b/src/strategies/mangrove-station-qv-scaled-to-mgv/schema.json @@ -59,10 +59,14 @@ "maxLength": 42 }, "erc6551Salt": { - "type": "number", + "type": "string", "title": "ERC6551 salt", - "examples": ["e.g. 0"], - "minimum": 0 + "examples": [ + "e.g. 0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "pattern": "^0x[a-fA-F0-9]{64}$", + "minLength": 66, + "maxLength": 66 }, "dssVestAddress": { "type": "string", diff --git a/src/strategies/station-constant-if-badge/examples.json b/src/strategies/station-constant-if-badge/examples.json index a56264370..6d069a333 100644 --- a/src/strategies/station-constant-if-badge/examples.json +++ b/src/strategies/station-constant-if-badge/examples.json @@ -4,23 +4,22 @@ "strategy": { "name": "station-constant-if-badge", "params": { - "membershipERC721": "0xd71c8619209cc95a81f8d9ba4fd704d9eff3ddd6", - "badgesERC1155": "0xd775e55e314164cce7f71f9f70fc905c907fc65e", + "membershipERC721": "0x33dbde2e093b7cf8446d9ac0de79220d42423501", + "badgesERC1155": "0xd1502a7659eaad60278ae3ef27edea849504f4da", "badgeId": 1, "constant": 1337, - "erc6551Registry": "0x02101dfB77FDE026414827Fdc604ddAF224F0921", - "erc6551Implementation": "0x2d25602551487c3f3354dd80d76d54383a243358", - "erc6551Salt": 0 + "erc6551Registry": "0x000000006551c19487814612e58FE06813775758", + "erc6551Implementation": "0x509b531c8e979c85375370c0ba92ac44173c2d12", + "erc6551Salt": "0x0000000000000000000000000000000000000000000000000000000000000000" } }, - "network": "5", + "network": "1", "addresses": [ - "0x4D7f3AEA074C6e8136C7e81ff8Af8BccdA3a7d89", - "0x4B977dC5bF15eC7FB9B2062CA15092B99d13b8F1", - "0xf78E7a442ea032a4D30FBA984c16a73Af5C915a0", - "0xAa01DeC5307CF17F20881A3286dcaA062578cea7", - "0xCD252d6AB26b7363E75d7451029C0f0729783AcE" + "0x5A8CA059a7e185ad01695136dbe5A721D4e053D6", + "0x1ba671ce4718d76D42609affbB567Bf1E71E0852", + "0x008B1FFe244bF31896C833bFf4Ad9009E7A0f4Eb", + "0x1b515D521dd0CBA174Bee666ED8f42449C8cA8bb" ], - "snapshot": 9852748 + "snapshot": 18779365 } ] diff --git a/src/strategies/station-constant-if-badge/index.ts b/src/strategies/station-constant-if-badge/index.ts index 0720abd67..9d7c64038 100644 --- a/src/strategies/station-constant-if-badge/index.ts +++ b/src/strategies/station-constant-if-badge/index.ts @@ -5,7 +5,7 @@ import { } from '../station-score-if-badge'; export const author = 'espendk'; -export const version = '1.0.0'; +export const version = '1.0.1'; export async function strategy( space, diff --git a/src/strategies/station-constant-if-badge/schema.json b/src/strategies/station-constant-if-badge/schema.json index 0b578d763..b160185df 100644 --- a/src/strategies/station-constant-if-badge/schema.json +++ b/src/strategies/station-constant-if-badge/schema.json @@ -50,10 +50,14 @@ "maxLength": 42 }, "erc6551Salt": { - "type": "number", + "type": "string", "title": "ERC6551 salt", - "examples": ["e.g. 0"], - "minimum": 0 + "examples": [ + "e.g. 0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "pattern": "^0x[a-fA-F0-9]{64}$", + "minLength": 66, + "maxLength": 66 } }, "required": [], diff --git a/src/strategies/station-score-if-badge/examples.json b/src/strategies/station-score-if-badge/examples.json index b90eef440..0bf2f5ee2 100644 --- a/src/strategies/station-score-if-badge/examples.json +++ b/src/strategies/station-score-if-badge/examples.json @@ -4,24 +4,23 @@ "strategy": { "name": "station-score-if-badge", "params": { - "membershipERC721": "0xd71c8619209cc95a81f8d9ba4fd704d9eff3ddd6", - "badgesERC1155": "0xd775e55e314164cce7f71f9f70fc905c907fc65e", + "membershipERC721": "0x33dbde2e093b7cf8446d9ac0de79220d42423501", + "badgesERC1155": "0xd1502a7659eaad60278ae3ef27edea849504f4da", "badgeId": 1, - "scoreERC20": "0x30D602cBfe96FC2C83fF31Bdf79d48De65f80733", + "scoreERC20": "0x5f120453dfd0c55f55370d1f718089ae0fcf6387", "scoreDecimals": 18, - "erc6551Registry": "0x02101dfB77FDE026414827Fdc604ddAF224F0921", - "erc6551Implementation": "0x2d25602551487c3f3354dd80d76d54383a243358", - "erc6551Salt": 0 + "erc6551Registry": "0x000000006551c19487814612e58FE06813775758", + "erc6551Implementation": "0x509b531c8e979c85375370c0ba92ac44173c2d12", + "erc6551Salt": "0x0000000000000000000000000000000000000000000000000000000000000000" } }, - "network": "5", + "network": "1", "addresses": [ - "0x4D7f3AEA074C6e8136C7e81ff8Af8BccdA3a7d89", - "0x4B977dC5bF15eC7FB9B2062CA15092B99d13b8F1", - "0xf78E7a442ea032a4D30FBA984c16a73Af5C915a0", - "0xAa01DeC5307CF17F20881A3286dcaA062578cea7", - "0xCD252d6AB26b7363E75d7451029C0f0729783AcE" + "0x5A8CA059a7e185ad01695136dbe5A721D4e053D6", + "0x1ba671ce4718d76D42609affbB567Bf1E71E0852", + "0x008B1FFe244bF31896C833bFf4Ad9009E7A0f4Eb", + "0x1b515D521dd0CBA174Bee666ED8f42449C8cA8bb" ], - "snapshot": 9852748 + "snapshot": 18779365 } ] diff --git a/src/strategies/station-score-if-badge/index.ts b/src/strategies/station-score-if-badge/index.ts index 9014a4d9c..78a5046dc 100644 --- a/src/strategies/station-score-if-badge/index.ts +++ b/src/strategies/station-score-if-badge/index.ts @@ -4,7 +4,7 @@ import { Contract } from '@ethersproject/contracts'; import { Multicaller } from '../../utils'; export const author = 'espendk'; -export const version = '1.0.0'; +export const version = '1.0.1'; // To avoid future memory issues, we limit the number of members supported by the strategy export const MAX_MEMBERS = 500; @@ -15,7 +15,7 @@ export const erc721_abi = [ ]; export const erc6551_registry_abi = [ - 'function account(address implementation, uint256 chainId, address tokenContract, uint256 tokenId, uint256 salt) external view returns (address)' + 'function account(address implementation, bytes32 salt, uint256 chainId, address tokenContract, uint256 tokenId) external view returns (address)' ]; export const erc1155_abi = [ @@ -51,7 +51,7 @@ export async function getAllMembers( membershipERC721: string, erc6551Registry: string, erc6551Implementation: string, - erc6551Salt: number + erc6551Salt: string ): Promise> { const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; @@ -86,10 +86,10 @@ export async function getAllMembers( membershipERC721Multicaller.call(id, membershipERC721, 'ownerOf', [id]); erc6551RegistryMulticaller.call(id, erc6551Registry, 'account', [ erc6551Implementation, + erc6551Salt, network, membershipERC721, - id, - erc6551Salt + id ]); } diff --git a/src/strategies/station-score-if-badge/schema.json b/src/strategies/station-score-if-badge/schema.json index 4eb2b4df1..c6ccb3598 100644 --- a/src/strategies/station-score-if-badge/schema.json +++ b/src/strategies/station-score-if-badge/schema.json @@ -59,10 +59,14 @@ "maxLength": 42 }, "erc6551Salt": { - "type": "number", + "type": "string", "title": "ERC6551 salt", - "examples": ["e.g. 0"], - "minimum": 0 + "examples": [ + "e.g. 0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "pattern": "^0x[a-fA-F0-9]{64}$", + "minLength": 66, + "maxLength": 66 } }, "required": [], From 13272739305fb8f6e44ed5d3a87816cf0db8ec7c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 19 Dec 2023 15:30:37 +0530 Subject: [PATCH 576/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.9.8 (#1376) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 451933fee..bd50c23e6 100755 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.9.7", + "@snapshot-labs/snapshot.js": "^0.9.8", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 5dd3124b3..91bc981c9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.9.7": - version "0.9.7" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.9.7.tgz#f384d6c085a64c808eaab077995a3e023526ded7" - integrity sha512-TFXNkJ33yY3+nPt2ZWDif/QcSmggfIyi/Cyo2N16xQ1ZNJvEwTjHuHPdX6chP4X0vqtsDn+RU6CtuHYibwWOUA== +"@snapshot-labs/snapshot.js@^0.9.8": + version "0.9.8" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.9.8.tgz#9e4264a1b4fd7ce3bc27022203fe6edf5a9643a9" + integrity sha512-Jg/dXs9BXCR6ETUUvAUAAetTy19KKLF1L15PChYZBXBNrymWqjMKeHaSbyPdvihrG77d9SWqEN6GiFbD8wDz1w== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 09e31e643bc81d8b34483a512d737b08e3b5e975 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 23 Dec 2023 00:36:46 +0530 Subject: [PATCH 577/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.9.9 (#1379) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index bd50c23e6..15453ce90 100755 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.9.8", + "@snapshot-labs/snapshot.js": "^0.9.9", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 91bc981c9..3b2f09d7d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.9.8": - version "0.9.8" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.9.8.tgz#9e4264a1b4fd7ce3bc27022203fe6edf5a9643a9" - integrity sha512-Jg/dXs9BXCR6ETUUvAUAAetTy19KKLF1L15PChYZBXBNrymWqjMKeHaSbyPdvihrG77d9SWqEN6GiFbD8wDz1w== +"@snapshot-labs/snapshot.js@^0.9.9": + version "0.9.9" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.9.9.tgz#c7c7f8209129a38e50621aa325833ddd373b23e1" + integrity sha512-9c9GVphUs/JwnNrQ39wvpjHhSZ3zqKUH5CSRXacwU1DSCmAg3/b21hauxavAUgK40oXCPkyZ5O1jrGKjbHeT8Q== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From b56b73524b333e6eacff01f0a56383d398311484 Mon Sep 17 00:00:00 2001 From: Coderdan Date: Sun, 24 Dec 2023 02:57:28 +0800 Subject: [PATCH 578/815] [aavegotchi-agip] Aavegotchi (#1378) * add strategies * chore: add wearables and update example * chore: cleanup * chore: cleanup --- .../aavegotchi-agip-17/examples.json | 8 ++++++-- src/strategies/aavegotchi-agip/examples.json | 4 ++-- src/strategies/aavegotchi-agip/index.ts | 20 ++++++++++++++++++- src/strategies/aavegotchi/examples.json | 8 ++++++-- 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/strategies/aavegotchi-agip-17/examples.json b/src/strategies/aavegotchi-agip-17/examples.json index 360eac9d2..a1f741ddb 100644 --- a/src/strategies/aavegotchi-agip-17/examples.json +++ b/src/strategies/aavegotchi-agip-17/examples.json @@ -8,7 +8,11 @@ } }, "network": "137", - "addresses": ["0x027Ffd3c119567e85998f4E6B9c3d83D5702660c"], - "snapshot": 22089223 + "addresses": [ + "0x027Ffd3c119567e85998f4E6B9c3d83D5702660c", + "0xC3c2e1Cf099Bc6e1fA94ce358562BCbD5cc59FE5", + "0x585E06CA576D0565a035301819FD2cfD7104c1E8" + ], + "snapshot": 50601487 } ] diff --git a/src/strategies/aavegotchi-agip/examples.json b/src/strategies/aavegotchi-agip/examples.json index 72a671a70..631a5cf86 100644 --- a/src/strategies/aavegotchi-agip/examples.json +++ b/src/strategies/aavegotchi-agip/examples.json @@ -10,10 +10,10 @@ }, "network": "137", "addresses": [ - "0x51195e21BDaE8722B29919db56d95Ef51FaecA6C", + "0x9730299b10A30bDbAF81815c99b4657c685314AB", "0xDd564df884Fd4e217c9ee6F65B4BA6e5641eAC63", "0xBfe09443556773958bae1699b786d8E9680B5571" ], - "snapshot": 39986904 + "snapshot": 51370819 } ] diff --git a/src/strategies/aavegotchi-agip/index.ts b/src/strategies/aavegotchi-agip/index.ts index d3c278216..83dc40d53 100644 --- a/src/strategies/aavegotchi-agip/index.ts +++ b/src/strategies/aavegotchi-agip/index.ts @@ -349,7 +349,25 @@ const prices: Prices = { '366': 10000, '367': 10000, '368': 10000, - '369': 10000 + '369': 10000, + '370': 5, + '371': 5, + '372': 5, + '373': 10, + '374': 100, + '375': 5, + '376': 100, + '377': 10, + '378': 100, + '379': 100, + '380': 300, + '381': 300, + '382': 300, + '383': 300, + '384': 2000, + '385': 10000, + '386': 10000, + '387': 10000 }; const tokenAbi = [ diff --git a/src/strategies/aavegotchi/examples.json b/src/strategies/aavegotchi/examples.json index 4e9e847ab..adc31be7f 100644 --- a/src/strategies/aavegotchi/examples.json +++ b/src/strategies/aavegotchi/examples.json @@ -15,7 +15,11 @@ } }, "network": "137", - "addresses": ["0x027Ffd3c119567e85998f4E6B9c3d83D5702660c"], - "snapshot": 12089223 + "addresses": [ + "0x027Ffd3c119567e85998f4E6B9c3d83D5702660c", + "0xC3c2e1Cf099Bc6e1fA94ce358562BCbD5cc59FE5", + "0x585E06CA576D0565a035301819FD2cfD7104c1E8" + ], + "snapshot": 50601487 } ] From ee38f8285cd3549294a1854cfaec8a9ad4438e25 Mon Sep 17 00:00:00 2001 From: Marsot Pierre Date: Thu, 28 Dec 2023 20:23:28 +0100 Subject: [PATCH 579/815] Vsdtoken [sd-vote-boost-twavp-vsdtoken] (#1380) * init * use sampleStep * voting power naming * strat init * compute vp * min block + vp formula --- src/strategies/index.ts | 2 + .../sd-vote-boost-twavp-vsdtoken/README.md | 28 +++ .../examples.json | 28 +++ .../sd-vote-boost-twavp-vsdtoken/index.ts | 188 ++++++++++++++++++ 4 files changed, 246 insertions(+) create mode 100644 src/strategies/sd-vote-boost-twavp-vsdtoken/README.md create mode 100644 src/strategies/sd-vote-boost-twavp-vsdtoken/examples.json create mode 100644 src/strategies/sd-vote-boost-twavp-vsdtoken/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index d9b454d1c..a4b38341b 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -362,6 +362,7 @@ import * as gelatoStaking from './gelato-staking'; import * as erc4626AssetsOf from './erc4626-assets-of'; import * as sdVoteBoostTWAVPV2 from './sd-vote-boost-twavp-v2'; import * as sdVoteBoostTWAVPV3 from './sd-vote-boost-twavp-v3'; +import * as sdVoteBoostTWAVPVsdToken from './sd-vote-boost-twavp-vsdtoken'; import * as friendTech from './friend-tech'; import * as moonbase from './moonbase'; import * as dssVestUnpaid from './dss-vest-unpaid'; @@ -776,6 +777,7 @@ const strategies = { 'friend-tech': friendTech, 'sd-vote-boost-twavp-v2': sdVoteBoostTWAVPV2, 'sd-vote-boost-twavp-v3': sdVoteBoostTWAVPV3, + 'sd-vote-boost-twavp-vsdtoken': sdVoteBoostTWAVPVsdToken, moonbase: moonbase, 'dss-vest-unpaid': dssVestUnpaid, 'dss-vest-balance-and-unpaid': dssVestBalanceAndUnpaid, diff --git a/src/strategies/sd-vote-boost-twavp-vsdtoken/README.md b/src/strategies/sd-vote-boost-twavp-vsdtoken/README.md new file mode 100644 index 000000000..71da0f5b0 --- /dev/null +++ b/src/strategies/sd-vote-boost-twavp-vsdtoken/README.md @@ -0,0 +1,28 @@ +# sd-vote-boost-twavp-vsdtoken + +This strategy is used by Stake DAO to vote with sdToken using Time Weighted Averaged Voting Power (TWAVP) system and adapted for veSDT boost delegation with possibility to whiteliste address to by pass TWAVP. + +``` +VotingPower(user) = veToken.balanceOf(liquidLocker) * (average.sdTokenGauge.working_balances(user) / sdTokenGauge.working_supply) +``` + +>_sampleSize: in days_ +>_sampleStep: the number of block for `average` calculation (max 5)_ + +Here is an example of parameters: + +```json +{ + "veToken": "0x5f3b5DfEb7B28CDbD7FAba78963EE202a494e2A2", + "liquidLocker": "0x52f541764E6e90eeBc5c21Ff570De0e2D63766B6", + "sdTokenGauge": "0x7f50786A0b15723D741727882ee99a0BF34e3466", + "sdToken": "0xD1b5651E55D4CeeD36251c61c50C889B36F6abB5", + "pools": ["0xca0253a98d16e9c1e3614cafda19318ee69772d0"], + "symbol": "sdToken", + "decimals": 18, + "sampleSize": 10, + "sampleStep": 5, + "botAddress": "", + "whiteListedAddress": ["0x1c0D72a330F2768dAF718DEf8A19BAb019EEAd09"] +} +``` \ No newline at end of file diff --git a/src/strategies/sd-vote-boost-twavp-vsdtoken/examples.json b/src/strategies/sd-vote-boost-twavp-vsdtoken/examples.json new file mode 100644 index 000000000..54cda66e5 --- /dev/null +++ b/src/strategies/sd-vote-boost-twavp-vsdtoken/examples.json @@ -0,0 +1,28 @@ +[ + { + "name": "Stake DAO vote boost using TWAVP for vsdTkn holders", + "strategy": { + "name": "sd-vote-boost-twavp-vsdtoken", + "params": { + "vsdToken": "0xE079ac07463ff375Ce48E8A9D76211C10696F3B8", + "sdTokenGauge": "0x7f50786A0b15723D741727882ee99a0BF34e3466", + "booster": "0x38d10708Ce535361F178f55E68DF7E85aCc66270", + "locker": "0x52f541764E6e90eeBc5c21Ff570De0e2D63766B6", + "veAddress": "0x5f3b5DfEb7B28CDbD7FAba78963EE202a494e2A2", + "symbol": "sdToken", + "decimals": 18, + "sampleSize": 10, + "sampleStep": 5, + "whiteListedAddress": ["0x1c0D72a330F2768dAF718DEf8A19BAb019EEAd09"] + } + }, + "network": "1", + "addresses": [ + "0xc59910E5E2dd8225623B663491aa754F7013F067", + "0xDdB50FfDbA4D89354E1088e4EA402de895562173", + "0xE1F7eaD40d33eeF30dCf15eB5efC45409001aAB8", + "0x1c0D72a330F2768dAF718DEf8A19BAb019EEAd09" + ], + "snapshot": 18870156 + } +] diff --git a/src/strategies/sd-vote-boost-twavp-vsdtoken/index.ts b/src/strategies/sd-vote-boost-twavp-vsdtoken/index.ts new file mode 100644 index 000000000..ff1acd4e2 --- /dev/null +++ b/src/strategies/sd-vote-boost-twavp-vsdtoken/index.ts @@ -0,0 +1,188 @@ +import { multicall } from '../../utils'; +import { BigNumber } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; + +export const author = 'pierremarsotlyon1'; +export const version = '0.0.1'; + +// Used ABI +const abi = [ + 'function balanceOf(address account) external view returns (uint256)', + 'function working_supply() external view returns (uint256)', + 'function totalSupply() external view returns (uint256)', + 'function working_balances(address account) external view returns (uint256)' +]; + +const MIN_BLOCK = 18835548; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + // Maximum of 5 multicall! + if (options.sampleStep > 5) { + throw new Error('maximum of 5 call'); + } + + // Maximum of 20 whitelisted address + if (options.whiteListedAddress.length > 20) { + throw new Error('maximum of 20 whitelisted address'); + } + + // --- Create block number list for twavp + // Obtain last block number + // Create block tag + let blockTag = 0; + if (typeof snapshot === 'number') { + blockTag = snapshot; + } else { + blockTag = await provider.getBlockNumber(); + } + + // Create block list + const blockList = getPreviousBlocks( + blockTag, + options.sampleStep, + options.sampleSize + ); + + const balanceOfQueries: any[] = []; + for(const address of addresses) { + balanceOfQueries.push([ + options.vsdToken, + 'balanceOf', + [address] + ]); + balanceOfQueries.push([ + options.vsdToken, + 'totalSupply', + [] + ]); + } + + const response: any[] = []; + for (let i = 0; i < options.sampleStep; i++) { + // Use good block number + blockTag = blockList[i]; + + const loopCalls: any[] = []; + + // Add mutlicall response to array + if (i === options.sampleStep - 1) { + // End + loopCalls.push([options.veAddress, 'balanceOf', [options.locker]]); + loopCalls.push([options.sdTokenGauge, 'working_supply']); + loopCalls.push([options.sdTokenGauge, 'working_balances', [options.booster]]); + loopCalls.push(...balanceOfQueries); + } else { + loopCalls.push(...balanceOfQueries); + } + + response.push( + await multicall(network, provider, abi, loopCalls, { blockTag }) + ); + } + + const lockerVeBalance = response[response.length - 1].shift()[0]; // Last response, latest block + const workingSupply = response[response.length - 1].shift()[0]; // Last response, latest block + const workingBalances = response[response.length - 1].shift()[0]; // Last response, latest block + + const totalVP = parseFloat(formatUnits(workingBalances, 18)) + / parseFloat(formatUnits(workingSupply, 18)) + * parseFloat(formatUnits(lockerVeBalance, 18)); + + return Object.fromEntries( + Array(addresses.length) + .fill('x') + .map((_, i) => { + // Init array of working balances for user + const userWorkingBalances: number[] = []; + + for (let j = 0; j < options.sampleStep; j++) { + const balanceOf = BigNumber.from(response[j].shift()[0]); + const totalSupply = BigNumber.from(response[j].shift()[0]); + + // Add working balance to array. + if(totalSupply.eq(0)) { + userWorkingBalances.push(0); + } else { + userWorkingBalances.push(balanceOf.div(totalSupply).toNumber()); + } + } + + // Get average working balance. + const averageWorkingBalance = average( + userWorkingBalances, + addresses[i], + options.whiteListedAddress + ); + + // Calculate voting power. + const votingPower = + totalVP != 0 + ? averageWorkingBalance * totalVP + : 0; + + // Return address and voting power + return [addresses[i], Number(votingPower)]; + }) + ); +} + + +function average( + numbers: number[], + address: string, + whiteListedAddress: string[] +): number { + // If no numbers, return 0 to avoid division by 0. + if (numbers.length === 0) return 0; + + // If address is whitelisted, return most recent working balance. i.e. no twavp applied. + if (whiteListedAddress.includes(address)) return numbers[numbers.length - 1]; + + // Init sum + let sum = 0; + // Loop through all elements and add them to sum + for (let i = 0; i < numbers.length; i++) { + sum += numbers[i]; + } + + // Return sum divided by array length to get mean + return sum / numbers.length; +} + + +function getPreviousBlocks( + currentBlockNumber: number, + numberOfBlocks: number, + daysInterval: number +): number[] { + // Estimate number of blocks per day + const blocksPerDay = 86400 / 12; + // Calculate total blocks interval + const totalBlocksInterval = blocksPerDay * daysInterval; + // Calculate block interval + const blockInterval = totalBlocksInterval / (numberOfBlocks - 1); + + // Init array of block numbers + const blockNumbers: number[] = []; + + for (let i = 0; i < numberOfBlocks; i++) { + // Calculate block number + let blockNumber = + currentBlockNumber - totalBlocksInterval + blockInterval * i; + if (blockNumber < MIN_BLOCK) { + blockNumber = MIN_BLOCK; + } + // Add block number to array + blockNumbers.push(Math.round(blockNumber)); + } + + // Return array of block numbers + return blockNumbers; +} \ No newline at end of file From cbe0f377c5dff412188c9a3f02ed9420afcf6911 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 31 Dec 2023 22:02:06 +0530 Subject: [PATCH 580/815] Automated lint (#1381) Co-authored-by: ChaituVR --- .../sd-vote-boost-twavp-vsdtoken/index.ts | 40 ++++++++----------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/src/strategies/sd-vote-boost-twavp-vsdtoken/index.ts b/src/strategies/sd-vote-boost-twavp-vsdtoken/index.ts index ff1acd4e2..0da66ee1d 100644 --- a/src/strategies/sd-vote-boost-twavp-vsdtoken/index.ts +++ b/src/strategies/sd-vote-boost-twavp-vsdtoken/index.ts @@ -51,19 +51,11 @@ export async function strategy( ); const balanceOfQueries: any[] = []; - for(const address of addresses) { - balanceOfQueries.push([ - options.vsdToken, - 'balanceOf', - [address] - ]); - balanceOfQueries.push([ - options.vsdToken, - 'totalSupply', - [] - ]); + for (const address of addresses) { + balanceOfQueries.push([options.vsdToken, 'balanceOf', [address]]); + balanceOfQueries.push([options.vsdToken, 'totalSupply', []]); } - + const response: any[] = []; for (let i = 0; i < options.sampleStep; i++) { // Use good block number @@ -76,7 +68,11 @@ export async function strategy( // End loopCalls.push([options.veAddress, 'balanceOf', [options.locker]]); loopCalls.push([options.sdTokenGauge, 'working_supply']); - loopCalls.push([options.sdTokenGauge, 'working_balances', [options.booster]]); + loopCalls.push([ + options.sdTokenGauge, + 'working_balances', + [options.booster] + ]); loopCalls.push(...balanceOfQueries); } else { loopCalls.push(...balanceOfQueries); @@ -91,9 +87,10 @@ export async function strategy( const workingSupply = response[response.length - 1].shift()[0]; // Last response, latest block const workingBalances = response[response.length - 1].shift()[0]; // Last response, latest block - const totalVP = parseFloat(formatUnits(workingBalances, 18)) - / parseFloat(formatUnits(workingSupply, 18)) - * parseFloat(formatUnits(lockerVeBalance, 18)); + const totalVP = + (parseFloat(formatUnits(workingBalances, 18)) / + parseFloat(formatUnits(workingSupply, 18))) * + parseFloat(formatUnits(lockerVeBalance, 18)); return Object.fromEntries( Array(addresses.length) @@ -107,7 +104,7 @@ export async function strategy( const totalSupply = BigNumber.from(response[j].shift()[0]); // Add working balance to array. - if(totalSupply.eq(0)) { + if (totalSupply.eq(0)) { userWorkingBalances.push(0); } else { userWorkingBalances.push(balanceOf.div(totalSupply).toNumber()); @@ -122,10 +119,7 @@ export async function strategy( ); // Calculate voting power. - const votingPower = - totalVP != 0 - ? averageWorkingBalance * totalVP - : 0; + const votingPower = totalVP != 0 ? averageWorkingBalance * totalVP : 0; // Return address and voting power return [addresses[i], Number(votingPower)]; @@ -133,7 +127,6 @@ export async function strategy( ); } - function average( numbers: number[], address: string, @@ -156,7 +149,6 @@ function average( return sum / numbers.length; } - function getPreviousBlocks( currentBlockNumber: number, numberOfBlocks: number, @@ -185,4 +177,4 @@ function getPreviousBlocks( // Return array of block numbers return blockNumbers; -} \ No newline at end of file +} From 334dceda1db1de3bfde83f69c8f6ffc19eb2ffd7 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Mon, 8 Jan 2024 12:28:43 +0530 Subject: [PATCH 581/815] Modify contract-call readme (#1383) --- src/strategies/contract-call/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/strategies/contract-call/README.md b/src/strategies/contract-call/README.md index 40becdc7b..011d62155 100644 --- a/src/strategies/contract-call/README.md +++ b/src/strategies/contract-call/README.md @@ -79,3 +79,13 @@ You can call methods with multiple inputs in any contract: ] } ``` + +### Params + +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| address | `string` | | Contract address | +| decimals | `number` | 18 | Decimals of the output | +| symbol | `string` | optional | Symbol of the output | +| methodABI | `object` | | ABI of the method to call | +| output | `string` | optional | Output type of the method to call | From cb97beaf4a2bdd879ef85f9b842fc88b7cb6a536 Mon Sep 17 00:00:00 2001 From: Marsot Pierre Date: Sat, 13 Jan 2024 10:17:38 +0100 Subject: [PATCH 582/815] add TWAVP balanceOf for sdCake holders (#1389) --- src/strategies/index.ts | 2 + .../sd-vote-boost-twavp-balanceof/README.md | 21 +++ .../examples.json | 24 +++ .../sd-vote-boost-twavp-balanceof/index.ts | 146 ++++++++++++++++++ 4 files changed, 193 insertions(+) create mode 100644 src/strategies/sd-vote-boost-twavp-balanceof/README.md create mode 100644 src/strategies/sd-vote-boost-twavp-balanceof/examples.json create mode 100644 src/strategies/sd-vote-boost-twavp-balanceof/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index a4b38341b..57e084813 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -363,6 +363,7 @@ import * as erc4626AssetsOf from './erc4626-assets-of'; import * as sdVoteBoostTWAVPV2 from './sd-vote-boost-twavp-v2'; import * as sdVoteBoostTWAVPV3 from './sd-vote-boost-twavp-v3'; import * as sdVoteBoostTWAVPVsdToken from './sd-vote-boost-twavp-vsdtoken'; +import * as sdVoteBoostTWAVPBalanceof from './sd-vote-boost-twavp-balanceof'; import * as friendTech from './friend-tech'; import * as moonbase from './moonbase'; import * as dssVestUnpaid from './dss-vest-unpaid'; @@ -778,6 +779,7 @@ const strategies = { 'sd-vote-boost-twavp-v2': sdVoteBoostTWAVPV2, 'sd-vote-boost-twavp-v3': sdVoteBoostTWAVPV3, 'sd-vote-boost-twavp-vsdtoken': sdVoteBoostTWAVPVsdToken, + 'sd-vote-boost-twavp-balanceof': sdVoteBoostTWAVPBalanceof, moonbase: moonbase, 'dss-vest-unpaid': dssVestUnpaid, 'dss-vest-balance-and-unpaid': dssVestBalanceAndUnpaid, diff --git a/src/strategies/sd-vote-boost-twavp-balanceof/README.md b/src/strategies/sd-vote-boost-twavp-balanceof/README.md new file mode 100644 index 000000000..d3f1f089f --- /dev/null +++ b/src/strategies/sd-vote-boost-twavp-balanceof/README.md @@ -0,0 +1,21 @@ +# sd-vote-boost-twavp-balanceof + +This strategy is used by Stake DAO to vote with sdToken using Time Weighted Averaged Voting Power (TWAVP) system based on a balanceOf with possibility to whitelist addresses to by pass TWAVP. + +>_sampleSize: in days_ +>_sampleStep: the number of block for `average` calculation (max 5)_ +>_blockPerSec: the number of block per seconds of the destination chain + +Here is an example of parameters: + +```json +{ + "sdTokenGauge": "0xE2496134149e6CD3f3A577C2B08A6f54fC23e6e4", + "symbol": "sdToken-gauge", + "decimals": 18, + "sampleSize": 10, + "sampleStep": 5, + "blockPerSec": 3, + "whiteListedAddress": [] +} +``` \ No newline at end of file diff --git a/src/strategies/sd-vote-boost-twavp-balanceof/examples.json b/src/strategies/sd-vote-boost-twavp-balanceof/examples.json new file mode 100644 index 000000000..acfda0bac --- /dev/null +++ b/src/strategies/sd-vote-boost-twavp-balanceof/examples.json @@ -0,0 +1,24 @@ +[ + { + "name": "Stake DAO vote boost using TWAVP balanceOf", + "strategy": { + "name": "sd-vote-boost-twavp-balanceof", + "params": { + "sdTokenGauge": "0xE2496134149e6CD3f3A577C2B08A6f54fC23e6e4", + "symbol": "sdToken-gauge", + "decimals": 18, + "sampleSize": 10, + "sampleStep": 5, + "blockPerSec": 3, + "whiteListedAddress": [] + } + }, + "network": "56", + "addresses": [ + "0xb734Ec7A75d65406fde5bcf9156cAB673ba1e1C5", + "0xee439Ee079AC05D9d33a6926A16e0c820fB2713A", + "0xc1133c83D409724727fF6699F14F040746e5AD01" + ], + "snapshot": 35181258 + } +] diff --git a/src/strategies/sd-vote-boost-twavp-balanceof/index.ts b/src/strategies/sd-vote-boost-twavp-balanceof/index.ts new file mode 100644 index 000000000..66f90344a --- /dev/null +++ b/src/strategies/sd-vote-boost-twavp-balanceof/index.ts @@ -0,0 +1,146 @@ +import { multicall } from '../../utils'; +import { BigNumber } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; + +export const author = 'pierremarsotlyon1'; +export const version = '0.0.1'; + +// Used ABI +const abi = [ + 'function balanceOf(address account) external view returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + // Maximum of 5 multicall! + if (options.sampleStep > 5) { + throw new Error('maximum of 5 call'); + } + + // Maximum of 20 whitelisted address + if (options.whiteListedAddress.length > 20) { + throw new Error('maximum of 20 whitelisted address'); + } + + // --- Create block number list for twavp + // Obtain last block number + // Create block tag + let blockTag = 0; + if (typeof snapshot === 'number') { + blockTag = snapshot; + } else { + blockTag = await provider.getBlockNumber(); + } + + // Create block list + const blockList = getPreviousBlocks( + blockTag, + options.sampleStep, + options.sampleSize, + options.blockPerSec + ); + + // Query working balance of users + const balanceOfQueries = addresses.map((address: any) => [ + options.sdTokenGauge, + 'balanceOf', + [address] + ]); + + // Execute multicall `sampleStep` times + const response: any[] = []; + for (let i = 0; i < options.sampleStep; i++) { + // Use good block number + blockTag = blockList[i]; + + response.push( + await multicall(network, provider, abi, balanceOfQueries, { blockTag }) + ); + } + + return Object.fromEntries( + Array(addresses.length) + .fill('x') + .map((_, i) => { + // Init array of working balances for user + const userBalances: BigNumber[] = []; + + for (let j = 0; j < options.sampleStep; j++) { + const balance = response[j].shift()[0]; + userBalances.push(balance); + } + + // Get average balance + const averageBalanceOf = parseFloat( + formatUnits( + average( + userBalances, + addresses[i], + options.whiteListedAddress + ), + options.decimals + ) + ); + + // Return address and voting power + return [addresses[i], Number(averageBalanceOf)]; + }) + ); +} + +function getPreviousBlocks( + currentBlockNumber: number, + numberOfBlocks: number, + daysInterval: number, + blockPerSec: number, +): number[] { + + const blocksPerDay = 86400 / blockPerSec; + + // Calculate total blocks interval + const totalBlocksInterval = blocksPerDay * daysInterval; + // Calculate block interval + const blockInterval = totalBlocksInterval / (numberOfBlocks - 1); + + // Init array of block numbers + const blockNumbers: number[] = []; + + for (let i = 0; i < numberOfBlocks; i++) { + // Calculate block number + const blockNumber = + currentBlockNumber - totalBlocksInterval + blockInterval * i; + // Add block number to array + blockNumbers.push(Math.round(blockNumber)); + } + + // Return array of block numbers + return blockNumbers; +} + +function average( + numbers: BigNumber[], + address: string, + whiteListedAddress: string[] +): BigNumber { + // If no numbers, return 0 to avoid division by 0. + if (numbers.length === 0) return BigNumber.from(0); + + // If address is whitelisted, return most recent working balance. i.e. no twavp applied. + if (whiteListedAddress.includes(address)) return numbers[numbers.length - 1]; + + // Init sum + let sum = BigNumber.from(0); + // Loop through all elements and add them to sum + for (let i = 0; i < numbers.length; i++) { + sum = sum.add(numbers[i]); + } + + // Return sum divided by array length to get mean + return sum.div(numbers.length); +} From 7e19db875bfca72eb2eae468e202812ea972dff7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 15 Jan 2024 10:51:52 +0530 Subject: [PATCH 583/815] Automated lint (#1390) Co-authored-by: ChaituVR --- src/strategies/sd-vote-boost-twavp-balanceof/index.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/strategies/sd-vote-boost-twavp-balanceof/index.ts b/src/strategies/sd-vote-boost-twavp-balanceof/index.ts index 66f90344a..f1b822a40 100644 --- a/src/strategies/sd-vote-boost-twavp-balanceof/index.ts +++ b/src/strategies/sd-vote-boost-twavp-balanceof/index.ts @@ -79,11 +79,7 @@ export async function strategy( // Get average balance const averageBalanceOf = parseFloat( formatUnits( - average( - userBalances, - addresses[i], - options.whiteListedAddress - ), + average(userBalances, addresses[i], options.whiteListedAddress), options.decimals ) ); @@ -98,9 +94,8 @@ function getPreviousBlocks( currentBlockNumber: number, numberOfBlocks: number, daysInterval: number, - blockPerSec: number, + blockPerSec: number ): number[] { - const blocksPerDay = 86400 / blockPerSec; // Calculate total blocks interval From dd89cb94dfa4eb4bf5ea52997c21e9f19b1101de Mon Sep 17 00:00:00 2001 From: 0xdapper <94534135+0xdapper@users.noreply.github.com> Date: Tue, 16 Jan 2024 12:02:50 +0530 Subject: [PATCH 584/815] feat: add vendor-v2-borrower-collateral-balance-of (#1391) --- src/strategies/index.ts | 3 + .../README.md | 13 +++ .../examples.json | 21 +++++ .../index.ts | 89 +++++++++++++++++++ .../schema.json | 42 +++++++++ 5 files changed, 168 insertions(+) create mode 100644 src/strategies/vendor-v2-borrower-collateral-balance-of/README.md create mode 100644 src/strategies/vendor-v2-borrower-collateral-balance-of/examples.json create mode 100644 src/strategies/vendor-v2-borrower-collateral-balance-of/index.ts create mode 100644 src/strategies/vendor-v2-borrower-collateral-balance-of/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 57e084813..0c5e62541 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -406,6 +406,7 @@ import * as synthetixQuadratic_1 from './synthetix-quadratic_1'; import * as synthetix_1 from './synthetix_1'; import * as totalAxionShares from './total-axion-shares'; import * as unipoolSameToken from './unipool-same-token'; +import * as vendorV2BorrowerCollateralBalanceOf from './vendor-v2-borrower-collateral-balance-of'; import * as voltVotingPower from './volt-voting-power'; import * as xdaiStakersAndHolders from './xdai-stakers-and-holders'; @@ -821,6 +822,8 @@ const strategies = { synthetix_1, 'total-axion-shares': totalAxionShares, 'unipool-same-token': unipoolSameToken, + 'vendor-v2-borrower-collateral-balance-of': + vendorV2BorrowerCollateralBalanceOf, 'volt-voting-power': voltVotingPower, 'xdai-stakers-and-holders': xdaiStakersAndHolders }; diff --git a/src/strategies/vendor-v2-borrower-collateral-balance-of/README.md b/src/strategies/vendor-v2-borrower-collateral-balance-of/README.md new file mode 100644 index 000000000..db56218c8 --- /dev/null +++ b/src/strategies/vendor-v2-borrower-collateral-balance-of/README.md @@ -0,0 +1,13 @@ +# vendor-v2-borrower-collateral-balance-of + +This returns the voting power of a borrower locked in a vendor lending pool. + +Here is an example of parameters: + +```json +{ + "address": "0xA4B49b1A717E9e002104E2B4517A8B7086DF479b", + "collateralDecimals": 9, + "weight": 5 +} +``` diff --git a/src/strategies/vendor-v2-borrower-collateral-balance-of/examples.json b/src/strategies/vendor-v2-borrower-collateral-balance-of/examples.json new file mode 100644 index 000000000..23d38f869 --- /dev/null +++ b/src/strategies/vendor-v2-borrower-collateral-balance-of/examples.json @@ -0,0 +1,21 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "vendor-v2-borrower-collateral-balance-of", + "params": { + "address": "0xA4B49b1A717E9e002104E2B4517A8B7086DF479b", + "collateralDecimals": 9, + "weight": 5 + } + }, + "network": "42161", + "addresses": [ + "0xeFAD4c712CBa7F7a136C6B3C6f861fb787a348a0", + "0xc12DE812ae612B6d514b52d529F97f6Acb524c8E", + "0x18252F28234C010Cf3353A82f3cBe71DB1B74773", + "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1" + ], + "snapshot": 170740021 + } +] diff --git a/src/strategies/vendor-v2-borrower-collateral-balance-of/index.ts b/src/strategies/vendor-v2-borrower-collateral-balance-of/index.ts new file mode 100644 index 000000000..5203367ef --- /dev/null +++ b/src/strategies/vendor-v2-borrower-collateral-balance-of/index.ts @@ -0,0 +1,89 @@ +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { AbiCoder } from '@ethersproject/abi'; +import { Multicaller } from '../../utils'; +import { BlockTag, StaticJsonRpcProvider } from '@ethersproject/providers'; + +export const author = '0xdapper'; +export const version = '0.1.0'; + +const abi = [ + 'function debts(address borrower) external view returns (uint256, uint256)', + // (poolType, owner, expiry, colToken, protocolFee, lendToken, ltv, pauseTime, lendRatio, feeRatesAndType) + 'function getPoolSettings() external view returns (uint8, address, uint48, address, uint48, address, uint48, uint48, uint256, address[], bytes32)' +]; + +const decodePoolSettings = (poolSettings: string) => { + const abiCoder = new AbiCoder(); + const [ + [ + poolType, + owner, + expiry, + colToken, + protocolFee, + lendToken, + ltv, + pauseTime, + lendRatio, + allowList, + feeRatesAndType + ] + ] = abiCoder.decode( + [ + '(uint8, address, uint48, address, uint48, address, uint48, uint48, uint256, address[], bytes32)' + ], + poolSettings + ); + return { + poolType, + owner, + expiry, + colToken, + protocolFee, + lendToken, + ltv, + pauseTime, + lendRatio, + feeRatesAndType, + allowList + }; +}; + +export async function strategy( + space, + network, + provider: StaticJsonRpcProvider, + addresses, + options, + snapshot +): Promise> { + const blockTag: BlockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const blockTime = (await provider.getBlock(blockTag)).timestamp; + const poolSettings = decodePoolSettings( + await provider.call( + { + to: options.address, + data: '0xe4a0ce2f' + }, + blockTag + ) + ); + const hasExpired = poolSettings.expiry < blockTime; + + const multi = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => + multi.call(address, options.address, 'debts', [address]) + ); + const result: Record = + await multi.execute(); + const multiplier = hasExpired ? 0 : options.weight || 1; + + return Object.fromEntries( + Object.entries(result).map(([address, [_debt, collAmount]]) => [ + address, + parseFloat(formatUnits(collAmount, options.collateralDecimals)) * + multiplier + ]) + ); +} diff --git a/src/strategies/vendor-v2-borrower-collateral-balance-of/schema.json b/src/strategies/vendor-v2-borrower-collateral-balance-of/schema.json new file mode 100644 index 000000000..c04bea0dd --- /dev/null +++ b/src/strategies/vendor-v2-borrower-collateral-balance-of/schema.json @@ -0,0 +1,42 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "address": { + "type": "string", + "title": "Contract address", + "examples": [ + "e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984" + ], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "collateralDecimals": { + "type": "number", + "examples": [ + 18 + ], + "title": "Decimals" + }, + "weight": { + "type": "number", + "title": "Weight", + "examples": [ + 0.5, + 2 + ] + } + }, + "required": [ + "address", + "collateralDecimals" + ], + "additionalProperties": false + } + } +} From 457d37919d459023f6b3c6c0a91dd5449058719a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 23 Jan 2024 10:04:26 +0530 Subject: [PATCH 585/815] Automated lint (#1393) Co-authored-by: ChaituVR --- .../schema.json | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/src/strategies/vendor-v2-borrower-collateral-balance-of/schema.json b/src/strategies/vendor-v2-borrower-collateral-balance-of/schema.json index c04bea0dd..3b978f04b 100644 --- a/src/strategies/vendor-v2-borrower-collateral-balance-of/schema.json +++ b/src/strategies/vendor-v2-borrower-collateral-balance-of/schema.json @@ -9,33 +9,23 @@ "address": { "type": "string", "title": "Contract address", - "examples": [ - "e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984" - ], + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], "pattern": "^0x[a-fA-F0-9]{40}$", "minLength": 42, "maxLength": 42 }, "collateralDecimals": { "type": "number", - "examples": [ - 18 - ], + "examples": [18], "title": "Decimals" }, "weight": { "type": "number", "title": "Weight", - "examples": [ - 0.5, - 2 - ] + "examples": [0.5, 2] } }, - "required": [ - "address", - "collateralDecimals" - ], + "required": ["address", "collateralDecimals"], "additionalProperties": false } } From 2d90343f258ac4c74e19126b9a363684a515d761 Mon Sep 17 00:00:00 2001 From: Benjamin Hughes <32072172+bghughes@users.noreply.github.com> Date: Tue, 23 Jan 2024 05:40:26 +0100 Subject: [PATCH 586/815] fix(): arrow-vesting drives only on unclaimed; update examples with relevant blocknumber (#1388) Co-authored-by: Chaitanya --- src/strategies/arrow-vesting/examples.json | 5 +++-- src/strategies/arrow-vesting/index.ts | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/strategies/arrow-vesting/examples.json b/src/strategies/arrow-vesting/examples.json index c862e4d7b..f3cfaa5e9 100644 --- a/src/strategies/arrow-vesting/examples.json +++ b/src/strategies/arrow-vesting/examples.json @@ -16,8 +16,9 @@ "0xB66f08DBd7A59B32e98033b9A1da08B5793DAb79", "0x5b8eD2A2CfFCD474B2E688fdeA21CB5c4350E575", "0x03b5Dc2CE78a7bEe9F66DD619b291595a2E166BB", - "0x06A61f56de8c6a2735D1Dea68340D201ddEd7348" + "0x06A61f56de8c6a2735D1Dea68340D201ddEd7348", + "0x252C855Cc3aB5f48229393Bc4DA129542a08C808" ], - "snapshot": 18879362 + "snapshot": 112192500 } ] diff --git a/src/strategies/arrow-vesting/index.ts b/src/strategies/arrow-vesting/index.ts index a8569d213..31bad26b8 100644 --- a/src/strategies/arrow-vesting/index.ts +++ b/src/strategies/arrow-vesting/index.ts @@ -14,7 +14,10 @@ const vestingContractAbi = [ 'function recipient() public view returns (address)', 'function total_locked() public view returns (uint256)', 'function start_time() public view returns (uint256)', - 'function end_time() public view returns (uint256)' + 'function unclaimed() public view returns (uint256)' + // don't need to check initialized? + // don't need to check admin? + // don't need to check future_admin? ]; export async function strategy( @@ -82,9 +85,9 @@ export async function strategy( [] ); vestingContractMulti.call( - `${vestingContractAddress}.end_time`, + `${vestingContractAddress}.unclaimed`, vestingContractAddress, - 'end_time', + 'unclaimed', [] ); }); @@ -106,15 +109,12 @@ export async function strategy( const start = params['start_time']; if (recipient in addressBalances && time > start) { - const locked = parseFloat( - formatUnits(params['total_locked'], options.decimals) + const unclaimedTokens = parseFloat( + formatUnits(params['unclaimed'], options.decimals) ); - const end = params['end_time']; - addressBalances[recipient] += Math.min( - (locked * (time - start)) / (end - start), - locked - ); + // Vested arrow that can be claimed is all that is counted in this strategy + addressBalances[recipient] += unclaimedTokens; } }); From 8f697e17c302f931e0e0c0206de346940220acb7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 23 Jan 2024 10:13:11 +0530 Subject: [PATCH 587/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.10.1 (#1384) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 15453ce90..9a96a9dc7 100755 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.9.9", + "@snapshot-labs/snapshot.js": "^0.10.1", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 3b2f09d7d..f43157be3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1363,10 +1363,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.9.9": - version "0.9.9" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.9.9.tgz#c7c7f8209129a38e50621aa325833ddd373b23e1" - integrity sha512-9c9GVphUs/JwnNrQ39wvpjHhSZ3zqKUH5CSRXacwU1DSCmAg3/b21hauxavAUgK40oXCPkyZ5O1jrGKjbHeT8Q== +"@snapshot-labs/snapshot.js@^0.10.1": + version "0.10.1" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.10.1.tgz#d783ee394d6e3ad3d3a6e91fea67411752d15180" + integrity sha512-PacD8HdsYZhb1Yifp6n+11Og+nZUvGhTosu+ejnEwhP6zQOFMg6gaIEsWGjoAMnjos0sgA/oIbWdPIzqJRTECw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From b79cf325678b23f3ba76768587fbd807713473f4 Mon Sep 17 00:00:00 2001 From: QYuQianchen <10935300+QYuQianchen@users.noreply.github.com> Date: Tue, 23 Jan 2024 12:45:09 +0800 Subject: [PATCH 588/815] [hopr-stake-and-balance-qv] Update "HOPR Stake and Balance QV" to version `0.2.0` (#1387) * modify safe staking * update strategy implementation for extended qv-like strategy * update readme --- .../hopr-stake-and-balance-qv/README.md | 38 +- .../hopr-stake-and-balance-qv/examples.json | 19 +- .../hopr-stake-and-balance-qv/index.ts | 480 ++++++++---------- .../hopr-stake-and-balance-qv/utils.ts | 334 ++++++++++++ 4 files changed, 571 insertions(+), 300 deletions(-) create mode 100644 src/strategies/hopr-stake-and-balance-qv/utils.ts diff --git a/src/strategies/hopr-stake-and-balance-qv/README.md b/src/strategies/hopr-stake-and-balance-qv/README.md index f66c4d948..e64db9ac9 100644 --- a/src/strategies/hopr-stake-and-balance-qv/README.md +++ b/src/strategies/hopr-stake-and-balance-qv/README.md @@ -1,31 +1,39 @@ # HOPR Stake and Balance QV This `hopr-stake-and-balance-qv` strategy calculates voting power with: -`(B1 + B2 + B3 + S1 + S2)^0.5` +`(B1 + B2 + sum((B_i + S_i) * F_i)) ^ exponent` where: -- B1: balance of HOPR token on mainnet -- B2: balance of HOPR token on Gnosis chain (xHOPR) -- B3: balance of wrapped HOPR token on Gnosis chain (wxHOPR) -- S1: amount of xHOPR token staked into the latest staking season -- S2: amount of wxHOPR token unclaimed from the latest staking season +- B1: HOPR token balance in the voting account on the mainnet +- B2: xHOPR token & wxHOPR token balance in the voting account on the Gnosis chain +- B_i: xHOPR token & wxHOPR token balance in the "Staking Safe", where the voting account is an owner, on the Gnosis chain +- S_i: wxHOPR token staked in outgoing HOPR Channels by HOPR nodes that are managed by the "Staking Safe", where the voting account is an owner, on the Gnosis chain +- F_i: Share of the voting account in the "Staking Safe", where the voting account is an owner, on the Gnosis chain +- exponent: Quadratic Voting-like exponent value. E.g., for quadratic-voting, the exponent is 0.5. This value can be set by the community to any value between 0 and 1, inclusive. Currently it is set at 0.75. + ## Parameters - "tokenAddress": Contract address of HOPR token on mainnet. Value should be `"0xf5581dfefd8fb0e4aec526be659cfab1f8c781da"` - "symbol": Token Symbol. Value should be `"HOPR"`. -- "season": Number of the ongoing season. E.g. `7`. - "fallbackGnosisBlock": Fallback block number on Gnosis chain, in case Gnosis block number cannot be translated from Ethereum mainnet due to subgraph issues. E.g. `27852687`, - "subgraphStudioProdQueryApiKey": Production decentralized subgraph studio query API key. If no key can be provided, use `null`. - "subgraphStudioDevAccountId": Development subgraph studio account ID. Note that this ID should not be exposed normally. If unknown, use `null`. - "subgraphHostedAccountName": Legacy hosted subgraph account name. Value is `"hoprnet"`. -- "useStake": If the staking program should be considered. If `false`, `S1 + S2 === 0`. Value should be set to `true`. -- "useHoprOnGnosis": If tokens on Gnosis chain should be considered. If `false`, `B2 + B3 === 0`. Value should be set to `true`. -- "useHoprOnMainnet": If tokens on Ethereum mainnet should be considered. If `false`, `B1 === 0`. Value should be set to `true`. -- "subgraphStudioProdAllSeasonQueryId": Production stake all season subgraph ID. Value is `"DrkbaCvNGVcNH1RghepLRy6NSHFi8Dmwp4T2LN3LqcjY"`. -- "subgraphStudioDevAllSeasonVersion": Latest development version of the stake all season subgraph. E.g. `"v0.0.9"` -- "subgraphStudioDevAllSeasonSubgraphName": Name of the staking subgraph in Graph Studio. Value should be `"hopr-stake-all-seasons"`. -- "subgraphHostedAllSeasonSubgraphName": Name of the staking subgraph in Graph Hosted service. Value should be `"hopr-stake-all-seasons"`. -- "subgraphStudioProdHoprOnGnosisQueryId": Latest development version of the HOPR token balances on Gnosis subgraph. Value should be `"njToE7kpetd3P9sJdYQPSq6yQjBs7w9DahQpBj6WAoD"`. +- "useSafeStake": If "Safe Staking" should be considered. If `false`, `S_i === 0` and `F_i === 0`. This value should be set to `true`, +- "useChannelStake": If tokens staked in outgoing channels should be considered. If `false`, `S_i === 0`. This value should be set to `true`, +- "useHoprOnGnosis": If tokens on Gnosis chain should be considered. If `false`, `B2 === 0` and `B_i === 0`. This value should be set to `true`. +- "useHoprOnMainnet": If tokens on Ethereum mainnet should be considered. If `false`, `B1 === 0`. This value should be set to `true`. + +- "subgraphStudioProdSafeStakeQueryId": ID of the "safe stake" subgraph in production. E.g. "DrkbaCvNGVcNH1RghepLRy6NSHFi8Dmwp4T2LN3LqcjY". +- "subgraphStudioDevSafeStakeSubgraphName": Name of the safe stake subgraph in Graph Studio. E.g. "hopr-nodes-dufour". +- "subgraphStudioDevSafeStakeVersion": Latest development version of the safe stake subgraph. E.g. "latest". +- "subgraphHostedSafeStakeSubgraphName": Name of the safe stake subgraph in Graph Hosted service. This servie does not exist, so the value should be `null`. +- "subgraphStudioProdChannelsQueryId": ID of the "channels" subgraph in production. E.g. "Feg6Jero3aQzesVYuqk253NNLyNAZZppbDPKFYEGJ1Hj". +- "subgraphStudioDevChannelsSubgraphName": Name of the channels subgraph in Graph Studio. E.g. "hopr-channels". +- "subgraphStudioDevChannelsVersion": Latest development version of the channels subgraph. E.g. "latest". +- "subgraphHostedChannelsSubgraphName": Name of the channels subgraph in Graph Hosted service. This servie does not exist, so the value should be `null`. +- "subgraphStudioProdHoprOnGnosisQueryId": ID of the HOPR token balances on Gnosis subgraph in production. Value should be `"njToE7kpetd3P9sJdYQPSq6yQjBs7w9DahQpBj6WAoD"`. - "subgraphStudioDevHoprOnGnosisSubgraphName": Name of the HOPR token balances on Gnosis subgraph in Graph Studio. Value should be "hopr-on-gnosis"` - "subgraphStudioDevHoprOnGnosisVersion": Latest development version of the HOPR token balances on Gnosis subgraph. E.g. "v0.0.2"` - "subgraphHostedHoprOnGnosisSubgraphName": Name of the HOPR token balances on Gnosis in Graph Hosted service. Value should be `"hopr-on-xdai"` +- "exponent": Quadratic Voting-like exponent value. E.g., for quadratic-voting, the exponent is 0.5. This value can be set by the community to any value between 0 and 1, inclusive. Currently it is set at `"0.75"`. diff --git a/src/strategies/hopr-stake-and-balance-qv/examples.json b/src/strategies/hopr-stake-and-balance-qv/examples.json index d56e72a4e..c04b7e2c7 100644 --- a/src/strategies/hopr-stake-and-balance-qv/examples.json +++ b/src/strategies/hopr-stake-and-balance-qv/examples.json @@ -6,22 +6,27 @@ "params": { "tokenAddress": "0xf5581dfefd8fb0e4aec526be659cfab1f8c781da", "symbol": "HOPR", - "season": 7, "fallbackGnosisBlock": 27852687, "subgraphStudioProdQueryApiKey": null, "subgraphStudioDevAccountId": null, "subgraphHostedAccountName": "hoprnet", - "useStake": true, + "useSafeStake": true, + "useChannelStake": true, "useHoprOnGnosis": true, "useHoprOnMainnet": true, - "subgraphStudioProdAllSeasonQueryId": "DrkbaCvNGVcNH1RghepLRy6NSHFi8Dmwp4T2LN3LqcjY", - "subgraphStudioDevAllSeasonVersion": "v0.0.9", - "subgraphStudioDevAllSeasonSubgraphName": "hopr-stake-all-seasons", - "subgraphHostedAllSeasonSubgraphName": "hopr-stake-all-seasons", + "subgraphStudioProdSafeStakeQueryId": "DrkbaCvNGVcNH1RghepLRy6NSHFi8Dmwp4T2LN3LqcjY", + "subgraphStudioDevSafeStakeSubgraphName": "hopr-nodes-dufour", + "subgraphStudioDevSafeStakeVersion": "latest", + "subgraphHostedSafeStakeSubgraphName": null, + "subgraphStudioProdChannelsQueryId": "Feg6Jero3aQzesVYuqk253NNLyNAZZppbDPKFYEGJ1Hj", + "subgraphStudioDevChannelsSubgraphName": "hopr-channels", + "subgraphStudioDevChannelsVersion": "latest", + "subgraphHostedChannelsSubgraphName": null, "subgraphStudioProdHoprOnGnosisQueryId": "njToE7kpetd3P9sJdYQPSq6yQjBs7w9DahQpBj6WAoD", "subgraphStudioDevHoprOnGnosisSubgraphName": "hopr-on-gnosis", "subgraphStudioDevHoprOnGnosisVersion": "v0.0.2", - "subgraphHostedHoprOnGnosisSubgraphName": "hopr-on-xdai" + "subgraphHostedHoprOnGnosisSubgraphName": "hopr-on-xdai", + "exponent": "0.75" } }, "network": "1", diff --git a/src/strategies/hopr-stake-and-balance-qv/index.ts b/src/strategies/hopr-stake-and-balance-qv/index.ts index d5e46b602..c8753b13f 100644 --- a/src/strategies/hopr-stake-and-balance-qv/index.ts +++ b/src/strategies/hopr-stake-and-balance-qv/index.ts @@ -1,250 +1,71 @@ import { formatUnits, parseUnits } from '@ethersproject/units'; import { BigNumber } from '@ethersproject/bignumber'; -import { multicall, subgraphRequest } from '../../utils'; +import { multicall } from '../../utils'; +import { + getGnosisBlockNumber, + getHostedSubgraphUrl, + getStudioDevSubgraphUrl, + getStudioProdSubgraphUrl, + hoprNodeStakeOnChannelsSubgraphQuery, + hoprTotalOnGnosisSubgraphQuery, + safeStakeSubgraphQuery, + trimArray +} from './utils'; /** - * @dev Calculate score based on Quadratic Voting system.Token balance comes from - * - Mainnet HOPR token balance, read from multicall - * - Gnosis chain, HOPR token balance, read from subgraph (xHOPR balance and wxHOPR balance) and multicall (mainnet HOPR balance) - * - Gnosis chain. HOPR token staked into the most recent stake season, read from subgraph. + * @dev Calculate score based on Quadratic Voting-like system. + * Votes should be casted by the admin (owner) account of SafeStake. + * Token balance comes from + * - the voter account: + * - Mainnet HOPR token balance, read from multicall + * - Gnosis chain, HOPR token balance, read from subgraph (xHOPR balance and wxHOPR balance) and multicall (mainnet HOPR balance) + * - safes created by the "HoprSafeStakeFactory" contract, where the voter account is an owner. Voting account's share of the safe: + * - Gnosis chain. Safe's HOPR token balance, read from subgraph (xHOPR balance and wxHOPR balance) and multicall (mainnet HOPR balance) + * - Gnosis chain. Safe's HOPR token staked into the production HoprChannels, read from subgraph. */ export const author = 'QYuQianchen'; -export const version = '0.1.0'; +export const version = '0.2.0'; +/* + ****************************************** + *************** PARAMETERS *************** + ****************************************** + */ const XDAI_BLOCK_HOSTED_SUBGRAPH_URL = - 'https://api.thegraph.com/subgraphs/name/1hive/xdai-blocks'; -const QUERY_LIMIT = 1000; // 1000 addresses per query in Subgraph + 'https://api.thegraph.com/subgraphs/name/1hive/xdai-blocks'; // convert mainnet block to its corresponding block on Gnosis chain const tokenAbi = ['function balanceOf(address) view returns (uint256)']; // get mainnet HOPR token balance -// const DEFAULT_HOPR_STAKING_ALL_SEASONS_PROD_SUBGRAPH_ID = 'DrkbaCvNGVcNH1RghepLRy6NSHFi8Dmwp4T2LN3LqcjY'; -// const DEFAULT_HOPR_ON_GNOSIS_PROD_SUBGRAPH_ID = 'njToE7kpetd3P9sJdYQPSq6yQjBs7w9DahQpBj6WAoD'; const DEFAULT_HOPR_HOSTED_ACCOUNT_NAME = 'hoprnet'; -const DEFAULT_HOPR_STAKING_ALL_SEASONS_HOSTED_SUBGRAPH_NAME = - 'hopr-stake-all-seasons'; -const DEFAULT_HOPR_BALANCE_ON_GNOSIS_HOSTED_SUBGRAPH_NAME = 'hopr-on-xdai'; - -function getStudioProdSubgraphUrl( - apiKey: string | null | undefined, - subgraphId: string -): string | null { - return !apiKey - ? null - : `https://gateway.thegraph.com/api/${apiKey}/subgraphs/id/${subgraphId}`; -} -function getStudioDevSubgraphUrl( - accountStudioId: string | null | undefined, - subgraphName: string, - version: string -): string | null { - return !accountStudioId - ? null - : `https://api.studio.thegraph.com/query/${accountStudioId}/${subgraphName}/${version}`; -} -function getHostedSubgraphUrl( - accountName: string, - subgraphName: string -): string { - return `https://api.thegraph.com/subgraphs/name/${accountName}/${subgraphName}`; -} +const DEFAULT_FACTOR = 0.75; // Quadratic-voting-like factor -/** - * Try to query subgraphs from three differnt endpoints (hosted service, studio for development, studio in production), if applicable - * @param hostedSubgraphUrl hosted subgrpah url - * @param stuidoDevSubgraphUrl development url foro studio subgraph - * @param studioProdSubgraphUrl production url foro studio subgraph - * @param builtQuery query object - * @returns null or an object of summed token balance per address +/* + ******************************************** + **************** CALCULATION *************** + ******************************************** */ -async function subgraphRequestsToVariousServices( - hostedSubgraphUrl: string, - stuidoDevSubgraphUrl: string | null, - studioProdSubgraphUrl: string | null, - builtQuery: any -): Promise { - try { - // first try with hosted service - return subgraphRequest(hostedSubgraphUrl, builtQuery); - } catch (error) { - // console.log('Failed to get data from hostedSubgraphUrl'); - } - - // then try with studio dev service - if (stuidoDevSubgraphUrl) { - try { - return subgraphRequest(stuidoDevSubgraphUrl, builtQuery); - } catch (error) { - // console.log('Failed to get data from stuidoDevSubgraphUrl'); - } - } - - // then try with studio prod service - if (studioProdSubgraphUrl) { - try { - return subgraphRequest(studioProdSubgraphUrl, builtQuery); - } catch (error) { - // console.log('Failed to get data from studioProdSubgraphUrl'); - } - } - return null; -} - -/** - * Get block number from Gnosis chain at a given timestamp. - * The timestamp of the returned block should be no-bigger than the desired timestamp - * @param timestamp number of timestamp - * @param fallbackBlockNumber fallback block number on Gnosis chain, in case no result gets returned. - * @returns a number - */ -async function getGnosisBlockNumber( - timestamp: number, - fallbackBlockNumber: number -): Promise { - const query = { - blocks: { - __args: { - first: 1, - orderBy: 'number', - orderDirection: 'desc', - where: { - timestamp_lte: timestamp - } - }, - number: true, - timestamp: true - } - }; - - // query from subgraph - const data = await subgraphRequestsToVariousServices( - XDAI_BLOCK_HOSTED_SUBGRAPH_URL, - null, - null, - query - ); - return !data ? fallbackBlockNumber : Number(data.blocks[0].number); -} - -async function stakingSubgraphQuery( - hostedSubgraphUrl: string, - stuidoDevSubgraphUrl: string | null, - studioProdSubgraphUrl: string | null, - seasonNumber: string, - addresses: string[], - blockNumber: number, - snapshot: number | string -): Promise<{ [propName: string]: BigNumber }> { - const query = { - stakingParticipations: { - __args: { - first: QUERY_LIMIT, - where: { - account_: { - id_in: addresses.map((adr) => adr.toLowerCase()) - }, - stakingSeason_: { - seasonNumber - } - } - }, - account: { - id: true - }, - actualLockedTokenAmount: true, - airdropLockedTokenAmount: true, - unclaimedRewards: true, - virtualLockedTokenAmount: true - } - }; - - if (snapshot !== 'latest') { - // @ts-ignore - query.stakingParticipations.__args.block = { number: blockNumber }; - } - - // query from subgraph - const data = await subgraphRequestsToVariousServices( - hostedSubgraphUrl, - stuidoDevSubgraphUrl, - studioProdSubgraphUrl, - query - ); - - // map result (data.accounts) to addresses - const entries = !data - ? addresses.map((addr) => [addr, BigNumber.from('0')]) - : data.stakingParticipations.map((d) => [ - d.account.id, - BigNumber.from(d.actualLockedTokenAmount) - .add(BigNumber.from(d.airdropLockedTokenAmount)) - .add(BigNumber.from(d.virtualLockedTokenAmount)) - .add(BigNumber.from(d.unclaimedRewards)) - ]); - return Object.fromEntries(entries); -} - -async function hoprTotalOnGnosisSubgraphQuery( - hostedSubgraphUrl: string, - stuidoDevSubgraphUrl: string | null, - studioProdSubgraphUrl: string | null, - addresses: string[], - blockNumber: number, - snapshot: number | string -): Promise<{ [propName: string]: BigNumber }> { - const query = { - accounts: { - __args: { - first: QUERY_LIMIT, - where: { - id_in: addresses.map((adr) => adr.toLowerCase()) - } - }, - id: true, - totalBalance: true - } - }; - - if (snapshot !== 'latest') { - // @ts-ignore - query.accounts.__args.block = { number: blockNumber }; - } - - // query from subgraph - const data = await subgraphRequestsToVariousServices( - hostedSubgraphUrl, - stuidoDevSubgraphUrl, - studioProdSubgraphUrl, - query - ); - - // map result (data.accounts) to addresses - const entries = !data - ? addresses.map((addr) => [addr, BigNumber.from('0')]) - : data.accounts.map((d) => [ - d.id, - parseUnits(d.totalBalance.toString(), 18) - ]); - return Object.fromEntries(entries); -} - /** * Calculate the final score - * @param shouldIncludeMainnetValue if the mainnet token balance should be taken into account - * @param subgraphScore Sum of score from two subgraphs - * @param mainnetTokenResults Multicall returned result, this should contain token balances in an array - * @param index index of the current address - * @returns squared root of the sum of subgraph scores and token amounts if the sum is above 1, if not, returns 0. + * Note that if the (mainnetBalance + gnosisBalance + safeStakingBalance) <= 1, the score is zero + * @param mainnetBalance HOPR token balance of the voting account, if the mainnet token balance should be taken into account. Otherwise, zero + * @param gnosisBalance xHOPR and wxHOPR token balance of the voting account, if the gnosis token balance should be taken into account. Otherwise, zero + * @param safeStakingBalance Voting account's summed share of all its owned safes, on the xHOPR/wxHOPR token balance and all the stakes in channels by their managed nodes. + * @param exponent QV-like exponent value. E.g., for quadratic-voting, the exponent is 0.5. This value can be set by the community to any value between 0 and 1, inclusive. Currently it is set at 0.75. + * @returns calculated score */ function calculateScore( - shouldIncludeMainnetValue: boolean, - subgraphScore: BigNumber, - mainnetTokenResults: BigNumber[], - index: number + mainnetBalance: BigNumber, + gnosisBalance: BigNumber, + safeStakingBalance: number, + exponent: number ) { - const summedAmount = shouldIncludeMainnetValue - ? subgraphScore.add(BigNumber.from(mainnetTokenResults[index].toString())) - : subgraphScore; - const summedAmountInEth = parseFloat(formatUnits(summedAmount, 18)); - if (summedAmountInEth > 1) { - return Math.sqrt(summedAmountInEth); + const total = + parseFloat( + formatUnits( + gnosisBalance.add(BigNumber.from(mainnetBalance.toString())), + 18 + ) + ) + safeStakingBalance; + if (total > 1) { + return Math.pow(total, exponent); } else { return 0; } @@ -265,7 +86,7 @@ export async function strategy( // Get the block on mainnet and find the corresponding time on Gnosis chain) const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - // get token balance (if applicable) and block + // get token balance (if applicable) of voters and block const [resHoprOnMainnet, block] = await Promise.all([ options.useHoprOnMainnet ? multicall( @@ -285,59 +106,143 @@ export async function strategy( // get the block number for subgraph query const subgraphBlock = await getGnosisBlockNumber( + XDAI_BLOCK_HOSTED_SUBGRAPH_URL, block.timestamp, options.fallbackGnosisBlock ); - // console.log( - // `Block on mainnet: ${block.number} and on Gnosis ${subgraphBlock}` - // ); // trim addresses to sub of "QUERY_LIMIT" addresses. - const addressSubsets = Array.apply( - null, - Array(Math.ceil(addresses.length / QUERY_LIMIT)) - ).map((_e, i) => addresses.slice(i * QUERY_LIMIT, (i + 1) * QUERY_LIMIT)); + const addressSubsets: string[][] = trimArray(addresses); + + // share of a safe per owner (voter) + const safeFactor = new Map(); + // total stake in Channels of all the nodes managed by the safe + const safeStakeInChannel = new Map(); + // mapping of owner address to an array of their owned safes + const ownerSafes = new Map(); - let returnedFromSubgraphStake; - if (options.useStake) { - // construct URLs for stake season - const hostedAllSeasonSubgraphUrl: string = getHostedSubgraphUrl( + if (options.useSafeStake) { + // array of nodes per safe + const safeNodes = new Map(); + // array of all the nodes managed by the safes where its owner is a voter + const nodes: string[] = []; + // Find the list of Safes (created by HoprStakeFactory contract) where the voting account is an owner, + // as well as the total number of owners of each safe + // construct URLs for safe stake subgraph + const hostedSafeStakeSubgraphUrl = getHostedSubgraphUrl( options.subgraphHostedAccountName ?? DEFAULT_HOPR_HOSTED_ACCOUNT_NAME, - options.subgraphHostedAllSeasonSubgraphName ?? - DEFAULT_HOPR_STAKING_ALL_SEASONS_HOSTED_SUBGRAPH_NAME + options.subgraphHostedSafeStakeSubgraphName ); - const stuidoDevAllSeasonSubgraphUrl = getStudioDevSubgraphUrl( + const stuidoDevSafeStakeSubgraphUrl = getStudioDevSubgraphUrl( options.subgraphStudioDevAccountId, - options.subgraphStudioDevAllSeasonSubgraphName, - options.subgraphStudioDevAllSeasonVersion + options.subgraphStudioDevSafeStakeSubgraphName, + options.subgraphStudioDevSafeStakeVersion ); - const studioProdAllSeasonSubgraphUrl = getStudioProdSubgraphUrl( + const studioProdSafeStakeSubgraphUrl = getStudioProdSubgraphUrl( options.subgraphStudioProdQueryApiKey, - options.subgraphStudioProdAllSeasonQueryId + options.subgraphStudioProdSafeStakeQueryId ); // get subgraph result for stake season - returnedFromSubgraphStake = await Promise.all( + const returnedFromSubgraphStake = await Promise.all( addressSubsets.map((subset) => - stakingSubgraphQuery( - hostedAllSeasonSubgraphUrl, - stuidoDevAllSeasonSubgraphUrl, - studioProdAllSeasonSubgraphUrl, - options.season.toString(), + safeStakeSubgraphQuery( + hostedSafeStakeSubgraphUrl, + stuidoDevSafeStakeSubgraphUrl, + studioProdSafeStakeSubgraphUrl, subset, subgraphBlock, snapshot ) ) ); + // parse the returned value + returnedFromSubgraphStake.forEach((resultSubset) => { + resultSubset.forEach((safe) => { + // 1. safe -> nodes + safeNodes.set(safe.safeAddress, safe.nodes); + nodes.concat(safe.nodes); + if (safe.owners.length == 0) { + // 2. safe -> factor + safeFactor.set(safe.safeAddress, 0); + } else { + // 2. safe -> factor + safeFactor.set(safe.safeAddress, 1 / safe.owners.length); + safe.owners.forEach((owner) => { + const registeredSafes = ownerSafes.get(owner) ?? []; + // 3. owner -> safes + ownerSafes.set(owner, [...registeredSafes, safe.safeAddress]); + }); + } + }); + }); + // trim addresses to sub of "QUERY_LIMIT" addresses. + const nodesSubsets: string[][] = trimArray(nodes); + + // when safe stake is used, check if channel stake is used + if (options.useChannelStake) { + // construct URLs for HOPR channels + const hostedChannelsSubgraphUrl = getHostedSubgraphUrl( + options.subgraphHostedAccountName ?? DEFAULT_HOPR_HOSTED_ACCOUNT_NAME, + options.subgraphHostedChannelsSubgraphName + ); + const stuidoDevChannelsSubgraphUrl = getStudioDevSubgraphUrl( + options.subgraphStudioDevAccountId, + options.subgraphStudioDevChannelsSubgraphName, + options.subgraphStudioDevChannelsVersion + ); + const studioProdChannelsSubgraphUrl = getStudioProdSubgraphUrl( + options.subgraphStudioProdQueryApiKey, + options.subgraphStudioProdChannelsQueryId + ); + // get subgraph result for hopr on gnosis + const returnedFromSubgraphChannels = await Promise.all( + nodesSubsets.map((subset) => + hoprNodeStakeOnChannelsSubgraphQuery( + hostedChannelsSubgraphUrl, + stuidoDevChannelsSubgraphUrl, + studioProdChannelsSubgraphUrl, + subset, + subgraphBlock, + snapshot + ) + ) + ); + // node-wxHOPR balance staked in Channels + const subgraphNodeStakeInChannels = Object.assign( + {}, + ...returnedFromSubgraphChannels + ); + // parse the returned value from channels + for (const key of safeNodes.keys()) { + const nodesManagedBySafe = safeNodes.get(key); + // populate safeStakeInChannel with safeAddress as key and the sum of all the stakes in nodes + if (!nodesManagedBySafe || nodesManagedBySafe.length == 0) { + safeStakeInChannel.set(key, BigNumber.from('0')); + } else { + const stakesInNodes = nodesManagedBySafe.reduce( + (acc, cur) => + (acc = acc.add( + parseUnits(subgraphNodeStakeInChannels[cur] ?? '0', 18) + )), + BigNumber.from('0') + ); + safeStakeInChannel.set(key, stakesInNodes); + } + } + } } + // trim addresses to sub of "QUERY_LIMIT" addresses. + const addressWithSafesSubsets: string[][] = trimArray( + addresses.concat(Array.from(safeFactor.keys())) + ); + let returnedFromSubgraphOnGnosis; if (options.useHoprOnGnosis) { // construct URLs for HOPR on Gnosis - const hostedHoprOnGnosisSubgraphUrl: string = getHostedSubgraphUrl( + const hostedHoprOnGnosisSubgraphUrl = getHostedSubgraphUrl( options.subgraphHostedAccountName ?? DEFAULT_HOPR_HOSTED_ACCOUNT_NAME, - options.subgraphHostedTokenOnGnosisSubgraphName ?? - DEFAULT_HOPR_BALANCE_ON_GNOSIS_HOSTED_SUBGRAPH_NAME + options.subgraphHostedHoprOnGnosisSubgraphName ); const stuidoDevHoprOnGnosisSubgraphUrl = getStudioDevSubgraphUrl( options.subgraphStudioDevAccountId, @@ -350,7 +255,7 @@ export async function strategy( ); // get subgraph result for hopr on gnosis returnedFromSubgraphOnGnosis = await Promise.all( - addressSubsets.map((subset) => + addressWithSafesSubsets.map((subset) => hoprTotalOnGnosisSubgraphQuery( hostedHoprOnGnosisSubgraphUrl, stuidoDevHoprOnGnosisSubgraphUrl, @@ -364,32 +269,51 @@ export async function strategy( } // get and parse balance from subgraph - const subgraphStakeBalanceStake = Object.assign( - {}, - ...returnedFromSubgraphStake - ); - const subgraphStakeBalanceOnGnosis = Object.assign( - {}, - ...returnedFromSubgraphOnGnosis - ); + const subgraphTokenBalanceOnGnosis: { [propName: string]: BigNumber } = + Object.assign({}, ...returnedFromSubgraphOnGnosis); - const subgraphScore: BigNumber[] = addresses.map((address) => - ( - subgraphStakeBalanceStake[address.toLowerCase()] ?? BigNumber.from('0') - ).add( - subgraphStakeBalanceOnGnosis[address.toLowerCase()] ?? BigNumber.from('0') - ) - ); + // sum of all the safes owned by the voting account + // = sum{ factor * (safe's x/wxHOPR balance + wxHOPR tokens staked in the Channels) } + const summedStakePerSafe = addresses.map((address) => { + // from the voting address, get all the safe addresses + const safes = ownerSafes.get(address) ?? []; + if (safes.length == 0) { + return BigNumber.from('0'); + } else { + return safes.reduce((acc, curSafe) => { + // factor * (x/wxHOPR token balance + safe stake in channels) + const curSafeFactor = safeFactor.get(curSafe) ?? 0; + if (curSafeFactor == 0) { + return acc; + } + const curSafeTokenBalance = + subgraphTokenBalanceOnGnosis[curSafe.toLowerCase()] ?? + BigNumber.from('0'); + const curSafeStakeInChannels = + safeStakeInChannel.get(curSafe.toLowerCase()) ?? BigNumber.from('0'); + return ( + acc + + curSafeFactor * + parseFloat( + formatUnits(curSafeTokenBalance.add(curSafeStakeInChannels), 18) + ) + ); + }); + } + }); // return sqrt(subgraph score + hopr on mainet score) return Object.fromEntries( addresses.map((adr, i) => [ adr, calculateScore( - options.useHoprOnMainnet, - subgraphScore[i], - resHoprOnMainnet, - i + options.useHoprOnMainnet ? resHoprOnMainnet[i] : BigNumber.from('0'), + options.useHoprOnGnosis + ? subgraphTokenBalanceOnGnosis[adr.toLowerCase()] ?? + BigNumber.from('0') + : BigNumber.from('0'), + summedStakePerSafe[i], + parseFloat(options.exponent ?? DEFAULT_FACTOR) ) ]) ); diff --git a/src/strategies/hopr-stake-and-balance-qv/utils.ts b/src/strategies/hopr-stake-and-balance-qv/utils.ts new file mode 100644 index 000000000..c8a72cff6 --- /dev/null +++ b/src/strategies/hopr-stake-and-balance-qv/utils.ts @@ -0,0 +1,334 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import { subgraphRequest } from '../../utils'; +import { parseUnits } from '@ethersproject/units'; + +/* + ****************************************** + ****************** TYPES ***************** + ****************************************** + */ +// details of a safe created by the NodeSafeFactory contract +export type Safe = { + safeAddress: string; + owners: string[]; + nodes: string[]; +}; + +/* + ****************************************** + *************** PARAMETERS *************** + ****************************************** + */ +const QUERY_LIMIT = 1000; // 1000 addresses per query in Subgraph + +/* + *********************************************** + **************** SUBGRAPH SETUP *************** + *********************************************** + */ +export function getStudioProdSubgraphUrl( + apiKey: string | null | undefined, + subgraphId: string +): string | null { + return !apiKey + ? null + : `https://gateway.thegraph.com/api/${apiKey}/subgraphs/id/${subgraphId}`; +} + +export function getStudioDevSubgraphUrl( + accountStudioId: string | null | undefined, + subgraphName: string, + version: string +): string | null { + return !accountStudioId + ? null + : `https://api.studio.thegraph.com/query/${accountStudioId}/${subgraphName}/${version}`; +} + +export function getHostedSubgraphUrl( + accountName: string, + subgraphName: string | null +): string | null { + return !subgraphName + ? null + : `https://api.thegraph.com/subgraphs/name/${accountName}/${subgraphName}`; +} + +/** + * Try to query subgraphs from three differnt endpoints (hosted service, studio for development, studio in production), if applicable + * @param hostedSubgraphUrl hosted subgrpah url + * @param stuidoDevSubgraphUrl development url foro studio subgraph + * @param studioProdSubgraphUrl production url foro studio subgraph + * @param builtQuery query object + * @returns null or an object of summed token balance per address + */ +export async function subgraphRequestsToVariousServices( + hostedSubgraphUrl: string | null, + stuidoDevSubgraphUrl: string | null, + studioProdSubgraphUrl: string | null, + builtQuery: any +): Promise { + if (hostedSubgraphUrl) { + try { + // first try with hosted service + return subgraphRequest(hostedSubgraphUrl, builtQuery); + } catch (error) { + // console.log('Failed to get data from hostedSubgraphUrl'); + } + } + + // then try with studio dev service + if (stuidoDevSubgraphUrl) { + try { + return subgraphRequest(stuidoDevSubgraphUrl, builtQuery); + } catch (error) { + // console.log('Failed to get data from stuidoDevSubgraphUrl'); + } + } + + // then try with studio prod service + if (studioProdSubgraphUrl) { + try { + return subgraphRequest(studioProdSubgraphUrl, builtQuery); + } catch (error) { + // console.log('Failed to get data from studioProdSubgraphUrl'); + } + } + return null; +} + +/* + ************************************************* + **************** SUBGRAPH QUERIES *************** + ************************************************* + */ +/** + * Get block number from Gnosis chain at a given timestamp. + * The timestamp of the returned block should be no-bigger than the desired timestamp + * @param queryUrl URL to the subgraph query URL + * @param timestamp number of timestamp + * @param fallbackBlockNumber fallback block number on Gnosis chain, in case no result gets returned. + * @returns a number + */ +export async function getGnosisBlockNumber( + queryUrl: string, + timestamp: number, + fallbackBlockNumber: number +): Promise { + const query = { + blocks: { + __args: { + first: 1, + orderBy: 'number', + orderDirection: 'desc', + where: { + timestamp_lte: timestamp + } + }, + number: true, + timestamp: true + } + }; + + // query from subgraph + const data = await subgraphRequestsToVariousServices( + queryUrl, + null, + null, + query + ); + return !data ? fallbackBlockNumber : Number(data.blocks[0].number); +} + +/** + * Get the list of safe address created by the HoprStakeFactory contract + * where the voting account is an owner. + * It also returns the share per owner (1 / total number of owners) of each safe. + * @param hostedSubgraphUrl url to the hosted subgraph + * @param stuidoDevSubgraphUrl url to the dev subgraph in the studio + * @param studioProdSubgraphUrl url to the production subgraph in the studio + * @param addresses address of voting accounts, which is an owner of the safe + * @param blockNumber block number of the snapshot + * @param snapshot snapshot + * @returns a key-value object where the key is safe address the value is the total number of owners. + */ +export async function safeStakeSubgraphQuery( + hostedSubgraphUrl: string | null, + stuidoDevSubgraphUrl: string | null, + studioProdSubgraphUrl: string | null, + addresses: string[], + blockNumber: number, + snapshot: number | string +): Promise { + const query = { + safes: { + __args: { + first: QUERY_LIMIT, + where: { + owners_: { + owner_in: addresses.map((adr) => adr.toLowerCase()) + } + } + }, + id: true, + owners: { + owner: { + id: true + } + }, + registeredNodesInNetworkRegistry: { + node: { + id: true + } + } + } + }; + + if (snapshot !== 'latest') { + // @ts-ignore + query.safes.__args.block = { number: blockNumber }; + } + + // query from subgraph + const data = await subgraphRequestsToVariousServices( + hostedSubgraphUrl, + stuidoDevSubgraphUrl, + studioProdSubgraphUrl, + query + ); + + // return parsed entries + if (!data || !data.safes || data.safe.length == 0) { + return []; + } else { + return data.safes.map((s) => { + return { + safeAddress: s.id, + owners: s.owners.map((o) => o.owner.id), + nodes: s.registeredNodesInNetworkRegistry.map((n) => n.node.id) + } as Safe; + }); + } +} + +/** + * Get the list of wxHOPR + xHOPR balance of addresses on Gnosis chain + * @param hostedSubgraphUrl url to the hosted subgraph + * @param stuidoDevSubgraphUrl url to the dev subgraph in the studio + * @param studioProdSubgraphUrl url to the production subgraph in the studio + * @param addresses address of wallets + * @param blockNumber block number of the snapshot + * @param snapshot snapshot + * @returns a key-value object where the key is the address and the value is the total HOPR token balance on Gnosis chain. + */ +export async function hoprTotalOnGnosisSubgraphQuery( + hostedSubgraphUrl: string | null, + stuidoDevSubgraphUrl: string | null, + studioProdSubgraphUrl: string | null, + addresses: string[], + blockNumber: number, + snapshot: number | string +): Promise<{ [propName: string]: BigNumber }> { + const query = { + accounts: { + __args: { + first: QUERY_LIMIT, + where: { + id_in: addresses.map((adr) => adr.toLowerCase()) + } + }, + id: true, + totalBalance: true + } + }; + + if (snapshot !== 'latest') { + // @ts-ignore + query.accounts.__args.block = { number: blockNumber }; + } + + // query from subgraph + const data = await subgraphRequestsToVariousServices( + hostedSubgraphUrl, + stuidoDevSubgraphUrl, + studioProdSubgraphUrl, + query + ); + + // map result (data.accounts) to addresses + const entries = !data + ? addresses.map((addr) => [addr, BigNumber.from('0')]) + : data.accounts.map((d) => [ + d.id, + parseUnits(d.totalBalance.toString(), 18) + ]); + return Object.fromEntries(entries); +} + +/** + * Get the total stake in all the outgoing channels per node + * @param hostedSubgraphUrl url to the hosted subgraph + * @param stuidoDevSubgraphUrl url to the dev subgraph in the studio + * @param studioProdSubgraphUrl url to the production subgraph in the studio + * @param addresses node addresses + * @param blockNumber block number of the snapshot + * @param snapshot snapshot + * @returns a key-value object where the key is the address and the value is the total HOPR token balance on Gnosis chain. + */ +export async function hoprNodeStakeOnChannelsSubgraphQuery( + hostedSubgraphUrl: string | null, + stuidoDevSubgraphUrl: string | null, + studioProdSubgraphUrl: string | null, + addresses: string[], + blockNumber: number, + snapshot: number | string +): Promise<{ [propName: string]: BigNumber }> { + const query = { + accounts: { + __args: { + first: QUERY_LIMIT, + where: { + id_in: addresses.map((adr) => adr.toLowerCase()) + } + }, + id: true, + balance: true + } + }; + + if (snapshot !== 'latest') { + // @ts-ignore + query.accounts.__args.block = { number: blockNumber }; + } + + // query from subgraph + const data = await subgraphRequestsToVariousServices( + hostedSubgraphUrl, + stuidoDevSubgraphUrl, + studioProdSubgraphUrl, + query + ); + + // map result (data.accounts) to addresses + const entries = !data + ? addresses.map((addr) => [addr, BigNumber.from('0')]) + : data.accounts.map((d) => [ + d.id, + parseUnits(d.totalBalance.toString(), 18) + ]); + return Object.fromEntries(entries); +} + +/* + *********************************************** + ******************** OTHERS ******************* + *********************************************** + */ +export function trimArray( + originalArray: Array, + size: number = QUERY_LIMIT +): Array> { + return Array.apply(null, Array(Math.ceil(originalArray.length / size))).map( + (_e, i) => originalArray.slice(i * size, (i + 1) * size) + ); +} From 22cd2c3acd990765ef9b66386ed5646f7833d25d Mon Sep 17 00:00:00 2001 From: johnmark13 Date: Thu, 25 Jan 2024 08:58:25 +0000 Subject: [PATCH 589/815] [nation3-passport-coop-with-delegations] Update behaviour on revoked passports by querying subgraph (#1396) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Make sure we have all the ERc20 balances that we need. * I think this is more simple.... * Still not beautiful, but in testing I believe that this is simplified and covers our use cases * Update index.ts Bump version as requested! * How cooperative model might work * Strip out the ERC20 * Update src/strategies/nation3-passport-coop-with-delegations/index.ts Co-authored-by: Chaitanya * Update src/strategies/nation3-passport-coop-with-delegations/index.ts Co-authored-by: Chaitanya * Update src/strategies/nation3-passport-coop-with-delegations/index.ts Co-authored-by: Chaitanya * Update index.ts As requested * Fix from breaking PR suggestions * Create CODEOWNERS * Largely untested, but passes unit tests * Checked with additional adresses and lower balances * Lint * Fix lint issues * Did we ever have a passport 0? * Update nation3-passport-coop-with-delegations to version to 0.3.0 * Remove CODEOWNERS * Automated lint (#1381) Co-authored-by: ChaituVR * 🐛 Fix breaking issue with revoked passports --------- Co-authored-by: JohnMark13 Co-authored-by: Chaitanya Co-authored-by: Aahna Ashina <95955389+aahna-ashina@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: ChaituVR Co-authored-by: Jamil Bousquet --- .../index.ts | 36 +++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/src/strategies/nation3-passport-coop-with-delegations/index.ts b/src/strategies/nation3-passport-coop-with-delegations/index.ts index 6fd51d1ea..42f56e945 100644 --- a/src/strategies/nation3-passport-coop-with-delegations/index.ts +++ b/src/strategies/nation3-passport-coop-with-delegations/index.ts @@ -1,10 +1,13 @@ import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; import { Multicaller } from '../../utils'; import { formatUnits } from '@ethersproject/units'; +import { subgraphRequest } from '../../utils'; export const author = 'nation3'; export const version = '0.3.0'; +type Query = {[key: string]: any} + const DECIMALS = 18; const balanceAbi = [ @@ -29,15 +32,10 @@ export async function strategy( ): Promise> { const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - 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, @@ -45,12 +43,38 @@ export async function strategy( { blockTag } ); + const erc721SignerCaller = new Multicaller(network, provider, signerAbi, { + blockTag + }); + const erc721OwnerCaller = new Multicaller(network, provider, ownerAbi, { + blockTag + }); + + const passportIssuanceSubgrgraph = "https://api.thegraph.com/subgraphs/name/nation3/passportissuance"; + + const revokedQuery: Query = { + revokes: { + id: true, + _to: true, + _tokenId: true, + } + } + + const revokedUsersResponse = await subgraphRequest(passportIssuanceSubgrgraph, revokedQuery); + + const revokedPassports: number[] = revokedUsersResponse.revokes.map(revokeObject => { + return BigNumber.from(revokeObject._tokenId).toNumber(); + }); + + erc721LastTokenIdCaller.call('lastTokenId', options.erc721, 'getNextId'); const lastIndex = await erc721LastTokenIdCaller.execute(); const lastTokenId = BigNumber.from(lastIndex.lastTokenId).toNumber(); for (let i = 1; i < lastTokenId; i++) { + if (revokedPassports.includes(i)) continue; + erc721SignerCaller.call(i, options.erc721, 'signerOf', [i]); erc721OwnerCaller.call(i, options.erc721, 'ownerOf', [i]); } From 73631021413335382eb9d5c976fcb42100d13029 Mon Sep 17 00:00:00 2001 From: SpaceFi <82010251+SpaceFinance@users.noreply.github.com> Date: Thu, 25 Jan 2024 17:03:34 +0800 Subject: [PATCH 590/815] [spacefi-blp] add blp strategy (#1394) * Add SpaceFi blp * Add files via upload * Add files via upload * Update src/strategies/spacefi-blp/index.ts Co-authored-by: Chaitanya * Update src/strategies/spacefi-blp/index.ts Co-authored-by: Chaitanya * Update index.ts * Update examples.json * Update README.md --------- Co-authored-by: Chaitanya --- src/strategies/index.ts | 2 ++ src/strategies/spacefi-blp/README.md | 33 ++++++++++++++++++++++ src/strategies/spacefi-blp/examples.json | 25 ++++++++++++++++ src/strategies/spacefi-blp/index.ts | 36 ++++++++++++++++++++++++ 4 files changed, 96 insertions(+) create mode 100644 src/strategies/spacefi-blp/README.md create mode 100644 src/strategies/spacefi-blp/examples.json create mode 100644 src/strategies/spacefi-blp/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 0c5e62541..6759234d2 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -243,6 +243,7 @@ import * as erc1155weighted from './erc1155-weighted-by-id'; import * as stakersAndHolders from './stakers-and-holders'; import * as banksyDao from './banksy-dao'; import * as spacey2025 from './spacey2025'; +import * as spacefiBlp from './spacefi-blp'; import * as sandmanDao from './sandman-dao'; import * as veBalanceOfAt from './ve-balance-of-at'; import * as veRibbon from './ve-ribbon'; @@ -663,6 +664,7 @@ const strategies = { 'stakers-and-holders': stakersAndHolders, 'banksy-dao': banksyDao, spacey2025: spacey2025, + 'spacefi-blp': spacefiBlp, 'sandman-dao': sandmanDao, 've-balance-of-at': veBalanceOfAt, 've-ribbon': veRibbon, diff --git a/src/strategies/spacefi-blp/README.md b/src/strategies/spacefi-blp/README.md new file mode 100644 index 000000000..d55676fbf --- /dev/null +++ b/src/strategies/spacefi-blp/README.md @@ -0,0 +1,33 @@ +# spacefi-blp + +This strategy returns the assets of nft and xspace in spacefi, including staking and in the market + +Here is an example of parameters: + +```json +[ + { + "name": "Example query", + "strategy": { + "name": "spacefi-blp", + "params": { + "blpAddress": "0x67B6c6E67F8f2CD1948ECD02221D141CBa3A4984", + "symbol": "blp", + "decimals": 18 + } + }, + "network": "324", + "addresses": [ + "0x8633500EF5c41CE955B4958AD5e61ca58A2B3cB6", + "0xAc2fbBC12cEe75158C38c5Ca34EfBb6343aFdcB3", + "0xb4B72F3843154B37580721ba9233fE86Da6e0416", + "0x89023d1284F565aF9Ad115ACDb2F512d35024723", + "0xEeC60E6a0Ca0F80Fa16e0E2267Ff4C2c1A46a447", + "0xfC87549072F3217140E7046d88D3873C8bF3B014", + "0xb6cE6Dd21598f24E840Bf2D43D8d4a1d57faEf4E", + "0x524E2631ceBFce2aF66FAcDBB160aC94A00751B3" + ], + "snapshot": 24739965 + } +] +``` diff --git a/src/strategies/spacefi-blp/examples.json b/src/strategies/spacefi-blp/examples.json new file mode 100644 index 000000000..083f3ec61 --- /dev/null +++ b/src/strategies/spacefi-blp/examples.json @@ -0,0 +1,25 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "spacefi-blp", + "params": { + "blpAddress": "0x67B6c6E67F8f2CD1948ECD02221D141CBa3A4984", + "symbol": "blp", + "decimals": 18 + } + }, + "network": "324", + "addresses": [ + "0x8633500EF5c41CE955B4958AD5e61ca58A2B3cB6", + "0xAc2fbBC12cEe75158C38c5Ca34EfBb6343aFdcB3", + "0xb4B72F3843154B37580721ba9233fE86Da6e0416", + "0x89023d1284F565aF9Ad115ACDb2F512d35024723", + "0xEeC60E6a0Ca0F80Fa16e0E2267Ff4C2c1A46a447", + "0xfC87549072F3217140E7046d88D3873C8bF3B014", + "0xb6cE6Dd21598f24E840Bf2D43D8d4a1d57faEf4E", + "0x524E2631ceBFce2aF66FAcDBB160aC94A00751B3" + ], + "snapshot": 24739965 + } +] diff --git a/src/strategies/spacefi-blp/index.ts b/src/strategies/spacefi-blp/index.ts new file mode 100644 index 000000000..f081f2008 --- /dev/null +++ b/src/strategies/spacefi-blp/index.ts @@ -0,0 +1,36 @@ +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'SpaceFinance'; +export const version = '0.1.0'; + +const abi = [ + 'function userInfo(address account) external view returns (uint256,uint256,uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const { blpAddress, decimals } = options; + + const multi = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => + multi.call(address, blpAddress, 'userInfo', [address]) + ); + const result: Record = await multi.execute(); + + return Object.fromEntries( + Object.entries(result).map(([address, blp]) => [ + address, + (Number(formatUnits(blp[0], decimals)) + + Number(formatUnits(blp[2], decimals))) + ]) + ); +} From f0df52db9a675f6ea2c5705fd74c49f8f8aead0a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 28 Jan 2024 22:23:09 +0530 Subject: [PATCH 591/815] Automated lint (#1398) Co-authored-by: ChaituVR --- .../index.ts | 23 +++++++++++-------- src/strategies/spacefi-blp/index.ts | 7 +++--- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/strategies/nation3-passport-coop-with-delegations/index.ts b/src/strategies/nation3-passport-coop-with-delegations/index.ts index 42f56e945..8975d3967 100644 --- a/src/strategies/nation3-passport-coop-with-delegations/index.ts +++ b/src/strategies/nation3-passport-coop-with-delegations/index.ts @@ -6,7 +6,7 @@ import { subgraphRequest } from '../../utils'; export const author = 'nation3'; export const version = '0.3.0'; -type Query = {[key: string]: any} +type Query = { [key: string]: any }; const DECIMALS = 18; @@ -50,22 +50,27 @@ export async function strategy( blockTag }); - const passportIssuanceSubgrgraph = "https://api.thegraph.com/subgraphs/name/nation3/passportissuance"; + const passportIssuanceSubgrgraph = + 'https://api.thegraph.com/subgraphs/name/nation3/passportissuance'; const revokedQuery: Query = { revokes: { id: true, _to: true, - _tokenId: true, + _tokenId: true } - } - - const revokedUsersResponse = await subgraphRequest(passportIssuanceSubgrgraph, revokedQuery); + }; - const revokedPassports: number[] = revokedUsersResponse.revokes.map(revokeObject => { - return BigNumber.from(revokeObject._tokenId).toNumber(); - }); + const revokedUsersResponse = await subgraphRequest( + passportIssuanceSubgrgraph, + revokedQuery + ); + const revokedPassports: number[] = revokedUsersResponse.revokes.map( + (revokeObject) => { + return BigNumber.from(revokeObject._tokenId).toNumber(); + } + ); erc721LastTokenIdCaller.call('lastTokenId', options.erc721, 'getNextId'); diff --git a/src/strategies/spacefi-blp/index.ts b/src/strategies/spacefi-blp/index.ts index f081f2008..410917481 100644 --- a/src/strategies/spacefi-blp/index.ts +++ b/src/strategies/spacefi-blp/index.ts @@ -24,13 +24,14 @@ export async function strategy( addresses.forEach((address) => multi.call(address, blpAddress, 'userInfo', [address]) ); - const result: Record = await multi.execute(); + const result: Record = + await multi.execute(); return Object.fromEntries( Object.entries(result).map(([address, blp]) => [ address, - (Number(formatUnits(blp[0], decimals)) + - Number(formatUnits(blp[2], decimals))) + Number(formatUnits(blp[0], decimals)) + + Number(formatUnits(blp[2], decimals)) ]) ); } From b431c6145f4ab119f09e46088b33040093e74277 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 28 Jan 2024 23:05:17 +0530 Subject: [PATCH 592/815] chore(deps): bump @snapshot-labs/snapshot.js from 0.9.9 to 0.10.1 (#1386) * chore(deps): bump @snapshot-labs/snapshot.js from 0.9.9 to 0.10.1 Bumps [@snapshot-labs/snapshot.js](https://github.com/snapshot-labs/snapshot.js) from 0.9.9 to 0.10.1. - [Release notes](https://github.com/snapshot-labs/snapshot.js/releases) - [Commits](https://github.com/snapshot-labs/snapshot.js/compare/v0.9.9...v0.10.1) --- updated-dependencies: - dependency-name: "@snapshot-labs/snapshot.js" dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * lint fixes --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Chaitanya --- package.json | 0 src/strategies/ocean-marketplace/index.ts | 2 +- .../index.ts | 2 +- yarn.lock | 201 +----------------- 4 files changed, 8 insertions(+), 197 deletions(-) mode change 100755 => 100644 package.json diff --git a/package.json b/package.json old mode 100755 new mode 100644 diff --git a/src/strategies/ocean-marketplace/index.ts b/src/strategies/ocean-marketplace/index.ts index de9b9bfdc..4261c0f5c 100644 --- a/src/strategies/ocean-marketplace/index.ts +++ b/src/strategies/ocean-marketplace/index.ts @@ -17,7 +17,7 @@ const OCEAN_SUBGRAPH_URL = { }; // Returns a BigDecimal as a BigNumber with 10^decimals extra zeros -export function bdToBn(bd, decimals) { +export function bdToBn(bd: string, decimals: number): BigNumber { let bn; const splitDecimal = bd.split('.'); diff --git a/src/strategies/vendor-v2-borrower-collateral-balance-of/index.ts b/src/strategies/vendor-v2-borrower-collateral-balance-of/index.ts index 5203367ef..df9d2fb6f 100644 --- a/src/strategies/vendor-v2-borrower-collateral-balance-of/index.ts +++ b/src/strategies/vendor-v2-borrower-collateral-balance-of/index.ts @@ -80,7 +80,7 @@ export async function strategy( const multiplier = hasExpired ? 0 : options.weight || 1; return Object.fromEntries( - Object.entries(result).map(([address, [_debt, collAmount]]) => [ + Object.entries(result).map(([address, [, collAmount]]) => [ address, parseFloat(formatUnits(collAmount, options.collateralDecimals)) * multiplier diff --git a/yarn.lock b/yarn.lock index f43157be3..517448187 100644 --- a/yarn.lock +++ b/yarn.lock @@ -316,22 +316,7 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@ethersproject/abi@^5.0.12": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.5.0.tgz#fb52820e22e50b854ff15ce1647cc508d6660613" - integrity sha512-loW7I4AohP5KycATvc0MgujU6JyCHPqHdeoo9z3Nr9xEiNioxa65ccdm1+fsoJhkuhdRtfcL8cfyGamz2AxZ5w== - dependencies: - "@ethersproject/address" "^5.5.0" - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/constants" "^5.5.0" - "@ethersproject/hash" "^5.5.0" - "@ethersproject/keccak256" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/strings" "^5.5.0" - -"@ethersproject/abi@^5.6.3", "@ethersproject/abi@^5.6.4": +"@ethersproject/abi@^5.0.12", "@ethersproject/abi@^5.6.3", "@ethersproject/abi@^5.6.4": version "5.6.4" resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.6.4.tgz#f6e01b6ed391a505932698ecc0d9e7a99ee60362" integrity sha512-TTeZUlCeIHG6527/2goZA6gW5F8Emoc7MrZDC7hhP84aRGvW3TEdTnZR08Ls88YXM1m2SuK42Osw/jSi3uO8gg== @@ -346,19 +331,6 @@ "@ethersproject/properties" "^5.6.0" "@ethersproject/strings" "^5.6.1" -"@ethersproject/abstract-provider@^5.5.0": - version "5.5.1" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.5.1.tgz#2f1f6e8a3ab7d378d8ad0b5718460f85649710c5" - integrity sha512-m+MA/ful6eKbxpr99xUYeRvLkfnlqzrF8SZ46d/xFB1A7ZVknYc/sXJG0RcufF52Qn2jeFj1hhcoQ7IXjNKUqg== - dependencies: - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/networks" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/transactions" "^5.5.0" - "@ethersproject/web" "^5.5.0" - "@ethersproject/abstract-provider@^5.6.1": version "5.6.1" resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.6.1.tgz#02ddce150785caf0c77fe036a0ebfcee61878c59" @@ -385,17 +357,6 @@ "@ethersproject/transactions" "^5.7.0" "@ethersproject/web" "^5.7.0" -"@ethersproject/abstract-signer@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.5.0.tgz#590ff6693370c60ae376bf1c7ada59eb2a8dd08d" - integrity sha512-lj//7r250MXVLKI7sVarXAbZXbv9P50lgmJQGr2/is82EwEb8r7HrxsmMqAjTsztMYy7ohrIhGMIml+Gx4D3mA== - dependencies: - "@ethersproject/abstract-provider" "^5.5.0" - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/abstract-signer@^5.6.2": version "5.6.2" resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.6.2.tgz#491f07fc2cbd5da258f46ec539664713950b0b33" @@ -418,29 +379,7 @@ "@ethersproject/logger" "^5.7.0" "@ethersproject/properties" "^5.7.0" -"@ethersproject/address@^5.0.2", "@ethersproject/address@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.5.0.tgz#bcc6f576a553f21f3dd7ba17248f81b473c9c78f" - integrity sha512-l4Nj0eWlTUh6ro5IbPTgbpT4wRbdH5l8CQf7icF7sb/SI3Nhd9Y9HzhonTSTi6CefI0necIw7LJqQPopPLZyWw== - dependencies: - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/keccak256" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/rlp" "^5.5.0" - -"@ethersproject/address@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.6.1.tgz#ab57818d9aefee919c5721d28cd31fd95eff413d" - integrity sha512-uOgF0kS5MJv9ZvCz7x6T2EXJSzotiybApn4XlOgoTX0xdtyVIJ7pF+6cGPxiEq/dpBiTfMiw7Yc81JcwhSYA0Q== - dependencies: - "@ethersproject/bignumber" "^5.6.2" - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/keccak256" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/rlp" "^5.6.1" - -"@ethersproject/address@^5.7.0": +"@ethersproject/address@^5.0.2", "@ethersproject/address@^5.6.1", "@ethersproject/address@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.7.0.tgz#19b56c4d74a3b0a46bfdbb6cfcc0a153fc697f37" integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA== @@ -451,13 +390,6 @@ "@ethersproject/logger" "^5.7.0" "@ethersproject/rlp" "^5.7.0" -"@ethersproject/base64@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.5.0.tgz#881e8544e47ed976930836986e5eb8fab259c090" - integrity sha512-tdayUKhU1ljrlHzEWbStXazDpsx4eg1dBXUSI6+mHlYklOXoXF6lZvw8tnD6oVaWfnMxAgRSKROg3cVKtCcppA== - dependencies: - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/base64@^5.6.1": version "5.6.1" resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.6.1.tgz#2c40d8a0310c9d1606c2c37ae3092634b41d87cb" @@ -507,21 +439,7 @@ "@ethersproject/logger" "^5.7.0" bn.js "^5.2.1" -"@ethersproject/bytes@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.5.0.tgz#cb11c526de657e7b45d2e0f0246fb3b9d29a601c" - integrity sha512-ABvc7BHWhZU9PNM/tANm/Qx4ostPGadAuQzWTr3doklZOhDlmcBqclrQe/ZXUIj3K8wC28oYeuRa+A37tX9kog== - dependencies: - "@ethersproject/logger" "^5.5.0" - -"@ethersproject/bytes@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.6.1.tgz#24f916e411f82a8a60412344bf4a813b917eefe7" - integrity sha512-NwQt7cKn5+ZE4uDn+X5RAXLp46E1chXoaMmrxAyA0rblpxz8t58lVkrHXoRIn0lz1joQElQ8410GqhTqMOwc6g== - dependencies: - "@ethersproject/logger" "^5.6.0" - -"@ethersproject/bytes@^5.7.0": +"@ethersproject/bytes@^5.5.0", "@ethersproject/bytes@^5.6.1", "@ethersproject/bytes@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.7.0.tgz#a00f6ea8d7e7534d6d87f47188af1148d71f155d" integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== @@ -565,35 +483,7 @@ "@ethersproject/properties" "^5.6.0" "@ethersproject/transactions" "^5.6.2" -"@ethersproject/hash@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.5.0.tgz#7cee76d08f88d1873574c849e0207dcb32380cc9" - integrity sha512-dnGVpK1WtBjmnp3mUT0PlU2MpapnwWI0PibldQEq1408tQBAbZpPidkWoVVuNMOl/lISO3+4hXZWCL3YV7qzfg== - dependencies: - "@ethersproject/abstract-signer" "^5.5.0" - "@ethersproject/address" "^5.5.0" - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/keccak256" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/strings" "^5.5.0" - -"@ethersproject/hash@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.6.1.tgz#224572ea4de257f05b4abf8ae58b03a67e99b0f4" - integrity sha512-L1xAHurbaxG8VVul4ankNX5HgQ8PNCTrnVXEiFnE9xoRnaUcgfD12tZINtDinSllxPLCtGwguQxJ5E6keE84pA== - dependencies: - "@ethersproject/abstract-signer" "^5.6.2" - "@ethersproject/address" "^5.6.1" - "@ethersproject/bignumber" "^5.6.2" - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/keccak256" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/strings" "^5.6.1" - -"@ethersproject/hash@^5.7.0": +"@ethersproject/hash@^5.6.1", "@ethersproject/hash@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.7.0.tgz#eb7aca84a588508369562e16e514b539ba5240a7" integrity sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g== @@ -684,13 +574,6 @@ resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892" integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== -"@ethersproject/networks@^5.5.0": - version "5.5.2" - resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.5.2.tgz#784c8b1283cd2a931114ab428dae1bd00c07630b" - integrity sha512-NEqPxbGBfy6O3x4ZTISb90SjEDkWYDUbEeIFhJly0F7sZjoQMnj5KYzMSkMkLKZ+1fGpx00EDpHQCy6PrDupkQ== - dependencies: - "@ethersproject/logger" "^5.5.0" - "@ethersproject/networks@^5.6.3": version "5.6.4" resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.6.4.tgz#51296d8fec59e9627554f5a8a9c7791248c8dc07" @@ -713,13 +596,6 @@ "@ethersproject/bytes" "^5.6.1" "@ethersproject/sha2" "^5.6.1" -"@ethersproject/properties@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.5.0.tgz#61f00f2bb83376d2071baab02245f92070c59995" - integrity sha512-l3zRQg3JkD8EL3CPjNK5g7kMx4qSwiR60/uk5IVjd3oq1MZR5qUg40CNOoEJoX5wc3DyY5bt9EbMk86C7x0DNA== - dependencies: - "@ethersproject/logger" "^5.5.0" - "@ethersproject/properties@^5.6.0": version "5.6.0" resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.6.0.tgz#38904651713bc6bdd5bdd1b0a4287ecda920fa04" @@ -768,14 +644,6 @@ "@ethersproject/bytes" "^5.6.1" "@ethersproject/logger" "^5.6.0" -"@ethersproject/rlp@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.5.0.tgz#530f4f608f9ca9d4f89c24ab95db58ab56ab99a0" - integrity sha512-hLv8XaQ8PTI9g2RHoQGf/WSxBfTB/NudRacbzdxmst5VHAqd1sMibWG7SENzT5Dj3yZ3kJYx+WiRYEcQTAkcYA== - dependencies: - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/rlp@^5.6.1": version "5.6.1" resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.6.1.tgz#df8311e6f9f24dcb03d59a2bac457a28a4fe2bd8" @@ -810,18 +678,6 @@ "@ethersproject/logger" "^5.6.0" hash.js "1.1.7" -"@ethersproject/signing-key@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.5.0.tgz#2aa37169ce7e01e3e80f2c14325f624c29cedbe0" - integrity sha512-5VmseH7qjtNmDdZBswavhotYbWB0bOwKIlOTSlX14rKn5c11QmJwGt4GHeo7NrL/Ycl7uo9AHvEqs5xZgFBTng== - dependencies: - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - bn.js "^4.11.9" - elliptic "6.5.4" - hash.js "1.1.7" - "@ethersproject/signing-key@^5.6.2": version "5.6.2" resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.6.2.tgz#8a51b111e4d62e5a62aee1da1e088d12de0614a3" @@ -897,21 +753,6 @@ "@ethersproject/constants" "^5.7.0" "@ethersproject/logger" "^5.7.0" -"@ethersproject/transactions@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.5.0.tgz#7e9bf72e97bcdf69db34fe0d59e2f4203c7a2908" - integrity sha512-9RZYSKX26KfzEd/1eqvv8pLauCKzDTub0Ko4LfIgaERvRuwyaNV78mJs7cpIgZaDl6RJui4o49lHwwCM0526zA== - dependencies: - "@ethersproject/address" "^5.5.0" - "@ethersproject/bignumber" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/constants" "^5.5.0" - "@ethersproject/keccak256" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/rlp" "^5.5.0" - "@ethersproject/signing-key" "^5.5.0" - "@ethersproject/transactions@^5.6.2": version "5.6.2" resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.6.2.tgz#793a774c01ced9fe7073985bb95a4b4e57a6370b" @@ -942,16 +783,7 @@ "@ethersproject/rlp" "^5.7.0" "@ethersproject/signing-key" "^5.7.0" -"@ethersproject/units@^5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.6.1.tgz#ecc590d16d37c8f9ef4e89e2005bda7ddc6a4e6f" - integrity sha512-rEfSEvMQ7obcx3KWD5EWWx77gqv54K6BKiZzKxkQJqtpriVsICrktIQmKl8ReNToPeIYPnFHpXvKpi068YFZXw== - dependencies: - "@ethersproject/bignumber" "^5.6.2" - "@ethersproject/constants" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - -"@ethersproject/units@^5.7.0": +"@ethersproject/units@^5.6.1", "@ethersproject/units@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.7.0.tgz#637b563d7e14f42deeee39245275d477aae1d8b1" integrity sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg== @@ -981,17 +813,6 @@ "@ethersproject/transactions" "^5.6.2" "@ethersproject/wordlists" "^5.6.1" -"@ethersproject/web@^5.5.0": - version "5.5.1" - resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.5.1.tgz#cfcc4a074a6936c657878ac58917a61341681316" - integrity sha512-olvLvc1CB12sREc1ROPSHTdFCdvMh0J5GSJYiQg2D0hdD4QmJDy8QYDb1CvoqD/bF1c++aeKv2sR5uduuG9dQg== - dependencies: - "@ethersproject/base64" "^5.5.0" - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - "@ethersproject/properties" "^5.5.0" - "@ethersproject/strings" "^5.5.0" - "@ethersproject/web@^5.6.1": version "5.6.1" resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.6.1.tgz#6e2bd3ebadd033e6fe57d072db2b69ad2c9bdf5d" @@ -1683,17 +1504,7 @@ ajv@^6.10.0, ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.0: - version "8.9.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.9.0.tgz#738019146638824dea25edcf299dcba1b0e7eb18" - integrity sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ== - dependencies: - fast-deep-equal "^3.1.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - uri-js "^4.2.2" - -ajv@^8.11.0: +ajv@^8.0.0, ajv@^8.11.0: version "8.11.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== From 587bc381c3b255e4821e4846f284ba8c50b02801 Mon Sep 17 00:00:00 2001 From: Wan <495709+wa0x6e@users.noreply.github.com> Date: Wed, 31 Jan 2024 18:34:16 +0700 Subject: [PATCH 593/815] fix: fix invalid block value passed to thegraph (#1399) --- src/strategies/synthetix/index.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/strategies/synthetix/index.ts b/src/strategies/synthetix/index.ts index c05ec10af..928a50e04 100644 --- a/src/strategies/synthetix/index.ts +++ b/src/strategies/synthetix/index.ts @@ -24,22 +24,27 @@ const MED_PRECISE_UNIT = 1e18; const SCALING_FACTOR = 1e5; function returnGraphParams(snapshot: number | string, addresses: string[]) { - return { + const params = { snxholders: { __args: { where: { id_in: addresses.map((address: string) => address.toLowerCase()) }, - first: 1000, - block: { - number: snapshot - } + first: 1000 }, id: true, initialDebtOwnership: true, debtEntryAtIndex: true } }; + + if (snapshot !== 'latest') { + (params.snxholders.__args as any).block = { + number: snapshot + }; + } + + return params; } const loadLastDebtLedgerEntry = async ( From 1a9c44a177aacbd762c3cb18aeb6e225589ddda9 Mon Sep 17 00:00:00 2001 From: Wan <495709+wa0x6e@users.noreply.github.com> Date: Wed, 31 Jan 2024 18:47:16 +0700 Subject: [PATCH 594/815] fix: enforce minimum decimal value (#1400) Co-authored-by: Chaitanya --- src/strategies/erc20-balance-of/schema.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/strategies/erc20-balance-of/schema.json b/src/strategies/erc20-balance-of/schema.json index 2113da8b8..0d5455492 100644 --- a/src/strategies/erc20-balance-of/schema.json +++ b/src/strategies/erc20-balance-of/schema.json @@ -23,7 +23,8 @@ "decimals": { "type": "number", "title": "Decimals", - "examples": ["e.g. 18"] + "examples": ["e.g. 18"], + "minimum": 0 } }, "required": ["address", "decimals"], From e1f49b21a4d9d5310e0ecd7d0674e5b4cb7b8a1a Mon Sep 17 00:00:00 2001 From: Wan <495709+wa0x6e@users.noreply.github.com> Date: Wed, 31 Jan 2024 20:09:36 +0700 Subject: [PATCH 595/815] fix: do not log response body on network error (#1401) --- src/strategies/api-v2/index.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/strategies/api-v2/index.ts b/src/strategies/api-v2/index.ts index 505e6804d..fdf1cb006 100644 --- a/src/strategies/api-v2/index.ts +++ b/src/strategies/api-v2/index.ts @@ -56,9 +56,10 @@ export async function strategy( responseData = JSON.parse(responseData); } catch (e) { throw new Error( - `[api-v2] Errors found in API: URL: ${url}, Status: ${ - response.status - }, Response: ${responseData.substring(0, 512)}` + `[api-v2] Errors found in API: URL: ${url}, Status: ${response.status}` + + response.ok + ? `, Response: ${responseData.substring(0, 512)}` + : '' ); } From d52983061e7f3c9a06fa2762aceb0bce0c342764 Mon Sep 17 00:00:00 2001 From: Marsot Pierre Date: Mon, 5 Feb 2024 10:33:55 +0100 Subject: [PATCH 596/815] twavp-4 new vp formula (#1403) --- src/strategies/index.ts | 2 + .../sd-vote-boost-twavp-v4/README.md | 28 +++ .../sd-vote-boost-twavp-v4/examples.json | 32 +++ .../sd-vote-boost-twavp-v4/index.ts | 198 ++++++++++++++++++ 4 files changed, 260 insertions(+) create mode 100644 src/strategies/sd-vote-boost-twavp-v4/README.md create mode 100644 src/strategies/sd-vote-boost-twavp-v4/examples.json create mode 100644 src/strategies/sd-vote-boost-twavp-v4/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 6759234d2..b0c920049 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -363,6 +363,7 @@ import * as gelatoStaking from './gelato-staking'; import * as erc4626AssetsOf from './erc4626-assets-of'; import * as sdVoteBoostTWAVPV2 from './sd-vote-boost-twavp-v2'; import * as sdVoteBoostTWAVPV3 from './sd-vote-boost-twavp-v3'; +import * as sdVoteBoostTWAVPV4 from './sd-vote-boost-twavp-v4'; import * as sdVoteBoostTWAVPVsdToken from './sd-vote-boost-twavp-vsdtoken'; import * as sdVoteBoostTWAVPBalanceof from './sd-vote-boost-twavp-balanceof'; import * as friendTech from './friend-tech'; @@ -781,6 +782,7 @@ const strategies = { 'friend-tech': friendTech, 'sd-vote-boost-twavp-v2': sdVoteBoostTWAVPV2, 'sd-vote-boost-twavp-v3': sdVoteBoostTWAVPV3, + 'sd-vote-boost-twavp-v4': sdVoteBoostTWAVPV4, 'sd-vote-boost-twavp-vsdtoken': sdVoteBoostTWAVPVsdToken, 'sd-vote-boost-twavp-balanceof': sdVoteBoostTWAVPBalanceof, moonbase: moonbase, diff --git a/src/strategies/sd-vote-boost-twavp-v4/README.md b/src/strategies/sd-vote-boost-twavp-v4/README.md new file mode 100644 index 000000000..470a65059 --- /dev/null +++ b/src/strategies/sd-vote-boost-twavp-v4/README.md @@ -0,0 +1,28 @@ +# sd-vote-boost-twavp-v4 + +This strategy is used by Stake DAO to vote with sdToken using Time Weighted Averaged Voting Power (TWAVP) system and adapted for veSDT boost delegation with possibility to whiteliste address to by pass TWAVP. + +``` +VotingPower(user) = veToken.balanceOf(liquidLocker) * (average.sdTokenGauge.working_balances(user) / sdTokenGauge.working_supply) +``` + +>_sampleSize: in days_ +>_sampleStep: the number of block for `average` calculation (max 5)_ + +Here is an example of parameters: + +```json +{ + "veToken": "0x5f3b5DfEb7B28CDbD7FAba78963EE202a494e2A2", + "liquidLocker": "0x52f541764E6e90eeBc5c21Ff570De0e2D63766B6", + "sdTokenGauge": "0x7f50786A0b15723D741727882ee99a0BF34e3466", + "sdToken": "0xD1b5651E55D4CeeD36251c61c50C889B36F6abB5", + "pools": ["0xca0253a98d16e9c1e3614cafda19318ee69772d0"], + "symbol": "sdToken", + "decimals": 18, + "sampleSize": 10, + "sampleStep": 5, + "botAddress": "", + "whiteListedAddress": ["0x1c0D72a330F2768dAF718DEf8A19BAb019EEAd09"] +} +``` \ No newline at end of file diff --git a/src/strategies/sd-vote-boost-twavp-v4/examples.json b/src/strategies/sd-vote-boost-twavp-v4/examples.json new file mode 100644 index 000000000..cb3dd2f42 --- /dev/null +++ b/src/strategies/sd-vote-boost-twavp-v4/examples.json @@ -0,0 +1,32 @@ +[ + { + "name": "Stake DAO vote boost using TWAVP V4", + "strategy": { + "name": "sd-vote-boost-twavp-v4", + "params": { + "veToken": "0x5f3b5DfEb7B28CDbD7FAba78963EE202a494e2A2", + "liquidLocker": "0x52f541764E6e90eeBc5c21Ff570De0e2D63766B6", + "sdTokenGauge": "0x7f50786A0b15723D741727882ee99a0BF34e3466", + "sdToken": "0xD1b5651E55D4CeeD36251c61c50C889B36F6abB5", + "pools": ["0xf7b55c3732ad8b2c2da7c24f30a69f55c54fb717","0xca0253a98d16e9c1e3614cafda19318ee69772d0"], + "symbol": "sdToken", + "decimals": 18, + "sampleSize": 10, + "sampleStep": 5, + "botAddress": "0xb4542526AfeE2FdA1D584213D1521272a398B42a", + "whiteListedAddress": ["0x1c0D72a330F2768dAF718DEf8A19BAb019EEAd09"] + } + }, + "network": "1", + "addresses": [ + "0x26a5994176d34D128C5e6ab80Fa0882A7df4fF00", + "0xDdB50FfDbA4D89354E1088e4EA402de895562173", + "0xb4542526AfeE2FdA1D584213D1521272a398B42a", + "0xE1F7eaD40d33eeF30dCf15eB5efC45409001aAB8", + "0xb0e83C2D71A991017e0116d58c5765Abc57384af", + "0x1c0D72a330F2768dAF718DEf8A19BAb019EEAd09", + "0xC6625129C9df3314a4dd604845488f4bA62F9dB8" + ], + "snapshot": 19133549 + } +] diff --git a/src/strategies/sd-vote-boost-twavp-v4/index.ts b/src/strategies/sd-vote-boost-twavp-v4/index.ts new file mode 100644 index 000000000..c2a2c11c8 --- /dev/null +++ b/src/strategies/sd-vote-boost-twavp-v4/index.ts @@ -0,0 +1,198 @@ +import { multicall } from '../../utils'; +import { BigNumber } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; + +export const author = 'pierremarsotlyon1'; +export const version = '0.0.1'; + +// Used ABI +const abi = [ + 'function balanceOf(address account) external view returns (uint256)', + 'function working_supply() external view returns (uint256)', + 'function totalSupply() external view returns (uint256)', + 'function working_balances(address account) external view returns (uint256)', + 'function balances(uint256 i) external view returns (uint256)', +]; + +const MIN_BOOST = 0.4; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + // Maximum of 5 multicall! + if (options.sampleStep > 5) { + throw new Error('maximum of 5 call'); + } + + // Maximum of 20 whitelisted address + if (options.whiteListedAddress.length > 20) { + throw new Error('maximum of 20 whitelisted address'); + } + + // Maximum of 500 pools address + if (options.pools.length > 500) { + throw new Error('maximum of 500 pools'); + } + + const calls: any[] = []; + calls.push([options.sdToken, 'totalSupply', []]); + + for (const pool of options.pools) { + calls.push([pool, 'balances', [1]]); + } + calls.push([options.veToken, 'balanceOf', [options.liquidLocker]]); + + // --- Create block number list for twavp + // Obtain last block number + // Create block tag + let blockTag = 0; + if (typeof snapshot === 'number') { + blockTag = snapshot; + } else { + blockTag = await provider.getBlockNumber(); + } + + // Create block list + const blockList = getPreviousBlocks( + blockTag, + options.sampleStep, + options.sampleSize + ); + + // Query working balance of users + const workingBalanceQuery = addresses.map((address: any) => [ + options.sdTokenGauge, + 'working_balances', + [address] + ]); + + // Execute multicall `sampleStep` times + const response: any[] = []; + for (let i = 0; i < options.sampleStep; i++) { + // Use good block number + blockTag = blockList[i]; + + const loopCalls: any[] = []; + + // Add mutlicall response to array + if (i === options.sampleStep - 1) { + // End + loopCalls.push([options.sdTokenGauge, 'working_supply']); + loopCalls.push(...workingBalanceQuery); + loopCalls.push(...calls); + } else { + loopCalls.push(...workingBalanceQuery); + } + + response.push( + await multicall(network, provider, abi, loopCalls, { blockTag }) + ); + } + + const workingSupply = parseFloat(formatUnits(response[response.length - 1].shift()[0], 18)); + const lockerVotingPower = parseFloat(formatUnits(response[response.length - 1].pop()[0], 18)); + + const poolsBalances = options.pools.map(() => response[response.length - 1].pop()[0]); + const sumPoolsBalance = parseFloat(formatUnits(poolsBalances.reduce((acc, balance) => acc.add(balance), BigNumber.from(0)), 18)); + + const sdTknSupply = parseFloat(formatUnits(response[response.length - 1].pop()[0], 18)); + + const liquidityVoteFee = MIN_BOOST + * sumPoolsBalance + * lockerVotingPower + / sdTknSupply; + + const totalUserVotes = lockerVotingPower - liquidityVoteFee; + + return Object.fromEntries( + Array(addresses.length) + .fill('x') + .map((_, i) => { + // Init array of working balances for user + const userWorkingBalances: BigNumber[] = []; + + for (let j = 0; j < options.sampleStep; j++) { + // Add working balance to array. + userWorkingBalances.push(response[j].shift()[0]); + } + + if (addresses[i].toLowerCase() === options.botAddress.toLowerCase()) { + return [ + addresses[i], + Number(liquidityVoteFee) + ]; + } else { + // Get average working balance. + const averageWorkingBalance = parseFloat( + formatUnits(average( + userWorkingBalances, + addresses[i], + options.whiteListedAddress + ), 18)); + + // Calculate voting power. + const userVote = + workingSupply != 0 + ? (averageWorkingBalance / workingSupply * totalUserVotes) + : 0; + + // Return address and voting power + return [addresses[i], Number(userVote)]; + } + }) + ); +} + +function getPreviousBlocks( + currentBlockNumber: number, + numberOfBlocks: number, + daysInterval: number +): number[] { + // Estimate number of blocks per day + const blocksPerDay = 86400 / 12; + // Calculate total blocks interval + const totalBlocksInterval = blocksPerDay * daysInterval; + // Calculate block interval + const blockInterval = totalBlocksInterval / (numberOfBlocks - 1); + + // Init array of block numbers + const blockNumbers: number[] = []; + + for (let i = 0; i < numberOfBlocks; i++) { + // Calculate block number + const blockNumber = + currentBlockNumber - totalBlocksInterval + blockInterval * i; + // Add block number to array + blockNumbers.push(Math.round(blockNumber)); + } + + // Return array of block numbers + return blockNumbers; +} + +function average( + numbers: BigNumber[], + address: string, + whiteListedAddress: string[] +): BigNumber { + // If no numbers, return 0 to avoid division by 0. + if (numbers.length === 0) return BigNumber.from(0); + + // If address is whitelisted, return most recent working balance. i.e. no twavp applied. + if (whiteListedAddress.includes(address)) return numbers[numbers.length - 1]; + + // Init sum + let sum = BigNumber.from(0); + // Loop through all elements and add them to sum + for (let i = 0; i < numbers.length; i++) { + sum = sum.add(numbers[i]); + } + + // Return sum divided by array length to get mean + return sum.div(numbers.length); +} From 0c9cb65df45269335355c884545a6a066baaa90d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 10 Feb 2024 23:35:57 +0400 Subject: [PATCH 597/815] Automated lint (#1406) Co-authored-by: wa0x6e --- .../sd-vote-boost-twavp-v4/examples.json | 5 +- .../sd-vote-boost-twavp-v4/index.ts | 55 ++++++++++++------- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/src/strategies/sd-vote-boost-twavp-v4/examples.json b/src/strategies/sd-vote-boost-twavp-v4/examples.json index cb3dd2f42..0ba8a46e2 100644 --- a/src/strategies/sd-vote-boost-twavp-v4/examples.json +++ b/src/strategies/sd-vote-boost-twavp-v4/examples.json @@ -8,7 +8,10 @@ "liquidLocker": "0x52f541764E6e90eeBc5c21Ff570De0e2D63766B6", "sdTokenGauge": "0x7f50786A0b15723D741727882ee99a0BF34e3466", "sdToken": "0xD1b5651E55D4CeeD36251c61c50C889B36F6abB5", - "pools": ["0xf7b55c3732ad8b2c2da7c24f30a69f55c54fb717","0xca0253a98d16e9c1e3614cafda19318ee69772d0"], + "pools": [ + "0xf7b55c3732ad8b2c2da7c24f30a69f55c54fb717", + "0xca0253a98d16e9c1e3614cafda19318ee69772d0" + ], "symbol": "sdToken", "decimals": 18, "sampleSize": 10, diff --git a/src/strategies/sd-vote-boost-twavp-v4/index.ts b/src/strategies/sd-vote-boost-twavp-v4/index.ts index c2a2c11c8..14005dd39 100644 --- a/src/strategies/sd-vote-boost-twavp-v4/index.ts +++ b/src/strategies/sd-vote-boost-twavp-v4/index.ts @@ -11,7 +11,7 @@ const abi = [ 'function working_supply() external view returns (uint256)', 'function totalSupply() external view returns (uint256)', 'function working_balances(address account) external view returns (uint256)', - 'function balances(uint256 i) external view returns (uint256)', + 'function balances(uint256 i) external view returns (uint256)' ]; const MIN_BOOST = 0.4; @@ -94,18 +94,32 @@ export async function strategy( ); } - const workingSupply = parseFloat(formatUnits(response[response.length - 1].shift()[0], 18)); - const lockerVotingPower = parseFloat(formatUnits(response[response.length - 1].pop()[0], 18)); + const workingSupply = parseFloat( + formatUnits(response[response.length - 1].shift()[0], 18) + ); + const lockerVotingPower = parseFloat( + formatUnits(response[response.length - 1].pop()[0], 18) + ); - const poolsBalances = options.pools.map(() => response[response.length - 1].pop()[0]); - const sumPoolsBalance = parseFloat(formatUnits(poolsBalances.reduce((acc, balance) => acc.add(balance), BigNumber.from(0)), 18)); + const poolsBalances = options.pools.map( + () => response[response.length - 1].pop()[0] + ); + const sumPoolsBalance = parseFloat( + formatUnits( + poolsBalances.reduce( + (acc, balance) => acc.add(balance), + BigNumber.from(0) + ), + 18 + ) + ); - const sdTknSupply = parseFloat(formatUnits(response[response.length - 1].pop()[0], 18)); + const sdTknSupply = parseFloat( + formatUnits(response[response.length - 1].pop()[0], 18) + ); - const liquidityVoteFee = MIN_BOOST - * sumPoolsBalance - * lockerVotingPower - / sdTknSupply; + const liquidityVoteFee = + (MIN_BOOST * sumPoolsBalance * lockerVotingPower) / sdTknSupply; const totalUserVotes = lockerVotingPower - liquidityVoteFee; @@ -122,23 +136,24 @@ export async function strategy( } if (addresses[i].toLowerCase() === options.botAddress.toLowerCase()) { - return [ - addresses[i], - Number(liquidityVoteFee) - ]; + return [addresses[i], Number(liquidityVoteFee)]; } else { // Get average working balance. const averageWorkingBalance = parseFloat( - formatUnits(average( - userWorkingBalances, - addresses[i], - options.whiteListedAddress - ), 18)); + formatUnits( + average( + userWorkingBalances, + addresses[i], + options.whiteListedAddress + ), + 18 + ) + ); // Calculate voting power. const userVote = workingSupply != 0 - ? (averageWorkingBalance / workingSupply * totalUserVotes) + ? (averageWorkingBalance / workingSupply) * totalUserVotes : 0; // Return address and voting power From ba4ca8a8e75730a75a25e73df9c3845a0e66b258 Mon Sep 17 00:00:00 2001 From: defininja <91393134+defininja@users.noreply.github.com> Date: Wed, 21 Feb 2024 11:45:43 +0530 Subject: [PATCH 598/815] [planet-finance-v2] Voting Strategy updated for New V3 Farm (#1402) * code for new voting strategy * new test address * code refactored after linting * removed extra multicall * remove extra call for exchange rate * Update src/strategies/planet-finance-v2/index.ts --------- Co-authored-by: defininja Co-authored-by: defininja Co-authored-by: Chaitanya --- .../planet-finance-v2/examples.json | 2 +- src/strategies/planet-finance-v2/index.ts | 123 +++++++++++------- 2 files changed, 76 insertions(+), 49 deletions(-) diff --git a/src/strategies/planet-finance-v2/examples.json b/src/strategies/planet-finance-v2/examples.json index bfefc7469..d9fbecf09 100644 --- a/src/strategies/planet-finance-v2/examples.json +++ b/src/strategies/planet-finance-v2/examples.json @@ -15,6 +15,6 @@ "0x19d4051F7740e6AA4494EBCc655a70f524878346", "0xa14EdA7b66Fa8B030905A57D97Da57553c56Ec0D" ], - "snapshot": 22001625 + "snapshot": 35721490 } ] diff --git a/src/strategies/planet-finance-v2/index.ts b/src/strategies/planet-finance-v2/index.ts index 637fe0927..c316c6364 100644 --- a/src/strategies/planet-finance-v2/index.ts +++ b/src/strategies/planet-finance-v2/index.ts @@ -4,36 +4,34 @@ import { Multicaller } from '../../utils'; import { strategy as erc20BalanceOfStrategy } from '../erc20-balance-of'; export const author = 'defininja'; -export const version = '0.0.2'; +export const version = '0.1.0'; -const planetFinanceFarmAbi = [ - 'function userInfo(uint256, address) view returns (uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256)' +//abi +// v3 farm abi for user-info +const planetFinanceV3FarmAbi = [ + 'function userInfo(uint256, address) view returns (uint256, uint256, uint256, uint256)' ]; +// erc20 abi for total supply and balance of const bep20Abi: any = [ 'function totalSupply() view returns (uint256)', 'function balanceOf(address) view returns (uint256)' ]; +//v2 aqua infinity pool abi const aquaInfinityAbi = [ 'function getUserGtokenBal(address) view returns (uint256)' ]; -const aquaLendingAbi = [ - 'function getAccountSnapshot(address) view returns (uint256,uint256,uint256,uint256)' -]; - -const gammaFarmAddress = '0x9EBce8B8d535247b2a0dfC0494Bc8aeEd7640cF9'; - -const aquaAddress = '0x72B7D61E8fC8cF971960DD9cfA59B8C829D91991'; - -const aquaBnbLpTokenAddress = '0x03028D2F8B275695A1c6AFB69A4765e3666e36d9'; +//addresses +const aquaAddress = '0x72B7D61E8fC8cF971960DD9cfA59B8C829D91991'; //aqua token address +const aquaBnbLpTokenAddress = '0x03028D2F8B275695A1c6AFB69A4765e3666e36d9'; //v2 aqua-bnb lp token address +const aquaInfinityAddress = '0xddd0626BB795BdF9CfA925da5102eFA5E7008114'; //v2 aqua infinity pool address +const v3FarmAddress = '0x405960AEAad7Ec8B419DEdb511dfe9D112dFc22d'; //v3 farm address +const aquaBtcbLpTokenAddress = '0x70B606c23D6E786BE7accAf31C8fEcEaf846AdF3'; // v3 aqua-btcb lp token address -const aquaLendingAddress = '0x2f5d7A9D8D32c16e41aF811744DB9f15d853E0A5'; - -const aquaInfinityAddress = '0xddd0626BB795BdF9CfA925da5102eFA5E7008114'; - -const increase_in_voting = 5; //increase 5 times +const increase_in_voting = 5; //increase weight 5 times while voting +const gAquaExchangeRate = "200000000416761667681474308"; //exchange rate of gAqua to aqua export async function strategy( space, @@ -49,7 +47,7 @@ export async function strategy( blockTag }); - // returns user's aqua balance ofr their address + // returns user's aqua balance for their wallet address let score: any = erc20BalanceOfStrategy( space, network, @@ -72,77 +70,106 @@ export async function strategy( { blockTag } ); - // returns user's aqua balance in aqua-bnb pool - let usersNewAquaBnbVaultBalances: any = multicall( + // returns user's shares in v3 aqua-btcb pool + let usersNewAquaBtcbVaultBalances: any = multicall( network, provider, - planetFinanceFarmAbi, + planetFinanceV3FarmAbi, addresses.map((address: any) => [ - gammaFarmAddress, + v3FarmAddress, 'userInfo', - ['2', address] + ['1', address] ]), { blockTag } ); - //AQUA LENDING - let usersAquaInLending: any = multicall( + // returns user's aqua balance in aqua pool + let usersNewAquaPoolBalances: any = multicall( network, provider, - aquaLendingAbi, + planetFinanceV3FarmAbi, addresses.map((address: any) => [ - aquaLendingAddress, - 'getAccountSnapshot', - [address] + v3FarmAddress, + 'userInfo', + ['2', address] ]), { blockTag } ); + // get all results const result = await Promise.all([ score, usergAquaBalInAquaInfinityVault, - usersNewAquaBnbVaultBalances, - usersAquaInLending + usersNewAquaBtcbVaultBalances, + usersNewAquaPoolBalances ]); - score = result[0]; - usergAquaBalInAquaInfinityVault = result[1]; - usersNewAquaBnbVaultBalances = result[2]; - usersAquaInLending = result[3]; + score = result[0]; //aqua balance of user's wallet address + usergAquaBalInAquaInfinityVault = result[1]; //aqua balance of infinitiy vault + usersNewAquaBtcbVaultBalances = result[2]; //shares in v3 aqua-btcb pool + usersNewAquaPoolBalances = result[3]; // shares in v3 aqua pool + //AQUA-BNB - // total supply of aqua bnb lp token + // total supply of v2 aqua bnb lp token erc20Multi.call('aquaBnbTotalSupply', aquaBnbLpTokenAddress, 'totalSupply'); - // aqua balance of aqua bnb lp + // aqua balance of v2 aqua bnb lp erc20Multi.call('aquaBnbAquaBal', aquaAddress, 'balanceOf', [ aquaBnbLpTokenAddress ]); - const erc20Result = await erc20Multi.execute(); + //AQUA-BTCB + // total supply of v3 aqua btcb lp token + erc20Multi.call('aquaBtcbTotalSupply', aquaBtcbLpTokenAddress, 'totalSupply'); - const totalSupply = erc20Result.aquaBnbTotalSupply.toString(); + // aqua balance of v3 aqua btcb lp + erc20Multi.call('aquaBtcbAquaBal', aquaAddress, 'balanceOf', [ + aquaBtcbLpTokenAddress + ]); - const contractAquaBalance = erc20Result.aquaBnbAquaBal.toString(); + // execute multi calls + const erc20Result = await erc20Multi.execute(); + // total supply of v3 aqua btcb lp token + const totalSupplyAquabtcb = erc20Result.aquaBtcbTotalSupply.toString(); + // aqua balance of v3 aqua btcb lp + const contractAquaBtcbBalance = erc20Result.aquaBtcbAquaBal.toString(); const res = Object.fromEntries( Object.entries(score).map((address: any, index) => { + /* + user's voting score = user's wallet aqua balance + aqua balance in v2 aqua-bnb pool + 5 times the aqua balance in v2 infinity vault + + aqua balance in lending + 5 times the aqua balance in v3 aqua pool + aqua balance in v3 aqua-btcb pool + */ return [ address[0], address[1] + - (parseFloat( - formatUnits(usersNewAquaBnbVaultBalances[index]['0'].toString(), 18) - ) / - parseFloat(formatUnits(totalSupply, 18))) * - parseFloat(formatUnits(contractAquaBalance, 18)) + parseFloat( formatUnits(usergAquaBalInAquaInfinityVault[index].toString(), 18) ) * - parseFloat(formatUnits(usersAquaInLending[index]['3'], 18)) * + parseFloat(formatUnits(gAquaExchangeRate, 18)) * increase_in_voting + - parseFloat(formatUnits(usersAquaInLending[index]['1'], 18)) * - parseFloat(formatUnits(usersAquaInLending[index]['3'], 18)) + increase_in_voting * + parseFloat( + formatUnits(usersNewAquaPoolBalances[index]['2'].toString(), 18) + ) + + (parseFloat( + formatUnits( + usersNewAquaBtcbVaultBalances[index]['2'].toString(), + 18 + ) + ) == 0 + ? 0 + : (parseFloat( + formatUnits( + usersNewAquaBtcbVaultBalances[index]['2'].toString(), + 18 + ) + ) / + parseFloat(formatUnits(totalSupplyAquabtcb, 18))) * + parseFloat(formatUnits(contractAquaBtcbBalance, 18)) + ) ]; }) ); From 27316d2beae4e7559c7d94e846a0ef5136a74570 Mon Sep 17 00:00:00 2001 From: Razvan Gabriel Apostu Date: Wed, 21 Feb 2024 08:20:07 +0200 Subject: [PATCH 599/815] chore: add new networks to sablier, cleanup config (#1404) --- src/strategies/sablier-v2/configuration.ts | 55 +++++++++------------- 1 file changed, 21 insertions(+), 34 deletions(-) diff --git a/src/strategies/sablier-v2/configuration.ts b/src/strategies/sablier-v2/configuration.ts index f29a36689..d2ef5bcf9 100644 --- a/src/strategies/sablier-v2/configuration.ts +++ b/src/strategies/sablier-v2/configuration.ts @@ -7,78 +7,65 @@ const chains = { arbitrum: '42161', avalanche: '43114', + base: '8453', bsc: '56', ethereum: '1', goerli: '5', gnosis: '100', optimism: '10', - polygon: '137' + optimismSepolia: '11155420', + polygon: '137', + scroll: '534352', + sepolia: '11155111' }; const deployments = { [chains.arbitrum]: { - contracts: [ - '0x197d655f3be03903fd25e7828c3534504bfe525e', // SablierV2LockupLinear - '0xa9efbef1a35ff80041f567391bdc9813b2d50197' // SablierV2LockupDynamic - ], subgraph: 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2-arbitrum' }, [chains.avalanche]: { - contracts: [ - '0x610346e9088afa70d6b03e96a800b3267e75ca19', // SablierV2LockupLinear - '0x665d1c8337f1035cfbe13dd94bb669110b975f5f' // SablierV2LockupDynamic - ], subgraph: 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2-avalanche' }, + [chains.base]: { + subgraph: + 'https://api.studio.thegraph.com/query/57079/sablier-v2-base/version/latest' + }, [chains.bsc]: { - contracts: [ - '0x3fe4333f62a75c2a85c8211c6aefd1b9bfde6e51', // SablierV2LockupLinear - '0xf2f3fef2454dca59eca929d2d8cd2a8669cc6214' // SablierV2LockupDynamic - ], subgraph: 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2-bsc' }, - [chains.ethereum]: { - contracts: [ - '0xb10daee1fcf62243ae27776d7a92d39dc8740f95', // SablierV2LockupLinear - '0x39efdc3dbb57b2388ccc4bb40ac4cb1226bc9e44' // SablierV2LockupDynamic - ], subgraph: 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2' }, [chains.goerli]: { - contracts: [ - '0x6e3678c005815ab34986d8d66a353cd3699103de', // SablierV2LockupLinear - '0x4be70ede968e9dba12db42b9869bec66bedc17d7' // SablierV2LockupDynamic - ], subgraph: 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2-goerli' }, [chains.gnosis]: { - contracts: [ - '0x685e92c9ca2bb23f1b596d0a7d749c0603e88585', // SablierV2LockupLinear - '0xeb148e4ec13aaa65328c0ba089a278138e9e53f9' // SablierV2LockupDynamic - ], subgraph: 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2-gnosis' }, [chains.optimism]: { - contracts: [ - '0xb923abdca17aed90eb5ec5e407bd37164f632bfd', // SablierV2LockupLinear - '0x6f68516c21e248cddfaf4898e66b2b0adee0e0d6' // SablierV2LockupDynamic - ], subgraph: 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2-optimism' }, + [chains.optimismSepolia]: { + subgraph: + 'https://api.studio.thegraph.com/query/57079/sablier-v2-optimism-sepolia/version/latest' + }, [chains.polygon]: { - contracts: [ - '0x67422c3e36a908d5c3237e9cffeb40bde7060f6e', // SablierV2LockupLinear - '0x7313addb53f96a4f710d3b91645c62b434190725' // SablierV2LockupDynamic - ], subgraph: 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2-polygon' + }, + [chains.scroll]: { + subgraph: + 'https://api.studio.thegraph.com/query/57079/sablier-v2-scroll/version/latest' + }, + [chains.sepolia]: { + subgraph: + 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2-sepolia' } }; From d8f00b2f81275931f5cce33ac528244a4e176c10 Mon Sep 17 00:00:00 2001 From: Kenny Rowe Date: Tue, 20 Feb 2024 22:25:26 -0800 Subject: [PATCH 600/815] [urbit-galaxies] Add Urbit Galaxy Voting - compatible with any Azimuth deployment (#1405) * Add the Urbit Galaxy voting strategy * add readme * Delete src/strategies/intex.ts --------- Co-authored-by: Chaitanya --- src/strategies/index.ts | 4 +- src/strategies/urbit-galaxies/README.md | 13 +++++ src/strategies/urbit-galaxies/examples.json | 30 +++++++++++ src/strategies/urbit-galaxies/index.ts | 59 +++++++++++++++++++++ 4 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 src/strategies/urbit-galaxies/README.md create mode 100644 src/strategies/urbit-galaxies/examples.json create mode 100644 src/strategies/urbit-galaxies/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index b0c920049..92f2d5dda 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -1,6 +1,7 @@ import { readFileSync } from 'fs'; import path from 'path'; +import * as urbitGalaxies from './urbit-galaxies/index'; import * as ecoVotingPower from './eco-voting-power'; import * as dpsNFTStrategy from './dps-nft-strategy'; import * as dpsNFTStrategyNova from './dps-nft-strategy-nova'; @@ -829,7 +830,8 @@ const strategies = { 'vendor-v2-borrower-collateral-balance-of': vendorV2BorrowerCollateralBalanceOf, 'volt-voting-power': voltVotingPower, - 'xdai-stakers-and-holders': xdaiStakersAndHolders + 'xdai-stakers-and-holders': xdaiStakersAndHolders, + 'urbit-galaxies': urbitGalaxies }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/urbit-galaxies/README.md b/src/strategies/urbit-galaxies/README.md new file mode 100644 index 000000000..305fe0c53 --- /dev/null +++ b/src/strategies/urbit-galaxies/README.md @@ -0,0 +1,13 @@ +# Signaling for Urbit Galaxies + +This strategy returns the voting power of all Urbit galaxies. If the Voting Proxy address is not set then the Owner address of the galaxy is used. + +Here is an example of parameters: + +```json +{ + "erc721Address": "0x33eecbf908478c10614626a9d304bfe18b78dd73", + "votingProxyAddress": "0x223c067F8CF28ae173EE5CafEa60cA44C335fecB", + "symbol": "URBITGALAXY" +} +``` diff --git a/src/strategies/urbit-galaxies/examples.json b/src/strategies/urbit-galaxies/examples.json new file mode 100644 index 000000000..11a9867fc --- /dev/null +++ b/src/strategies/urbit-galaxies/examples.json @@ -0,0 +1,30 @@ +[ + { + "name": "ERC-721 with TokenID Urbit Galaxies with Proxy", + "strategy": { + "name": "urbit-galaxies", + "params": { + "erc721Address": "0x33eecbf908478c10614626a9d304bfe18b78dd73", + "votingProxyAddress": "0x223c067F8CF28ae173EE5CafEa60cA44C335fecB", + "symbol": "URBITGALAXY" + } + }, + "network": "1", + "addresses": [ + "0xb73532B04FB598F5d719Ec40be68DB02F798bCf3", + "0x0e49ab776681630f34d0f0c57D261fD5918f51C8", + "0xCAEDf5af5D421EBEff1e7a497b5Af1Aba1795b94", + "0xD5e69E7C2EAf78a544b8d1B5cE261A0a698ac3E7", + "0x24BfBd0bF3Be1a211E699324294C8F30E73b66eC", + "0x82B185E172Dfd340DC23E553Ef26258609C3cE2e", + "0x61c97a1E7C9ddaE1f11e313e84a3ad921E2CE4e6", + "0xD977B146acCacf8701A56A97d2C98955F28909e2", + "0x274d8716845D9eb95E29c0E2836B9c5aB2A76D40", + "0xFb7eA0EFfBFB887E822531DA3BEE747B89926eEB", + "0x48353A9aF7F835Aa7EA878FE56984F20eed8230C", + "0xC4E588Eb3ef88Fd8Bbbae554968bC82101b637e6" + + ], + "snapshot": 19179657 + } +] diff --git a/src/strategies/urbit-galaxies/index.ts b/src/strategies/urbit-galaxies/index.ts new file mode 100644 index 000000000..d24534093 --- /dev/null +++ b/src/strategies/urbit-galaxies/index.ts @@ -0,0 +1,59 @@ +// index.ts +import { multicall } from '../../utils'; + +export const author = 'kennyrowe'; +export const version = '0.1.0'; +export const name = 'urbitGalaxies'; + +const erc721ABI = [ + 'function ownerOf(uint256 tokenId) external view returns (address owner)' +]; + +const votingProxyABI = [ + 'function getVotingProxy(uint32 _point) external view returns (address)' +]; + +interface StrategyOptions { + erc721Address: string; // ERC-721 Contract address for Urbit galaxies + votingProxyAddress: string; // Voting Proxy contract address + symbol: string; // Token symbol (optional, for UI purposes) +} + +export async function strategy( + space: string, + network: string, + provider: any, + addresses: string[], + options: StrategyOptions, + snapshot: number | 'latest' +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const score = {} as Record; + + type MulticallParam = [string, string, any[]]; + const ownerCalls: MulticallParam[] = []; + const proxyCalls : MulticallParam[] = []; + for (let tokenId = 0; tokenId <= 255; tokenId++) { + ownerCalls.push([options.erc721Address, 'ownerOf', [tokenId]]); + proxyCalls.push([options.votingProxyAddress, 'getVotingProxy', [tokenId]]); + } + + const [ownerResponses, proxyResponses] = await Promise.all([ + multicall(network, provider, erc721ABI, ownerCalls, { blockTag }), + multicall(network, provider, votingProxyABI, proxyCalls, { blockTag }) + ]); + + ownerResponses.forEach((value, index) => { + const ownerAddress = value[0]; + const proxyAddress = proxyResponses[index][0]; + + // Determine the effective voter (proxy or owner) + const effectiveVoter = proxyAddress !== '0x0000000000000000000000000000000000000000' ? proxyAddress : ownerAddress; + + if (addresses.includes(effectiveVoter)) { + score[effectiveVoter] = (score[effectiveVoter] || 0) + 1; + } + }); + + return score; +} From d8ab99d97defc0144d980da7145f6d638adf2c44 Mon Sep 17 00:00:00 2001 From: Mitch <67759413+divine-comedian@users.noreply.github.com> Date: Wed, 21 Feb 2024 00:57:18 -0600 Subject: [PATCH 601/815] add minime-balance-supply strategy (#1409) Co-authored-by: Mitch Oz Co-authored-by: Chaitanya --- src/strategies/index.ts | 2 + .../README.md | 30 +++++++++++++ .../examples.json | 44 +++++++++++++++++++ .../index.ts | 37 ++++++++++++++++ 4 files changed, 113 insertions(+) create mode 100644 src/strategies/minime-balance-vs-supply-weighted/README.md create mode 100644 src/strategies/minime-balance-vs-supply-weighted/examples.json create mode 100644 src/strategies/minime-balance-vs-supply-weighted/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 92f2d5dda..d2d8d36a7 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -412,8 +412,10 @@ import * as unipoolSameToken from './unipool-same-token'; import * as vendorV2BorrowerCollateralBalanceOf from './vendor-v2-borrower-collateral-balance-of'; import * as voltVotingPower from './volt-voting-power'; import * as xdaiStakersAndHolders from './xdai-stakers-and-holders'; +import * as minimeBalanceVsSupplyWeighted from './minime-balance-vs-supply-weighted'; const strategies = { + 'minime-balance-vs-supply-weighted': minimeBalanceVsSupplyWeighted, 'cap-voting-power': capVotingPower, 'izumi-veizi': izumiVeiZi, 'eco-voting-power': ecoVotingPower, diff --git a/src/strategies/minime-balance-vs-supply-weighted/README.md b/src/strategies/minime-balance-vs-supply-weighted/README.md new file mode 100644 index 000000000..bf440f20d --- /dev/null +++ b/src/strategies/minime-balance-vs-supply-weighted/README.md @@ -0,0 +1,30 @@ +# minime-balance-vs-supply-weighted + +This strategy returns the percent of the total supply of a token that is held by voters in a snapshot multiplied by a weight. It is tailored to be used by a minime token contract but could be used by any token contract that has a function that can return the total/current supply of the given token. It additionaly can have a weight added to it. + +First this function will call the specific token contract by the input ABI view-only function (no args), it will save the response. After that it follows a standard erc20-balance-of-weighted strategy (h/t Tanz0rz) to get the token balance. We divide the balance by the total supply then multiply it by the weight to arrive at the final voting power. + +Here is an example of parameters: + +```json +{ + "address": "0x16ef294ed9aeca7541183f19e4a5d01cebab88fb", + "symbol": "REP", + "decimals": 18, + "weight": 0.5, + "methodABI": { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + } +} +``` diff --git a/src/strategies/minime-balance-vs-supply-weighted/examples.json b/src/strategies/minime-balance-vs-supply-weighted/examples.json new file mode 100644 index 000000000..bb72b4fde --- /dev/null +++ b/src/strategies/minime-balance-vs-supply-weighted/examples.json @@ -0,0 +1,44 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "minime-balance-vs-supply-weighted", + "params": { + "address": "0x16ef294ed9aeca7541183f19e4a5d01cebab88fb", + "symbol": "rGIV", + "decimals": 18, + "weight": 0.5, + "methodABI": { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + } + } + }, + "network": "10", + "addresses": [ + "0x5D28FE1e9F895464aab52287d85Ebff32B351674", + "0x6D97d65aDfF6771b31671443a6b9512104312d3D", + "0x839395e20bbB182fa440d08F850E6c7A8f6F0780", + "0x701d0ECB3BA780De7b2b36789aEC4493A426010a", + "0x00d18ca9782bE1CaEF611017c2Fbc1a39779A57C", + "0x826976d7C600d45FB8287CA1d7c76FC8eb732030", + "0xC46c67Bb7E84490D7EbdD0b8ecDaca68Cf3823F4", + "0xed8DB37778804A913670d9367aAf4F043AAd938b", + "0xA4D506434445Bb7303eA34A07bc38484cdC64a95", + "0x10a84b835C5df26f2A380B3E00bCC84A66cD2d34", + "0x2Ea846Dc38C6b6451909F1E7ff2bF613a96DC1F3", + "0x8F48094a12c8F99d616AE8F3305D5eC73cBAA6b6" + ], + "snapshot": 116220147 + } +] diff --git a/src/strategies/minime-balance-vs-supply-weighted/index.ts b/src/strategies/minime-balance-vs-supply-weighted/index.ts new file mode 100644 index 000000000..82d3f9699 --- /dev/null +++ b/src/strategies/minime-balance-vs-supply-weighted/index.ts @@ -0,0 +1,37 @@ +import { call } from '../../utils'; +import { strategy as erc20BalanceOfStrategy } from '../erc20-balance-of'; + +export const author = 'divine-comedian'; +export const version = '1.1.0'; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const totalSupply = await call( + provider, + [options.methodABI], + [options.address, options.methodABI.name], + { blockTag } + ); + + const scores = await erc20BalanceOfStrategy( + space, + network, + provider, + addresses, + options, + snapshot + ); + return Object.fromEntries( + Object.entries(scores).map((score) => [ + score[0], + (score[1] / totalSupply) * options.weight + ]) + ); +} From 5d5d668b02ad414bd66050dec4a956eba8e8ae96 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 22 Feb 2024 16:16:30 +0530 Subject: [PATCH 602/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.0 (#1411) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 9a96a9dc7..dcff23206 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.10.1", + "@snapshot-labs/snapshot.js": "^0.11.0", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 517448187..4e8c074d6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.10.1": - version "0.10.1" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.10.1.tgz#d783ee394d6e3ad3d3a6e91fea67411752d15180" - integrity sha512-PacD8HdsYZhb1Yifp6n+11Og+nZUvGhTosu+ejnEwhP6zQOFMg6gaIEsWGjoAMnjos0sgA/oIbWdPIzqJRTECw== +"@snapshot-labs/snapshot.js@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.0.tgz#148a7eed01c128689bab28c033abd87cfe41a54c" + integrity sha512-HSvsty6tNiaq7JngzGBMOayA3qEmwjLMhvnapY6TL1FgQcKwx7u4Xwruw9vZu34MU8MdmBcQanxyaz6XP3t+oA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 1af7f4e143258cd9fc8efb84b1786d46b3db5115 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 22 Feb 2024 23:34:21 +0530 Subject: [PATCH 603/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.1 (#1412) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index dcff23206..cb30fa13f 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.0", + "@snapshot-labs/snapshot.js": "^0.11.1", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 4e8c074d6..00997b953 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.0": - version "0.11.0" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.0.tgz#148a7eed01c128689bab28c033abd87cfe41a54c" - integrity sha512-HSvsty6tNiaq7JngzGBMOayA3qEmwjLMhvnapY6TL1FgQcKwx7u4Xwruw9vZu34MU8MdmBcQanxyaz6XP3t+oA== +"@snapshot-labs/snapshot.js@^0.11.1": + version "0.11.1" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.1.tgz#dfbbb3daafa225212f19bb3c94bdfc4c13519ba7" + integrity sha512-Z6TWJpSi6Q22Jfb2/z5QWbPAElSXQyieWr/N/miL3KOTpfDCAt5oOWbXUHk8sUa1C4ik8hIXeLmvTxTWxp1h7Q== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" @@ -1199,6 +1199,7 @@ "@ethersproject/units" "^5.7.0" "@ethersproject/wallet" "^5.6.2" ajv "^8.11.0" + ajv-errors "^3.0.0" ajv-formats "^2.1.1" cross-fetch "^3.1.6" json-to-graphql-query "^2.2.4" @@ -1487,6 +1488,11 @@ aes-js@3.0.0: resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" integrity sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0= +ajv-errors@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-3.0.0.tgz#e54f299f3a3d30fe144161e5f0d8d51196c527bc" + integrity sha512-V3wD15YHfHz6y0KdhYFjyy9vWtEVALT9UrxfN3zqlI6dMioHnJrqOYfyPKol3oqrnCM9uwkcdCwkJ0WUcbLMTQ== + ajv-formats@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" From fb606a32e598397dd19ffe9595e456a1056db25e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 25 Feb 2024 18:02:37 +0530 Subject: [PATCH 604/815] Automated lint (#1413) Co-authored-by: ChaituVR --- src/strategies/planet-finance-v2/index.ts | 6 ++--- src/strategies/urbit-galaxies/examples.json | 25 ++++++++++----------- src/strategies/urbit-galaxies/index.ts | 13 ++++++----- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/strategies/planet-finance-v2/index.ts b/src/strategies/planet-finance-v2/index.ts index c316c6364..6eb42c8ed 100644 --- a/src/strategies/planet-finance-v2/index.ts +++ b/src/strategies/planet-finance-v2/index.ts @@ -31,7 +31,7 @@ const v3FarmAddress = '0x405960AEAad7Ec8B419DEdb511dfe9D112dFc22d'; //v3 farm ad const aquaBtcbLpTokenAddress = '0x70B606c23D6E786BE7accAf31C8fEcEaf846AdF3'; // v3 aqua-btcb lp token address const increase_in_voting = 5; //increase weight 5 times while voting -const gAquaExchangeRate = "200000000416761667681474308"; //exchange rate of gAqua to aqua +const gAquaExchangeRate = '200000000416761667681474308'; //exchange rate of gAqua to aqua export async function strategy( space, @@ -109,7 +109,6 @@ export async function strategy( usersNewAquaBtcbVaultBalances = result[2]; //shares in v3 aqua-btcb pool usersNewAquaPoolBalances = result[3]; // shares in v3 aqua pool - //AQUA-BNB // total supply of v2 aqua bnb lp token erc20Multi.call('aquaBnbTotalSupply', aquaBnbLpTokenAddress, 'totalSupply'); @@ -168,8 +167,7 @@ export async function strategy( ) ) / parseFloat(formatUnits(totalSupplyAquabtcb, 18))) * - parseFloat(formatUnits(contractAquaBtcbBalance, 18)) - ) + parseFloat(formatUnits(contractAquaBtcbBalance, 18))) ]; }) ); diff --git a/src/strategies/urbit-galaxies/examples.json b/src/strategies/urbit-galaxies/examples.json index 11a9867fc..94a58cae9 100644 --- a/src/strategies/urbit-galaxies/examples.json +++ b/src/strategies/urbit-galaxies/examples.json @@ -11,19 +11,18 @@ }, "network": "1", "addresses": [ - "0xb73532B04FB598F5d719Ec40be68DB02F798bCf3", - "0x0e49ab776681630f34d0f0c57D261fD5918f51C8", - "0xCAEDf5af5D421EBEff1e7a497b5Af1Aba1795b94", - "0xD5e69E7C2EAf78a544b8d1B5cE261A0a698ac3E7", - "0x24BfBd0bF3Be1a211E699324294C8F30E73b66eC", - "0x82B185E172Dfd340DC23E553Ef26258609C3cE2e", - "0x61c97a1E7C9ddaE1f11e313e84a3ad921E2CE4e6", - "0xD977B146acCacf8701A56A97d2C98955F28909e2", - "0x274d8716845D9eb95E29c0E2836B9c5aB2A76D40", - "0xFb7eA0EFfBFB887E822531DA3BEE747B89926eEB", - "0x48353A9aF7F835Aa7EA878FE56984F20eed8230C", - "0xC4E588Eb3ef88Fd8Bbbae554968bC82101b637e6" - + "0xb73532B04FB598F5d719Ec40be68DB02F798bCf3", + "0x0e49ab776681630f34d0f0c57D261fD5918f51C8", + "0xCAEDf5af5D421EBEff1e7a497b5Af1Aba1795b94", + "0xD5e69E7C2EAf78a544b8d1B5cE261A0a698ac3E7", + "0x24BfBd0bF3Be1a211E699324294C8F30E73b66eC", + "0x82B185E172Dfd340DC23E553Ef26258609C3cE2e", + "0x61c97a1E7C9ddaE1f11e313e84a3ad921E2CE4e6", + "0xD977B146acCacf8701A56A97d2C98955F28909e2", + "0x274d8716845D9eb95E29c0E2836B9c5aB2A76D40", + "0xFb7eA0EFfBFB887E822531DA3BEE747B89926eEB", + "0x48353A9aF7F835Aa7EA878FE56984F20eed8230C", + "0xC4E588Eb3ef88Fd8Bbbae554968bC82101b637e6" ], "snapshot": 19179657 } diff --git a/src/strategies/urbit-galaxies/index.ts b/src/strategies/urbit-galaxies/index.ts index d24534093..41bfcd609 100644 --- a/src/strategies/urbit-galaxies/index.ts +++ b/src/strategies/urbit-galaxies/index.ts @@ -32,7 +32,7 @@ export async function strategy( type MulticallParam = [string, string, any[]]; const ownerCalls: MulticallParam[] = []; - const proxyCalls : MulticallParam[] = []; + const proxyCalls: MulticallParam[] = []; for (let tokenId = 0; tokenId <= 255; tokenId++) { ownerCalls.push([options.erc721Address, 'ownerOf', [tokenId]]); proxyCalls.push([options.votingProxyAddress, 'getVotingProxy', [tokenId]]); @@ -48,12 +48,15 @@ export async function strategy( const proxyAddress = proxyResponses[index][0]; // Determine the effective voter (proxy or owner) - const effectiveVoter = proxyAddress !== '0x0000000000000000000000000000000000000000' ? proxyAddress : ownerAddress; + const effectiveVoter = + proxyAddress !== '0x0000000000000000000000000000000000000000' + ? proxyAddress + : ownerAddress; if (addresses.includes(effectiveVoter)) { - score[effectiveVoter] = (score[effectiveVoter] || 0) + 1; - } - }); + score[effectiveVoter] = (score[effectiveVoter] || 0) + 1; + } + }); return score; } From 9ce09f93d6affac589a6c14c9e446e5bec78dae9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 26 Feb 2024 13:37:42 +0530 Subject: [PATCH 605/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.2 (#1414) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index cb30fa13f..c7e823361 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.1", + "@snapshot-labs/snapshot.js": "^0.11.2", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 00997b953..f55243d1f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.1": - version "0.11.1" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.1.tgz#dfbbb3daafa225212f19bb3c94bdfc4c13519ba7" - integrity sha512-Z6TWJpSi6Q22Jfb2/z5QWbPAElSXQyieWr/N/miL3KOTpfDCAt5oOWbXUHk8sUa1C4ik8hIXeLmvTxTWxp1h7Q== +"@snapshot-labs/snapshot.js@^0.11.2": + version "0.11.2" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.2.tgz#de3a9063a50dcd4ea0d4cfa76c90642ac5438066" + integrity sha512-++No+Fvmifxu8DbffQxCqNf0PcyvaK0BQ6N96EWVbkgYr5RgOTSvnvMMxWoXLwARm+6dFX0VTDf4ERU87SPRpA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 38c6897d1fe3487257df57ed68506b011910f710 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 27 Feb 2024 09:17:01 +0530 Subject: [PATCH 606/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.3 (#1415) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index c7e823361..f033074c5 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.2", + "@snapshot-labs/snapshot.js": "^0.11.3", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index f55243d1f..a83d09aa0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.2": - version "0.11.2" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.2.tgz#de3a9063a50dcd4ea0d4cfa76c90642ac5438066" - integrity sha512-++No+Fvmifxu8DbffQxCqNf0PcyvaK0BQ6N96EWVbkgYr5RgOTSvnvMMxWoXLwARm+6dFX0VTDf4ERU87SPRpA== +"@snapshot-labs/snapshot.js@^0.11.3": + version "0.11.3" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.3.tgz#6ce8bee2dcf6614281a3f8841fe5ca4ddb59b41d" + integrity sha512-bP4+vkWnOYZmNM1wPzuGoJYUwUl0TprmmO8Uq+sAg6hOTdWLmFeOzeETLuVr2geOnUg43LG9Oz73bKnaIxW+Yg== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From ec4fb9a1b3adb59e8832dac5c03fe7490c57aad5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 Mar 2024 17:26:10 +0530 Subject: [PATCH 607/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.6 (#1417) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f033074c5..6c8216fe4 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.3", + "@snapshot-labs/snapshot.js": "^0.11.6", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index a83d09aa0..a0eb07f2b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.3": - version "0.11.3" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.3.tgz#6ce8bee2dcf6614281a3f8841fe5ca4ddb59b41d" - integrity sha512-bP4+vkWnOYZmNM1wPzuGoJYUwUl0TprmmO8Uq+sAg6hOTdWLmFeOzeETLuVr2geOnUg43LG9Oz73bKnaIxW+Yg== +"@snapshot-labs/snapshot.js@^0.11.6": + version "0.11.6" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.6.tgz#371b26f2b01337faa4f8403cb5b633854b625ed8" + integrity sha512-4cMg5Ur+0vjgliN+GB3GbZ1HOiZUQBIzxEFsUKUkw1ze1/5lOi9X1Jv0+zqXpCPmbs9WMAT/fNHcplMNjcZUPg== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From b7680860e2fe972012f6da86aa67fb3bf52264c1 Mon Sep 17 00:00:00 2001 From: propchain-development <100083866+propchain-development@users.noreply.github.com> Date: Tue, 5 Mar 2024 10:32:25 +0100 Subject: [PATCH 608/815] [vesting-balance-of] adding vesting-balance-of call (#1420) * adding vesting-balance-of call * Delete yarn.lock * removing package-lock.json, adding yarn as per readme * Update src/strategies/vesting-balance-of/index.ts * Update index.ts Co-authored-by: Chaitanya * Update yarn.lock --------- Co-authored-by: Tobias Athenstaedt Co-authored-by: Chaitanya --- src/strategies/index.ts | 4 +- src/strategies/vesting-balance-of/README.md | 25 +++++ .../vesting-balance-of/examples.json | 36 +++++++ src/strategies/vesting-balance-of/index.ts | 94 +++++++++++++++++++ src/strategies/vesting-balance-of/schema.json | 59 ++++++++++++ 5 files changed, 217 insertions(+), 1 deletion(-) create mode 100644 src/strategies/vesting-balance-of/README.md create mode 100644 src/strategies/vesting-balance-of/examples.json create mode 100644 src/strategies/vesting-balance-of/index.ts create mode 100644 src/strategies/vesting-balance-of/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index d2d8d36a7..56c43ff00 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -413,6 +413,7 @@ import * as vendorV2BorrowerCollateralBalanceOf from './vendor-v2-borrower-colla import * as voltVotingPower from './volt-voting-power'; import * as xdaiStakersAndHolders from './xdai-stakers-and-holders'; import * as minimeBalanceVsSupplyWeighted from './minime-balance-vs-supply-weighted'; +import * as vestingBalanceOf from './vesting-balance-of'; const strategies = { 'minime-balance-vs-supply-weighted': minimeBalanceVsSupplyWeighted, @@ -833,7 +834,8 @@ const strategies = { vendorV2BorrowerCollateralBalanceOf, 'volt-voting-power': voltVotingPower, 'xdai-stakers-and-holders': xdaiStakersAndHolders, - 'urbit-galaxies': urbitGalaxies + 'urbit-galaxies': urbitGalaxies, + 'vesting-balance-of': vestingBalanceOf }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/vesting-balance-of/README.md b/src/strategies/vesting-balance-of/README.md new file mode 100644 index 000000000..c6d48716e --- /dev/null +++ b/src/strategies/vesting-balance-of/README.md @@ -0,0 +1,25 @@ +# vesting-balance-of + +This strategy retrieves vested balance for specific wallets on a custom developed vesting contract. +An example of this contract can be found on [etherscan](https://etherscan.io/address/0xE14885C5d632Abff9c04AEEf8e5fb88C0F6872DA). + +The contract stores a list of vestings which is accessible via a `vestingPropertiesList()` method allowing to retrieve a +full list of vestings without direct reference to users. A second method allows to retrieve the link of a user to a specific +vesting via `userPropertiesList(address wallet)` using the wallet's address as parameter. + +With this strategy up to **5** buckets can be checked at once. Only one bucket is required. If multiple buckets are checked +the total balance is returned. +*Decimals* is a global setting being applied to all buckets. + +Here is an example of parameters: + +```json +{ + "vesting_1": "0xE14885C5d632Abff9c04AEEf8e5fb88C0F6872DA", + "vesting_2": "0x4fc18B68960A6ED7eab07451f0d755D857FF329d", + "vesting_3": "0x955866b5a5E8aa8619aC09C422046095654414da", + "vesting_4": "0x6b175474e89094c44da98b954eedeac495271d0f", + "vesting_5": "0x6b175474e89094c44da98b954eedeac495271d0f", + "decimals": 18 +} +``` diff --git a/src/strategies/vesting-balance-of/examples.json b/src/strategies/vesting-balance-of/examples.json new file mode 100644 index 000000000..f7bc80313 --- /dev/null +++ b/src/strategies/vesting-balance-of/examples.json @@ -0,0 +1,36 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "vesting-balance-of", + "params": { + "vesting_1": "0xE14885C5d632Abff9c04AEEf8e5fb88C0F6872DA", + "vesting_2": "0x4fc18B68960A6ED7eab07451f0d755D857FF329d", + "vesting_3": "0x955866b5a5E8aa8619aC09C422046095654414da", + "decimals": 18 + } + }, + "network": "1", + "addresses": [ + "0xC8b0DF0295777c62E674A8862510719Df81d2628", + "0xB3F52FC25496DA7c5778698aA8F850b5DF39ac52", + "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", + "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", + "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e", + "0x1d5E65a087eBc3d03a294412E46CE5D6882969f4", + "0x1f254336E5c46639A851b9CfC165697150a6c327", + "0x2ec3F80BeDA63Ede96BA20375032CDD3aAfb3030", + "0x4AcBcA6BE2f8D2540bBF4CA77E45dA0A4a095Fa2", + "0x4F3D348a6D09837Ae7961B1E0cEe2cc118cec777", + "0x6D7f23A509E212Ba7773EC1b2505d1A134f54fbe", + "0x07a1f6fc89223c5ebD4e4ddaE89Ac97629856A0f", + "0x8d5F05270da470e015b67Ab5042BDbE2D2FEFB48", + "0x8d07D225a769b7Af3A923481E1FdF49180e6A265", + "0x8f60501dE5b9b01F9EAf1214dbE1924aA97F7fd0", + "0x9B8e8dD9151260c21CB6D7cc59067cd8DF306D58", + "0x17ea92D6FfbAA1c7F6B117c1E9D0c88ABdc8b84C", + "0x38C0039247A31F3939baE65e953612125cB88268" + ], + "snapshot": 19292147 + } +] diff --git a/src/strategies/vesting-balance-of/index.ts b/src/strategies/vesting-balance-of/index.ts new file mode 100644 index 000000000..fffcc4634 --- /dev/null +++ b/src/strategies/vesting-balance-of/index.ts @@ -0,0 +1,94 @@ +import {BigNumber, BigNumberish} from '@ethersproject/bignumber'; +import {formatUnits} from '@ethersproject/units'; +import {Multicaller} from '../../utils'; + +export const author = 'propchain-development'; +export const version = '0.1.0'; + + +const vestingABI = [ + 'function userPropertiesList(address wallet) view returns (tuple(bool isActive, uint256 spentAmount, uint256 vestingId, bool tgeClaimed) userProperties)', + 'function vestingPropertiesList() view returns (tuple(uint256 amountForUser, uint256 tgeAmountForUser, uint256 startTime, uint256 tickCount, uint256 tickDuration, uint256 unallocatedAmount, bool active)[] vestingList)' +] + +interface Options { + vesting_1: string, + vesting_2?: string, + vesting_3?: string, + vesting_4?: string, + vesting_5?: string, + vesting_6?: string, + decimals: number +} + +interface VestingProperties { + amountForUser: BigNumberish, + tgeAmountForUser: BigNumberish, + startTime: BigNumberish, + tickCount: BigNumberish, + tickDuration: BigNumberish, + unallocatedAmount: BigNumberish, + active: boolean +} + +interface UserProperties { + isActive: boolean, + spentAmount: BigNumberish, + vestingId: BigNumberish, + tgeClaimed: boolean +} + +export async function strategy( + space, + network, + provider, + addresses, + options: Options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multi = new Multicaller( + network, + provider, + vestingABI, { blockTag } + ); + + multi.call(options.vesting_1, options.vesting_1, 'vestingPropertiesList', []) + if(options.vesting_2) + multi.call(options.vesting_2, options.vesting_1, 'vestingPropertiesList', []) + if(options.vesting_3) + multi.call(options.vesting_3, options.vesting_1, 'vestingPropertiesList', []) + if(options.vesting_4) + multi.call(options.vesting_4, options.vesting_1, 'vestingPropertiesList', []) + + const vestingRecords: Record = await multi.execute(); + + addresses.forEach((address: string) => { + multi.call(address+"_"+options.vesting_1, options.vesting_1, 'userPropertiesList', [address]); + if(options.vesting_2) + multi.call(address+"_"+options.vesting_2, options.vesting_2, 'userPropertiesList', [address]); + if(options.vesting_3) + multi.call(address+"_"+options.vesting_3, options.vesting_3, 'userPropertiesList', [address]) + if(options.vesting_4) + multi.call(address+"_"+options.vesting_4, options.vesting_4, 'userPropertiesList', [address]) + if(options.vesting_5) + multi.call(address+"_"+options.vesting_5, options.vesting_5, 'userPropertiesList', [address]) + }); + const userProperties: Record = await multi.execute(); + + let filteredRecords : Record = {}; + Object.entries(userProperties).forEach(([identifier, user]) => { + const [addr, vestingBucket] = identifier.split("_"); + if(!filteredRecords[addr]) + filteredRecords[addr] = 0; + + if(!user.isActive) + return; + + const amountRaw = vestingRecords[vestingBucket][BigNumber.from(user.vestingId).toNumber()].amountForUser + filteredRecords[addr] += parseFloat(formatUnits(amountRaw, options.decimals)); + }); + + return filteredRecords; +} diff --git a/src/strategies/vesting-balance-of/schema.json b/src/strategies/vesting-balance-of/schema.json new file mode 100644 index 000000000..c7ad46b7a --- /dev/null +++ b/src/strategies/vesting-balance-of/schema.json @@ -0,0 +1,59 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "decimals": { + "type": "number", + "title": "Decimals on all vesting contracts", + "examples": ["e.g. 18"] + }, + "vesting_1": { + "type": "string", + "title": "Vesting contract addresses", + "examples": ["e.g. 0xE14885C5d632Abff9c04AEEf8e5fb88C0F6872DA"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "vesting_2": { + "type": "string", + "title": "Vesting contract addresses", + "examples": ["e.g. 0xE14885C5d632Abff9c04AEEf8e5fb88C0F6872DA"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "vesting_3": { + "type": "string", + "title": "Vesting contract addresses", + "examples": ["e.g. 0xE14885C5d632Abff9c04AEEf8e5fb88C0F6872DA"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "vesting_4": { + "type": "string", + "title": "Vesting contract addresses", + "examples": ["e.g. 0xE14885C5d632Abff9c04AEEf8e5fb88C0F6872DA"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "vesting_5": { + "type": "string", + "title": "Vesting contract addresses", + "examples": ["e.g. 0xE14885C5d632Abff9c04AEEf8e5fb88C0F6872DA"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } + }, + "required": ["vesting_1", "decimals"], + "additionalProperties": false + } + } +} From a9b1a5c56155ea8899bed1801a5d3a824c317ce1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 5 Mar 2024 20:58:36 +0530 Subject: [PATCH 609/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.7 (#1421) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 6c8216fe4..2a9913c80 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.6", + "@snapshot-labs/snapshot.js": "^0.11.7", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index a0eb07f2b..09c276fa0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.6": - version "0.11.6" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.6.tgz#371b26f2b01337faa4f8403cb5b633854b625ed8" - integrity sha512-4cMg5Ur+0vjgliN+GB3GbZ1HOiZUQBIzxEFsUKUkw1ze1/5lOi9X1Jv0+zqXpCPmbs9WMAT/fNHcplMNjcZUPg== +"@snapshot-labs/snapshot.js@^0.11.7": + version "0.11.7" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.7.tgz#118a4ab50beb4a0f985a5d873833cdef77e7b405" + integrity sha512-h9/Ex/e0oX1k4dw56IQCI8xsDpdrjQ1P88QVNuelZoagzf4ONrmMFNsSail0fu2DGvR99SCr4fnE+g+lNAuD5w== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 5adadc6807f3c11b1a816dedbe272f6f5a78891c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 7 Mar 2024 11:12:37 +0530 Subject: [PATCH 610/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.8 (#1422) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 2a9913c80..6da9db704 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.7", + "@snapshot-labs/snapshot.js": "^0.11.8", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 09c276fa0..f912e5634 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.7": - version "0.11.7" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.7.tgz#118a4ab50beb4a0f985a5d873833cdef77e7b405" - integrity sha512-h9/Ex/e0oX1k4dw56IQCI8xsDpdrjQ1P88QVNuelZoagzf4ONrmMFNsSail0fu2DGvR99SCr4fnE+g+lNAuD5w== +"@snapshot-labs/snapshot.js@^0.11.8": + version "0.11.8" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.8.tgz#7d8c1c0b049f72835518a2c65a44380fbc8990d8" + integrity sha512-kHdkdmIC5te3oVdbwKZ7Tykw7qih3bMmlnYvXP7TqeO44pLlqlMmaRguB7Uq+fcENbx4g3v7MW2oREWBoDGwpg== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From f6fa2941a161acc69783e9ca0d1abf67afe4098c Mon Sep 17 00:00:00 2001 From: Shubham Patel Date: Sun, 10 Mar 2024 22:40:18 +0530 Subject: [PATCH 611/815] [push-voting-power] Added support for tokens staked in Push V2 pool (#1425) * Added support for tokens staked in Push V2 pool * Update src/strategies/push-voting-power/index.ts Co-authored-by: Chaitanya --------- Co-authored-by: Shubham Co-authored-by: Chaitanya --- src/strategies/push-voting-power/README.md | 8 +-- .../push-voting-power/examples.json | 8 ++- src/strategies/push-voting-power/index.ts | 52 +++++++++++++++---- 3 files changed, 52 insertions(+), 16 deletions(-) diff --git a/src/strategies/push-voting-power/README.md b/src/strategies/push-voting-power/README.md index ea0ebf709..722f71a29 100644 --- a/src/strategies/push-voting-power/README.md +++ b/src/strategies/push-voting-power/README.md @@ -2,8 +2,8 @@ This strategy weighs the vote using: - Amount of `$PUSH` delegated to user -- Amount of `$PUSH` staked in Push staking pool -- Amount of `$PUSH-LP` staked in LP staking pool +- Amount of `$PUSH` staked in Push V1 and V2 staking pool +- Amount of `$PUSH-LP` staked in LP staking pool V1 and V2 The voting power is calculated in terms of `$PUSH`, so `$PUSH-LP` tokens are converted to `$PUSH` using on chain data from Uniswap-V2 Router, WETH and USDT token contracts. @@ -18,7 +18,9 @@ The voting power is calculated in terms of `$PUSH`, so `$PUSH-LP` tokens are con "uniswapV2Router02": "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D", "WETHAddress": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "USDTAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7", - + + "pushUniStakingV2":"0x9D2513F5b539DC774C66b28ACEc94e4bD00105C2", + "pushStakingInfoCoreV2": "0x66329Fdd4042928BfCAB60b179e1538D56eeeeeE", "decimals": 18 } ``` \ No newline at end of file diff --git a/src/strategies/push-voting-power/examples.json b/src/strategies/push-voting-power/examples.json index 590d1ba7e..13ed8b126 100644 --- a/src/strategies/push-voting-power/examples.json +++ b/src/strategies/push-voting-power/examples.json @@ -13,6 +13,8 @@ "WETHAddress": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "USDTAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7", + "pushUniStakingV2":"0x9D2513F5b539DC774C66b28ACEc94e4bD00105C2", + "pushStakingInfoCoreV2": "0x66329Fdd4042928BfCAB60b179e1538D56eeeeeE", "decimals": 18 } }, @@ -24,8 +26,10 @@ "0x5913760160d245d0C9A05a8a956012694281bEE3", "0x4b9D53246eD18db31f26Fc59b6e47a9efC3C1213", "0x89c1151cA988ca5372b569A30d24964A94Ad05FD", - "0xE08fcc423566BF10B53e32E05d24C0429F91111A" + "0xE08fcc423566BF10B53e32E05d24C0429F91111A", + "0xD66f2F1d86C0c5477aA1612cA92f03297A5477B0", + "0xaB8a67743325347Aa53bCC66850f8F13df87e3AF" ], - "snapshot": 13626267 + "snapshot": 19381155 } ] diff --git a/src/strategies/push-voting-power/index.ts b/src/strategies/push-voting-power/index.ts index 149fdf3b9..1859b4458 100644 --- a/src/strategies/push-voting-power/index.ts +++ b/src/strategies/push-voting-power/index.ts @@ -2,8 +2,10 @@ import { formatUnits } from '@ethersproject/units'; import { BigNumber } from '@ethersproject/bignumber'; import { multicall } from '../../utils'; -export const author = 'mujtaba1747'; -export const version = '0.1.0'; +//0.1.0 was authered by mujtaba1747 + +export const author = 'ethereum-push-notification-service'; +export const version = '0.2.0'; const tokenBNtoNumber = (tokenBn) => { return ( @@ -14,7 +16,8 @@ const tokenBNtoNumber = (tokenBn) => { const sharedABI = [ 'function balanceOf(address user, address token) view returns (uint256)', - 'function getAmountsOut(uint256 amountIn, address[] path) view returns (uint256[] amounts)' + 'function getAmountsOut(uint256 amountIn, address[] path) view returns (uint256[] amounts)', + 'function userFeesInfo(address user) view returns(uint256,uint256,uint256,uint256)' ]; const wethABI = ['function balanceOf(address) view returns (uint256)']; @@ -78,13 +81,36 @@ export async function strategy( [address.toLowerCase(), options.pushLPTokenAddr] ]) ), - { blockTag } ); + const responseStakedV2 = await multicall( + network, + provider, + sharedABI, + + addresses + .map((address: any) => [ + options.pushStakingInfoCoreV2, + 'userFeesInfo', + [address.toLowerCase()] + ]).concat( + addresses.map((address: any) => [ + options.pushUniStakingV2, + 'balanceOf', + [address.toLowerCase(), options.pushLPTokenAddr] + ]) + ), + { blockTag } + ); + const responseStakedPUSH = responseStaked.slice(0, addresses.length); + let responseStakedPUSHV2 = responseStakedV2.slice(0, addresses.length); + responseStakedPUSHV2 = responseStakedPUSHV2.map((value, i) => {return value[0].toString()}); +const responseStakedLP = responseStaked.slice(addresses.length); + const responseStakedLPV2 = responseStakedV2.slice(addresses.length); - const responseStakedLP = responseStaked.slice(addresses.length); + const responseWETH = await multicall( network, @@ -121,9 +147,7 @@ export async function strategy( // pushPrice and wethPrice are in terms of USDT const pushPrice = responseLPConversion[0]['amounts'][2].toNumber() / 1e6; - const wethPrice = responseLPConversion[1]['amounts'][1].toNumber() / 1e6; - const responseEPNSLPToken = await multicall( network, provider, @@ -132,24 +156,30 @@ export async function strategy( { blockTag } ); + // Calculating price of EPNS-LP Tokens in terms of EPNS Tokens const uniLpTotalSupply = tokenBNtoNumber(responseEPNSLPToken[0][0]); - const uniLpPrice = (pushAmountReserve * pushPrice + wethAmountReserve * wethPrice) / uniLpTotalSupply; +const lpToPushRatio = uniLpPrice / pushPrice; - const lpToPushRatio = uniLpPrice / pushPrice; - +// console.log(uniLpTotalSupply) return Object.fromEntries( responseDelegatedPUSH.map((value, i) => [ addresses[i], - // Voting Power = Delegated PUSH + Staked PUSH + Staked UNI-LP PUSH + // Voting Power = Delegated PUSH + Staked PUSH V1 + Staked PUSH V2 +Staked Uni-LP V2 + Staked UNI-LP PUSH parseFloat(formatUnits(value.toString(), options.decimals)) + parseFloat( formatUnits(responseStakedPUSH[i].toString(), options.decimals) ) + + parseFloat(formatUnits(responseStakedPUSHV2[i], options.decimals))+ + parseFloat( + formatUnits(responseStakedLPV2[i].toString(), options.decimals) + ) * + lpToPushRatio + + parseFloat( formatUnits(responseStakedLP[i].toString(), options.decimals) ) * From d2b3263fac61c6baf2ecb1dc1ad4a5f364851583 Mon Sep 17 00:00:00 2001 From: Muhammad Asim Hayat <33583734+asim07@users.noreply.github.com> Date: Wed, 13 Mar 2024 14:41:00 +0500 Subject: [PATCH 612/815] [stake-mine-liquid-helios] strategy added (#1428) * strategy added * Apply suggestions from code review * Minor Change --------- Co-authored-by: Chaitanya --- src/strategies/index.ts | 4 +- .../stake-mine-liquid-helios/README.md | 15 ++ .../stake-mine-liquid-helios/examples.json | 38 +++++ .../stake-mine-liquid-helios/index.ts | 135 ++++++++++++++++++ .../stake-mine-liquid-helios/schema.json | 51 +++++++ 5 files changed, 242 insertions(+), 1 deletion(-) create mode 100755 src/strategies/stake-mine-liquid-helios/README.md create mode 100755 src/strategies/stake-mine-liquid-helios/examples.json create mode 100755 src/strategies/stake-mine-liquid-helios/index.ts create mode 100755 src/strategies/stake-mine-liquid-helios/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 56c43ff00..f8cef937b 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -414,6 +414,7 @@ import * as voltVotingPower from './volt-voting-power'; import * as xdaiStakersAndHolders from './xdai-stakers-and-holders'; import * as minimeBalanceVsSupplyWeighted from './minime-balance-vs-supply-weighted'; import * as vestingBalanceOf from './vesting-balance-of'; +import * as stakeMineLiquidHelios from './stake-mine-liquid-helios'; const strategies = { 'minime-balance-vs-supply-weighted': minimeBalanceVsSupplyWeighted, @@ -835,7 +836,8 @@ const strategies = { 'volt-voting-power': voltVotingPower, 'xdai-stakers-and-holders': xdaiStakersAndHolders, 'urbit-galaxies': urbitGalaxies, - 'vesting-balance-of': vestingBalanceOf + 'vesting-balance-of': vestingBalanceOf, + 'stake-mine-liquid-helios' : stakeMineLiquidHelios, }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/stake-mine-liquid-helios/README.md b/src/strategies/stake-mine-liquid-helios/README.md new file mode 100755 index 000000000..42be3ee10 --- /dev/null +++ b/src/strategies/stake-mine-liquid-helios/README.md @@ -0,0 +1,15 @@ +# stake-mine-liquid-helios + +This strategy determines voting power for users on helios platform that has shares, liquid and mintable hlx dependencies. + +Here is an example of parameters: + +```json +{ + "address": "0x2614f29C39dE46468A921Fd0b41fdd99A01f2EDf", + "symbol": "HLX", + "decimals": 18, + "tokenWeight": 1, + "sharesWeight": 420, +} +``` diff --git a/src/strategies/stake-mine-liquid-helios/examples.json b/src/strategies/stake-mine-liquid-helios/examples.json new file mode 100755 index 000000000..e9e94ca49 --- /dev/null +++ b/src/strategies/stake-mine-liquid-helios/examples.json @@ -0,0 +1,38 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "stake-mine-liquid-helios", + "params": { + "address": "0x2614f29C39dE46468A921Fd0b41fdd99A01f2EDf", + "symbol": "HLX", + "decimals": 18, + "tokenWeight": 1, + "sharesWeight": 420, + "mintableWeight": 0.1 + } + }, + "network": "1", + "addresses": [ + "0x362aC45CfcB7970876eBE9C40358448C16DBCAfC", + "0xb778d98a2C966873D6B0Bc75aC8744e90bCf93d5", + "0x86B63808E1361e1F3e526838b2340501E6fd990A", + "0x22E91b096E3732C9Dc343e39d78c03A21b41EC34", + "0xFB89446dA803185dAf457a1CBA9f4F61c288B59a", + "0x999C89A2C5E7EF834C99D3F1c68059580bf29AdD", + "0x13C44b1FCEE99f396fA1CD77E6A5272bDD6cC559", + "0xBe474903F17C769fcFfB81c1Aeb830AE67142D91", + "0x79841213Ec3343cB63769b34f97e77108fC4232D", + "0x15E5B9B9Adf208cC7CA3aE1e6a49506eB5f397Dd", + "0xb0d1A98b4669eC986DB27f925b85A951A390Ca42", + "0x8764633f85F18dB033Ae7EA4A9C9812E4020CE4F", + "0x35E900026018aE6Da90d9f7d7122d05aD9de57c4", + "0x1A70d7CB0D232f50aCaC5C45F94310BAe993ee6D", + "0x8cdE74df83bf46c5d410f0938bc51ba54554b61F", + "0xD50C50D2c8Fa127c1fa36B6a628af5A82d6bB0d3", + "0xdE7Da75ac2D367379DE565C928D447dC5e385f2C", + "0x3E82555Af4f5908487969E40cCAF9081B74e23c9" + ], + "snapshot": 19381155 + } +] diff --git a/src/strategies/stake-mine-liquid-helios/index.ts b/src/strategies/stake-mine-liquid-helios/index.ts new file mode 100755 index 000000000..259a56260 --- /dev/null +++ b/src/strategies/stake-mine-liquid-helios/index.ts @@ -0,0 +1,135 @@ +import { formatUnits } from '@ethersproject/units'; +import { multicall } from '../../utils'; +import { BigNumber } from '@ethersproject/bignumber'; +import { BigNumberish } from '@ethersproject/bignumber'; + +export const author = 'asim07'; +export const version = '0.1.0'; + +const abi = [ + 'function balanceOf(address account) external view returns (uint256)', + 'function getUserCurrentActiveShares(address) external view returns (uint256)', + 'function getUserMints(address) external view returns ((uint256,uint256,uint256,(uint256,uint16,uint256,uint48,uint48,uint256,uint256,uint256,uint256,uint256,uint256,uint256))[])' +]; + +enum MintStatus { + ACTIVE, + CLAIMED, + BURNED +} + +interface UserMintInfo { + mintPower: BigNumberish; + numOfDays: number; + mintableHlx: BigNumberish; + mintStartTs: number; + maturityTs: number; + mintPowerBonus: BigNumberish; + EAABonus: BigNumberish; + mintedHlx: BigNumberish; + mintCost: BigNumberish; + penalty: BigNumberish; + titanBurned: BigNumberish; + status: MintStatus; +} + +interface UserMint { + mId: BigNumberish; + hRank: BigNumberish; + gMintPower: BigNumberish; + mintInfo: UserMintInfo; +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const { + address: tokenAddress, + sharesWeight, + tokenWeight, + mintableWeight, + decimals + } = options; + + const tokenResponse: BigNumber[] = await multicall( + network, + provider, + abi, + addresses.map((address: any) => { + return [tokenAddress, 'balanceOf', [address.toLowerCase()]]; + }), + { blockTag } + ); + + const userMintsResponses: UserMint[][][] = await multicall( + network, + provider, + abi, + addresses.map((address: any) => { + return [tokenAddress, 'getUserMints', [address.toLowerCase()]]; + }), + { blockTag } + ); + // Calculate and sum mintableHlx for each user + const mintableHlxSums = userMintsResponses.map( + (userMints) => + userMints.reduce( + (userSum, mints) => + userSum + + mints.reduce((sum, mint) => { + // Extract mintableHlx, ensure mint[3] is defined and mint[3][2] is not undefined + const mintableHlx = + mint[3] && mint[3][2] !== undefined && parseInt(mint[3][11]) === 0 + ? parseFloat(formatUnits(mint[3][2], decimals)) + : 0; + return sum + mintableHlx; // Sum mintableHlx for this mint to the total for the current user's mints + }, 0), + 0 + ) // Start with 0 sum for each user + ); + + const tokenBalances = Object.fromEntries( + Object.entries(tokenResponse).map(([address, balance]) => [ + address, + formatUnits(balance.toString(), decimals) + ]) + ); + + const shares = await multicall( + network, + provider, + abi, + addresses.map((address: any) => { + return [ + tokenAddress, + 'getUserCurrentActiveShares', + [address.toLowerCase()] + ]; + }), + { blockTag } + ); + + return Object.fromEntries( + shares.map((value, index) => { + const formattedShares = +( + parseFloat(formatUnits(value.toString(), decimals)) * sharesWeight ?? 0 + ); + const formattedBalance = +( + parseFloat(tokenBalances[index].toString()) * tokenWeight ?? 0 + ); + const formattedMintable = +( + parseFloat(mintableHlxSums[index].toString()) * mintableWeight ?? 0 + ); + const sum = formattedBalance + formattedShares + formattedMintable; + + return [addresses[index], sum]; + }) + ); +} diff --git a/src/strategies/stake-mine-liquid-helios/schema.json b/src/strategies/stake-mine-liquid-helios/schema.json new file mode 100755 index 000000000..63d95de92 --- /dev/null +++ b/src/strategies/stake-mine-liquid-helios/schema.json @@ -0,0 +1,51 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. UNI"], + "maxLength": 16 + }, + "address": { + "type": "string", + "title": "Contract address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 18"], + "minimum": 0 + }, + "tokenWeight": { + "type": "number", + "title": "Token Weight", + "examples": ["e.g. 1"] + }, + "sharesWeight": { + "type": "number", + "title": "Shares Weight", + "examples": ["e.g. 420"], + "minimum": 0 + }, + "mintableWeight": { + "type": "number", + "title": "Mintable Weight", + "examples": ["e.g. 0.1"], + "minimum": 0 + } + }, + "required": ["address", "decimals"], + "additionalProperties": false + } + } +} From e8b29c19e613e9154ff2e98922a7354dd0cccaed Mon Sep 17 00:00:00 2001 From: Mitch <67759413+divine-comedian@users.noreply.github.com> Date: Wed, 13 Mar 2024 12:50:42 -0600 Subject: [PATCH 613/815] [giveth-gnosis-balance-supply-weighted-v3] add giveth-gnosis-balance-supply-weighted-v3 strategy (#1429) * add new giveth gnosis strategy * Update src/strategies/giveth-gnosis-balance-supply-weighted-v3/index.ts --------- Co-authored-by: Mitch Oz Co-authored-by: Chaitanya --- .../README.md | 12 ++ .../examples.json | 20 ++++ .../index.ts | 103 ++++++++++++++++++ src/strategies/index.ts | 3 + 4 files changed, 138 insertions(+) create mode 100644 src/strategies/giveth-gnosis-balance-supply-weighted-v3/README.md create mode 100644 src/strategies/giveth-gnosis-balance-supply-weighted-v3/examples.json create mode 100644 src/strategies/giveth-gnosis-balance-supply-weighted-v3/index.ts diff --git a/src/strategies/giveth-gnosis-balance-supply-weighted-v3/README.md b/src/strategies/giveth-gnosis-balance-supply-weighted-v3/README.md new file mode 100644 index 000000000..6e375a908 --- /dev/null +++ b/src/strategies/giveth-gnosis-balance-supply-weighted-v3/README.md @@ -0,0 +1,12 @@ +# Giveth Gnosis balance + +This strategy sums up all the GIV on xDai, including the ones that are staked in Honeyswap pools, Sushiswap pools, single staked on GIV pool and GIVpower. This version divide the balance by the circulating supply of GIV and multiplies it by a weight. + +Here is an example of parameters: + +```json +{ + "symbol": "GIV", + "decimals": 18 +} +``` diff --git a/src/strategies/giveth-gnosis-balance-supply-weighted-v3/examples.json b/src/strategies/giveth-gnosis-balance-supply-weighted-v3/examples.json new file mode 100644 index 000000000..ed0d66784 --- /dev/null +++ b/src/strategies/giveth-gnosis-balance-supply-weighted-v3/examples.json @@ -0,0 +1,20 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "giveth-gnosis-balance-supply-weighted-v3", + "params": { + "symbol": "GIV", + "decimals": 18, + "weight": 0.5 + } + }, + "network": "100", + "addresses": [ + "0x839395e20bbb182fa440d08f850e6c7a8f6f0780", + "0x960a16c9070a9bbbb03e1bfd418982636d56d77d", + "0x826976d7C600d45FB8287CA1d7c76FC8eb732030" + ], + "snapshot": 32900726 + } +] diff --git a/src/strategies/giveth-gnosis-balance-supply-weighted-v3/index.ts b/src/strategies/giveth-gnosis-balance-supply-weighted-v3/index.ts new file mode 100644 index 000000000..0f965b1e6 --- /dev/null +++ b/src/strategies/giveth-gnosis-balance-supply-weighted-v3/index.ts @@ -0,0 +1,103 @@ +import { subgraphRequest } from '../../utils'; +import { getAddress } from '@ethersproject/address'; +import { formatUnits } from '@ethersproject/units'; + +export const author = 'divine-comedian'; +export const version = '0.1.0'; + +const GIVETH_SUBGRAPH_API = + 'https://api.thegraph.com/subgraphs/name/giveth/giveth-economy-second-xdai'; +const XDAI_BLOCKS_API = + 'https://api.thegraph.com/subgraphs/name/elkfinance/xdai-blocks'; + +const CIRUCLATING_SUPPLY_API = 'https://circulating.giveth.io/token-supply'; +// "supplyField" : "circulating", + +const blockParams = { + blocks: { + __args: { + first: 1, + orderBy: 'timestamp', + orderDirection: 'desc', + where: { + timestamp_lte: '' + } + }, + number: true + } +}; + +const pairParams = { + pair: { + __args: { + id: '' + }, + reserve0: true, + totalSupply: true + } +}; + +const params = { + tokenBalances: { + __args: { + orderBy: 'id', + orderDirection: 'asc', + where: { + user_in: [] + } + }, + id: true, + balance: true, + token: true + } +}; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const block = await provider.getBlock(blockTag); + blockParams.blocks.__args.where.timestamp_lte = block.timestamp; + const xDaiBlock = await subgraphRequest(XDAI_BLOCKS_API, blockParams); + const blockNumber = Number(xDaiBlock.blocks[0].number); + // @ts-ignore + params.tokenBalances.__args.block = { number: blockNumber }; + if (snapshot !== 'latest') { + // @ts-ignore + pairParams.pair.__args.block = { number: blockNumber }; + } + + params.tokenBalances.__args.where.user_in = addresses.map((address) => + address.toLowerCase() + ); + + const data = subgraphRequest(GIVETH_SUBGRAPH_API, params); + const supply = fetch(CIRUCLATING_SUPPLY_API, { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + } + }); + const [supplyData, balanceData] = await Promise.all([supply, data]); + const supplyJSON = await supplyData.json(); + const circulatingSupply = parseFloat( + formatUnits(supplyJSON.circulating, options.decimals) + ); + const score = {}; + balanceData.tokenBalances.map((addressBalance) => { + const id = addressBalance.id.split('-')[1]; + const prevScore = score[getAddress(id)] ? score[getAddress(id)] : 0; + score[getAddress(id)] = + prevScore + + (parseFloat(formatUnits(addressBalance.balance, options.decimals)) / + circulatingSupply) * + options.weight; + }); + return score; +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index f8cef937b..77f40e0ff 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -414,9 +414,12 @@ import * as voltVotingPower from './volt-voting-power'; import * as xdaiStakersAndHolders from './xdai-stakers-and-holders'; import * as minimeBalanceVsSupplyWeighted from './minime-balance-vs-supply-weighted'; import * as vestingBalanceOf from './vesting-balance-of'; +import * as givethGnosisBalanceSupplyWeightedV3 from './giveth-gnosis-balance-supply-weighted-v3'; import * as stakeMineLiquidHelios from './stake-mine-liquid-helios'; const strategies = { + 'giveth-gnosis-balance-supply-weighted-v3': + givethGnosisBalanceSupplyWeightedV3, 'minime-balance-vs-supply-weighted': minimeBalanceVsSupplyWeighted, 'cap-voting-power': capVotingPower, 'izumi-veizi': izumiVeiZi, From 58bbd0ff169db8a37d4dc1ff0e3732aeb8309c4f Mon Sep 17 00:00:00 2001 From: Mitch <67759413+divine-comedian@users.noreply.github.com> Date: Wed, 13 Mar 2024 23:13:49 -0600 Subject: [PATCH 614/815] giveth-balance supply weighted (#1431) Co-authored-by: Mitch Oz --- .../giveth-balances-supply-weighted/README.md | 3 + .../examples.json | 28 ++++++++ .../giveth-balances-supply-weighted/index.ts | 70 +++++++++++++++++++ src/strategies/index.ts | 2 + 4 files changed, 103 insertions(+) create mode 100644 src/strategies/giveth-balances-supply-weighted/README.md create mode 100644 src/strategies/giveth-balances-supply-weighted/examples.json create mode 100644 src/strategies/giveth-balances-supply-weighted/index.ts diff --git a/src/strategies/giveth-balances-supply-weighted/README.md b/src/strategies/giveth-balances-supply-weighted/README.md new file mode 100644 index 000000000..c7f503532 --- /dev/null +++ b/src/strategies/giveth-balances-supply-weighted/README.md @@ -0,0 +1,3 @@ +# Giveth Balances Supply Weighted + +This strategy is used to get the balance of tokens a user holds + the amount they have staked in GIVpower. It gets the sum of those balances, divides it by the circulating supply of the GIV token from an API endpoint then applies a weight to it. \ No newline at end of file diff --git a/src/strategies/giveth-balances-supply-weighted/examples.json b/src/strategies/giveth-balances-supply-weighted/examples.json new file mode 100644 index 000000000..932f20fb1 --- /dev/null +++ b/src/strategies/giveth-balances-supply-weighted/examples.json @@ -0,0 +1,28 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "giveth-balances-supply-weighted", + "params": { + "tokenAddress": "0x528CDc92eAB044E1E39FE43B9514bfdAB4412B98", + "stakedAddress": "0x301C739CF6bfb6B47A74878BdEB13f92F13Ae5E7", + "supplyApi": "https://circulating.giveth.io/token-supply", + "supplyField": "circulating", + "weight": 0.5, + "symbol": "GIV", + "decimals": 18, + "methodABI": { + "method" : "function depositTokenBalance(address) public view returns (uint256)", + "name": "depositTokenBalance" + } + } + }, + "network": "10", + "addresses": [ + "0x826976d7C600d45FB8287CA1d7c76FC8eb732030", + "0x839395e20bbB182fa440d08F850E6c7A8f6F0780", + "0x960A16c9070A9BbbB03e1bFd418982636D56D77d" + ], + "snapshot": 117386958 + } +] \ No newline at end of file diff --git a/src/strategies/giveth-balances-supply-weighted/index.ts b/src/strategies/giveth-balances-supply-weighted/index.ts new file mode 100644 index 000000000..bacd78575 --- /dev/null +++ b/src/strategies/giveth-balances-supply-weighted/index.ts @@ -0,0 +1,70 @@ +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; +import { BigNumber } from '@ethersproject/bignumber'; + +export const author = 'divine-comedian'; +export const version = '0.1.0'; + +const abi = [ + 'function balanceOf(address account) external view returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const supply = fetch(options.supplyApi, { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + } + }).then((response) => response.json()); + + const tokenMulti = new Multicaller(network, provider, abi, { blockTag }); + const stakedMulti = new Multicaller( + network, + provider, + [options.methodABI.method] as string[], + { + blockTag + } + ); + addresses.forEach((address) => { + tokenMulti.call(address, options.tokenAddress, 'balanceOf', [address]), + stakedMulti.call(address, options.stakedAddress, options.methodABI.name, [ + address + ]); + }); + const tokenBalance = tokenMulti.execute(); + const stakedBalance = stakedMulti.execute(); + + const [supplyResult, tokenResult, stakedResult]: [ + any, + Record, + Record + ] = await Promise.all([supply, tokenBalance, stakedBalance]); + + const circulatingSupply = parseFloat( + formatUnits(supplyResult[options.supplyField], options.decimals) + ); + + return Object.fromEntries( + Object.entries(tokenResult).map(([address, tokenBalance]) => { + const stakedBalance = stakedResult[address]; + const totalBalance = tokenBalance.add(stakedBalance); + return [ + address, + (parseFloat(formatUnits(totalBalance, options.decimals)) / + circulatingSupply) * + options.weight + ]; + }) + ); +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 77f40e0ff..3ae65b45a 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -414,10 +414,12 @@ import * as voltVotingPower from './volt-voting-power'; import * as xdaiStakersAndHolders from './xdai-stakers-and-holders'; import * as minimeBalanceVsSupplyWeighted from './minime-balance-vs-supply-weighted'; import * as vestingBalanceOf from './vesting-balance-of'; +import * as givethBalancesSupplyWeighted from './giveth-balances-supply-weighted'; import * as givethGnosisBalanceSupplyWeightedV3 from './giveth-gnosis-balance-supply-weighted-v3'; import * as stakeMineLiquidHelios from './stake-mine-liquid-helios'; const strategies = { + 'giveth-balances-supply-weighted': givethBalancesSupplyWeighted, 'giveth-gnosis-balance-supply-weighted-v3': givethGnosisBalanceSupplyWeightedV3, 'minime-balance-vs-supply-weighted': minimeBalanceVsSupplyWeighted, From dfbb795526c7d3ea86a073fa4c09dfaa8337b089 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 14 Mar 2024 11:38:20 +0530 Subject: [PATCH 615/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.9 (#1432) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 6da9db704..f5fccdd29 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.8", + "@snapshot-labs/snapshot.js": "^0.11.9", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index f912e5634..7d700cdaa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.8": - version "0.11.8" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.8.tgz#7d8c1c0b049f72835518a2c65a44380fbc8990d8" - integrity sha512-kHdkdmIC5te3oVdbwKZ7Tykw7qih3bMmlnYvXP7TqeO44pLlqlMmaRguB7Uq+fcENbx4g3v7MW2oREWBoDGwpg== +"@snapshot-labs/snapshot.js@^0.11.9": + version "0.11.9" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.9.tgz#2f7063c5d36f96a59ea0f5df44d7c36897c7f74f" + integrity sha512-o/FPyva4803Vsp2bBxPGzG9Zio9NS2mL7FYez46p4WukZOSEgKZuefEb5j5SKlmACbEf7oKMDeFv/MQ+qKVUqA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 61141052d8b58bbfc4cde91c2da49e4d91b21323 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 14 Mar 2024 19:13:56 +0530 Subject: [PATCH 616/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.10 (#1434) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f5fccdd29..887b0de98 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.9", + "@snapshot-labs/snapshot.js": "^0.11.10", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 7d700cdaa..66a5cb297 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.9": - version "0.11.9" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.9.tgz#2f7063c5d36f96a59ea0f5df44d7c36897c7f74f" - integrity sha512-o/FPyva4803Vsp2bBxPGzG9Zio9NS2mL7FYez46p4WukZOSEgKZuefEb5j5SKlmACbEf7oKMDeFv/MQ+qKVUqA== +"@snapshot-labs/snapshot.js@^0.11.10": + version "0.11.10" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.10.tgz#38bf1abd01da5a3f4780e048a08da52fc35723e8" + integrity sha512-BvhV/OJIK5yAfv0xNXBk30BGARuaPXUwZuM5O1qNFB1JbR/OJJ+WUrpnLPMLPjyBcGhClcfnwmp6ehngBXRyqg== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 7e4ed1048c204e3c5be24081756c6dc8bc4d7f04 Mon Sep 17 00:00:00 2001 From: Mitch <67759413+divine-comedian@users.noreply.github.com> Date: Thu, 14 Mar 2024 10:02:00 -0600 Subject: [PATCH 617/815] add missing formatUnits to totalSupply (#1435) Co-authored-by: Mitch Oz --- src/strategies/minime-balance-vs-supply-weighted/index.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/strategies/minime-balance-vs-supply-weighted/index.ts b/src/strategies/minime-balance-vs-supply-weighted/index.ts index 82d3f9699..67a027ab2 100644 --- a/src/strategies/minime-balance-vs-supply-weighted/index.ts +++ b/src/strategies/minime-balance-vs-supply-weighted/index.ts @@ -1,8 +1,9 @@ import { call } from '../../utils'; import { strategy as erc20BalanceOfStrategy } from '../erc20-balance-of'; +import { formatUnits } from '@ethersproject/units'; export const author = 'divine-comedian'; -export const version = '1.1.0'; +export const version = '1.1.1'; export async function strategy( space, @@ -31,7 +32,8 @@ export async function strategy( return Object.fromEntries( Object.entries(scores).map((score) => [ score[0], - (score[1] / totalSupply) * options.weight + (score[1] / parseFloat(formatUnits(totalSupply, options.decimals))) * + options.weight ]) ); } From b235d3173db90d8266b88579d8981aa12e8edc42 Mon Sep 17 00:00:00 2001 From: Nguyen Ngoc Tan <84736451+tangobeo@users.noreply.github.com> Date: Fri, 15 Mar 2024 15:17:18 +0700 Subject: [PATCH 618/815] [faraland-staking] update subgraph URL (#1433) * update subgraph URL * Update src/strategies/faraland-staking/index.ts * Update examples.json * Update examples.json --------- Co-authored-by: Chaitanya --- src/strategies/faraland-staking/examples.json | 6 +++++- src/strategies/faraland-staking/index.ts | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/strategies/faraland-staking/examples.json b/src/strategies/faraland-staking/examples.json index 0d5eaae85..4f7d82d20 100644 --- a/src/strategies/faraland-staking/examples.json +++ b/src/strategies/faraland-staking/examples.json @@ -9,7 +9,11 @@ } }, "network": "56", - "addresses": ["0x3f105F78359ad80562B4c34296a87b8e66c584C5"], + "addresses": [ + "0x0207ab50c85ea8c96b6189bf1fc19b9f1b879207", + "0x0037a30c54b059f0213b070ff59b2c889b03c680", + "0x27aea25f12f766103d2ee71143349952e480ab0f" + ], "snapshot": 10913859 } ] diff --git a/src/strategies/faraland-staking/index.ts b/src/strategies/faraland-staking/index.ts index 1357adde0..e645adf3e 100644 --- a/src/strategies/faraland-staking/index.ts +++ b/src/strategies/faraland-staking/index.ts @@ -2,11 +2,11 @@ import { getAddress } from '@ethersproject/address'; import { subgraphRequest } from '../../utils'; const FLASHSTAKE_SUBGRAPH_URL = { - '1': 'https://queries-graphnode.faraland.io/subgraphs/name/edwardevans094/farastore-v12', - '56': 'https://queries-graphnode.faraland.io/subgraphs/name/edwardevans094/farastore-v12' + '1': 'https://queries-graphnode-x.faraland.io/subgraphs/name/edwardevans094/farastore-v1', + '56': 'https://queries-graphnode-x.faraland.io/subgraphs/name/edwardevans094/farastore-v1' }; -export const author = 'edwardEvans094'; +export const author = 'toniqhz'; export const version = '0.1.0'; export async function strategy( From a242bfbeea47ec3fa8fe57040fc77a67ade52f9b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 15 Mar 2024 14:41:57 +0530 Subject: [PATCH 619/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.11 (#1436) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 887b0de98..768c27486 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.10", + "@snapshot-labs/snapshot.js": "^0.11.11", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 66a5cb297..2fea897c2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.10": - version "0.11.10" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.10.tgz#38bf1abd01da5a3f4780e048a08da52fc35723e8" - integrity sha512-BvhV/OJIK5yAfv0xNXBk30BGARuaPXUwZuM5O1qNFB1JbR/OJJ+WUrpnLPMLPjyBcGhClcfnwmp6ehngBXRyqg== +"@snapshot-labs/snapshot.js@^0.11.11": + version "0.11.11" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.11.tgz#5793bc466e54742dfbba4cece18c8cf775f0c781" + integrity sha512-O7WDdoPURaFFCWyUuA+JZiVQe/Eo7kphiMgxegM/odnwMRD8mnMejOOWi8VCoDRaKt7krcwt/H9lBd4cgv1uDQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From c9b3e743b7a5c458907693242f8b443000c39726 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 17 Mar 2024 22:28:21 +0530 Subject: [PATCH 620/815] Automated lint (#1426) Co-authored-by: ChaituVR --- .../examples.json | 6 +- src/strategies/index.ts | 2 +- .../push-voting-power/examples.json | 2 +- src/strategies/push-voting-power/index.ts | 25 ++- src/strategies/vesting-balance-of/index.ts | 144 +++++++++++------- 5 files changed, 108 insertions(+), 71 deletions(-) diff --git a/src/strategies/giveth-balances-supply-weighted/examples.json b/src/strategies/giveth-balances-supply-weighted/examples.json index 932f20fb1..6e01cffbc 100644 --- a/src/strategies/giveth-balances-supply-weighted/examples.json +++ b/src/strategies/giveth-balances-supply-weighted/examples.json @@ -12,9 +12,9 @@ "symbol": "GIV", "decimals": 18, "methodABI": { - "method" : "function depositTokenBalance(address) public view returns (uint256)", + "method": "function depositTokenBalance(address) public view returns (uint256)", "name": "depositTokenBalance" - } + } } }, "network": "10", @@ -25,4 +25,4 @@ ], "snapshot": 117386958 } -] \ No newline at end of file +] diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 3ae65b45a..ac4f7f4a3 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -842,7 +842,7 @@ const strategies = { 'xdai-stakers-and-holders': xdaiStakersAndHolders, 'urbit-galaxies': urbitGalaxies, 'vesting-balance-of': vestingBalanceOf, - 'stake-mine-liquid-helios' : stakeMineLiquidHelios, + 'stake-mine-liquid-helios': stakeMineLiquidHelios }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/push-voting-power/examples.json b/src/strategies/push-voting-power/examples.json index 13ed8b126..fadb4a251 100644 --- a/src/strategies/push-voting-power/examples.json +++ b/src/strategies/push-voting-power/examples.json @@ -13,7 +13,7 @@ "WETHAddress": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "USDTAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7", - "pushUniStakingV2":"0x9D2513F5b539DC774C66b28ACEc94e4bD00105C2", + "pushUniStakingV2": "0x9D2513F5b539DC774C66b28ACEc94e4bD00105C2", "pushStakingInfoCoreV2": "0x66329Fdd4042928BfCAB60b179e1538D56eeeeeE", "decimals": 18 } diff --git a/src/strategies/push-voting-power/index.ts b/src/strategies/push-voting-power/index.ts index 1859b4458..c126616ba 100644 --- a/src/strategies/push-voting-power/index.ts +++ b/src/strategies/push-voting-power/index.ts @@ -84,7 +84,7 @@ export async function strategy( { blockTag } ); - const responseStakedV2 = await multicall( + const responseStakedV2 = await multicall( network, provider, sharedABI, @@ -94,7 +94,8 @@ export async function strategy( options.pushStakingInfoCoreV2, 'userFeesInfo', [address.toLowerCase()] - ]).concat( + ]) + .concat( addresses.map((address: any) => [ options.pushUniStakingV2, 'balanceOf', @@ -102,16 +103,16 @@ export async function strategy( ]) ), { blockTag } - ); + ); const responseStakedPUSH = responseStaked.slice(0, addresses.length); let responseStakedPUSHV2 = responseStakedV2.slice(0, addresses.length); - responseStakedPUSHV2 = responseStakedPUSHV2.map((value, i) => {return value[0].toString()}); -const responseStakedLP = responseStaked.slice(addresses.length); + responseStakedPUSHV2 = responseStakedPUSHV2.map((value, i) => { + return value[0].toString(); + }); + const responseStakedLP = responseStaked.slice(addresses.length); const responseStakedLPV2 = responseStakedV2.slice(addresses.length); - - const responseWETH = await multicall( network, provider, @@ -156,15 +157,14 @@ const responseStakedLP = responseStaked.slice(addresses.length); { blockTag } ); - // Calculating price of EPNS-LP Tokens in terms of EPNS Tokens const uniLpTotalSupply = tokenBNtoNumber(responseEPNSLPToken[0][0]); const uniLpPrice = (pushAmountReserve * pushPrice + wethAmountReserve * wethPrice) / uniLpTotalSupply; -const lpToPushRatio = uniLpPrice / pushPrice; + const lpToPushRatio = uniLpPrice / pushPrice; -// console.log(uniLpTotalSupply) + // console.log(uniLpTotalSupply) return Object.fromEntries( responseDelegatedPUSH.map((value, i) => [ addresses[i], @@ -174,12 +174,11 @@ const lpToPushRatio = uniLpPrice / pushPrice; parseFloat( formatUnits(responseStakedPUSH[i].toString(), options.decimals) ) + - parseFloat(formatUnits(responseStakedPUSHV2[i], options.decimals))+ + parseFloat(formatUnits(responseStakedPUSHV2[i], options.decimals)) + parseFloat( formatUnits(responseStakedLPV2[i].toString(), options.decimals) ) * - lpToPushRatio - + + lpToPushRatio + parseFloat( formatUnits(responseStakedLP[i].toString(), options.decimals) ) * diff --git a/src/strategies/vesting-balance-of/index.ts b/src/strategies/vesting-balance-of/index.ts index fffcc4634..481bb47c2 100644 --- a/src/strategies/vesting-balance-of/index.ts +++ b/src/strategies/vesting-balance-of/index.ts @@ -1,41 +1,40 @@ -import {BigNumber, BigNumberish} from '@ethersproject/bignumber'; -import {formatUnits} from '@ethersproject/units'; -import {Multicaller} from '../../utils'; +import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; export const author = 'propchain-development'; export const version = '0.1.0'; - const vestingABI = [ 'function userPropertiesList(address wallet) view returns (tuple(bool isActive, uint256 spentAmount, uint256 vestingId, bool tgeClaimed) userProperties)', 'function vestingPropertiesList() view returns (tuple(uint256 amountForUser, uint256 tgeAmountForUser, uint256 startTime, uint256 tickCount, uint256 tickDuration, uint256 unallocatedAmount, bool active)[] vestingList)' -] +]; interface Options { - vesting_1: string, - vesting_2?: string, - vesting_3?: string, - vesting_4?: string, - vesting_5?: string, - vesting_6?: string, - decimals: number + vesting_1: string; + vesting_2?: string; + vesting_3?: string; + vesting_4?: string; + vesting_5?: string; + vesting_6?: string; + decimals: number; } interface VestingProperties { - amountForUser: BigNumberish, - tgeAmountForUser: BigNumberish, - startTime: BigNumberish, - tickCount: BigNumberish, - tickDuration: BigNumberish, - unallocatedAmount: BigNumberish, - active: boolean + amountForUser: BigNumberish; + tgeAmountForUser: BigNumberish; + startTime: BigNumberish; + tickCount: BigNumberish; + tickDuration: BigNumberish; + unallocatedAmount: BigNumberish; + active: boolean; } interface UserProperties { - isActive: boolean, - spentAmount: BigNumberish, - vestingId: BigNumberish, - tgeClaimed: boolean + isActive: boolean; + spentAmount: BigNumberish; + vestingId: BigNumberish; + tgeClaimed: boolean; } export async function strategy( @@ -48,46 +47,85 @@ export async function strategy( ): Promise> { const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - const multi = new Multicaller( - network, - provider, - vestingABI, { blockTag } - ); + const multi = new Multicaller(network, provider, vestingABI, { blockTag }); - multi.call(options.vesting_1, options.vesting_1, 'vestingPropertiesList', []) - if(options.vesting_2) - multi.call(options.vesting_2, options.vesting_1, 'vestingPropertiesList', []) - if(options.vesting_3) - multi.call(options.vesting_3, options.vesting_1, 'vestingPropertiesList', []) - if(options.vesting_4) - multi.call(options.vesting_4, options.vesting_1, 'vestingPropertiesList', []) + multi.call(options.vesting_1, options.vesting_1, 'vestingPropertiesList', []); + if (options.vesting_2) + multi.call( + options.vesting_2, + options.vesting_1, + 'vestingPropertiesList', + [] + ); + if (options.vesting_3) + multi.call( + options.vesting_3, + options.vesting_1, + 'vestingPropertiesList', + [] + ); + if (options.vesting_4) + multi.call( + options.vesting_4, + options.vesting_1, + 'vestingPropertiesList', + [] + ); - const vestingRecords: Record = await multi.execute(); + const vestingRecords: Record = + await multi.execute(); addresses.forEach((address: string) => { - multi.call(address+"_"+options.vesting_1, options.vesting_1, 'userPropertiesList', [address]); - if(options.vesting_2) - multi.call(address+"_"+options.vesting_2, options.vesting_2, 'userPropertiesList', [address]); - if(options.vesting_3) - multi.call(address+"_"+options.vesting_3, options.vesting_3, 'userPropertiesList', [address]) - if(options.vesting_4) - multi.call(address+"_"+options.vesting_4, options.vesting_4, 'userPropertiesList', [address]) - if(options.vesting_5) - multi.call(address+"_"+options.vesting_5, options.vesting_5, 'userPropertiesList', [address]) + multi.call( + address + '_' + options.vesting_1, + options.vesting_1, + 'userPropertiesList', + [address] + ); + if (options.vesting_2) + multi.call( + address + '_' + options.vesting_2, + options.vesting_2, + 'userPropertiesList', + [address] + ); + if (options.vesting_3) + multi.call( + address + '_' + options.vesting_3, + options.vesting_3, + 'userPropertiesList', + [address] + ); + if (options.vesting_4) + multi.call( + address + '_' + options.vesting_4, + options.vesting_4, + 'userPropertiesList', + [address] + ); + if (options.vesting_5) + multi.call( + address + '_' + options.vesting_5, + options.vesting_5, + 'userPropertiesList', + [address] + ); }); const userProperties: Record = await multi.execute(); - let filteredRecords : Record = {}; + const filteredRecords: Record = {}; Object.entries(userProperties).forEach(([identifier, user]) => { - const [addr, vestingBucket] = identifier.split("_"); - if(!filteredRecords[addr]) - filteredRecords[addr] = 0; + const [addr, vestingBucket] = identifier.split('_'); + if (!filteredRecords[addr]) filteredRecords[addr] = 0; - if(!user.isActive) - return; + if (!user.isActive) return; - const amountRaw = vestingRecords[vestingBucket][BigNumber.from(user.vestingId).toNumber()].amountForUser - filteredRecords[addr] += parseFloat(formatUnits(amountRaw, options.decimals)); + const amountRaw = + vestingRecords[vestingBucket][BigNumber.from(user.vestingId).toNumber()] + .amountForUser; + filteredRecords[addr] += parseFloat( + formatUnits(amountRaw, options.decimals) + ); }); return filteredRecords; From 259917e2e889bfbb95b265753f162c99ce34512d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 18 Mar 2024 10:00:11 +0530 Subject: [PATCH 621/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.12 (#1437) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 768c27486..4ad9eef27 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.11", + "@snapshot-labs/snapshot.js": "^0.11.12", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 2fea897c2..d4d962914 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.11": - version "0.11.11" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.11.tgz#5793bc466e54742dfbba4cece18c8cf775f0c781" - integrity sha512-O7WDdoPURaFFCWyUuA+JZiVQe/Eo7kphiMgxegM/odnwMRD8mnMejOOWi8VCoDRaKt7krcwt/H9lBd4cgv1uDQ== +"@snapshot-labs/snapshot.js@^0.11.12": + version "0.11.12" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.12.tgz#11add14cdee05726bba4df57b30984c0784f81a8" + integrity sha512-oHD/Ld3mfKrzq+7GeNuqsR3wjWc6xPAyZdqTzICg4ZuxJwMueU99hK13WZUZeJoyIoqkQoXMeKXGUHMbWYn3SQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 287fba1e102d88ec029b559f8b288492c28e9834 Mon Sep 17 00:00:00 2001 From: Macaron Chef <78917582+macaronchef@users.noreply.github.com> Date: Tue, 19 Mar 2024 05:20:38 +0300 Subject: [PATCH 622/815] [single-staking-longtermstaking-balanceof] strategy for long term vault balance (#1430) * strategy for long term vault balance * strategy added to index.ts strategy single-staking-longtermstaking-balanceof added to src/strategies/index.ts * Update src/strategies/index.ts * Update src/strategies/index.ts * Update src/strategies/index.ts * fixed --------- Co-authored-by: Chaitanya --- src/strategies/index.ts | 2 + .../README.md | 12 +++++ .../examples.json | 20 ++++++++ .../index.ts | 51 +++++++++++++++++++ 4 files changed, 85 insertions(+) create mode 100644 src/strategies/single-staking-longtermstaking-balanceof/README.md create mode 100644 src/strategies/single-staking-longtermstaking-balanceof/examples.json create mode 100644 src/strategies/single-staking-longtermstaking-balanceof/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index ac4f7f4a3..41a358ebe 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -184,6 +184,7 @@ import * as flexaCapacityStaking from './flexa-capacity-staking'; import * as sunriseGamingUniv2Lp from './sunrisegaming-univ2-lp'; import * as sunriseGamingStaking from './sunrisegaming-staking'; import * as singleStakingAutoCompoundBalanceOf from './single-staking-autocompound-balanceof'; +import * as singleStakingLongTermStakingBalanceOf from './single-staking-longtermstaking-balanceof'; import * as singleStakingPoolsBalanceOf from './single-staking-pools-balanceof'; import * as occStakeOf from './occ-stake-of'; import * as hoprBridgedBalance from './hopr-bridged-balance'; @@ -615,6 +616,7 @@ const strategies = { 'sunrisegaming-univ2-lp': sunriseGamingUniv2Lp, 'sunrisegaming-staking': sunriseGamingStaking, 'single-staking-autocompound-balanceof': singleStakingAutoCompoundBalanceOf, + 'single-staking-longtermstaking-balanceof': singleStakingLongTermStakingBalanceOf, 'single-staking-pools-balanceof': singleStakingPoolsBalanceOf, 'hopr-stake-and-balance-qv': hoprStakeAndBalanceQV, 'hopr-bridged-balance': hoprBridgedBalance, diff --git a/src/strategies/single-staking-longtermstaking-balanceof/README.md b/src/strategies/single-staking-longtermstaking-balanceof/README.md new file mode 100644 index 000000000..669fd64c6 --- /dev/null +++ b/src/strategies/single-staking-longtermstaking-balanceof/README.md @@ -0,0 +1,12 @@ +# single-staking-autocompound-balanceof + +Used for fetching the staked token balance in an long term single staking vault. + +Here is an example of parameters: + +```json +{ + "stakingPoolAddress": "0xe69D70069877929fda936dE5E5c83b441822D63F", + "decimals": 18 +} +``` diff --git a/src/strategies/single-staking-longtermstaking-balanceof/examples.json b/src/strategies/single-staking-longtermstaking-balanceof/examples.json new file mode 100644 index 000000000..eb696de24 --- /dev/null +++ b/src/strategies/single-staking-longtermstaking-balanceof/examples.json @@ -0,0 +1,20 @@ +[ + { + "name": "Single Staking Amount from Long Term Vault", + "strategy": { + "name": "single-staking-longtermstaking-balanceof", + "params": { + "stakingPoolAddress": "0xe69D70069877929fda936dE5E5c83b441822D63F", + "symbol": "MCRN", + "decimals": 18 + } + }, + "network": "56", + "addresses": [ + "0x46D8e47b9A6487FDAB0a700b269A452cFeED49Aa", + "0x46D8e47b9A6487FDAB0a700b269A452cFeED49Aa", + "0x46D8e47b9A6487FDAB0a700b269A452cFeED49Aa" + ], + "snapshot": 37085430 + } +] \ No newline at end of file diff --git a/src/strategies/single-staking-longtermstaking-balanceof/index.ts b/src/strategies/single-staking-longtermstaking-balanceof/index.ts new file mode 100644 index 000000000..68d87dad6 --- /dev/null +++ b/src/strategies/single-staking-longtermstaking-balanceof/index.ts @@ -0,0 +1,51 @@ +/* eslint-disable prettier/prettier */ +import { formatUnits } from '@ethersproject/units'; +import { multicall, Multicaller } from '../../utils'; + +export const author = 'macaronchef'; +export const version = '0.1.0'; +export const dependOnOtherAddress = false; + +const abi = [ + 'function userInfo(address) view returns (uint256 shares, uint256 lastDepositedTime, uint256 macaronAtLastUserAction, uint256 lastUserActionTime, uint256 lockStartTime, uint256 lockEndTime, uint256 userBoostedShare, bool locked, uint256 lockedAmount)', + 'function getPricePerFullShare() view returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multi = new Multicaller(network, provider, abi, { blockTag }); + + addresses.forEach((address) => + multi.call(address, options.stakingPoolAddress, 'userInfo', [address]) + ); + + const [[[getPricePerFullShare]]] = await Promise.all([ + multicall( + network, + provider, + abi, + [[options.stakingPoolAddress, 'getPricePerFullShare', []]], + { blockTag } + ) + ]); + + const result: Record = await multi.execute(); + + return Object.fromEntries( + Object.entries(result).map(([address, userInfo]) => { + const fee = formatUnits(userInfo.userBoostedShare, options.decimals); + return [ + address, + (parseFloat(formatUnits(userInfo.shares, options.decimals)) * parseFloat(formatUnits(getPricePerFullShare, options.decimals))) - parseFloat(fee) + ]; + }) + ); +} From bd5e4859da59ed4f8ed3ab7072ccfac4f95a35d5 Mon Sep 17 00:00:00 2001 From: Nguyen Ngoc Tan <84736451+tangobeo@users.noreply.github.com> Date: Tue, 19 Mar 2024 13:10:42 +0700 Subject: [PATCH 623/815] [faraland-staking] update subgraph URL (#1438) * update subgraph URL * Update src/strategies/faraland-staking/index.ts * Update examples.json * Update examples.json * Update subgraph URL * Update examples.json --------- Co-authored-by: Chaitanya --- src/strategies/faraland-staking/examples.json | 6 +++--- src/strategies/faraland-staking/index.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/strategies/faraland-staking/examples.json b/src/strategies/faraland-staking/examples.json index 4f7d82d20..18bc17558 100644 --- a/src/strategies/faraland-staking/examples.json +++ b/src/strategies/faraland-staking/examples.json @@ -10,9 +10,9 @@ }, "network": "56", "addresses": [ - "0x0207ab50c85ea8c96b6189bf1fc19b9f1b879207", - "0x0037a30c54b059f0213b070ff59b2c889b03c680", - "0x27aea25f12f766103d2ee71143349952e480ab0f" + "0x5ce2e064ca2207f110a69b2bcf1e90e6c3ccec0e", + "0x7b2fc00d4f60c42098862c5a5e9f9e6f5f7762d4", + "0x843ef28f7eb99727d21a015955172b767fbcb84d" ], "snapshot": 10913859 } diff --git a/src/strategies/faraland-staking/index.ts b/src/strategies/faraland-staking/index.ts index e645adf3e..6d0d081e4 100644 --- a/src/strategies/faraland-staking/index.ts +++ b/src/strategies/faraland-staking/index.ts @@ -2,8 +2,8 @@ import { getAddress } from '@ethersproject/address'; import { subgraphRequest } from '../../utils'; const FLASHSTAKE_SUBGRAPH_URL = { - '1': 'https://queries-graphnode-x.faraland.io/subgraphs/name/edwardevans094/farastore-v1', - '56': 'https://queries-graphnode-x.faraland.io/subgraphs/name/edwardevans094/farastore-v1' + '1': 'https://queries-graphnode-x.faraland.io/subgraphs/name/edwardevans094/staking-v1', + '56': 'https://queries-graphnode-x.faraland.io/subgraphs/name/edwardevans094/staking-v1' }; export const author = 'toniqhz'; From 62d707780e34642d8182acb423537171ee125087 Mon Sep 17 00:00:00 2001 From: Ahmad Yazdani <36488976+ahmadyazdanii@users.noreply.github.com> Date: Fri, 22 Mar 2024 22:44:46 +0330 Subject: [PATCH 624/815] [pokt-network-pda] Add Pokt network strategy (#1440) * new [pokt network]: add the pokt-network-pda strategy * fix [pokt network]: change decimal function and update examples * fix [pokt network]: fix gateway logic * Update README.md * new [pokt network]: remove wallets which does not have citizen PDA point * fix [pokt network]: change example block tag to make unit tests valid when using snapshot tag * fix [pokt network]: change format of one of strategy in index file Co-authored-by: Chaitanya * fix [pokt network]: change author --------- Co-authored-by: mehrdad mirmohammadsadeghi <35366864+mehrdadmms@users.noreply.github.com> Co-authored-by: Chaitanya --- src/strategies/index.ts | 4 +- src/strategies/pokt-network-pda/README.md | 20 ++ src/strategies/pokt-network-pda/examples.json | 32 +++ src/strategies/pokt-network-pda/index.ts | 231 ++++++++++++++++++ src/strategies/pokt-network-pda/schema.json | 35 +++ 5 files changed, 321 insertions(+), 1 deletion(-) create mode 100644 src/strategies/pokt-network-pda/README.md create mode 100644 src/strategies/pokt-network-pda/examples.json create mode 100644 src/strategies/pokt-network-pda/index.ts create mode 100644 src/strategies/pokt-network-pda/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 41a358ebe..f5e6b7821 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -415,6 +415,7 @@ import * as voltVotingPower from './volt-voting-power'; import * as xdaiStakersAndHolders from './xdai-stakers-and-holders'; import * as minimeBalanceVsSupplyWeighted from './minime-balance-vs-supply-weighted'; import * as vestingBalanceOf from './vesting-balance-of'; +import * as poktNetworkPDA from './pokt-network-pda'; import * as givethBalancesSupplyWeighted from './giveth-balances-supply-weighted'; import * as givethGnosisBalanceSupplyWeightedV3 from './giveth-gnosis-balance-supply-weighted-v3'; import * as stakeMineLiquidHelios from './stake-mine-liquid-helios'; @@ -844,7 +845,8 @@ const strategies = { 'xdai-stakers-and-holders': xdaiStakersAndHolders, 'urbit-galaxies': urbitGalaxies, 'vesting-balance-of': vestingBalanceOf, - 'stake-mine-liquid-helios': stakeMineLiquidHelios + 'stake-mine-liquid-helios': stakeMineLiquidHelios, + 'pokt-network-pda': poktNetworkPDA }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/pokt-network-pda/README.md b/src/strategies/pokt-network-pda/README.md new file mode 100644 index 000000000..e04097fce --- /dev/null +++ b/src/strategies/pokt-network-pda/README.md @@ -0,0 +1,20 @@ +# Pocket Network Strategy v1 + +This strategy manages to fetch the latest PDAs' snapshot from Arweave and proceeds to calculate the voting power of each wallet using the following formula: +- If wallet is not a POKT Citizen their vote will be zero +- The ratio between impact house and stake house is 80:20 +- Each builder from the impact house has one vote providing their point is more than 0 +- Stakers are as follows: +- Validators and liquidity providers collectively hold 50% of the stake house which will be calculated by summing all of their points and then SQRT of that total +- Gateways hold 50% of the staker house which will be caclulated using SQRT of their points + +# Example +Here is an example of parameters: + +```json +{ + "arweave_network": "DEVNET", + "owner_address": "0x7adc6c9d79c8afd8700da4c3ca87d8aa68d31b9d", + "decimals": 8 +} +``` diff --git a/src/strategies/pokt-network-pda/examples.json b/src/strategies/pokt-network-pda/examples.json new file mode 100644 index 000000000..cd98a8cf5 --- /dev/null +++ b/src/strategies/pokt-network-pda/examples.json @@ -0,0 +1,32 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "pokt-network-pda", + "params": { + "arweave_network": "DEVNET", + "owner_address": "0x857d9c5696fb6be080ce0d8cd10719a64a116bc4", + "decimals": 8 + } + }, + "network": "1", + "addresses": [ + "0x4ba90A88649E707F28Ec0f9Ca1f2008729aEf3B1", + "0x8424B45e4EA18522A4eAD068da80773b5A62F19a", + "0x098a699E7faE9f4FaB9F79683fe0fAdf283E1D00", + "0xBF722B58DBA78204213Aa04CC0706190C6054B6A", + "0xac10A4BbCFeC8ada8C2FAb9A66F40d27e6395E82", + "0x0eaa99C8119F7adA3633E1ad1381c5E9199A2BfD", + "0xaBdd13102A86E502eb5A1e4b171471eB4d90420f", + "0x73f87225EE3aF28d8Db4dBaedFC7a75be45e25bb", + "0x3470504CdE4c2a7c23D56c69F3C7A02E7912603C", + "0xf34c63ad647E9805D02415ce458600306D71017B", + "0x7f5B8015AB71BfCAF3457d1AEc9C284f489852b4", + "0x9181a3b3ad8Ba29B6ff755183717392a1cf49375", + "0x959836EAec8fF42B708b7D5F8071B6e206ED8D64", + "0x7923232a8E880CAB98123f30DE49F7b4305b67f9", + "0x906AE094dD28Aa02cFBfAe776B800d4a7903e2F2" + ], + "snapshot": 19483363 + } +] diff --git a/src/strategies/pokt-network-pda/index.ts b/src/strategies/pokt-network-pda/index.ts new file mode 100644 index 000000000..4950aa5f6 --- /dev/null +++ b/src/strategies/pokt-network-pda/index.ts @@ -0,0 +1,231 @@ +import fetch from 'cross-fetch'; +import { subgraphRequest } from '../../utils'; +import { EnumType } from 'json-to-graphql-query'; + +// Interfaces +interface PoktNetworkOptions { + arweave_network: 'MAINNET' | 'DEVNET'; + owner_address: string; + decimals: number; +} + +interface ArweaveBlockResponse { + transactions: { + edges: [ + { + node: { + id: string; + }; + } + ]; + }; +} + +interface StoreDomainBlock { + point: number; + PDAs: string; +} + +interface StakerDomainBlock { + validator?: Block; + gateway?: Block; + 'liquidity provider'?: Block; +} + +interface PDAScores { + [walletAddress: string]: { + citizen?: StoreDomainBlock; + builder?: StoreDomainBlock; + staker?: StakerDomainBlock; + }; +} + +interface SumHousesPoints { + builder_points: number; + validator_and_liquidity_provider_points: number; + gateway_points: number; +} + +// Major constants +export const author = 'Microflow-xyz'; +export const version = '0.1.0'; +// Constants +const IRYS_NETWORK_GRAPHQL_URL = { + MAINNET: 'https://node1.irys.xyz/graphql', + DEVNET: 'https://devnet.irys.xyz/graphql' +}; +const ARWEAVE_BASE_URL = 'https://arweave.net'; +const ARWEAVE_POKT_NETWORK_TAGS = [ + { name: 'Content-Type', values: ['application/json'] }, + { name: 'Application-ID', values: ['POKT-NETWORK-PDA-SCORING-SYSTEM'] }, + { name: 'Data-ID', values: ['PDAs-SCORES'] } +]; +const HOUSE_SHARES = { + builder: 0.8, + staker: 0.2 +}; +const STAKER_HOUSE_SHARES = { + validator_and_liquidity_provider: 0.5, + gateway: 0.5 +}; + +function calculateSumHousesPoints(PDAScores: PDAScores): SumHousesPoints { + const result = { + builder_points: 0, + validator_and_liquidity_provider_points: 0, + gateway_points: 0 + }; + + for (const walletAddr in PDAScores) { + if (Object.prototype.hasOwnProperty.call(PDAScores, walletAddr)) { + const scoreBlock = PDAScores[walletAddr]; + const builderHouse = scoreBlock.builder; + const stakerHouse = scoreBlock.staker; + const citizenHouse = scoreBlock.citizen; + + if (citizenHouse && citizenHouse.point > 0) { + if (builderHouse && builderHouse.point > 0) { + result.builder_points += 1; + } + + if (stakerHouse) { + const validatorHouse = stakerHouse.validator; + const gatewayHouse = stakerHouse.gateway; + const liquidityProviderHouse = stakerHouse['liquidity provider']; + + if (validatorHouse || liquidityProviderHouse) { + const validatorHousePoint = validatorHouse?.point || 0; + const liquidityProviderHousePoint = + liquidityProviderHouse?.point || 0; + + result.validator_and_liquidity_provider_points += Math.sqrt( + validatorHousePoint + liquidityProviderHousePoint + ); + } + + if (gatewayHouse && gatewayHouse.point > 0) { + result.gateway_points += Math.sqrt(gatewayHouse.point); + } + } + } + } + } + + return result; +} + +function calculateHousesPower( + PDAScores: PDAScores, + powers: Record, + sumHousesPoints: SumHousesPoints +) { + for (const walletAddr in powers) { + if (Object.prototype.hasOwnProperty.call(powers, walletAddr)) { + if (walletAddr in PDAScores) { + const scoreBlock = PDAScores[walletAddr]; + const builderHouse = scoreBlock.builder; + const stakerHouse = scoreBlock.staker; + const citizenHouse = scoreBlock.citizen; + + if (citizenHouse && citizenHouse.point > 0) { + if (builderHouse && builderHouse.point > 0) { + powers[walletAddr] += + (1 / sumHousesPoints.builder_points) * HOUSE_SHARES.builder; + } + + if (stakerHouse) { + const validatorHouse = stakerHouse.validator; + const gatewayHouse = stakerHouse.gateway; + const liquidityProviderHouse = stakerHouse['liquidity provider']; + + if (validatorHouse || liquidityProviderHouse) { + const validatorHousePoint = validatorHouse?.point || 0; + const liquidityProviderHousePoint = + liquidityProviderHouse?.point || 0; + + powers[walletAddr] += + (Math.sqrt(validatorHousePoint + liquidityProviderHousePoint) / + sumHousesPoints.validator_and_liquidity_provider_points) * + STAKER_HOUSE_SHARES.validator_and_liquidity_provider * + HOUSE_SHARES.staker; + } + + if (gatewayHouse && gatewayHouse.point > 0) { + powers[walletAddr] += + (Math.sqrt(gatewayHouse.point) / + sumHousesPoints.gateway_points) * + STAKER_HOUSE_SHARES.gateway * + HOUSE_SHARES.staker; + } + } + } + } + } + } +} + +async function getArweaveBlock( + url: string, + ownerAddress: string, + timestamp: number +): Promise { + const query = { + transactions: { + __args: { + tags: ARWEAVE_POKT_NETWORK_TAGS, + owners: [ownerAddress], + order: new EnumType('DESC'), + first: 1, + timestamp: { to: timestamp * 1000 } + }, + edges: { + node: { + id: true + } + } + } + }; + + return subgraphRequest(url, query); +} + +async function getArweaveData(arweaveBlockID: string): Promise { + const arweaveDataURL = new URL(arweaveBlockID, ARWEAVE_BASE_URL); + const response = await fetch(arweaveDataURL); + + return response.json(); +} + +export async function strategy( + space: string, + network: string, + provider, + addresses: Array, + options: PoktNetworkOptions, + snapshot: string | number | undefined +): Promise> { + const powers: Record = + Object.fromEntries(addresses.map((address) => [address, 0.0])) || {}; + + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const timestamp = (await provider.getBlock(blockTag)).timestamp; + + const arweaveBlock = await getArweaveBlock( + IRYS_NETWORK_GRAPHQL_URL[options.arweave_network], + options.owner_address, + timestamp + ); + const arweaveBlockID = arweaveBlock?.transactions?.edges?.[0]?.node?.id; + + if (arweaveBlockID) { + const arweaveData = await getArweaveData(arweaveBlockID); + + const sumHousesPoints = calculateSumHousesPoints(arweaveData); + calculateHousesPower(arweaveData, powers, sumHousesPoints); + } + + return Object.keys(powers).reduce((current, key) => { + current[key] = parseFloat(powers[key].toFixed(options.decimals)); + return current; + }, {}); +} diff --git a/src/strategies/pokt-network-pda/schema.json b/src/strategies/pokt-network-pda/schema.json new file mode 100644 index 000000000..8774a8386 --- /dev/null +++ b/src/strategies/pokt-network-pda/schema.json @@ -0,0 +1,35 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "arweave_network": { + "type": "string", + "title": "Arweave Network", + "examples": ["MAINNET", "DEVNET"], + "enum": ["MAINNET", "DEVNET"], + "default": "MAINNET" + }, + "owner_address": { + "type": "string", + "title": "Owner address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 18"], + "minimum": 0 + } + }, + "required": ["owner_address", "decimals"], + "additionalProperties": false + } + } +} From b60f95efd360e1a1b140c33cb06cd87529fe0a70 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 23 Mar 2024 00:50:45 +0530 Subject: [PATCH 625/815] Automated lint (#1442) Co-authored-by: ChaituVR --- src/strategies/index.ts | 3 ++- .../single-staking-longtermstaking-balanceof/examples.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/strategies/index.ts b/src/strategies/index.ts index f5e6b7821..a805ff582 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -617,7 +617,8 @@ const strategies = { 'sunrisegaming-univ2-lp': sunriseGamingUniv2Lp, 'sunrisegaming-staking': sunriseGamingStaking, 'single-staking-autocompound-balanceof': singleStakingAutoCompoundBalanceOf, - 'single-staking-longtermstaking-balanceof': singleStakingLongTermStakingBalanceOf, + 'single-staking-longtermstaking-balanceof': + singleStakingLongTermStakingBalanceOf, 'single-staking-pools-balanceof': singleStakingPoolsBalanceOf, 'hopr-stake-and-balance-qv': hoprStakeAndBalanceQV, 'hopr-bridged-balance': hoprBridgedBalance, diff --git a/src/strategies/single-staking-longtermstaking-balanceof/examples.json b/src/strategies/single-staking-longtermstaking-balanceof/examples.json index eb696de24..e8bdd313e 100644 --- a/src/strategies/single-staking-longtermstaking-balanceof/examples.json +++ b/src/strategies/single-staking-longtermstaking-balanceof/examples.json @@ -17,4 +17,4 @@ ], "snapshot": 37085430 } -] \ No newline at end of file +] From add59e15595a2aff97c3b43ebb3b17b60b32812b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 23 Mar 2024 00:53:07 +0530 Subject: [PATCH 626/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.13 (#1441) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Chaitanya --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 4ad9eef27..1ba2a036b 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.12", + "@snapshot-labs/snapshot.js": "^0.11.13", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index d4d962914..a26f71a84 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.12": - version "0.11.12" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.12.tgz#11add14cdee05726bba4df57b30984c0784f81a8" - integrity sha512-oHD/Ld3mfKrzq+7GeNuqsR3wjWc6xPAyZdqTzICg4ZuxJwMueU99hK13WZUZeJoyIoqkQoXMeKXGUHMbWYn3SQ== +"@snapshot-labs/snapshot.js@^0.11.13": + version "0.11.13" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.13.tgz#863a51132b0e76dd1f694e27f4b6e838b7c648b2" + integrity sha512-bUmAsL6yshPA+7m2HYP3aBYV/sftH5pEzaBsIWRX2s4ZYYxcaQytFjtZnRZaM5ae7xBIemb/O9TcOYnfJUFtlw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From c3987a065beed14f1bf72622d70e101bcc2d41ab Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 24 Mar 2024 01:24:06 +0530 Subject: [PATCH 627/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.14 (#1443) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 1ba2a036b..29818a6ce 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.13", + "@snapshot-labs/snapshot.js": "^0.11.14", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index a26f71a84..918810bbc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.13": - version "0.11.13" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.13.tgz#863a51132b0e76dd1f694e27f4b6e838b7c648b2" - integrity sha512-bUmAsL6yshPA+7m2HYP3aBYV/sftH5pEzaBsIWRX2s4ZYYxcaQytFjtZnRZaM5ae7xBIemb/O9TcOYnfJUFtlw== +"@snapshot-labs/snapshot.js@^0.11.14": + version "0.11.14" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.14.tgz#f0ab907d5740bf1d72c1a582aa798fae1ba93cdb" + integrity sha512-FhB4ZQXq81PuTYa6cXJHf4S72KKQZaYtl7vWcAEDQms8uvtCZ5FIokRyWZcKgggckFlrsco0zRyyKxSmmDxrAg== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 23b3ffb92004eaca5794101ebc26b776ae9dc8ae Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 25 Mar 2024 11:27:23 +0530 Subject: [PATCH 628/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.15 (#1444) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 29818a6ce..385bde0e0 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.14", + "@snapshot-labs/snapshot.js": "^0.11.15", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 918810bbc..cb8bd07c8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.14": - version "0.11.14" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.14.tgz#f0ab907d5740bf1d72c1a582aa798fae1ba93cdb" - integrity sha512-FhB4ZQXq81PuTYa6cXJHf4S72KKQZaYtl7vWcAEDQms8uvtCZ5FIokRyWZcKgggckFlrsco0zRyyKxSmmDxrAg== +"@snapshot-labs/snapshot.js@^0.11.15": + version "0.11.15" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.15.tgz#8c9dfb8a718d8ad003dbf2df3a184c10cbce8ac1" + integrity sha512-UM7kIJ72r1+qnPQ1JEqJW1UpcvDhAW8np332BwizO7cvHbqJzJqvQl0YjK2EldD8BffZ+kxp8ltXKoA9dPr6CQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 18beeab08c07556b34ab1f40e598962efeaef795 Mon Sep 17 00:00:00 2001 From: Ahmad Yazdani <36488976+ahmadyazdanii@users.noreply.github.com> Date: Thu, 28 Mar 2024 08:48:23 +0330 Subject: [PATCH 629/815] [pokt-network-pda] Update pokt network strategy (#1445) * new [pokt network]: add the pokt-network-pda strategy * fix [pokt network]: change decimal function and update examples * fix [pokt network]: fix gateway logic * Update README.md * new [pokt network]: remove wallets which does not have citizen PDA point * fix [pokt network]: change example block tag to make unit tests valid when using snapshot tag * fix [pokt network]: change format of one of strategy in index file Co-authored-by: Chaitanya * fix [pokt network]: change author * update [pokt network]: add the multiply prop --------- Co-authored-by: mehrdad mirmohammadsadeghi <35366864+mehrdadmms@users.noreply.github.com> Co-authored-by: Chaitanya --- src/strategies/pokt-network-pda/examples.json | 3 ++- src/strategies/pokt-network-pda/index.ts | 6 +++++- src/strategies/pokt-network-pda/schema.json | 11 +++++++++-- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/strategies/pokt-network-pda/examples.json b/src/strategies/pokt-network-pda/examples.json index cd98a8cf5..5f7744a6f 100644 --- a/src/strategies/pokt-network-pda/examples.json +++ b/src/strategies/pokt-network-pda/examples.json @@ -6,7 +6,8 @@ "params": { "arweave_network": "DEVNET", "owner_address": "0x857d9c5696fb6be080ce0d8cd10719a64a116bc4", - "decimals": 8 + "decimals": 8, + "multiply": 2 } }, "network": "1", diff --git a/src/strategies/pokt-network-pda/index.ts b/src/strategies/pokt-network-pda/index.ts index 4950aa5f6..df2aad3d9 100644 --- a/src/strategies/pokt-network-pda/index.ts +++ b/src/strategies/pokt-network-pda/index.ts @@ -7,6 +7,7 @@ interface PoktNetworkOptions { arweave_network: 'MAINNET' | 'DEVNET'; owner_address: string; decimals: number; + multiply: number; } interface ArweaveBlockResponse { @@ -225,7 +226,10 @@ export async function strategy( } return Object.keys(powers).reduce((current, key) => { - current[key] = parseFloat(powers[key].toFixed(options.decimals)); + current[key] = parseFloat( + (powers[key] * 10 ** options.multiply).toFixed(options.decimals) + ); + return current; }, {}); } diff --git a/src/strategies/pokt-network-pda/schema.json b/src/strategies/pokt-network-pda/schema.json index 8774a8386..1ea156e26 100644 --- a/src/strategies/pokt-network-pda/schema.json +++ b/src/strategies/pokt-network-pda/schema.json @@ -22,13 +22,20 @@ "maxLength": 42 }, "decimals": { - "type": "number", + "type": "integer", "title": "Decimals", "examples": ["e.g. 18"], "minimum": 0 + }, + "multiply": { + "type": "integer", + "title": "Multiply", + "examples": ["e.g. 18"], + "default": 0, + "minimum": 0 } }, - "required": ["owner_address", "decimals"], + "required": ["owner_address", "decimals", "multiply"], "additionalProperties": false } } From 1ac0c3c106ea16d12443c6eeecf1f94e581f3e41 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Sat, 30 Mar 2024 20:08:41 +0530 Subject: [PATCH 630/815] [uniswap-v3] fix: Add subgraph option to uniswap-v3 strategy (#1446) * [uniswap-v3] fix: Add subgraph to uniswap-v3 strategy * [uniswap-v3] fix: Add subgraph to uniswap-v3 strategy --- src/strategies/uniswap-v3/README.md | 10 ++++++++++ src/strategies/uniswap-v3/index.ts | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 src/strategies/uniswap-v3/README.md diff --git a/src/strategies/uniswap-v3/README.md b/src/strategies/uniswap-v3/README.md new file mode 100644 index 000000000..0389e98eb --- /dev/null +++ b/src/strategies/uniswap-v3/README.md @@ -0,0 +1,10 @@ +# Uniswap V3 + +This strategy fetches the reserves of the user's positions in Uniswap V3. + +## Params + +|| **name** || **description** || **default** || +|| tokenReserve || Token reserve to consider for scoring || || +|| poolAddress || Pool address to fetch the positions from. || || +|| subgraph || Subgraph URL to fetch the data from. || uniswap-v3 subgraph URL || diff --git a/src/strategies/uniswap-v3/index.ts b/src/strategies/uniswap-v3/index.ts index 84c1e9a9d..5ffbd6a8a 100644 --- a/src/strategies/uniswap-v3/index.ts +++ b/src/strategies/uniswap-v3/index.ts @@ -63,7 +63,7 @@ export async function strategy( } const rawData = await subgraphRequest( - UNISWAP_V3_SUBGRAPH_URL[network], + options.subgraph || UNISWAP_V3_SUBGRAPH_URL[network], params ); From 46da723cac27276022d21b5babfc211a3ed1ec2b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 2 Apr 2024 18:37:11 +0530 Subject: [PATCH 631/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.16 (#1448) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 385bde0e0..016c3b7c7 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.15", + "@snapshot-labs/snapshot.js": "^0.11.16", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index cb8bd07c8..1aea0101d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.15": - version "0.11.15" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.15.tgz#8c9dfb8a718d8ad003dbf2df3a184c10cbce8ac1" - integrity sha512-UM7kIJ72r1+qnPQ1JEqJW1UpcvDhAW8np332BwizO7cvHbqJzJqvQl0YjK2EldD8BffZ+kxp8ltXKoA9dPr6CQ== +"@snapshot-labs/snapshot.js@^0.11.16": + version "0.11.16" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.16.tgz#36d88a75adeb4b418ba163fb426aa8bfbb0952bb" + integrity sha512-jE3ZUpsQTZT3t3h+2NTu7ZhrUuvSIUixBZ3ziG54GNo/z2j24d5JrwagbJHFlNsqJQ1b84lA3cwO6UexJMGdOQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 1651d368fd3d18fbee235a0e33e9e308120d4259 Mon Sep 17 00:00:00 2001 From: Marsot Pierre Date: Sat, 6 Apr 2024 15:11:02 +0200 Subject: [PATCH 632/815] vsdcrv arbitrum (#1447) --- src/strategies/index.ts | 2 + .../README.md | 28 +++ .../examples.json | 31 +++ .../index.ts | 191 ++++++++++++++++++ .../examples.json | 4 +- .../sd-vote-boost-twavp-vsdtoken/index.ts | 8 +- 6 files changed, 258 insertions(+), 6 deletions(-) create mode 100644 src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/README.md create mode 100644 src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/examples.json create mode 100644 src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index a805ff582..948c5771c 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -367,6 +367,7 @@ import * as sdVoteBoostTWAVPV2 from './sd-vote-boost-twavp-v2'; import * as sdVoteBoostTWAVPV3 from './sd-vote-boost-twavp-v3'; import * as sdVoteBoostTWAVPV4 from './sd-vote-boost-twavp-v4'; import * as sdVoteBoostTWAVPVsdToken from './sd-vote-boost-twavp-vsdtoken'; +import * as sdVoteBoostTWAVPVCrossChain from './sd-vote-boost-twavp-vsdcrv-crosschain'; import * as sdVoteBoostTWAVPBalanceof from './sd-vote-boost-twavp-balanceof'; import * as friendTech from './friend-tech'; import * as moonbase from './moonbase'; @@ -798,6 +799,7 @@ const strategies = { 'sd-vote-boost-twavp-v3': sdVoteBoostTWAVPV3, 'sd-vote-boost-twavp-v4': sdVoteBoostTWAVPV4, 'sd-vote-boost-twavp-vsdtoken': sdVoteBoostTWAVPVsdToken, + 'sd-vote-boost-twavp-vsdcrv-crosschain': sdVoteBoostTWAVPVCrossChain, 'sd-vote-boost-twavp-balanceof': sdVoteBoostTWAVPBalanceof, moonbase: moonbase, 'dss-vest-unpaid': dssVestUnpaid, diff --git a/src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/README.md b/src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/README.md new file mode 100644 index 000000000..9f122580b --- /dev/null +++ b/src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/README.md @@ -0,0 +1,28 @@ +# sd-vote-boost-twavp-vsdcrv-vsdtoken + +This strategy is used by Stake DAO to vote with sdToken using Time Weighted Averaged Voting Power (TWAVP) system and adapted for veSDT boost delegation with possibility to whiteliste address to by pass TWAVP. + +``` +VotingPower(user) = veToken.balanceOf(liquidLocker) * (average.sdTokenGauge.working_balances(user) / sdTokenGauge.working_supply) +``` + +>_sampleSize: in days_ +>_sampleStep: the number of block for `average` calculation (max 5)_ + +Here is an example of parameters: + +```json +{ + "veToken": "0x5f3b5DfEb7B28CDbD7FAba78963EE202a494e2A2", + "liquidLocker": "0x52f541764E6e90eeBc5c21Ff570De0e2D63766B6", + "sdTokenGauge": "0x7f50786A0b15723D741727882ee99a0BF34e3466", + "sdToken": "0xD1b5651E55D4CeeD36251c61c50C889B36F6abB5", + "pools": ["0xca0253a98d16e9c1e3614cafda19318ee69772d0"], + "symbol": "sdToken", + "decimals": 18, + "sampleSize": 10, + "sampleStep": 5, + "botAddress": "", + "whiteListedAddress": ["0x1c0D72a330F2768dAF718DEf8A19BAb019EEAd09"] +} +``` \ No newline at end of file diff --git a/src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/examples.json b/src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/examples.json new file mode 100644 index 000000000..3f65e2c6e --- /dev/null +++ b/src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/examples.json @@ -0,0 +1,31 @@ +[ + { + "name": "Stake DAO vote boost using TWAVP for vsdTkn holders", + "strategy": { + "name": "sd-vote-boost-twavp-vsdcrv-crosschain", + "params": { + "vsdToken": "0xE079ac07463ff375Ce48E8A9D76211C10696F3B8", + "sdTokenGauge": "0x7f50786A0b15723D741727882ee99a0BF34e3466", + "booster": "0x38d10708Ce535361F178f55E68DF7E85aCc66270", + "locker": "0x52f541764E6e90eeBc5c21Ff570De0e2D63766B6", + "veAddress": "0x5f3b5DfEb7B28CDbD7FAba78963EE202a494e2A2", + "symbol": "sdToken", + "decimals": 18, + "sampleSize": 10, + "sampleStep": 4, + "whiteListedAddress": ["0x1c0D72a330F2768dAF718DEf8A19BAb019EEAd09"], + "targetChainId": "42161", + "targetVsdcrv": "0x62d5a59e0d67c0381aad53b201b4a1b8dcd2c833", + "blocksPerDay": 288000 + } + }, + "network": "1", + "addresses": [ + "0xfdb1157ac847d334b8912df1cd24a93ee22ff3d0", + "0xb85246768cfea42b0c935265db798c9ae457646f", + "0xd4f94d0aaa640bbb72b5eec2d85f6d114d81a88e", + "0xb0e83c2d71a991017e0116d58c5765abc57384af" + ], + "snapshot": 19526425 + } +] diff --git a/src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/index.ts b/src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/index.ts new file mode 100644 index 000000000..b7603eb12 --- /dev/null +++ b/src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/index.ts @@ -0,0 +1,191 @@ +import { getAddress } from '@ethersproject/address'; +import { getProvider, multicall, subgraphRequest } from '../../utils'; +import { BigNumber } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; + +export const author = 'pierremarsotlyon1'; +export const version = '0.0.1'; + +// Used ABI +const abi = [ + 'function balanceOf(address account) external view returns (uint256)', + 'function working_supply() external view returns (uint256)', + 'function totalSupply() external view returns (uint256)', + 'function working_balances(address account) external view returns (uint256)' +]; + +const MIN_BLOCK = 18835548; + +async function getIDChainBlock(snapshot, provider, chainId) { + const ts = (await provider.getBlock(snapshot)).timestamp; + const query = { + blocks: { + __args: { + where: { + ts: ts, + network_in: [chainId] + } + }, + number: true + } + }; + const url = 'https://blockfinder.snapshot.org'; + const data = await subgraphRequest(url, query); + return data.blocks[0].number; +} + + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + // Maximum of 5 multicall! + if (options.sampleStep > 5) { + throw new Error('maximum of 5 call'); + } + + // Maximum of 20 whitelisted address + if (options.whiteListedAddress.length > 20) { + throw new Error('maximum of 20 whitelisted address'); + } + + // --- Create block number list for twavp + // Obtain last block number + // Create block tag + let blockTag = 0; + if (typeof snapshot === 'number') { + blockTag = snapshot; + } else { + blockTag = await provider.getBlockNumber(); + } + + const destinationChainProvider = getProvider(options.targetChainId); + // Get corresponding block number on the destination chain side + const destinationChainBlockTag = await getIDChainBlock(blockTag, provider, options.targetChainId); + + // Create block list + const blockList = getPreviousBlocks( + destinationChainBlockTag, + options.sampleStep, + options.sampleSize, + options.blocksPerDay + ); + + const balanceOfQueries: any[] = []; + for (const address of addresses) { + balanceOfQueries.push([options.targetVsdcrv, 'balanceOf', [address]]); + } + + // Max 4 calls on destination chain because we need one call for mainnet one + const response: any[] = []; + for (let i = 0; i < options.sampleStep; i++) { + response.push( + await multicall(options.targetChainId, destinationChainProvider, abi, balanceOfQueries, { blockTag: blockList[i] }) + ); + } + + const mainChainResponses = await multicall(network, provider, abi, [ + [options.veAddress, 'balanceOf', [options.locker]], + [options.sdTokenGauge, 'working_supply'], + [options.sdTokenGauge, 'working_balances', [options.booster]], + [options.vsdToken, 'totalSupply', []] + ], { blockTag }) + + const lockerVeBalance = mainChainResponses.shift()[0]; // Last response, latest block + const workingSupply = mainChainResponses.shift()[0]; // Last response, latest block + const workingBalances = mainChainResponses.shift()[0]; // Last response, latest block + const vsdCRVTotalSupply = parseFloat(formatUnits(BigNumber.from(mainChainResponses.shift()[0]), 18)); // Last response, latest block + + const totalVP = + (parseFloat(formatUnits(workingBalances, 18)) / + parseFloat(formatUnits(workingSupply, 18))) * + parseFloat(formatUnits(lockerVeBalance, 18)); + + return Object.fromEntries( + Array(addresses.length) + .fill('x') + .map((_, i) => { + // Init array of working balances for user + const userWorkingBalances: number[] = []; + + for (let j = 0; j < options.sampleStep; j++) { + const balanceOf = parseFloat(formatUnits(BigNumber.from(response[j].shift()[0]), 18)); + + // Add working balance to array. + if (vsdCRVTotalSupply === 0) { + userWorkingBalances.push(0); + } else { + userWorkingBalances.push(balanceOf / vsdCRVTotalSupply); + } + } + + // Get average working balance. + const averageWorkingBalance = average( + userWorkingBalances, + addresses[i], + options.whiteListedAddress + ); + + // Calculate voting power. + const votingPower = totalVP != 0 ? averageWorkingBalance * totalVP : 0; + + // Return address and voting power + return [getAddress(addresses[i]), Number(votingPower)]; + }) + ); +} + +function average( + numbers: number[], + address: string, + whiteListedAddress: string[] +): number { + // If no numbers, return 0 to avoid division by 0. + if (numbers.length === 0) return 0; + + // If address is whitelisted, return most recent working balance. i.e. no twavp applied. + if (whiteListedAddress.includes(address)) return numbers[numbers.length - 1]; + + // Init sum + let sum = 0; + // Loop through all elements and add them to sum + for (let i = 0; i < numbers.length; i++) { + sum += numbers[i]; + } + + // Return sum divided by array length to get mean + return sum / numbers.length; +} + +function getPreviousBlocks( + currentBlockNumber: number, + numberOfBlocks: number, + daysInterval: number, + blocksPerDay: number, +): number[] { + // Calculate total blocks interval + const totalBlocksInterval = blocksPerDay * daysInterval; + // Calculate block interval + const blockInterval = totalBlocksInterval / (numberOfBlocks - 1); + + // Init array of block numbers + const blockNumbers: number[] = []; + + for (let i = 0; i < numberOfBlocks; i++) { + // Calculate block number + let blockNumber = + currentBlockNumber - totalBlocksInterval + blockInterval * i; + if (blockNumber < MIN_BLOCK) { + blockNumber = MIN_BLOCK; + } + // Add block number to array + blockNumbers.push(Math.round(blockNumber)); + } + + // Return array of block numbers + return blockNumbers; +} diff --git a/src/strategies/sd-vote-boost-twavp-vsdtoken/examples.json b/src/strategies/sd-vote-boost-twavp-vsdtoken/examples.json index 54cda66e5..8c483bab6 100644 --- a/src/strategies/sd-vote-boost-twavp-vsdtoken/examples.json +++ b/src/strategies/sd-vote-boost-twavp-vsdtoken/examples.json @@ -18,11 +18,11 @@ }, "network": "1", "addresses": [ - "0xc59910E5E2dd8225623B663491aa754F7013F067", + "0x1c953fd17bE2812AB08bbbE221BB7d2687fc884B", "0xDdB50FfDbA4D89354E1088e4EA402de895562173", "0xE1F7eaD40d33eeF30dCf15eB5efC45409001aAB8", "0x1c0D72a330F2768dAF718DEf8A19BAb019EEAd09" ], - "snapshot": 18870156 + "snapshot": 19526583 } ] diff --git a/src/strategies/sd-vote-boost-twavp-vsdtoken/index.ts b/src/strategies/sd-vote-boost-twavp-vsdtoken/index.ts index 0da66ee1d..603b43cad 100644 --- a/src/strategies/sd-vote-boost-twavp-vsdtoken/index.ts +++ b/src/strategies/sd-vote-boost-twavp-vsdtoken/index.ts @@ -100,14 +100,14 @@ export async function strategy( const userWorkingBalances: number[] = []; for (let j = 0; j < options.sampleStep; j++) { - const balanceOf = BigNumber.from(response[j].shift()[0]); - const totalSupply = BigNumber.from(response[j].shift()[0]); + const balanceOf = parseFloat(formatUnits(BigNumber.from(response[j].shift()[0]), 18)); + const totalSupply = parseFloat(formatUnits(BigNumber.from(response[j].shift()[0]), 18)); // Add working balance to array. - if (totalSupply.eq(0)) { + if (totalSupply === 0) { userWorkingBalances.push(0); } else { - userWorkingBalances.push(balanceOf.div(totalSupply).toNumber()); + userWorkingBalances.push(balanceOf / totalSupply); } } From 3b21cf16c67b31518e5ee95a7ccedcf2a7ad26a3 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Sat, 6 Apr 2024 20:34:58 +0530 Subject: [PATCH 633/815] [pokt-network-pda] Change schema to number (#1450) --- src/strategies/pokt-network-pda/schema.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/strategies/pokt-network-pda/schema.json b/src/strategies/pokt-network-pda/schema.json index 1ea156e26..b83ce11ff 100644 --- a/src/strategies/pokt-network-pda/schema.json +++ b/src/strategies/pokt-network-pda/schema.json @@ -22,13 +22,13 @@ "maxLength": 42 }, "decimals": { - "type": "integer", + "type": "number", "title": "Decimals", "examples": ["e.g. 18"], "minimum": 0 }, "multiply": { - "type": "integer", + "type": "number", "title": "Multiply", "examples": ["e.g. 18"], "default": 0, From a1aab0404cc76f082b872ab3e5953dcb30af16d3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 6 Apr 2024 21:10:19 +0530 Subject: [PATCH 634/815] Automated lint (#1451) Co-authored-by: ChaituVR --- .../index.ts | 43 +++++++++++++------ .../sd-vote-boost-twavp-vsdtoken/index.ts | 8 +++- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/index.ts b/src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/index.ts index b7603eb12..19e0ec64d 100644 --- a/src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/index.ts +++ b/src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/index.ts @@ -34,7 +34,6 @@ async function getIDChainBlock(snapshot, provider, chainId) { return data.blocks[0].number; } - export async function strategy( space, network, @@ -65,7 +64,11 @@ export async function strategy( const destinationChainProvider = getProvider(options.targetChainId); // Get corresponding block number on the destination chain side - const destinationChainBlockTag = await getIDChainBlock(blockTag, provider, options.targetChainId); + const destinationChainBlockTag = await getIDChainBlock( + blockTag, + provider, + options.targetChainId + ); // Create block list const blockList = getPreviousBlocks( @@ -84,21 +87,35 @@ export async function strategy( const response: any[] = []; for (let i = 0; i < options.sampleStep; i++) { response.push( - await multicall(options.targetChainId, destinationChainProvider, abi, balanceOfQueries, { blockTag: blockList[i] }) + await multicall( + options.targetChainId, + destinationChainProvider, + abi, + balanceOfQueries, + { blockTag: blockList[i] } + ) ); } - const mainChainResponses = await multicall(network, provider, abi, [ - [options.veAddress, 'balanceOf', [options.locker]], - [options.sdTokenGauge, 'working_supply'], - [options.sdTokenGauge, 'working_balances', [options.booster]], - [options.vsdToken, 'totalSupply', []] - ], { blockTag }) + const mainChainResponses = await multicall( + network, + provider, + abi, + [ + [options.veAddress, 'balanceOf', [options.locker]], + [options.sdTokenGauge, 'working_supply'], + [options.sdTokenGauge, 'working_balances', [options.booster]], + [options.vsdToken, 'totalSupply', []] + ], + { blockTag } + ); const lockerVeBalance = mainChainResponses.shift()[0]; // Last response, latest block const workingSupply = mainChainResponses.shift()[0]; // Last response, latest block const workingBalances = mainChainResponses.shift()[0]; // Last response, latest block - const vsdCRVTotalSupply = parseFloat(formatUnits(BigNumber.from(mainChainResponses.shift()[0]), 18)); // Last response, latest block + const vsdCRVTotalSupply = parseFloat( + formatUnits(BigNumber.from(mainChainResponses.shift()[0]), 18) + ); // Last response, latest block const totalVP = (parseFloat(formatUnits(workingBalances, 18)) / @@ -113,7 +130,9 @@ export async function strategy( const userWorkingBalances: number[] = []; for (let j = 0; j < options.sampleStep; j++) { - const balanceOf = parseFloat(formatUnits(BigNumber.from(response[j].shift()[0]), 18)); + const balanceOf = parseFloat( + formatUnits(BigNumber.from(response[j].shift()[0]), 18) + ); // Add working balance to array. if (vsdCRVTotalSupply === 0) { @@ -165,7 +184,7 @@ function getPreviousBlocks( currentBlockNumber: number, numberOfBlocks: number, daysInterval: number, - blocksPerDay: number, + blocksPerDay: number ): number[] { // Calculate total blocks interval const totalBlocksInterval = blocksPerDay * daysInterval; diff --git a/src/strategies/sd-vote-boost-twavp-vsdtoken/index.ts b/src/strategies/sd-vote-boost-twavp-vsdtoken/index.ts index 603b43cad..6137b7e70 100644 --- a/src/strategies/sd-vote-boost-twavp-vsdtoken/index.ts +++ b/src/strategies/sd-vote-boost-twavp-vsdtoken/index.ts @@ -100,8 +100,12 @@ export async function strategy( const userWorkingBalances: number[] = []; for (let j = 0; j < options.sampleStep; j++) { - const balanceOf = parseFloat(formatUnits(BigNumber.from(response[j].shift()[0]), 18)); - const totalSupply = parseFloat(formatUnits(BigNumber.from(response[j].shift()[0]), 18)); + const balanceOf = parseFloat( + formatUnits(BigNumber.from(response[j].shift()[0]), 18) + ); + const totalSupply = parseFloat( + formatUnits(BigNumber.from(response[j].shift()[0]), 18) + ); // Add working balance to array. if (totalSupply === 0) { From e69121df2dbe238ec6da2ff98811f96186371b50 Mon Sep 17 00:00:00 2001 From: Marsot Pierre Date: Wed, 10 Apr 2024 06:19:36 +0200 Subject: [PATCH 635/815] [sd-vote-boost-twavp-vsdcrv-crosschain] Feature/eng 463 vsdcrv arbitrum snapshot strategy (#1453) * vsdcrv arbitrum * add bot vp allocation --- .../examples.json | 11 ++- .../index.ts | 90 ++++++++++++------- 2 files changed, 65 insertions(+), 36 deletions(-) diff --git a/src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/examples.json b/src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/examples.json index 3f65e2c6e..fafd74dfd 100644 --- a/src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/examples.json +++ b/src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/examples.json @@ -16,16 +16,19 @@ "whiteListedAddress": ["0x1c0D72a330F2768dAF718DEf8A19BAb019EEAd09"], "targetChainId": "42161", "targetVsdcrv": "0x62d5a59e0d67c0381aad53b201b4a1b8dcd2c833", - "blocksPerDay": 288000 + "blocksPerDay": 288000, + "pools": [ + "0xb85246768cfea42b0c935265db798c9ae457646f" + ], + "botAddress": "0xb4542526AfeE2FdA1D584213D1521272a398B42a" } }, "network": "1", "addresses": [ - "0xfdb1157ac847d334b8912df1cd24a93ee22ff3d0", - "0xb85246768cfea42b0c935265db798c9ae457646f", + "0xfDB1157ac847D334b8912df1cd24a93Ee22ff3d0", "0xd4f94d0aaa640bbb72b5eec2d85f6d114d81a88e", "0xb0e83c2d71a991017e0116d58c5765abc57384af" ], - "snapshot": 19526425 + "snapshot": 19611503 } ] diff --git a/src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/index.ts b/src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/index.ts index 19e0ec64d..8401201bc 100644 --- a/src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/index.ts +++ b/src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/index.ts @@ -34,6 +34,7 @@ async function getIDChainBlock(snapshot, provider, chainId) { return data.blocks[0].number; } + export async function strategy( space, network, @@ -62,13 +63,24 @@ export async function strategy( blockTag = await provider.getBlockNumber(); } + const poolAddressesToAdd: string[] = []; + + if (options.pools) { + for (const poolAddress of options.pools) { + const exists = addresses.find((address: string) => address.toLowerCase() === poolAddress.toLowerCase()); + if (!exists) { + poolAddressesToAdd.push(poolAddress); + } + } + + if (poolAddressesToAdd.length > 0) { + addresses = addresses.concat(poolAddressesToAdd); + } + } + const destinationChainProvider = getProvider(options.targetChainId); // Get corresponding block number on the destination chain side - const destinationChainBlockTag = await getIDChainBlock( - blockTag, - provider, - options.targetChainId - ); + const destinationChainBlockTag = await getIDChainBlock(blockTag, provider, options.targetChainId); // Create block list const blockList = getPreviousBlocks( @@ -87,42 +99,28 @@ export async function strategy( const response: any[] = []; for (let i = 0; i < options.sampleStep; i++) { response.push( - await multicall( - options.targetChainId, - destinationChainProvider, - abi, - balanceOfQueries, - { blockTag: blockList[i] } - ) + await multicall(options.targetChainId, destinationChainProvider, abi, balanceOfQueries, { blockTag: blockList[i] }) ); } - const mainChainResponses = await multicall( - network, - provider, - abi, - [ - [options.veAddress, 'balanceOf', [options.locker]], - [options.sdTokenGauge, 'working_supply'], - [options.sdTokenGauge, 'working_balances', [options.booster]], - [options.vsdToken, 'totalSupply', []] - ], - { blockTag } - ); + const mainChainResponses = await multicall(network, provider, abi, [ + [options.veAddress, 'balanceOf', [options.locker]], + [options.sdTokenGauge, 'working_supply'], + [options.sdTokenGauge, 'working_balances', [options.booster]], + [options.vsdToken, 'totalSupply', []] + ], { blockTag }) const lockerVeBalance = mainChainResponses.shift()[0]; // Last response, latest block const workingSupply = mainChainResponses.shift()[0]; // Last response, latest block const workingBalances = mainChainResponses.shift()[0]; // Last response, latest block - const vsdCRVTotalSupply = parseFloat( - formatUnits(BigNumber.from(mainChainResponses.shift()[0]), 18) - ); // Last response, latest block + const vsdCRVTotalSupply = parseFloat(formatUnits(BigNumber.from(mainChainResponses.shift()[0]), 18)); // Last response, latest block const totalVP = (parseFloat(formatUnits(workingBalances, 18)) / parseFloat(formatUnits(workingSupply, 18))) * parseFloat(formatUnits(lockerVeBalance, 18)); - return Object.fromEntries( + const votingPowers = Object.fromEntries( Array(addresses.length) .fill('x') .map((_, i) => { @@ -130,9 +128,7 @@ export async function strategy( const userWorkingBalances: number[] = []; for (let j = 0; j < options.sampleStep; j++) { - const balanceOf = parseFloat( - formatUnits(BigNumber.from(response[j].shift()[0]), 18) - ); + const balanceOf = parseFloat(formatUnits(BigNumber.from(response[j].shift()[0]), 18)); // Add working balance to array. if (vsdCRVTotalSupply === 0) { @@ -156,6 +152,36 @@ export async function strategy( return [getAddress(addresses[i]), Number(votingPower)]; }) ); + + // Assign 0 to pools and vp to bot address + const userAddresses = Object.keys(votingPowers); + + if (options.pools) { + const haveBotAddress = addresses.find((user: string) => user.toLowerCase() === options.botAddress.toLowerCase()); + if (haveBotAddress) { + let botVotingPower = 0; + for (const user of userAddresses) { + const isPool = options.pools.find((poolAddress: string) => poolAddress.toLowerCase() === user.toLowerCase()); + if (isPool) { + botVotingPower += votingPowers[user]; + votingPowers[user] = 0; + } + } + + votingPowers[getAddress(options.botAddress)] = Number(botVotingPower); + } + } + + // Remove pool addresses added previously + const vps = {}; + for(const user of userAddresses) { + const isAdded = poolAddressesToAdd.find((poolAddress: string) => poolAddress.toLowerCase() === user.toLowerCase()); + if(!isAdded) { + vps[user] = votingPowers[user]; + } + } + + return vps; } function average( @@ -184,7 +210,7 @@ function getPreviousBlocks( currentBlockNumber: number, numberOfBlocks: number, daysInterval: number, - blocksPerDay: number + blocksPerDay: number, ): number[] { // Calculate total blocks interval const totalBlocksInterval = blocksPerDay * daysInterval; From a0b5ff2f7e37ab547cbbaeac70b0036d684f600b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 14 Apr 2024 18:28:05 +0530 Subject: [PATCH 636/815] Automated lint (#1454) Co-authored-by: ChaituVR --- .../examples.json | 4 +- .../index.ts | 64 +++++++++++++------ 2 files changed, 47 insertions(+), 21 deletions(-) diff --git a/src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/examples.json b/src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/examples.json index fafd74dfd..9640ec784 100644 --- a/src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/examples.json +++ b/src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/examples.json @@ -17,9 +17,7 @@ "targetChainId": "42161", "targetVsdcrv": "0x62d5a59e0d67c0381aad53b201b4a1b8dcd2c833", "blocksPerDay": 288000, - "pools": [ - "0xb85246768cfea42b0c935265db798c9ae457646f" - ], + "pools": ["0xb85246768cfea42b0c935265db798c9ae457646f"], "botAddress": "0xb4542526AfeE2FdA1D584213D1521272a398B42a" } }, diff --git a/src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/index.ts b/src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/index.ts index 8401201bc..4c9f10588 100644 --- a/src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/index.ts +++ b/src/strategies/sd-vote-boost-twavp-vsdcrv-crosschain/index.ts @@ -34,7 +34,6 @@ async function getIDChainBlock(snapshot, provider, chainId) { return data.blocks[0].number; } - export async function strategy( space, network, @@ -67,7 +66,9 @@ export async function strategy( if (options.pools) { for (const poolAddress of options.pools) { - const exists = addresses.find((address: string) => address.toLowerCase() === poolAddress.toLowerCase()); + const exists = addresses.find( + (address: string) => address.toLowerCase() === poolAddress.toLowerCase() + ); if (!exists) { poolAddressesToAdd.push(poolAddress); } @@ -80,7 +81,11 @@ export async function strategy( const destinationChainProvider = getProvider(options.targetChainId); // Get corresponding block number on the destination chain side - const destinationChainBlockTag = await getIDChainBlock(blockTag, provider, options.targetChainId); + const destinationChainBlockTag = await getIDChainBlock( + blockTag, + provider, + options.targetChainId + ); // Create block list const blockList = getPreviousBlocks( @@ -99,21 +104,35 @@ export async function strategy( const response: any[] = []; for (let i = 0; i < options.sampleStep; i++) { response.push( - await multicall(options.targetChainId, destinationChainProvider, abi, balanceOfQueries, { blockTag: blockList[i] }) + await multicall( + options.targetChainId, + destinationChainProvider, + abi, + balanceOfQueries, + { blockTag: blockList[i] } + ) ); } - const mainChainResponses = await multicall(network, provider, abi, [ - [options.veAddress, 'balanceOf', [options.locker]], - [options.sdTokenGauge, 'working_supply'], - [options.sdTokenGauge, 'working_balances', [options.booster]], - [options.vsdToken, 'totalSupply', []] - ], { blockTag }) + const mainChainResponses = await multicall( + network, + provider, + abi, + [ + [options.veAddress, 'balanceOf', [options.locker]], + [options.sdTokenGauge, 'working_supply'], + [options.sdTokenGauge, 'working_balances', [options.booster]], + [options.vsdToken, 'totalSupply', []] + ], + { blockTag } + ); const lockerVeBalance = mainChainResponses.shift()[0]; // Last response, latest block const workingSupply = mainChainResponses.shift()[0]; // Last response, latest block const workingBalances = mainChainResponses.shift()[0]; // Last response, latest block - const vsdCRVTotalSupply = parseFloat(formatUnits(BigNumber.from(mainChainResponses.shift()[0]), 18)); // Last response, latest block + const vsdCRVTotalSupply = parseFloat( + formatUnits(BigNumber.from(mainChainResponses.shift()[0]), 18) + ); // Last response, latest block const totalVP = (parseFloat(formatUnits(workingBalances, 18)) / @@ -128,7 +147,9 @@ export async function strategy( const userWorkingBalances: number[] = []; for (let j = 0; j < options.sampleStep; j++) { - const balanceOf = parseFloat(formatUnits(BigNumber.from(response[j].shift()[0]), 18)); + const balanceOf = parseFloat( + formatUnits(BigNumber.from(response[j].shift()[0]), 18) + ); // Add working balance to array. if (vsdCRVTotalSupply === 0) { @@ -157,11 +178,16 @@ export async function strategy( const userAddresses = Object.keys(votingPowers); if (options.pools) { - const haveBotAddress = addresses.find((user: string) => user.toLowerCase() === options.botAddress.toLowerCase()); + const haveBotAddress = addresses.find( + (user: string) => user.toLowerCase() === options.botAddress.toLowerCase() + ); if (haveBotAddress) { let botVotingPower = 0; for (const user of userAddresses) { - const isPool = options.pools.find((poolAddress: string) => poolAddress.toLowerCase() === user.toLowerCase()); + const isPool = options.pools.find( + (poolAddress: string) => + poolAddress.toLowerCase() === user.toLowerCase() + ); if (isPool) { botVotingPower += votingPowers[user]; votingPowers[user] = 0; @@ -174,9 +200,11 @@ export async function strategy( // Remove pool addresses added previously const vps = {}; - for(const user of userAddresses) { - const isAdded = poolAddressesToAdd.find((poolAddress: string) => poolAddress.toLowerCase() === user.toLowerCase()); - if(!isAdded) { + for (const user of userAddresses) { + const isAdded = poolAddressesToAdd.find( + (poolAddress: string) => poolAddress.toLowerCase() === user.toLowerCase() + ); + if (!isAdded) { vps[user] = votingPowers[user]; } } @@ -210,7 +238,7 @@ function getPreviousBlocks( currentBlockNumber: number, numberOfBlocks: number, daysInterval: number, - blocksPerDay: number, + blocksPerDay: number ): number[] { // Calculate total blocks interval const totalBlocksInterval = blocksPerDay * daysInterval; From 056428f569a8996995333c59c7aa5bf799f0dcaa Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 14 Apr 2024 19:02:41 +0530 Subject: [PATCH 637/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.17 (#1455) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 016c3b7c7..43e7ce090 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.16", + "@snapshot-labs/snapshot.js": "^0.11.17", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 1aea0101d..495e0eb25 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.16": - version "0.11.16" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.16.tgz#36d88a75adeb4b418ba163fb426aa8bfbb0952bb" - integrity sha512-jE3ZUpsQTZT3t3h+2NTu7ZhrUuvSIUixBZ3ziG54GNo/z2j24d5JrwagbJHFlNsqJQ1b84lA3cwO6UexJMGdOQ== +"@snapshot-labs/snapshot.js@^0.11.17": + version "0.11.17" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.17.tgz#e54a14622956515aba8b6333cbe423e6af3f2250" + integrity sha512-+zM274cRplyN17PQQpP391XhZOV+1ET/bppIY7YfvAIid+q+7TwaTK3VD2kq00ZA2AdasR/f0dwvieKUnTyTUg== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 96cfd37ddf442865ba1accbdd0f2f355bb0a6946 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 20 Apr 2024 07:44:21 +0530 Subject: [PATCH 638/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.18 (#1456) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 43e7ce090..f466d7d04 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.17", + "@snapshot-labs/snapshot.js": "^0.11.18", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 495e0eb25..127723255 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.17": - version "0.11.17" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.17.tgz#e54a14622956515aba8b6333cbe423e6af3f2250" - integrity sha512-+zM274cRplyN17PQQpP391XhZOV+1ET/bppIY7YfvAIid+q+7TwaTK3VD2kq00ZA2AdasR/f0dwvieKUnTyTUg== +"@snapshot-labs/snapshot.js@^0.11.18": + version "0.11.18" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.18.tgz#d8557f4204691245bdfd986e8a0cd352786954ae" + integrity sha512-cNCyCr007K1uMyQ/ju+VwFWlOkuEVPd+fRCWRJPpikGoLgNUuESFw+7GMPLFkGnDvVPTZ2X3vME23aAxme/h8A== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From fec72491bcdc300c95e57a9c763f8556d485e214 Mon Sep 17 00:00:00 2001 From: RAFAQAT ALI Date: Mon, 22 Apr 2024 23:40:51 +0500 Subject: [PATCH 639/815] [a51-farming] Add a51-farming strategy (#1458) * fix indexOf issue * remove addr * remove yarn.lock * add a51-farming --- src/strategies/a51-farming/README.md | 10 ++ src/strategies/a51-farming/examples.json | 20 ++++ src/strategies/a51-farming/index.ts | 119 +++++++++++++++++++++++ src/strategies/index.ts | 4 +- 4 files changed, 152 insertions(+), 1 deletion(-) create mode 100644 src/strategies/a51-farming/README.md create mode 100644 src/strategies/a51-farming/examples.json create mode 100644 src/strategies/a51-farming/index.ts diff --git a/src/strategies/a51-farming/README.md b/src/strategies/a51-farming/README.md new file mode 100644 index 000000000..6103be1af --- /dev/null +++ b/src/strategies/a51-farming/README.md @@ -0,0 +1,10 @@ +# A51 Farming + +This strategy fetches the user's amount from the farming. + +## Params + +|| **name** || **description** || **default** || +|| farmingVaultAddress || Address of the A51 farming vault || || +|| isToken0 || Is the token0 desired token || || +|| decimals || decimals of desired token || || diff --git a/src/strategies/a51-farming/examples.json b/src/strategies/a51-farming/examples.json new file mode 100644 index 000000000..6b814646f --- /dev/null +++ b/src/strategies/a51-farming/examples.json @@ -0,0 +1,20 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "a51-farming", + "params": { + "farmingVaultAddress": "0x5ea84bb07f399fbf58c504929864b5fcbdc8300b", + "isToken0": false, + "decimals": 18 + } + }, + "network": "137", + "addresses": [ + "0x0895fcb879d7b0d36f23b3f68b6192c532ffad01", + "0x072fb32a9d71482d970090daef0e90cd8c665113", + "0x75f2BbF3A10B67134A780fB7D6da5808265111F7" + ], + "snapshot": 55932446 + } +] diff --git a/src/strategies/a51-farming/index.ts b/src/strategies/a51-farming/index.ts new file mode 100644 index 000000000..f037ea9d5 --- /dev/null +++ b/src/strategies/a51-farming/index.ts @@ -0,0 +1,119 @@ +import { getAddress } from '@ethersproject/address'; +import { Multicaller, subgraphRequest } from '../../utils'; + +export const author = 'rafaqat11'; +export const version = '0.1.0'; + +const A51_STAKING_SUBGRAPH_URL = { + '137': + 'https://api.thegraph.com/subgraphs/name/hamzabhatti125/farming-polygon' +}; + +const vaultABI = { + inputs: [], + name: 'getPositionDetails', + outputs: [ + { internalType: 'uint256', name: 'amount0', type: 'uint256' }, + { internalType: 'uint256', name: 'amount1', type: 'uint256' }, + { internalType: 'uint256', name: 'fees0', type: 'uint256' }, + { internalType: 'uint256', name: 'fees1', type: 'uint256' }, + { internalType: 'uint128', name: 'baseLiquidity', type: 'uint128' }, + { internalType: 'uint128', name: 'rangeLiquidity', type: 'uint128' } + ], + stateMutability: 'nonpayable', + type: 'function' +}; + +const params = { + vaults: { + __args: { + where: { + id: '' + } + }, + id: true, + stakingAddress: true, + totalLpLocked: true + }, + rewards: { + __args: { + where: { + vault: '', + userAddress_in: [] + } + }, + vault: { id: true }, + userAddress: true, + stakingAddress: true, + totalUserLockedLp: true + } +}; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const farmingVaultAddress = ( + options.farmingVaultAddress as string + ).toLowerCase(); + + const isToken0 = options.isToken0 as boolean; + const decimals = Number(options.decimals); + + const _addresses = (addresses as string[]).map((addr) => addr.toLowerCase()); + + //@ts-ignore + params.vaults.__args.where.id = farmingVaultAddress; + + //@ts-ignore + params.rewards.__args.where.vault = farmingVaultAddress; + + //@ts-ignore + params.rewards.__args.where.userAddress_in = _addresses; + + const rawData = (await subgraphRequest( + options.subgraph || A51_STAKING_SUBGRAPH_URL[network], + params + )) as { + vaults: { + id: string; + stakingAddress: string; + totalLpLocked: string; + }[]; + rewards: { + vault: { id: string }; + userAddress: string; + stakingAddress: string; + totalUserLockedLp: string; + }[]; + }; + + const vaultAddress = rawData.vaults[0].stakingAddress; + const totalLpLocked = rawData.vaults[0].totalLpLocked; + + const multi = new Multicaller(network, provider, [vaultABI], { + blockTag + }); + multi.call('result', vaultAddress, vaultABI.name, []); + const multiRes = await multi.execute(); + + const userAmountShare: { [key: string]: number } = {}; + + rawData.rewards.forEach((reward) => { + const totalAmount = isToken0 + ? Number(multiRes['result'][0]) + : Number(multiRes['result'][1]); + + userAmountShare[getAddress(reward.userAddress)] = + (Number(reward.totalUserLockedLp) / Number(totalLpLocked)) * + (totalAmount / 10 ** decimals); + }); + + return userAmountShare; +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 948c5771c..766777f2d 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -420,6 +420,7 @@ import * as poktNetworkPDA from './pokt-network-pda'; import * as givethBalancesSupplyWeighted from './giveth-balances-supply-weighted'; import * as givethGnosisBalanceSupplyWeightedV3 from './giveth-gnosis-balance-supply-weighted-v3'; import * as stakeMineLiquidHelios from './stake-mine-liquid-helios'; +import * as a51Farming from './a51-farming'; const strategies = { 'giveth-balances-supply-weighted': givethBalancesSupplyWeighted, @@ -849,7 +850,8 @@ const strategies = { 'urbit-galaxies': urbitGalaxies, 'vesting-balance-of': vestingBalanceOf, 'stake-mine-liquid-helios': stakeMineLiquidHelios, - 'pokt-network-pda': poktNetworkPDA + 'pokt-network-pda': poktNetworkPDA, + 'a51-farming': a51Farming }; Object.keys(strategies).forEach(function (strategyName) { From e9d11d1b43c97d4bc0fada7c90ebfc5dd3664c3e Mon Sep 17 00:00:00 2001 From: RAFAQAT ALI Date: Tue, 23 Apr 2024 15:16:55 +0500 Subject: [PATCH 640/815] [a51-vault-balance] Add a51-vault-balance strategy (#1459) * fix indexOf issue * remove addr * remove yarn.lock * add a51-farming * add a51-vault-balance --- src/strategies/a51-vault-balance/README.md | 10 ++ .../a51-vault-balance/examples.json | 20 ++++ src/strategies/a51-vault-balance/index.ts | 106 ++++++++++++++++++ src/strategies/index.ts | 5 +- 4 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 src/strategies/a51-vault-balance/README.md create mode 100644 src/strategies/a51-vault-balance/examples.json create mode 100644 src/strategies/a51-vault-balance/index.ts diff --git a/src/strategies/a51-vault-balance/README.md b/src/strategies/a51-vault-balance/README.md new file mode 100644 index 000000000..32f66a5a6 --- /dev/null +++ b/src/strategies/a51-vault-balance/README.md @@ -0,0 +1,10 @@ +# A51 Vault Balance + +This strategy fetches the user's amount from the vault. + +## Params + +|| **name** || **description** || **default** || +|| vaultAddress || Address of the A51 vault || || +|| isToken0 || Is the token0 desired token || || +|| decimals || decimals of desired token || || diff --git a/src/strategies/a51-vault-balance/examples.json b/src/strategies/a51-vault-balance/examples.json new file mode 100644 index 000000000..8a0354d55 --- /dev/null +++ b/src/strategies/a51-vault-balance/examples.json @@ -0,0 +1,20 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "a51-vault-balance", + "params": { + "vaultAddress": "0x2ba1bc7d00ed1cb31379ee28a88968d90a6c2f49", + "isToken0": false, + "decimals": 18 + } + }, + "network": "137", + "addresses": [ + "0x22b77d7135174e1002d543ef8ff16a775db9ae5f", + "0x75f2bbf3a10b67134a780fb7d6da5808265111f7", + "0xfcae8fbaabb5336d8f4ddd76e6542fd6b89be68e" + ], + "snapshot": 55932446 + } +] diff --git a/src/strategies/a51-vault-balance/index.ts b/src/strategies/a51-vault-balance/index.ts new file mode 100644 index 000000000..cbbb20d74 --- /dev/null +++ b/src/strategies/a51-vault-balance/index.ts @@ -0,0 +1,106 @@ +import { getAddress } from '@ethersproject/address'; +import { Multicaller, subgraphRequest } from '../../utils'; + +export const author = 'rafaqat11'; +export const version = '0.1.0'; + +const A51_VAULT_SUBGRAPH_URL = { + '137': + 'https://api.thegraph.com/subgraphs/name/hamzabhatti125/unipilot-quickswap-stats' +}; + +const vaultABI = { + inputs: [], + name: 'getPositionDetails', + outputs: [ + { internalType: 'uint256', name: 'amount0', type: 'uint256' }, + { internalType: 'uint256', name: 'amount1', type: 'uint256' }, + { internalType: 'uint256', name: 'fees0', type: 'uint256' }, + { internalType: 'uint256', name: 'fees1', type: 'uint256' }, + { internalType: 'uint128', name: 'baseLiquidity', type: 'uint128' }, + { internalType: 'uint128', name: 'rangeLiquidity', type: 'uint128' } + ], + stateMutability: 'nonpayable', + type: 'function' +}; + +const params = { + vaults: { + __args: { + where: { + id: '' + } + }, + id: true, + totalLiquidity: true, + positions: { + __args: { + where: { + user_in: [] + } + }, + user: { id: true }, + balance: true + } + } +}; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const vaultAddress = (options.vaultAddress as string).toLowerCase(); + + const isToken0 = options.isToken0 as boolean; + const decimals = Number(options.decimals); + + const _addresses = (addresses as string[]).map((addr) => addr.toLowerCase()); + + //@ts-ignore + params.vaults.__args.where.id = vaultAddress; + + //@ts-ignore + params.vaults.positions.__args.where.user_in = _addresses; + + const rawData = (await subgraphRequest( + options.subgraph || A51_VAULT_SUBGRAPH_URL[network], + params + )) as { + vaults: { + id: string; + totalLiquidity: string; + positions: { + user: { + id: string; + }; + balance: string; + }[]; + }[]; + }; + + const multi = new Multicaller(network, provider, [vaultABI], { + blockTag + }); + multi.call('result', vaultAddress, vaultABI.name, []); + const multiRes = await multi.execute(); + + const userAmountShare: { [key: string]: number } = {}; + + rawData.vaults[0].positions.forEach((pos) => { + const totalAmount = isToken0 + ? Number(multiRes['result'][0]) + : Number(multiRes['result'][1]); + + userAmountShare[getAddress(pos.user.id)] = + (Number(pos.balance) / Number(rawData.vaults[0].totalLiquidity)) * + (totalAmount / 10 ** decimals); + }); + + return userAmountShare; +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 766777f2d..218601481 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -421,6 +421,8 @@ import * as givethBalancesSupplyWeighted from './giveth-balances-supply-weighted import * as givethGnosisBalanceSupplyWeightedV3 from './giveth-gnosis-balance-supply-weighted-v3'; import * as stakeMineLiquidHelios from './stake-mine-liquid-helios'; import * as a51Farming from './a51-farming'; +import * as a51VaultBalance from './a51-vault-balance'; + const strategies = { 'giveth-balances-supply-weighted': givethBalancesSupplyWeighted, @@ -851,7 +853,8 @@ const strategies = { 'vesting-balance-of': vestingBalanceOf, 'stake-mine-liquid-helios': stakeMineLiquidHelios, 'pokt-network-pda': poktNetworkPDA, - 'a51-farming': a51Farming + 'a51-farming': a51Farming, + 'a51-vault-balance': a51VaultBalance }; Object.keys(strategies).forEach(function (strategyName) { From f5540e32a9a90319d02945102075206fbc3192ea Mon Sep 17 00:00:00 2001 From: RAFAQAT ALI Date: Wed, 24 Apr 2024 14:26:22 +0500 Subject: [PATCH 641/815] [quickswap-v3] Add quickswap-v3 strategy (#1460) * fix indexOf issue * remove addr * remove yarn.lock * add a51-farming * add a51-vault-balance * add quickswap-v3 --- src/strategies/index.ts | 5 +- src/strategies/quickswap-v3/README.md | 12 +++ src/strategies/quickswap-v3/examples.json | 31 ++++++ src/strategies/quickswap-v3/helper.ts | 89 +++++++++++++++++ src/strategies/quickswap-v3/index.ts | 114 ++++++++++++++++++++++ 5 files changed, 249 insertions(+), 2 deletions(-) create mode 100644 src/strategies/quickswap-v3/README.md create mode 100644 src/strategies/quickswap-v3/examples.json create mode 100644 src/strategies/quickswap-v3/helper.ts create mode 100644 src/strategies/quickswap-v3/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 218601481..c79b3b328 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -422,7 +422,7 @@ import * as givethGnosisBalanceSupplyWeightedV3 from './giveth-gnosis-balance-su import * as stakeMineLiquidHelios from './stake-mine-liquid-helios'; import * as a51Farming from './a51-farming'; import * as a51VaultBalance from './a51-vault-balance'; - +import * as quickswapv3 from './quickswap-v3'; const strategies = { 'giveth-balances-supply-weighted': givethBalancesSupplyWeighted, @@ -854,7 +854,8 @@ const strategies = { 'stake-mine-liquid-helios': stakeMineLiquidHelios, 'pokt-network-pda': poktNetworkPDA, 'a51-farming': a51Farming, - 'a51-vault-balance': a51VaultBalance + 'a51-vault-balance': a51VaultBalance, + 'quickswap-v3': quickswapv3 }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/quickswap-v3/README.md b/src/strategies/quickswap-v3/README.md new file mode 100644 index 000000000..9113ea961 --- /dev/null +++ b/src/strategies/quickswap-v3/README.md @@ -0,0 +1,12 @@ +# Quickswap V3 + +This strategy fetches the reserves of the user's positions in Quickswap V3. + +## Params + +|| **name** || **description** || **default** || +|| subgraph || subgraph url for position infor. || || +|| poolAddress || Pool address of which position belong to || || +|| isToken0 || Is desired token is token0 for scoring || || +|| token0 || token0 infor. like id, symbol & decimals || || +|| token0 || token1 infor. like id, symbol & decimals || || diff --git a/src/strategies/quickswap-v3/examples.json b/src/strategies/quickswap-v3/examples.json new file mode 100644 index 000000000..5ea546b7b --- /dev/null +++ b/src/strategies/quickswap-v3/examples.json @@ -0,0 +1,31 @@ +[ + { + "name": "quickswap-v3 query", + "strategy": { + "name": "quickswap-v3", + "params": { + "subgraph": "https://api.studio.thegraph.com/query/20036/pos-mngr/v0.0.2", + "poolAddress": "0x86a448e1d9c1A31c093fA66F42b096A98297B072", + "isToken0": false, + "token0": { + "id": "0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270", + "symbol": "WMATIC", + "decimals": 18 + }, + "token1": { + "id": "0xe9e7c09e82328c3107d367f6c617cf9977e63ed0", + "symbol": "A51", + "decimals": 18 + } + } + }, + "network": "137", + "addresses": [ + "0x7f38595deacce8c4151bae0263adcecc40137da9", + "0x732a1d8bdf86ba67ccff57823b2e8935a050d18d", + "0x460610729fd088a7f3152871132883213955deea", + "0x4eF03f0eA9e744F22B768E17628cE39a2f48AbE5" + ], + "snapshot": 56124731 + } +] diff --git a/src/strategies/quickswap-v3/helper.ts b/src/strategies/quickswap-v3/helper.ts new file mode 100644 index 000000000..aabf7e9c2 --- /dev/null +++ b/src/strategies/quickswap-v3/helper.ts @@ -0,0 +1,89 @@ +import { FeeAmount, Pool, Position } from '@uniswap/v3-sdk'; +import { Token } from '@uniswap/sdk-core'; + +type IReserves = { + network: number; + tickLower: number; + tickUpper: number; + liquidity: string; + posLiquidity: string; + tick: number; + price: string; + token0: { + id: string; + symbol: string; + decimals: number; + }; + token1: { + id: string; + symbol: string; + decimals: number; + }; +}; + +export const getFeeAmount = (): FeeAmount => FeeAmount.LOW; + +export const getAllReserves = (positionInfo: IReserves[]) => { + return positionInfo?.map((info) => { + return getReserves(info); + }); +}; + +export const getReserves = ({ + tickLower, + tickUpper, + liquidity, + posLiquidity, + tick, + price, + token0, + token1, + network +}: IReserves) => { + const [_baseToken, _quoteToken] = [ + new Token(network, token0.id, Number(token0.decimals), token0.symbol), + new Token(network, token1.id, Number(token1.decimals), token1.symbol) + ]; + if (Number(tick) < Number(tickLower) || Number(tick) > Number(tickUpper)) { + return { + token0Reserve: 0, + token1Reserve: 0, + poolTick: 0, + position: undefined, + inRange: false + }; + } + + const _fee = getFeeAmount(); + const pool = new Pool( + _baseToken, + _quoteToken, + _fee, + price, + liquidity, + Number(tick) + ); + + if (pool) { + const position = new Position({ + pool, + liquidity: posLiquidity, + tickLower: Number(tickLower), + tickUpper: Number(tickUpper) + }); + return { + token0Reserve: parseFloat(position.amount0.toSignificant(4)), + token1Reserve: parseFloat(position.amount1.toSignificant(4)), + poolTick: tick, + position, + inRange: true + }; + } + return { + token0Reserve: 0, + token1Reserve: 0, + poolTick: 0, + position: undefined, + inRange: false + }; +}; diff --git a/src/strategies/quickswap-v3/index.ts b/src/strategies/quickswap-v3/index.ts new file mode 100644 index 000000000..6be0bad67 --- /dev/null +++ b/src/strategies/quickswap-v3/index.ts @@ -0,0 +1,114 @@ +import { getAddress } from '@ethersproject/address'; +import { multicall, subgraphRequest } from '../../utils'; +import { getAllReserves } from './helper'; + +export const author = 'rafaqat11'; +export const version = '0.1.0'; + +const liquidity = { + inputs: [], + name: 'liquidity', + outputs: [{ internalType: 'uint128', name: '', type: 'uint128' }], + stateMutability: 'view', + type: 'function' +}; +const globalState = { + inputs: [], + name: 'globalState', + outputs: [ + { internalType: 'uint160', name: 'price', type: 'uint160' }, + { internalType: 'int24', name: 'tick', type: 'int24' }, + { internalType: 'uint16', name: 'fee', type: 'uint16' }, + { internalType: 'uint16', name: 'timepointIndex', type: 'uint16' }, + { internalType: 'uint8', name: 'communityFeeToken0', type: 'uint8' }, + { internalType: 'uint8', name: 'communityFeeToken1', type: 'uint8' }, + { internalType: 'bool', name: 'unlocked', type: 'bool' } + ], + stateMutability: 'view', + type: 'function' +}; + +const poolABI = [globalState, liquidity]; + +const params = { + positions: { + __args: { + where: { + pool: '', + from_in: [] + } + }, + id: true, + from: true, + lowerTick: true, + upperTick: true, + liquidity: true + } +}; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const key = options.isToken0 ? 'token0Reserve' : 'token1Reserve'; + + const poolAddress = options.poolAddress.toLowerCase(); + const _addresses = addresses.map((address) => address.toLowerCase()); + + params.positions.__args.where.pool = poolAddress; + params.positions.__args.where.from_in = _addresses; + + const { positions } = (await subgraphRequest(options.subgraph, params)) as { + positions: { + id: string; + from: string; + lowerTick: number; + upperTick: number; + liquidity: string; + }[]; + }; + + const res = await multicall( + network, + provider, + poolABI, + [ + [poolAddress, globalState.name, []], + [poolAddress, liquidity.name, []] + ], + { blockTag } + ); + + const tick = res[0]?.tick?.toString(); + const price = res[0]?.price?.toString(); + const poolLiquidity = res[1]?.toString(); + console.log('network', network); + + const reserves = getAllReserves( + positions.map((pos) => ({ + network: Number(network), + liquidity: poolLiquidity, + posLiquidity: pos.liquidity, + price, + tick, + token0: options.token0, + token1: options.token1, + tickLower: pos.lowerTick, + tickUpper: pos.upperTick + })) + ); + + const ret = {}; + + positions.forEach((pos, idx) => { + ret[getAddress(pos.from)] = reserves[idx][key]; + }); + + return ret; +} From a7a363ff2c1a8f283aad0a80d5fbd1f6a8a5495a Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Sat, 27 Apr 2024 23:58:56 +0530 Subject: [PATCH 642/815] [reliquary] Change multicall limit to 200 --- src/strategies/reliquary/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategies/reliquary/index.ts b/src/strategies/reliquary/index.ts index c05471b6c..5aa3ee279 100644 --- a/src/strategies/reliquary/index.ts +++ b/src/strategies/reliquary/index.ts @@ -32,7 +32,7 @@ export async function strategy( const multi = new Multicaller(network, provider, abi, { blockTag, - limit: 475 + limit: 200 }); for (const address of addresses) { From 2558afd4d1a0264507ac08b7d77760c35ab242d8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 29 Apr 2024 12:35:28 +0530 Subject: [PATCH 643/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.19 (#1461) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f466d7d04..01338b1c1 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.18", + "@snapshot-labs/snapshot.js": "^0.11.19", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 127723255..edfb5459e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.18": - version "0.11.18" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.18.tgz#d8557f4204691245bdfd986e8a0cd352786954ae" - integrity sha512-cNCyCr007K1uMyQ/ju+VwFWlOkuEVPd+fRCWRJPpikGoLgNUuESFw+7GMPLFkGnDvVPTZ2X3vME23aAxme/h8A== +"@snapshot-labs/snapshot.js@^0.11.19": + version "0.11.19" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.19.tgz#436118728a46eee4b5a973a3334bd176cd27c2ac" + integrity sha512-ZsakhVsz0ylFqT3WhmJwxompsZrimFml6a4T10+aMS18oLFlwW0qooiahbmeSQ6Z9A9+KKeKmHl18VbHbdZg4w== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 2cdb72fca851c7ffacbc19a137f5e5858fdc3776 Mon Sep 17 00:00:00 2001 From: "Jongseung (John) Lim" Date: Fri, 3 May 2024 03:22:55 -0400 Subject: [PATCH 644/815] feat: add erc20 balance of with bazaar batch auction linear vesting (#1465) --- .../examples.json | 25 +++ .../index.ts | 169 ++++++++++++++++++ .../schema.json | 46 +++++ src/strategies/index.ts | 5 +- 4 files changed, 244 insertions(+), 1 deletion(-) create mode 100644 src/strategies/balance-of-with-bazaar-batch-auction-linear-vesting-power/examples.json create mode 100644 src/strategies/balance-of-with-bazaar-batch-auction-linear-vesting-power/index.ts create mode 100644 src/strategies/balance-of-with-bazaar-batch-auction-linear-vesting-power/schema.json diff --git a/src/strategies/balance-of-with-bazaar-batch-auction-linear-vesting-power/examples.json b/src/strategies/balance-of-with-bazaar-batch-auction-linear-vesting-power/examples.json new file mode 100644 index 000000000..e226acbf6 --- /dev/null +++ b/src/strategies/balance-of-with-bazaar-batch-auction-linear-vesting-power/examples.json @@ -0,0 +1,25 @@ +[ + { + "name": "ERC20 balanceOf with linear vesting of bazaar auction participants", + "strategy": { + "name": "balance-of-with-bazaar-batch-auction-linear-vesting-power", + "params": { + "address": "0x32fb7d6e0cbeb9433772689aa4647828cc7cbba8", + "symbol": "COVE", + "decimals": 18, + "auctionAddress": "0x2f3715F710076Cfdb5AA872Bc8a4b965a07c3A08", + "vestingDuration": 31536000 + } + }, + "network": "1", + "addresses": [ + "0x7Bd578354b0B2f02E656f1bDC0e41a80f860534b", + "0xD24B84C386cc65c49Dd596E59d950c54298cD429", + "0x5c5D1F39d21e304c4664E933c50DeF24A5C66D86", + "0x98b69D0B81fb1966eBe0Af76789425706e5aFe7B", + "0xF4880975728EE25A96C701c225c9EF58Eebe5a5b", + "0x77796c658d75A232ECDBf92c5d71Ec082F735780" + ], + "snapshot": 19784128 + } +] diff --git a/src/strategies/balance-of-with-bazaar-batch-auction-linear-vesting-power/index.ts b/src/strategies/balance-of-with-bazaar-batch-auction-linear-vesting-power/index.ts new file mode 100644 index 000000000..95caedfa1 --- /dev/null +++ b/src/strategies/balance-of-with-bazaar-batch-auction-linear-vesting-power/index.ts @@ -0,0 +1,169 @@ +import { Multicaller, subgraphRequest } from '../../utils'; +import { formatUnits } from '@ethersproject/units'; + +export const author = 'penandlim'; +export const version = '1.0.0'; + +const abi = [ + 'function subscriptions(address user) external view returns (uint256)', + 'function endTime() external view returns (uint256)', + 'function balanceOf(address user) external view returns (uint256)', + 'function floorQuoteAmount() external view returns (uint256)', + 'function totalSubscriptions() external view returns (uint256)', + 'function totalProjectTokenAmount() external view returns (uint256)' +]; + +const GRAPH_BLOCK_API_URL = + 'https://api.thegraph.com/subgraphs/name/blocklytics/ethereum-blocks'; + +async function getNearestBlockNumberBeforeTimestamp(timestamp: number) { + const rawData = await subgraphRequest(GRAPH_BLOCK_API_URL, { + blocks: { + __args: { + first: 1, + orderBy: 'timestamp', + orderDirection: 'desc', + where: { + timestamp_lte: timestamp + } + }, + number: true, + timestamp: true + } + }); + return Number(rawData.blocks[0].number); +} + +function min(a: bigint, b: bigint) { + return a < b ? a : b; +} + +function max(a: bigint, b: bigint) { + return a > b ? a : b; +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + // Get the subscription balances at the snapshot block + // If they have claimed from the auction, this will be 0 and their amount will have been added to their wallet balance + const multiSnapshotBlock = new Multicaller(network, provider, abi, { + blockTag + }); + addresses.forEach((address: any) => { + multiSnapshotBlock.call( + `subscriptions.${address}`, + options.auctionAddress, + 'subscriptions', + [address] + ); + multiSnapshotBlock.call( + `balanceOf.${address}`, + options.address, + 'balanceOf', + [address] + ); + }); + multiSnapshotBlock.call('endTime', options.auctionAddress, 'endTime'); + multiSnapshotBlock.call( + 'totalSubscriptions', + options.auctionAddress, + 'totalSubscriptions' + ); + multiSnapshotBlock.call( + 'totalProjectTokenAmount', + options.auctionAddress, + 'totalProjectTokenAmount' + ); + multiSnapshotBlock.call( + 'floorQuoteAmount', + options.auctionAddress, + 'floorQuoteAmount' + ); + const multiSnapshotBlockResult = await multiSnapshotBlock.execute(); + const snapshotTimestamp = BigInt( + (await provider.getBlock(blockTag)).timestamp + ); + const auctionEndTimestamp = BigInt(multiSnapshotBlockResult.endTime); + const totalSubscriptions = BigInt( + multiSnapshotBlockResult.totalSubscriptions + ); + const totalProjectTokenAmount = BigInt( + multiSnapshotBlockResult.totalProjectTokenAmount + ); + const floorQuoteAmount = BigInt(multiSnapshotBlockResult.floorQuoteAmount); + + // Get the cloest block number before the end of the auction + const auctionEndBlock = await getNearestBlockNumberBeforeTimestamp( + Number(auctionEndTimestamp) + ); + + // Get the subscription amounts at the end of the auction + // This will match the subscription amounts at the snapshot block if the user has not claimed from the auction + const multiAuctionEnd = new Multicaller(network, provider, abi, { + blockTag: auctionEndBlock + }); + addresses.forEach((address: any) => { + multiAuctionEnd.call( + `subscriptions.${address}`, + options.auctionAddress, + 'subscriptions', + [address] + ); + }); + const multiAuctionEndResult = await multiAuctionEnd.execute(); + const vestingDuration = BigInt(options.vestingDuration); + + // Any amount that was bought from the auction need to be linearly vested for {options.vestingDuration} time + return Object.fromEntries( + addresses + .map((address) => { + const subscribedAmount = BigInt( + multiAuctionEndResult.subscriptions[address] + ); + const remainingSubscribedAmount = BigInt( + multiSnapshotBlockResult.subscriptions[address] + ); + const walletBalance = BigInt( + multiSnapshotBlockResult.balanceOf[address] + ); + + if (subscribedAmount === 0n) { + // User was not in the auction, return their wallet balance + return [address, walletBalance]; + } else { + // Calculate the maximum amount that should be vested + const maxVestedAmount = + (subscribedAmount * totalProjectTokenAmount) / + max(totalSubscriptions, floorQuoteAmount); + // Calculate the vested amount based on the time since the auction ended + const timeSinceAuctionEnded = snapshotTimestamp - auctionEndTimestamp; + const vestedAmount = + vestingDuration > 0n + ? (maxVestedAmount * + max(0n, min(timeSinceAuctionEnded, vestingDuration))) / + vestingDuration + : maxVestedAmount; + + // Determine the final balance based on whether the user has claimed from the auction + const finalBalance = + remainingSubscribedAmount === 0n + ? walletBalance - maxVestedAmount + vestedAmount + : walletBalance + vestedAmount; + + return [address, finalBalance]; + } + }) + .map(([address, amount]) => [ + address, + parseFloat(formatUnits(amount.toString(), options.decimals)) + ]) + ); +} diff --git a/src/strategies/balance-of-with-bazaar-batch-auction-linear-vesting-power/schema.json b/src/strategies/balance-of-with-bazaar-batch-auction-linear-vesting-power/schema.json new file mode 100644 index 000000000..733f2f536 --- /dev/null +++ b/src/strategies/balance-of-with-bazaar-batch-auction-linear-vesting-power/schema.json @@ -0,0 +1,46 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "address": { + "type": "string", + "title": "ERC20 Token address", + "examples": ["e.g. 0x32fb7d6e0cbeb9433772689aa4647828cc7cbba8"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "symbol" : { + "type": "string", + "title": "ERC20 Token symbol", + "examples": ["e.g. COVE"] + }, + "decimals": { + "type": "number", + "title": "ERC20 Token decimals", + "examples": ["e.g. 18"] + }, + "auctionAddress": { + "type": "string", + "title": "Bazaar Batch Auction address", + "examples": ["e.g. 0x2f3715F710076Cfdb5AA872Bc8a4b965a07c3A08"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "vestingDuration": { + "type": "number", + "title": "Vesting duration in seconds", + "examples": ["e.g. 31536000"] + } + }, + "required": ["address", "decimals", "auctionAddress", "vestingDuration"], + "additionalProperties": false + } + } + } + \ No newline at end of file diff --git a/src/strategies/index.ts b/src/strategies/index.ts index c79b3b328..a2e0d803d 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -423,6 +423,7 @@ import * as stakeMineLiquidHelios from './stake-mine-liquid-helios'; import * as a51Farming from './a51-farming'; import * as a51VaultBalance from './a51-vault-balance'; import * as quickswapv3 from './quickswap-v3'; +import * as balanceOfWithBazaarBatchAuctionLinearVestingPower from './balance-of-with-bazaar-batch-auction-linear-vesting-power'; const strategies = { 'giveth-balances-supply-weighted': givethBalancesSupplyWeighted, @@ -855,7 +856,9 @@ const strategies = { 'pokt-network-pda': poktNetworkPDA, 'a51-farming': a51Farming, 'a51-vault-balance': a51VaultBalance, - 'quickswap-v3': quickswapv3 + 'quickswap-v3': quickswapv3, + 'balance-of-with-bazaar-batch-auction-linear-vesting-power': + balanceOfWithBazaarBatchAuctionLinearVestingPower }; Object.keys(strategies).forEach(function (strategyName) { From c1aabf6d7eba3632c31357aad6c1322773365be0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 5 May 2024 15:38:26 +0530 Subject: [PATCH 645/815] Automated lint (#1470) Co-authored-by: ChaituVR --- .../schema.json | 83 +++++++++---------- 1 file changed, 41 insertions(+), 42 deletions(-) diff --git a/src/strategies/balance-of-with-bazaar-batch-auction-linear-vesting-power/schema.json b/src/strategies/balance-of-with-bazaar-batch-auction-linear-vesting-power/schema.json index 733f2f536..7333f2ee7 100644 --- a/src/strategies/balance-of-with-bazaar-batch-auction-linear-vesting-power/schema.json +++ b/src/strategies/balance-of-with-bazaar-batch-auction-linear-vesting-power/schema.json @@ -1,46 +1,45 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", - "$ref": "#/definitions/Strategy", - "definitions": { - "Strategy": { - "title": "Strategy", - "type": "object", - "properties": { - "address": { - "type": "string", - "title": "ERC20 Token address", - "examples": ["e.g. 0x32fb7d6e0cbeb9433772689aa4647828cc7cbba8"], - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - }, - "symbol" : { - "type": "string", - "title": "ERC20 Token symbol", - "examples": ["e.g. COVE"] - }, - "decimals": { - "type": "number", - "title": "ERC20 Token decimals", - "examples": ["e.g. 18"] - }, - "auctionAddress": { - "type": "string", - "title": "Bazaar Batch Auction address", - "examples": ["e.g. 0x2f3715F710076Cfdb5AA872Bc8a4b965a07c3A08"], - "pattern": "^0x[a-fA-F0-9]{40}$", - "minLength": 42, - "maxLength": 42 - }, - "vestingDuration": { - "type": "number", - "title": "Vesting duration in seconds", - "examples": ["e.g. 31536000"] - } + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "address": { + "type": "string", + "title": "ERC20 Token address", + "examples": ["e.g. 0x32fb7d6e0cbeb9433772689aa4647828cc7cbba8"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 }, - "required": ["address", "decimals", "auctionAddress", "vestingDuration"], - "additionalProperties": false - } + "symbol": { + "type": "string", + "title": "ERC20 Token symbol", + "examples": ["e.g. COVE"] + }, + "decimals": { + "type": "number", + "title": "ERC20 Token decimals", + "examples": ["e.g. 18"] + }, + "auctionAddress": { + "type": "string", + "title": "Bazaar Batch Auction address", + "examples": ["e.g. 0x2f3715F710076Cfdb5AA872Bc8a4b965a07c3A08"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "vestingDuration": { + "type": "number", + "title": "Vesting duration in seconds", + "examples": ["e.g. 31536000"] + } + }, + "required": ["address", "decimals", "auctionAddress", "vestingDuration"], + "additionalProperties": false } } - \ No newline at end of file +} From 298b8d31b8ca9fa21458ae4b740747c80fa6197e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 6 May 2024 13:16:16 +0400 Subject: [PATCH 646/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.20 (#1468) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 01338b1c1..c7b242482 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.19", + "@snapshot-labs/snapshot.js": "^0.11.20", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index edfb5459e..680a061b8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.19": - version "0.11.19" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.19.tgz#436118728a46eee4b5a973a3334bd176cd27c2ac" - integrity sha512-ZsakhVsz0ylFqT3WhmJwxompsZrimFml6a4T10+aMS18oLFlwW0qooiahbmeSQ6Z9A9+KKeKmHl18VbHbdZg4w== +"@snapshot-labs/snapshot.js@^0.11.20": + version "0.11.20" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.20.tgz#8a532b77406e4d292399c2f9c141f50cee182741" + integrity sha512-6o1IemIGBiBk5uwIfCcS+Muefm8xCqUo7+IVINDsMqorJZHVMM1dIZFDhyl72t3ZB+CErrtza2F0QrqzQjjigQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From d129810378fc8547b6036a270daeea05e31efdd8 Mon Sep 17 00:00:00 2001 From: "system32.eth" <23362597+Raecaug@users.noreply.github.com> Date: Tue, 7 May 2024 03:32:13 -0400 Subject: [PATCH 647/815] [lrc-l2-nft-balance-of]chore(Loopring): Update to latest query URL (#1472) * Update README.md Update graph query URL * Update README.md Update query URL * Update examples.json Update to latest query URL * Update examples.json Update to latest query URL --- src/strategies/lrc-l2-nft-balance-of/README.md | 2 +- src/strategies/lrc-l2-nft-balance-of/examples.json | 2 +- src/strategies/lrc-nft-search-mult/README.md | 2 +- src/strategies/lrc-nft-search-mult/examples.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/strategies/lrc-l2-nft-balance-of/README.md b/src/strategies/lrc-l2-nft-balance-of/README.md index 121c5c972..e031a59b4 100644 --- a/src/strategies/lrc-l2-nft-balance-of/README.md +++ b/src/strategies/lrc-l2-nft-balance-of/README.md @@ -6,7 +6,7 @@ Here is an example of parameters: ```json { - "graph": "https://api.thegraph.com/subgraphs/name/juanmardefago/loopring36", + "graph": "https://api.thegraph.com/subgraphs/name/loopring/loopring", "minter_account_id": "74447", "tokens": ["token (Collection) id's to include"], "blacklisted_account_ids": ["38482"], diff --git a/src/strategies/lrc-l2-nft-balance-of/examples.json b/src/strategies/lrc-l2-nft-balance-of/examples.json index 0f2c7cec1..e7e7d1c49 100644 --- a/src/strategies/lrc-l2-nft-balance-of/examples.json +++ b/src/strategies/lrc-l2-nft-balance-of/examples.json @@ -4,7 +4,7 @@ "strategy": { "name": "lrc-l2-nft-balance-of", "params": { - "graph": "https://api.thegraph.com/subgraphs/name/juanmardefago/loopring36", + "graph": "https://api.thegraph.com/subgraphs/name/loopring/loopring", "minter_account_id": "74447", "tokens": ["0xc76eca2937b006606ebe717621409e4c2df906f1"], "blacklisted_account_ids": ["38482"], diff --git a/src/strategies/lrc-nft-search-mult/README.md b/src/strategies/lrc-nft-search-mult/README.md index f98fdfffa..00d5a9ba6 100644 --- a/src/strategies/lrc-nft-search-mult/README.md +++ b/src/strategies/lrc-nft-search-mult/README.md @@ -12,7 +12,7 @@ Here is an example of parameters: ```json { - "graph": "https://api.thegraph.com/subgraphs/name/juanmardefago/loopring36", + "graph": "https://api.thegraph.com/subgraphs/name/loopring/loopring", "minter_account_id": "74447", "tokens": ["token (Collection contract address) to include"], "nft_ids": ["nftIDs, unique to every nft, even those under the same token contract"], diff --git a/src/strategies/lrc-nft-search-mult/examples.json b/src/strategies/lrc-nft-search-mult/examples.json index e0eaba892..21b3f111f 100644 --- a/src/strategies/lrc-nft-search-mult/examples.json +++ b/src/strategies/lrc-nft-search-mult/examples.json @@ -4,7 +4,7 @@ "strategy": { "name": "lrc-nft-search-mult", "params": { - "graph": "https://api.thegraph.com/subgraphs/name/juanmardefago/loopring36", + "graph": "https://api.thegraph.com/subgraphs/name/loopring/loopring", "minter_account_id": "157510", "tokens": ["0xb6d91e38e4ac53c9f8952c6c6b1c7aee66c8b6f0"], "nft_ids": [ From 25164198f68a149b0d1e9290f2d25305bed7b23b Mon Sep 17 00:00:00 2001 From: samepant Date: Tue, 7 May 2024 03:44:00 -0400 Subject: [PATCH 648/815] [split-delegation] add split delegation strategy (#1466) * rename to split-delegation * remove log * update readme * add back delegate-registry-v2 * remove unused param * replace unused arg --- src/strategies/index.ts | 2 + src/strategies/split-delegation/README.md | 15 +++++ src/strategies/split-delegation/examples.json | 37 ++++++++++++ src/strategies/split-delegation/index.ts | 56 +++++++++++++++++++ 4 files changed, 110 insertions(+) create mode 100644 src/strategies/split-delegation/README.md create mode 100644 src/strategies/split-delegation/examples.json create mode 100644 src/strategies/split-delegation/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index a2e0d803d..7e5d1d53d 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -355,6 +355,7 @@ import * as starlayVeBalanceOfLockerId from './starlay-ve-balance-of-locker-id'; import * as winrStaking from './winr-staking'; import * as spaceid from './spaceid'; import * as delegateRegistryV2 from './delegate-registry-v2'; +import * as splitDelegation from './split-delegation'; import * as hatsProtocolSingleVotePerOrg from './hats-protocol-single-vote-per-org'; import * as karmaDiscordRoles from './karma-discord-roles'; import * as seedifyHoldStakingFarming from './seedify-cumulative-voting-power-hodl-staking-farming'; @@ -789,6 +790,7 @@ const strategies = { 'winr-staking': winrStaking, spaceid, 'delegate-registry-v2': delegateRegistryV2, + 'split-delegation': splitDelegation, 'hats-protocol-single-vote-per-org': hatsProtocolSingleVotePerOrg, 'karma-discord-roles': karmaDiscordRoles, 'seedify-cumulative-voting-power-hodl-staking-farming': diff --git a/src/strategies/split-delegation/README.md b/src/strategies/split-delegation/README.md new file mode 100644 index 000000000..fa5f7d7ac --- /dev/null +++ b/src/strategies/split-delegation/README.md @@ -0,0 +1,15 @@ +# Split Delegation + +A general-purpose delegate registry. + +## Features + +- Delegate to multiple addresses (specify the percentage of your vote-weight for each). +- Cascading delegations (Delegate A -> Delegate B -> Delegate C = Delegate C's total voting power = A + B + C) +- Expiring delegations +- Automatic vote weight adjustment based on token balance changes. +- Delegation revocation at any time. + +## Setting it up + +Mimic the structure found in `./examples.json`, with your required substrategies in an array on the `strategies` field. The other required field is `totalSupply`. This field should represent the total amount of tokens to be used as the denominator for your voting strategies, used to calculate the percent of voting power each member of your space controls. This is most often the total supply of your token, or the sum of the total supplies of the various tokens you are using. diff --git a/src/strategies/split-delegation/examples.json b/src/strategies/split-delegation/examples.json new file mode 100644 index 000000000..5ebce851d --- /dev/null +++ b/src/strategies/split-delegation/examples.json @@ -0,0 +1,37 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "split-delegation", + "params": { + "backendUrl": "https://delegate-api.gnosisguild.org", + "totalSupply": 1000000000, + "strategies": [ + { + "name": "erc20-balance-of", + "network": "1", + "params": { + "symbol": "LDO", + "address": "0x5a98fcbea516cf06857215779fd812ca3bef1b32", + "decimals": 18 + } + } + ] + } + }, + "network": "1", + "addresses": [ + "0x4af84812e595B5B0997A457eb3d5Ad8a3C1F6A0B", + "0x109B9744397ACf987A1abB5bB4EeF7362ab9Ff66", + "0x6CD69c3e7326Dec94596988AA6E5533ade51B52e", + "0xd1c7e00f41ce970F5A36686b172b9EAFc3700aAE", + "0x008756e24b06267B9D2488E5bf50091fC26C8e8d", + "0xb4F70F2F0f1A27276571a12e60c64E321f40d47C", + "0x70a613eA53b71abcBd9b32eAFB86362a31D5164C", + "0xcC18535935dAfa418A41C761C74586feF1952575", + "0xeE44C6fF39aC347d59e6b840D8412f60a7c2FAD1", + "0x7603a58A27ef77136398073D0E7453Ef0F650633" + ], + "snapshot": 19777000 + } +] diff --git a/src/strategies/split-delegation/index.ts b/src/strategies/split-delegation/index.ts new file mode 100644 index 000000000..0fe006658 --- /dev/null +++ b/src/strategies/split-delegation/index.ts @@ -0,0 +1,56 @@ +import fetch from 'cross-fetch'; +import { StaticJsonRpcProvider } from '@ethersproject/providers'; +import { Strategy } from '@snapshot-labs/snapshot.js/dist/voting/types'; + +export const author = 'gnosisguild'; +export const version = '1.0.0'; + +const DEFAULT_BACKEND_URL = 'https://delegate-api.gnosisguild.org'; + +type Params = { + backendUrl: string; + strategies: Strategy[]; + totalSupply: string | number; +}; + +export async function strategy( + space: string, + network: string, + _provider: StaticJsonRpcProvider, + addresses: string[], + options: Params = { + backendUrl: DEFAULT_BACKEND_URL, + strategies: [], + totalSupply: 0 + }, + snapshot: string | number +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + if (options.strategies.length > 8) + throw new Error('Maximum 8 strategies allowed'); + + const response = await fetch( + `${options.backendUrl}/api/v1/${space}/${blockTag}/voting-power`, + { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + options: { + strategies: options.strategies, + network: Number(network) + }, + addresses + }) + } + ); + + const votingPowerByAddress = (await response.json()) as { + [k: string]: number; + }; + + return votingPowerByAddress; +} From b676da1d3c054074eb3993d53231b389e64cabe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?gm=E1=B5=8D=E1=B5=90?= <4529189+oyyblin@users.noreply.github.com> Date: Tue, 7 May 2024 19:42:30 -0700 Subject: [PATCH 649/815] [galxe-staking] add galxe-staking strategy (#1474) * [galxe] add galxe-staking strategy * Update src/strategies/galxe-staking/index.ts --------- Co-authored-by: Chaitanya --- src/strategies/galxe-staking/README.md | 12 ++++++++ src/strategies/galxe-staking/examples.json | 19 ++++++++++++ src/strategies/galxe-staking/index.ts | 35 ++++++++++++++++++++++ src/strategies/galxe-staking/schema.json | 33 ++++++++++++++++++++ src/strategies/index.ts | 2 ++ 5 files changed, 101 insertions(+) create mode 100644 src/strategies/galxe-staking/README.md create mode 100644 src/strategies/galxe-staking/examples.json create mode 100644 src/strategies/galxe-staking/index.ts create mode 100644 src/strategies/galxe-staking/schema.json diff --git a/src/strategies/galxe-staking/README.md b/src/strategies/galxe-staking/README.md new file mode 100644 index 000000000..068ff7688 --- /dev/null +++ b/src/strategies/galxe-staking/README.md @@ -0,0 +1,12 @@ +# Galxe-Staking + +Strategy that returns voting power based on staked GAL token. + +Here is an example of parameters: + +```json +{ + "address": "0x7bBE09E066077b3888432EedEC958F64B2E47239", + "decimals": 18 +} +``` diff --git a/src/strategies/galxe-staking/examples.json b/src/strategies/galxe-staking/examples.json new file mode 100644 index 000000000..a83d2d25c --- /dev/null +++ b/src/strategies/galxe-staking/examples.json @@ -0,0 +1,19 @@ +[ + { + "name": "Galxe Staking", + "strategy": { + "name": "galxe-staking", + "params": { + "address": "0x7bBE09E066077b3888432EedEC958F64B2E47239", + "decimals": 18 + } + }, + "network": "56", + "addresses": [ + "0x93Cb1a4A9Bdea09162548243fD298F57cFc27F70", + "0xb85b3D61439a3d70D3DF7913a3A764F352b32C55", + "0x0Eb7570db974F2f57145eA9224A61e280A2E7457" + ], + "snapshot": 38145814 + } +] diff --git a/src/strategies/galxe-staking/index.ts b/src/strategies/galxe-staking/index.ts new file mode 100644 index 000000000..18aa8ef7b --- /dev/null +++ b/src/strategies/galxe-staking/index.ts @@ -0,0 +1,35 @@ +import { BigNumberish } from '@ethersproject/bignumber'; +import { Multicaller } from '../../utils'; +import { formatUnits } from '@ethersproject/units'; + +export const author = 'oyyblin'; +export const version = '0.1.0'; + +const abi = [ + 'function getStakeAmount(address) external view returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multi = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => { + multi.call(address, options.address, 'getStakeAmount', [address]); + }); + + const result: Record = await multi.execute(); + + return Object.fromEntries( + Object.entries(result).map(([address, balance]) => [ + address, + parseFloat(formatUnits(balance, options.decimals)) + ]) + ); +} diff --git a/src/strategies/galxe-staking/schema.json b/src/strategies/galxe-staking/schema.json new file mode 100644 index 000000000..2113da8b8 --- /dev/null +++ b/src/strategies/galxe-staking/schema.json @@ -0,0 +1,33 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. UNI"], + "maxLength": 16 + }, + "address": { + "type": "string", + "title": "Contract address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 18"] + } + }, + "required": ["address", "decimals"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 7e5d1d53d..4dcc0fb1e 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -208,6 +208,7 @@ import * as digitalaxMonaStakersMatic from './digitalax-mona-stakers-matic'; import * as digitalaxLPStakersMatic from './digitalax-lp-stakers-matic'; import * as galaxyNftWithScore from './galaxy-nft-with-score'; import * as galxeLoyaltyPoints from './galxe-loyalty-points'; +import * as galxeStaking from './galxe-staking'; import * as gatenetTotalStaked from './gatenet-total-staked'; import * as vesper from './vesper'; import * as thales from './thales'; @@ -648,6 +649,7 @@ const strategies = { 'digitalax-mona-quickswap': digitalaxMonaQuickswap, 'galaxy-nft-with-score': galaxyNftWithScore, 'galxe-loyalty-points': galxeLoyaltyPoints, + 'galxe-staking': galxeStaking, 'gatenet-total-staked': gatenetTotalStaked, vesper, thales, From 26c455b8afb909862ae275f919e600fce0b83c79 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Thu, 9 May 2024 19:43:35 +0530 Subject: [PATCH 650/815] [reliquary] Reduce mulitcall limit to 100 (#1476) --- src/strategies/reliquary/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategies/reliquary/index.ts b/src/strategies/reliquary/index.ts index 5aa3ee279..ed23eaf6d 100644 --- a/src/strategies/reliquary/index.ts +++ b/src/strategies/reliquary/index.ts @@ -32,7 +32,7 @@ export async function strategy( const multi = new Multicaller(network, provider, abi, { blockTag, - limit: 200 + limit: 150 }); for (const address of addresses) { From 426813e6ca324e1f039df64215bbf5b76628d1e3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 19 May 2024 09:02:58 +0530 Subject: [PATCH 651/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.23 (#1477) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index c7b242482..558dc0890 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.20", + "@snapshot-labs/snapshot.js": "^0.11.23", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 680a061b8..8aa4070ab 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.20": - version "0.11.20" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.20.tgz#8a532b77406e4d292399c2f9c141f50cee182741" - integrity sha512-6o1IemIGBiBk5uwIfCcS+Muefm8xCqUo7+IVINDsMqorJZHVMM1dIZFDhyl72t3ZB+CErrtza2F0QrqzQjjigQ== +"@snapshot-labs/snapshot.js@^0.11.23": + version "0.11.23" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.23.tgz#d032e632ea3838a1908071571377be240cb303e2" + integrity sha512-td4nE5BZeePNMci9llFmbSOqLkc0seKk/iyFCTH5OLOKr7mbERu5dKei0lwAHFGa5O1w4PtXqn/HlIZVUyq+ow== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 8f0650953c2aad8d023e64f7cf07205ff43c237c Mon Sep 17 00:00:00 2001 From: thierbig Date: Tue, 21 May 2024 05:37:13 -0400 Subject: [PATCH 652/815] [whitelist-weighted-json] New strategy (#1480) * Add whitelist weighted strategy json * Added strategy to index.ts and make tests pass with correct example --- src/strategies/index.ts | 2 + .../whitelist-weighted-json/README.md | 10 +++++ .../whitelist-weighted-json/examples.json | 18 ++++++++ .../whitelist-weighted-json/index.ts | 42 +++++++++++++++++++ 4 files changed, 72 insertions(+) create mode 100644 src/strategies/whitelist-weighted-json/README.md create mode 100644 src/strategies/whitelist-weighted-json/examples.json create mode 100644 src/strategies/whitelist-weighted-json/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 4dcc0fb1e..e446102da 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -92,6 +92,7 @@ import * as theGraphDelegation from './the-graph-delegation'; import * as theGraphIndexing from './the-graph-indexing'; import * as whitelist from './whitelist'; import * as whitelistWeighted from './whitelist-weighted'; +import * as whitelistWeightedJson from './whitelist-weighted-json'; import * as tokenlon from './tokenlon'; import * as pobHash from './pob-hash'; import * as erc1155BalanceOf from './erc1155-balance-of'; @@ -545,6 +546,7 @@ const strategies = { 'the-graph-indexing': theGraphIndexing, whitelist, 'whitelist-weighted': whitelistWeighted, + 'whitelist-weighted-json': whitelistWeightedJson, tokenlon, 'pob-hash': pobHash, 'comp-like-votes': compLikeVotes, diff --git a/src/strategies/whitelist-weighted-json/README.md b/src/strategies/whitelist-weighted-json/README.md new file mode 100644 index 000000000..07095e0d3 --- /dev/null +++ b/src/strategies/whitelist-weighted-json/README.md @@ -0,0 +1,10 @@ +# Whitelist Weighted Strategy Json + +This strategy returns weighted votes for addresses matching a whitelist returned from a .json file. The json file must match the following format: + +{"addresses": + { + "0xa478c2975ab1ea89e8196811f51a7b7ade33eb11": 5, + "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7": 2 + } +} diff --git a/src/strategies/whitelist-weighted-json/examples.json b/src/strategies/whitelist-weighted-json/examples.json new file mode 100644 index 000000000..2d02783b3 --- /dev/null +++ b/src/strategies/whitelist-weighted-json/examples.json @@ -0,0 +1,18 @@ +[ + { + "name": "Whitelist weighted address strategy via hosted json file", + "strategy": { + "name": "whitelist-weighted-json", + "params": { + "url": "https://proposals.kenglernitas.wtf/batel_combined_weighted_voting_power.json" + } + }, + "network": "8453", + "addresses": [ + "0xc4e9e087a811be812f85e49f2a41603d9a0991a9", + "0x542a0eaf1358480ec0703f07bc3120a6503ebbc1", + "0x9f31068a18d8511755de024e8eccf073dfd01d8f" + ], + "snapshot": 14694443 + } +] diff --git a/src/strategies/whitelist-weighted-json/index.ts b/src/strategies/whitelist-weighted-json/index.ts new file mode 100644 index 000000000..352360d23 --- /dev/null +++ b/src/strategies/whitelist-weighted-json/index.ts @@ -0,0 +1,42 @@ +import fetch from 'cross-fetch'; +import { getAddress } from '@ethersproject/address'; + +export const author = 'thierbig'; +export const version = '0.1.0'; + +export async function strategy(space, network, provider, addresses, options) { + const url = options.url; + + if (!url) throw new Error('Invalid url'); + + const response = await fetch(url, { + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + } + }); + let responseData: any = await response.text(); + + try { + responseData = JSON.parse(responseData); + } catch (e) { + throw new Error( + `[whitelist-weighted-json] Errors found in API: URL: ${url}, Status: ${response.status}` + + response.ok + ? `, Response: ${responseData.substring(0, 512)}` + : '' + ); + } + + const whitelist = Object.fromEntries( + Object.entries(responseData.addresses).map(([addr, weight]) => [ + addr.toLowerCase(), + weight + ]) + ); + + const results=Object.fromEntries( + addresses.map((address) => [getAddress(address), whitelist[address.toLowerCase()] || 0]) + ); + return results; +} From eb04d2aa1d199246a01e5e22186a3f552a89394c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crist=C3=B3v=C3=A3o?= <12870300+cristovaoth@users.noreply.github.com> Date: Fri, 24 May 2024 08:34:33 +0200 Subject: [PATCH 653/815] [safe-vested] Optimize Strategy: safe-vested (#1481) * Add createAllocationMap function * Refactor to use allocationMap for more efficient lookups instead of linear searches through the allocations json arrays * Avoid creating a new result object in each reducer iteration very expensive; use simple assignment on the existing result object instead. * Improve examples.json: Include one address with vesting vote power. Adjust blockNumber to one after both vesting pool contracts are deployed --- src/strategies/safe-vested/examples.json | 4 +-- src/strategies/safe-vested/index.ts | 42 ++++++++++++++++-------- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/strategies/safe-vested/examples.json b/src/strategies/safe-vested/examples.json index 3924bb74b..280f9bc95 100644 --- a/src/strategies/safe-vested/examples.json +++ b/src/strategies/safe-vested/examples.json @@ -9,7 +9,7 @@ } }, "network": "1", - "snapshot": 15800000, + "snapshot": 17778299, "addresses": [ "0x9970dcab40e29a84D1020DeaEa443dCE1d8471b7", "0x1230B3d59858296A31053C1b8562Ecf89A2f888b", @@ -18,7 +18,7 @@ "0xf2565317F3Ae8Ae9EA98E9Fe1e7FADC77F823cbD", "0x37b828802FAeA4244d176Da386CF632F5Bbc414F", "0xA8FFD6B87388F8d5FACfDa0147d9B0Da511539b6", - "0xd7539FCdC0aB79a7B688b04387cb128E75cb77Dc" + "0x0Ca678b984186b0117501C00d4A6B4F8F342D06D" ] } ] diff --git a/src/strategies/safe-vested/index.ts b/src/strategies/safe-vested/index.ts index 6398d6c07..f88366321 100644 --- a/src/strategies/safe-vested/index.ts +++ b/src/strategies/safe-vested/index.ts @@ -51,6 +51,7 @@ export async function strategy( } }); const allocationsList: [[AllocationDetails]] = await response.json(); + const allocationMap = createAllocationMap(allocationsList); const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; const multi = new Multicaller(network, provider, abi, { @@ -60,9 +61,7 @@ export async function strategy( // Get current vesting state from smart contract using the vestingId addresses.forEach((address) => { - const addressAllocations = allocationsList.find( - (allocations: AllocationDetails[]) => allocations[0].account === address - ); + const addressAllocations = allocationMap[address]; if (addressAllocations) { addressAllocations.forEach(({ contract, vestingId }) => { @@ -73,12 +72,10 @@ export async function strategy( const vestings = await multi.execute(); - const flatAllocationsList = allocationsList.flat(); // Check vesting state, consider only unclaimed amounts and group allocations to the same account - return Object.keys(vestings).reduce((acc, key) => { - const { account, amount } = flatAllocationsList.find( - ({ vestingId }) => vestingId === key - ) as AllocationDetails; + return Object.keys(vestings).reduce((result, key) => { + // get it from the map by vestingId. A entry is guaranteed to exist + const [{ account, amount }] = allocationMap[key]!; const hasAlreadyClaimed = vestings[key].account === account; let currentVestingAmount; @@ -95,16 +92,35 @@ export async function strategy( : '0'; } - const previousAmount = acc[account]; + const previousAmount = result[account]; // If account received multiple allocations sum them // Else we just return the currentAmount const pendingVestedAmount = previousAmount ? parseUnits(previousAmount.toString()).add(currentVestingAmount) : currentVestingAmount; - return { - ...acc, + return Object.assign(result, { [account]: parseFloat(formatUnits(pendingVestedAmount)) - }; - }, {}); + }); + }, {} as Record); +} + +function createAllocationMap(allocations: AllocationDetails[][]) { + const result: Record = {}; + + for (const allocation of allocations.flat()) { + const { account, vestingId } = allocation; + + if (!result[account]) { + result[account] = []; + } + + if (!result[vestingId]) { + result[vestingId] = []; + } + result[account].push(allocation); + result[vestingId].push(allocation); + } + + return result; } From 16be31322b9dd956a5e85919803dd4bee4de134d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 May 2024 17:47:46 +0530 Subject: [PATCH 654/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.24 (#1482) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 558dc0890..b2dfac31c 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.23", + "@snapshot-labs/snapshot.js": "^0.11.24", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 8aa4070ab..0f88ea21d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.23": - version "0.11.23" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.23.tgz#d032e632ea3838a1908071571377be240cb303e2" - integrity sha512-td4nE5BZeePNMci9llFmbSOqLkc0seKk/iyFCTH5OLOKr7mbERu5dKei0lwAHFGa5O1w4PtXqn/HlIZVUyq+ow== +"@snapshot-labs/snapshot.js@^0.11.24": + version "0.11.24" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.24.tgz#013d9306236dd0a74ac8bcb31a14c5edbd68a960" + integrity sha512-LORRX/0zFdy4pRMWLjoOEh0wB0foNjpxovKi3V5uho5RDB73V5sUSoj3NG4pmz/ZyQREAyqma2/LgpJqyHcirQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 327a58840dda343789178193d144394c88b54f78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crist=C3=B3v=C3=A3o?= Date: Tue, 28 May 2024 06:39:29 +0200 Subject: [PATCH 655/815] Keep the allocationMap in global cache variable, inside the strategy. (#1483) --- src/strategies/safe-vested/index.ts | 58 +++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/src/strategies/safe-vested/index.ts b/src/strategies/safe-vested/index.ts index f88366321..16673ffe6 100644 --- a/src/strategies/safe-vested/index.ts +++ b/src/strategies/safe-vested/index.ts @@ -1,5 +1,7 @@ import fetch from 'cross-fetch'; import { formatUnits, parseUnits } from '@ethersproject/units'; +import { isAddress } from '@ethersproject/address'; +import { isHexString } from '@ethersproject/bytes'; import { Multicaller } from '../../utils'; @@ -11,7 +13,7 @@ const abi = [ 'function vestings(bytes32) view returns (address account, uint8 curveType, bool managed, uint16 durationWeeks, uint64 startDate, uint128 amount, uint128 amountClaimed, uint64 pausingDate, bool cancelled)' ]; -type AllocationDetails = { +type Allocation = { account: string; contract: string; vestingId: string; @@ -35,6 +37,25 @@ const canStillClaim = (claimDateLimit: string | undefined): boolean => { return true; }; +let _allocationMap: Record | null = null; + +async function loadAllocationMap( + options: Options +): Promise> { + if (!_allocationMap) { + const response = await fetch(options.allocationsSource, { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + } + }); + _allocationMap = createAllocationMap(await response.json()); + } + + return _allocationMap; +} + export async function strategy( space: string, network: string, @@ -43,15 +64,7 @@ export async function strategy( options: Options, snapshot: number | string = 'latest' ) { - const response = await fetch(options.allocationsSource, { - method: 'GET', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json' - } - }); - const allocationsList: [[AllocationDetails]] = await response.json(); - const allocationMap = createAllocationMap(allocationsList); + const allocationMap = await loadAllocationMap(options); const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; const multi = new Multicaller(network, provider, abi, { @@ -105,11 +118,22 @@ export async function strategy( }, {} as Record); } -function createAllocationMap(allocations: AllocationDetails[][]) { - const result: Record = {}; - - for (const allocation of allocations.flat()) { - const { account, vestingId } = allocation; +function createAllocationMap( + rawAllocations: any[][] +): Record { + const result: Record = {}; + + for (const rawAllocation of rawAllocations.flat()) { + const { account, contract, vestingId, amount } = rawAllocation; + + if ( + !isAddress(account) || + !isAddress(contract) || + (!isHexString(vestingId) && vestingId.length == 66) || + String(BigInt(amount)) != amount + ) { + throw new Error(`Invalid Allocation Entry: ${rawAllocation}`); + } if (!result[account]) { result[account] = []; @@ -118,6 +142,10 @@ function createAllocationMap(allocations: AllocationDetails[][]) { if (!result[vestingId]) { result[vestingId] = []; } + + // trimmed down allocation + const allocation = { account, contract, vestingId, amount }; + result[account].push(allocation); result[vestingId].push(allocation); } From 3b51d52216ff6241cd773f8d39e2d67407a90669 Mon Sep 17 00:00:00 2001 From: samepant Date: Tue, 28 May 2024 01:02:03 -0400 Subject: [PATCH 656/815] [split-delegation] API request body schema update, update README and example (#1484) * update api call with new request body schema * add delegateOverride to readme and example --- src/strategies/split-delegation/README.md | 11 ++++++++++- src/strategies/split-delegation/examples.json | 1 + src/strategies/split-delegation/index.ts | 15 +++++++++++---- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/strategies/split-delegation/README.md b/src/strategies/split-delegation/README.md index fa5f7d7ac..30b114df5 100644 --- a/src/strategies/split-delegation/README.md +++ b/src/strategies/split-delegation/README.md @@ -12,4 +12,13 @@ A general-purpose delegate registry. ## Setting it up -Mimic the structure found in `./examples.json`, with your required substrategies in an array on the `strategies` field. The other required field is `totalSupply`. This field should represent the total amount of tokens to be used as the denominator for your voting strategies, used to calculate the percent of voting power each member of your space controls. This is most often the total supply of your token, or the sum of the total supplies of the various tokens you are using. +Mimic the structure found in `./examples.json`, and fill in the parameters. + +Parameters: + +- `strategies` + - This field is an array of the snapshot strategies you want to use to calculate raw voting score. +- `totalSupply` + - This field should represent the total amount of tokens to be used as the denominator for your voting strategies, used to calculate the percent of voting power each member of your space controls. This is most often the total supply of your token, or the sum of the total supplies of the various tokens you are using. +- `delegationOverride` + - This field is optional, and defaults to `false`. If set to `true`, addresses who have delegated can still vote in a poll and have that vote counted with the weight associated with their account, overriding the vote of their delegate. If set to `false`, addresses that have delegated will not be able to override their delegate's vote. _*This should only be used for smaller spaces, as it requires more computation per vote*_ diff --git a/src/strategies/split-delegation/examples.json b/src/strategies/split-delegation/examples.json index 5ebce851d..db0121cac 100644 --- a/src/strategies/split-delegation/examples.json +++ b/src/strategies/split-delegation/examples.json @@ -6,6 +6,7 @@ "params": { "backendUrl": "https://delegate-api.gnosisguild.org", "totalSupply": 1000000000, + "delegationOverride": false, "strategies": [ { "name": "erc20-balance-of", diff --git a/src/strategies/split-delegation/index.ts b/src/strategies/split-delegation/index.ts index 0fe006658..ecd2dd9ee 100644 --- a/src/strategies/split-delegation/index.ts +++ b/src/strategies/split-delegation/index.ts @@ -11,6 +11,7 @@ type Params = { backendUrl: string; strategies: Strategy[]; totalSupply: string | number; + delegationOverride?: boolean; }; export async function strategy( @@ -21,7 +22,8 @@ export async function strategy( options: Params = { backendUrl: DEFAULT_BACKEND_URL, strategies: [], - totalSupply: 0 + totalSupply: 0, + delegationOverride: false }, snapshot: string | number ): Promise> { @@ -39,9 +41,14 @@ export async function strategy( 'Content-Type': 'application/json' }, body: JSON.stringify({ - options: { - strategies: options.strategies, - network: Number(network) + strategy: { + name: 'split-delegation', + network: Number(network), + params: { + totalSupply: options.totalSupply, + delegationOverride: options.delegationOverride, + strategies: options.strategies + } }, addresses }) From 0c2ff29ca640508a6db514e1a98bd7e3c705b1c4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 28 May 2024 10:34:17 +0530 Subject: [PATCH 657/815] Automated lint (#1485) Co-authored-by: ChaituVR --- src/strategies/whitelist-weighted-json/examples.json | 2 +- src/strategies/whitelist-weighted-json/index.ts | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/strategies/whitelist-weighted-json/examples.json b/src/strategies/whitelist-weighted-json/examples.json index 2d02783b3..7c1f4a908 100644 --- a/src/strategies/whitelist-weighted-json/examples.json +++ b/src/strategies/whitelist-weighted-json/examples.json @@ -4,7 +4,7 @@ "strategy": { "name": "whitelist-weighted-json", "params": { - "url": "https://proposals.kenglernitas.wtf/batel_combined_weighted_voting_power.json" + "url": "https://proposals.kenglernitas.wtf/batel_combined_weighted_voting_power.json" } }, "network": "8453", diff --git a/src/strategies/whitelist-weighted-json/index.ts b/src/strategies/whitelist-weighted-json/index.ts index 352360d23..a15fb975f 100644 --- a/src/strategies/whitelist-weighted-json/index.ts +++ b/src/strategies/whitelist-weighted-json/index.ts @@ -22,7 +22,7 @@ export async function strategy(space, network, provider, addresses, options) { } catch (e) { throw new Error( `[whitelist-weighted-json] Errors found in API: URL: ${url}, Status: ${response.status}` + - response.ok + response.ok ? `, Response: ${responseData.substring(0, 512)}` : '' ); @@ -35,8 +35,11 @@ export async function strategy(space, network, provider, addresses, options) { ]) ); - const results=Object.fromEntries( - addresses.map((address) => [getAddress(address), whitelist[address.toLowerCase()] || 0]) + const results = Object.fromEntries( + addresses.map((address) => [ + getAddress(address), + whitelist[address.toLowerCase()] || 0 + ]) ); return results; } From e50d4c30f231a3dec7175c46268e0c795faa13bb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 28 May 2024 11:48:56 +0530 Subject: [PATCH 658/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.25 (#1486) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index b2dfac31c..c65445f6f 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.24", + "@snapshot-labs/snapshot.js": "^0.11.25", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 0f88ea21d..deb4ae2c6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.24": - version "0.11.24" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.24.tgz#013d9306236dd0a74ac8bcb31a14c5edbd68a960" - integrity sha512-LORRX/0zFdy4pRMWLjoOEh0wB0foNjpxovKi3V5uho5RDB73V5sUSoj3NG4pmz/ZyQREAyqma2/LgpJqyHcirQ== +"@snapshot-labs/snapshot.js@^0.11.25": + version "0.11.25" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.25.tgz#61970545999ae8c6ec3fcc1344cd92f445839ef3" + integrity sha512-YmdTefKZDVUsJNQXIwiKV/oj1Vch0RQb+1tGKOhma8UDuL4OMgClbliKjU52vSQeiFNgtVeW0aci2/BmlnmwTA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 315ed5dd5e105ffc9cabd7253dee3b7adf76c881 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 28 May 2024 17:18:01 +0530 Subject: [PATCH 659/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.26 (#1487) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index c65445f6f..0be9b413c 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.25", + "@snapshot-labs/snapshot.js": "^0.11.26", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index deb4ae2c6..5cc4580b3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.25": - version "0.11.25" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.25.tgz#61970545999ae8c6ec3fcc1344cd92f445839ef3" - integrity sha512-YmdTefKZDVUsJNQXIwiKV/oj1Vch0RQb+1tGKOhma8UDuL4OMgClbliKjU52vSQeiFNgtVeW0aci2/BmlnmwTA== +"@snapshot-labs/snapshot.js@^0.11.26": + version "0.11.26" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.26.tgz#2787e643e2e9b5c27562b431a32f0fd6c22f151f" + integrity sha512-MwJROAnthtH+pu9xPz0pVH8fqQ7VoTn23M3bsRcTrFPpqH0Rl3an3YreGzUCKTVdWBlWRPHvKdgdtfrIr3cgMA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From c2bc557d7b7037236ca2bdc1ba2c529f2cf529f6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 31 May 2024 10:31:06 +0530 Subject: [PATCH 660/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.27 (#1488) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 0be9b413c..eb4e45b19 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.26", + "@snapshot-labs/snapshot.js": "^0.11.27", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 5cc4580b3..87c0e82b7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.26": - version "0.11.26" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.26.tgz#2787e643e2e9b5c27562b431a32f0fd6c22f151f" - integrity sha512-MwJROAnthtH+pu9xPz0pVH8fqQ7VoTn23M3bsRcTrFPpqH0Rl3an3YreGzUCKTVdWBlWRPHvKdgdtfrIr3cgMA== +"@snapshot-labs/snapshot.js@^0.11.27": + version "0.11.27" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.27.tgz#f341f810e61d6dce72f00ddd1a57bde338b9a6b3" + integrity sha512-oCKY0thlLeSh2fYrVzPCzHb9HHyfRqLD55IGBrCgUUORJP78w3TvlscXwP0LgdNPuN3pNaDNwLGKUrx4GayB/w== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From efcd42debf15fae367d243db798a33385c7230b1 Mon Sep 17 00:00:00 2001 From: ChaituVR Date: Sun, 2 Jun 2024 22:01:33 +0530 Subject: [PATCH 661/815] Update uniswap subgraph --- src/strategies/uniswap/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategies/uniswap/index.ts b/src/strategies/uniswap/index.ts index 52acbe540..0e209d64f 100644 --- a/src/strategies/uniswap/index.ts +++ b/src/strategies/uniswap/index.ts @@ -2,7 +2,7 @@ import { getAddress } from '@ethersproject/address'; import { subgraphRequest } from '../../utils'; const UNISWAP_SUBGRAPH_URL = { - '1': 'https://api.thegraph.com/subgraphs/name/ianlapham/uniswap-v2-dev' + '1': 'https://gateway-arbitrum.network.thegraph.com/api/5e18263ac1ce55a37039f226cc665e8d/subgraphs/id/FEtpnfQ1aqF8um2YktEkfzFD11ZKrfurvBLPeQzv9JB1' }; export const author = 'snapshot-labs'; From de08dedf7f15ae45f3f8d472bc4bc183bcbccaf8 Mon Sep 17 00:00:00 2001 From: propchain-development <100083866+propchain-development@users.noreply.github.com> Date: Sun, 2 Jun 2024 18:57:08 +0200 Subject: [PATCH 662/815] [staking-balance-of-v2] New strategy staking v2 (#1489) * staking v1 and v2 * fixing review items --------- Co-authored-by: Tobias Athenstaedt --- src/strategies/index.ts | 4 +- .../staking-balance-of-v2/README.md | 28 +++++ .../staking-balance-of-v2/examples.json | 38 ++++++ src/strategies/staking-balance-of-v2/index.ts | 112 ++++++++++++++++++ .../staking-balance-of-v2/schema.json | 59 +++++++++ 5 files changed, 240 insertions(+), 1 deletion(-) create mode 100644 src/strategies/staking-balance-of-v2/README.md create mode 100644 src/strategies/staking-balance-of-v2/examples.json create mode 100644 src/strategies/staking-balance-of-v2/index.ts create mode 100644 src/strategies/staking-balance-of-v2/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index e446102da..c61cd5323 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -419,6 +419,7 @@ import * as voltVotingPower from './volt-voting-power'; import * as xdaiStakersAndHolders from './xdai-stakers-and-holders'; import * as minimeBalanceVsSupplyWeighted from './minime-balance-vs-supply-weighted'; import * as vestingBalanceOf from './vesting-balance-of'; +import * as stakingBalanceOfV2 from './staking-balance-of-v2'; import * as poktNetworkPDA from './pokt-network-pda'; import * as givethBalancesSupplyWeighted from './giveth-balances-supply-weighted'; import * as givethGnosisBalanceSupplyWeightedV3 from './giveth-gnosis-balance-supply-weighted-v3'; @@ -864,7 +865,8 @@ const strategies = { 'a51-vault-balance': a51VaultBalance, 'quickswap-v3': quickswapv3, 'balance-of-with-bazaar-batch-auction-linear-vesting-power': - balanceOfWithBazaarBatchAuctionLinearVestingPower + balanceOfWithBazaarBatchAuctionLinearVestingPower, + 'staking-balance-of-v2': stakingBalanceOfV2, }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/staking-balance-of-v2/README.md b/src/strategies/staking-balance-of-v2/README.md new file mode 100644 index 000000000..971d814cc --- /dev/null +++ b/src/strategies/staking-balance-of-v2/README.md @@ -0,0 +1,28 @@ +# staking-balance-of-v2 + +This strategy retrieves staked balance for specific wallets on a custom developed staking contract. +An example of this contract can be found on [etherscan](https://etherscan.io/address/0x59Ca57ca0f03c6E383a2d8dfE4c73c21174e7c8A) and is referenced as "Staking V2". +This contract also support multiple stakes by the same user on the same pool, all being handled individually. + +The contract stores a list of staking buckets which is accessible via a `getUserInfo(uint256 pid, address wallet)` method allowing to retrieve +information about the user's staked amount. In contrast to the `v1` strategy and its supported contract, the administrative information is removed +from the contract for better performance. +Another method provided by the contract (`getPoolInfo(uint256 pid)`) returns information on the pool itself. The information will be used to calculate +the weight of a user's stake on the contract - in general, longer pool lockups are considered more valuable than shorter lockups. + +With this strategy up to **3** buckets can be checked at once. Only one bucket is required. If multiple buckets are checked +the total balance is returned. +*Decimals* is a global setting being applied to all buckets. + +Here is an example of parameters: + +```json +{ + "staking_contract": "0x59Ca57ca0f03c6E383a2d8dfE4c73c21174e7c8A", + "pid_1": "1", + "pid_2": "2", + "pid_3": "3", + "decimals": 18, + "maxTimeInPool": "63072000" +} +``` diff --git a/src/strategies/staking-balance-of-v2/examples.json b/src/strategies/staking-balance-of-v2/examples.json new file mode 100644 index 000000000..2b210c6ea --- /dev/null +++ b/src/strategies/staking-balance-of-v2/examples.json @@ -0,0 +1,38 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "staking-balance-of-v2", + "params": { + "staking_contract": "0x59Ca57ca0f03c6E383a2d8dfE4c73c21174e7c8A", + "pid_1": "1", + "pid_2": "2", + "pid_3": "3", + "maxTimeInPool": "63072000", + "decimals": 18 + } + }, + "network": "1", + "addresses": [ + "0xE31Bb1A9a271B754cbaDCD5e993c883d8E4cf9af", + "0xa759997AC89A1ab156f2b17093d4FDdC9f0db1AF", + "0xa759997AC89A1ab156f2b17093d4FDdC9f0db1AF", + "0x7dd4FCbFe76B59b4D7Ed7F3DF7077f126F633C97", + "0x0F2C000DECca60752233Aa3bBC5D35ee0f2dacE7", + "0x1d5E65a087eBc3d03a294412E46CE5D6882969f4", + "0x1f254336E5c46639A851b9CfC165697150a6c327", + "0x2ec3F80BeDA63Ede96BA20375032CDD3aAfb3030", + "0x4AcBcA6BE2f8D2540bBF4CA77E45dA0A4a095Fa2", + "0x4F3D348a6D09837Ae7961B1E0cEe2cc118cec777", + "0x6D7f23A509E212Ba7773EC1b2505d1A134f54fbe", + "0x07a1f6fc89223c5ebD4e4ddaE89Ac97629856A0f", + "0x8d5F05270da470e015b67Ab5042BDbE2D2FEFB48", + "0x8d07D225a769b7Af3A923481E1FdF49180e6A265", + "0x8f60501dE5b9b01F9EAf1214dbE1924aA97F7fd0", + "0x9B8e8dD9151260c21CB6D7cc59067cd8DF306D58", + "0x17ea92D6FfbAA1c7F6B117c1E9D0c88ABdc8b84C", + "0x38C0039247A31F3939baE65e953612125cB88268" + ], + "snapshot": 20002770 + } +] diff --git a/src/strategies/staking-balance-of-v2/index.ts b/src/strategies/staking-balance-of-v2/index.ts new file mode 100644 index 000000000..97b4a298e --- /dev/null +++ b/src/strategies/staking-balance-of-v2/index.ts @@ -0,0 +1,112 @@ +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; +import {BigNumber, BigNumberish} from "@ethersproject/bignumber"; + +export const author = 'propchain-development'; +export const version = '0.1.0'; + +const vestingABI = [ + 'function getUserInfo(uint256 _pid, address _account) view returns (uint256 amount)', + 'function getPoolInfo(uint256 _pid) view returns (uint256 startTime, address rewardsToken, address penaltyWallet, uint256 apyPercent, uint256 totalStaked, bool active, uint256 claimTimeLimit, uint256 minStakeAmount, uint256 penaltyFee, uint256 penaltyTimeLimit, bool isVIPPool)' +]; + +interface Options { + staking_contract: string; + pid_1: string; + pid_2?: string; + pid_3?: string; + maxTimeInPool: BigNumberish; + decimals: number; +} + +interface PoolInfo { + startTime: BigNumberish; + rewardsToken: string + penaltyWallet: string, + apyPercent: BigNumberish, + totalStaked: BigNumberish, + active: boolean, + claimTimeLimit: BigNumberish, + minStakeAmount: BigNumberish, + penaltyFee: BigNumberish, + penaltyTimeLimit: BigNumberish + isVIPPool: boolean +} + +export async function strategy( + space, + network, + provider, + addresses, + options: Options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multi = new Multicaller(network, provider, vestingABI, { blockTag }); + + multi.call(options.pid_1, options.staking_contract, 'getPoolInfo', [options.pid_1]); + if (options.pid_2) + multi.call( + options.pid_2, + options.staking_contract, + 'getPoolInfo', + [options.pid_2] + ); + if (options.pid_3) + multi.call( + options.pid_3, + options.staking_contract, + 'getPoolInfo', + [options.pid_3] + ); + + + const poolRecords : Record = await multi.execute(); + + addresses.forEach((address: string) => { + if (poolRecords[options.pid_1].active) { + multi.call( + address + '_' + options.pid_1, + options.staking_contract, + 'getUserInfo', + [options.pid_1, address] + ); + } + if (options.pid_2 && poolRecords[options.pid_2].active) + multi.call( + address + '_' + options.pid_2, + options.staking_contract, + 'getUserInfo', + [options.pid_2, address] + ); + if (options.pid_3 && poolRecords[options.pid_3].active) + multi.call( + address + '_' + options.pid_3, + options.staking_contract, + 'getUserInfo', + [options.pid_3, address] + ); + }); + const userProperties: Record = await multi.execute(); + + const filteredRecords: Record = {}; + Object.entries(userProperties).forEach(([identifier, userAmount]) => { + const [addr, pid] = identifier.split('_'); + const poolInfo: PoolInfo = poolRecords[pid]; + + if (!filteredRecords[addr]) filteredRecords[addr] = 0; + + if(!poolInfo.active) return; + if (parseInt(pid) === 0) return; + + const weight = BigNumber.from(poolInfo.penaltyTimeLimit).toNumber() / BigNumber.from(options.maxTimeInPool).toNumber(); + const votingPower = parseFloat( + formatUnits(userAmount, options.decimals) + ) * weight; + + filteredRecords[addr] += votingPower + }); + + return filteredRecords; +} diff --git a/src/strategies/staking-balance-of-v2/schema.json b/src/strategies/staking-balance-of-v2/schema.json new file mode 100644 index 000000000..b5c15fd31 --- /dev/null +++ b/src/strategies/staking-balance-of-v2/schema.json @@ -0,0 +1,59 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "decimals": { + "type": "number", + "title": "Decimals on all staking contracts", + "examples": ["e.g. 18"] + }, + "staking_contract": { + "type": "string", + "title": "Staking contract addresses", + "examples": ["e.g. 0x59Ca57ca0f03c6E383a2d8dfE4c73c21174e7c8A"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "pid_1": { + "type": "string", + "title": "Pool ID on vesting contract", + "examples": ["e.g. 1"], + "pattern": "^[0-9]+$", + "minLength": 1, + "maxLength": 5 + }, + "pid_2": { + "type": "string", + "title": "Pool ID on vesting contract", + "examples": ["e.g. 2"], + "pattern": "^[0-9]+$", + "minLength": 1, + "maxLength": 5 + }, + "pid_3": { + "type": "string", + "title": "Pool ID on vesting contract", + "examples": ["e.g. 3"], + "pattern": "^[0-9]+$", + "minLength": 1, + "maxLength": 5 + }, + "maxTimeInPool": { + "type": "string", + "title": "Maximum staking time per stake event. In seconds.", + "examples": ["e.g. 63072000"], + "pattern": "^[0-9]+$", + "minLength": 1, + "maxLength": 10 + } + }, + "required": ["staking_contract", "decimals", "maxTimeInPool", "pid_1"], + "additionalProperties": false + } + } +} From e84177ccb345ba039a580536e09c9f2ce5822695 Mon Sep 17 00:00:00 2001 From: propchain-development <100083866+propchain-development@users.noreply.github.com> Date: Sun, 2 Jun 2024 19:08:45 +0200 Subject: [PATCH 663/815] [staking-balance-of-v1] New strategy staking balance v1 (#1490) * staking balance v1 * Update src/strategies/index.ts * review item --------- Co-authored-by: Tobias Athenstaedt Co-authored-by: Chaitanya --- src/strategies/index.ts | 2 + .../staking-balance-of-v1/README.md | 27 ++++ .../staking-balance-of-v1/examples.json | 38 ++++++ src/strategies/staking-balance-of-v1/index.ts | 118 ++++++++++++++++++ .../staking-balance-of-v1/schema.json | 59 +++++++++ 5 files changed, 244 insertions(+) create mode 100644 src/strategies/staking-balance-of-v1/README.md create mode 100644 src/strategies/staking-balance-of-v1/examples.json create mode 100644 src/strategies/staking-balance-of-v1/index.ts create mode 100644 src/strategies/staking-balance-of-v1/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index c61cd5323..f77c9cfd6 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -428,6 +428,7 @@ import * as a51Farming from './a51-farming'; import * as a51VaultBalance from './a51-vault-balance'; import * as quickswapv3 from './quickswap-v3'; import * as balanceOfWithBazaarBatchAuctionLinearVestingPower from './balance-of-with-bazaar-batch-auction-linear-vesting-power'; +import * as stakingBalanceOfV1 from './staking-balance-of-v1'; const strategies = { 'giveth-balances-supply-weighted': givethBalancesSupplyWeighted, @@ -866,6 +867,7 @@ const strategies = { 'quickswap-v3': quickswapv3, 'balance-of-with-bazaar-batch-auction-linear-vesting-power': balanceOfWithBazaarBatchAuctionLinearVestingPower, + 'staking-balance-of-v1': stakingBalanceOfV1, 'staking-balance-of-v2': stakingBalanceOfV2, }; diff --git a/src/strategies/staking-balance-of-v1/README.md b/src/strategies/staking-balance-of-v1/README.md new file mode 100644 index 000000000..aed899bbb --- /dev/null +++ b/src/strategies/staking-balance-of-v1/README.md @@ -0,0 +1,27 @@ +# staking-balance-of-v1 + +This strategy retrieves staked balance for specific wallets on a custom developed staking contract. +An example of this contract can be found on [etherscan](https://etherscan.io/address/0x0a3476c1ea4ef65416016876c67e1a14e3575d73) and is referenced as "Staking V1". + +The contract stores a list of staking buckets which is accessible via a `getUserInfo(uint256 pid, address wallet)` method allowing to retrieve +information about the user's staked amount as well as other administrative information. The administrative information is irrelevant for this' +voting strategy's purpose. +Another method provided by the contract (`getPoolInfo(uint256 pid)`) returns information on the pool itself. The information will be used to calculate +the weight of a user's stake on the contract - in general, longer pool lockups are considered more valuable than shorter lockups. + +With this strategy up to **3** buckets can be checked at once. Only one bucket is required. If multiple buckets are checked +the total balance is returned. +*Decimals* is a global setting being applied to all buckets. + +Here is an example of parameters: + +```json +{ + "staking_contract": "0x0a3476c1ea4ef65416016876c67e1a14e3575d73", + "pid_1": "1", + "pid_2": "2", + "pid_3": "3", + "decimals": 18, + "maxTimeInPool": "63072000" +} +``` diff --git a/src/strategies/staking-balance-of-v1/examples.json b/src/strategies/staking-balance-of-v1/examples.json new file mode 100644 index 000000000..73842ec28 --- /dev/null +++ b/src/strategies/staking-balance-of-v1/examples.json @@ -0,0 +1,38 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "staking-balance-of-v1", + "params": { + "staking_contract": "0x0a3476c1ea4ef65416016876c67e1a14e3575d73", + "pid_1": "1", + "pid_2": "2", + "pid_3": "3", + "maxTimeInPool": "63072000", + "decimals": 18 + } + }, + "network": "1", + "addresses": [ + "0xE31Bb1A9a271B754cbaDCD5e993c883d8E4cf9af", + "0xa759997AC89A1ab156f2b17093d4FDdC9f0db1AF", + "0xa759997AC89A1ab156f2b17093d4FDdC9f0db1AF", + "0x7dd4FCbFe76B59b4D7Ed7F3DF7077f126F633C97", + "0x0F2C000DECca60752233Aa3bBC5D35ee0f2dacE7", + "0x1d5E65a087eBc3d03a294412E46CE5D6882969f4", + "0x1f254336E5c46639A851b9CfC165697150a6c327", + "0x2ec3F80BeDA63Ede96BA20375032CDD3aAfb3030", + "0x4AcBcA6BE2f8D2540bBF4CA77E45dA0A4a095Fa2", + "0x4F3D348a6D09837Ae7961B1E0cEe2cc118cec777", + "0x6D7f23A509E212Ba7773EC1b2505d1A134f54fbe", + "0x07a1f6fc89223c5ebD4e4ddaE89Ac97629856A0f", + "0x8d5F05270da470e015b67Ab5042BDbE2D2FEFB48", + "0x8d07D225a769b7Af3A923481E1FdF49180e6A265", + "0x8f60501dE5b9b01F9EAf1214dbE1924aA97F7fd0", + "0x9B8e8dD9151260c21CB6D7cc59067cd8DF306D58", + "0x17ea92D6FfbAA1c7F6B117c1E9D0c88ABdc8b84C", + "0x38C0039247A31F3939baE65e953612125cB88268" + ], + "snapshot": 20002770 + } +] diff --git a/src/strategies/staking-balance-of-v1/index.ts b/src/strategies/staking-balance-of-v1/index.ts new file mode 100644 index 000000000..fee1eff1f --- /dev/null +++ b/src/strategies/staking-balance-of-v1/index.ts @@ -0,0 +1,118 @@ +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; +import {BigNumber, BigNumberish} from "@ethersproject/bignumber"; + +export const author = 'propchain-development'; +export const version = '0.1.0'; + +const vestingABI = [ + 'function getUserInfo(uint256 _pid, address _account) view returns (uint256 amount, uint256 totalRedeemed, uint256 lastClaimTimestamp, uint256 depositTimestamp)', + 'function getPoolInfo(uint256 _pid) view returns (uint256 startTime, address rewardsToken, address penaltyWallet, uint256 apyPercent, uint256 totalStaked, bool active, uint256 claimTimeLimit, uint256 penaltyFee, uint256 penaltyTimeLimit, bool isVIPPool)' +]; + +interface Options { + staking_contract: string; + pid_1: string; + pid_2?: string; + pid_3?: string; + maxTimeInPool: BigNumberish; + decimals: number; +} + +interface PoolInfo { + startTime: BigNumberish; + rewardsToken: string + penaltyWallet: string, + apyPercent: BigNumberish, + totalStaked: BigNumberish, + active: boolean, + claimTimeLimit: BigNumberish, + penaltyFee: BigNumberish, + penaltyTimeLimit: BigNumberish + isVIPPool: boolean +} + +interface UserProperties { + amount: BigNumberish, + totalRedeemed: BigNumberish, + lastClaimTimestamp: BigNumberish, + depositTimestamp: BigNumberish +} + +export async function strategy( + space, + network, + provider, + addresses, + options: Options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multi = new Multicaller(network, provider, vestingABI, { blockTag }); + + multi.call(options.pid_1, options.staking_contract, 'getPoolInfo', [options.pid_1]); + if (options.pid_2) + multi.call( + options.pid_2, + options.staking_contract, + 'getPoolInfo', + [options.pid_2] + ); + if (options.pid_3) + multi.call( + options.pid_3, + options.staking_contract, + 'getPoolInfo', + [options.pid_3] + ); + + + const poolRecords : Record = await multi.execute(); + + addresses.forEach((address: string) => { + if (poolRecords[options.pid_1].active) { + multi.call( + address + '_' + options.pid_1, + options.staking_contract, + 'getUserInfo', + [options.pid_1, address] + ); + } + if (options.pid_2 && poolRecords[options.pid_2].active) + multi.call( + address + '_' + options.pid_2, + options.staking_contract, + 'getUserInfo', + [options.pid_2, address] + ); + if (options.pid_3 && poolRecords[options.pid_3].active) + multi.call( + address + '_' + options.pid_3, + options.staking_contract, + 'getUserInfo', + [options.pid_3, address] + ); + }); + const userProperties: Record = await multi.execute(); + + const filteredRecords: Record = {}; + Object.entries(userProperties).forEach(([identifier, user]) => { + const [addr, pid] = identifier.split('_'); + const poolInfo: PoolInfo = poolRecords[pid]; + + if (!filteredRecords[addr]) filteredRecords[addr] = 0; + + if(!poolInfo.active) return; + if (parseInt(pid) === 0) return; + + const weight = BigNumber.from(poolInfo.penaltyTimeLimit).toNumber() / BigNumber.from(options.maxTimeInPool).toNumber(); + const votingPower = parseFloat( + formatUnits(user.amount, options.decimals) + ) * weight; + + filteredRecords[addr] += votingPower + }); + + return filteredRecords; +} diff --git a/src/strategies/staking-balance-of-v1/schema.json b/src/strategies/staking-balance-of-v1/schema.json new file mode 100644 index 000000000..3e3cd7a8c --- /dev/null +++ b/src/strategies/staking-balance-of-v1/schema.json @@ -0,0 +1,59 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "decimals": { + "type": "number", + "title": "Decimals on all staking contracts", + "examples": ["e.g. 18"] + }, + "staking_contract": { + "type": "string", + "title": "Staking contract addresses", + "examples": ["e.g. 0x0a3476c1ea4ef65416016876c67e1a14e3575d73"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "pid_1": { + "type": "string", + "title": "Pool ID on vesting contract", + "examples": ["e.g. 1"], + "pattern": "^[0-9]+$", + "minLength": 1, + "maxLength": 5 + }, + "pid_2": { + "type": "string", + "title": "Pool ID on vesting contract", + "examples": ["e.g. 2"], + "pattern": "^[0-9]+$", + "minLength": 1, + "maxLength": 5 + }, + "pid_3": { + "type": "string", + "title": "Pool ID on vesting contract", + "examples": ["e.g. 3"], + "pattern": "^[0-9]+$", + "minLength": 1, + "maxLength": 5 + }, + "maxTimeInPool": { + "type": "string", + "title": "Maximum staking time per stake event. In seconds.", + "examples": ["e.g. 63072000"], + "pattern": "^[0-9]+$", + "minLength": 1, + "maxLength": 10 + } + }, + "required": ["staking_contract", "decimals", "maxTimeInPool", "pid_1"], + "additionalProperties": false + } + } +} From bdbd660cb07f003d74ad6573c60306d174659ab2 Mon Sep 17 00:00:00 2001 From: ChaituVR Date: Mon, 3 Jun 2024 15:56:30 +0530 Subject: [PATCH 664/815] Change Uniswap strategy subgraph to hosted subgraph --- src/strategies/uniswap/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategies/uniswap/index.ts b/src/strategies/uniswap/index.ts index 0e209d64f..52acbe540 100644 --- a/src/strategies/uniswap/index.ts +++ b/src/strategies/uniswap/index.ts @@ -2,7 +2,7 @@ import { getAddress } from '@ethersproject/address'; import { subgraphRequest } from '../../utils'; const UNISWAP_SUBGRAPH_URL = { - '1': 'https://gateway-arbitrum.network.thegraph.com/api/5e18263ac1ce55a37039f226cc665e8d/subgraphs/id/FEtpnfQ1aqF8um2YktEkfzFD11ZKrfurvBLPeQzv9JB1' + '1': 'https://api.thegraph.com/subgraphs/name/ianlapham/uniswap-v2-dev' }; export const author = 'snapshot-labs'; From 6bc50426f8c8d4717d7760980a6810d171b676a6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 4 Jun 2024 16:53:08 +0530 Subject: [PATCH 665/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.28 (#1491) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index eb4e45b19..d5285b4aa 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.27", + "@snapshot-labs/snapshot.js": "^0.11.28", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 87c0e82b7..017b0669e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.27": - version "0.11.27" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.27.tgz#f341f810e61d6dce72f00ddd1a57bde338b9a6b3" - integrity sha512-oCKY0thlLeSh2fYrVzPCzHb9HHyfRqLD55IGBrCgUUORJP78w3TvlscXwP0LgdNPuN3pNaDNwLGKUrx4GayB/w== +"@snapshot-labs/snapshot.js@^0.11.28": + version "0.11.28" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.28.tgz#e9e180b0bb6fb43801862cade524ab7cb269d830" + integrity sha512-kcs5gyO84i1ybneH2V0RxwHDb/9aHy0hmYKoUQcrt46EMH0ItY3SBRVqxW/Sdb4vteuo5fRlfcLApWJqA2IG9w== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From e0ed367552cb97f619fd572afd91d37372df9cf0 Mon Sep 17 00:00:00 2001 From: Revantark Date: Wed, 5 Jun 2024 17:24:47 +0530 Subject: [PATCH 666/815] [garden-stakes] Add garden-stakes strategy (#1492) * add garden-staker strategy * update readme * use multi-call to fetch nonces --- src/strategies/garden-stakes/README.md | 13 ++++ src/strategies/garden-stakes/examples.json | 26 ++++++++ src/strategies/garden-stakes/index.ts | 74 ++++++++++++++++++++++ src/strategies/garden-stakes/schema.json | 22 +++++++ src/strategies/index.ts | 2 + 5 files changed, 137 insertions(+) create mode 100644 src/strategies/garden-stakes/README.md create mode 100644 src/strategies/garden-stakes/examples.json create mode 100644 src/strategies/garden-stakes/index.ts create mode 100644 src/strategies/garden-stakes/schema.json diff --git a/src/strategies/garden-stakes/README.md b/src/strategies/garden-stakes/README.md new file mode 100644 index 000000000..700553d32 --- /dev/null +++ b/src/strategies/garden-stakes/README.md @@ -0,0 +1,13 @@ +# garden-stakes + +This strategy is used to get the votes of the users based on the amount of stakes they have in the garden staker contract. + +Getting the votes from the contract is not straightforward. First, we need to fetch the nonce of the user in the contract, which represents the number of stakes the user has. Then, we calculate an ID called stakeId, which is the hash of the user address and the nonce. Finally, we can get the user's votes by calling the `stakes` function with the stakeId. Users can have multiple stakes, so we need to iterate over all the stakes to get the total votes of the user. + +Here is an example of parameters: + +```json +{ + "gardenStakerAddress": "0xe2239938Ce088148b3Ab398b2b77Eedfcd9d1AfC" +} +``` diff --git a/src/strategies/garden-stakes/examples.json b/src/strategies/garden-stakes/examples.json new file mode 100644 index 000000000..a1688de92 --- /dev/null +++ b/src/strategies/garden-stakes/examples.json @@ -0,0 +1,26 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "garden-stakes", + "params": { + "gardenStakerAddress": "0xe2239938Ce088148b3Ab398b2b77Eedfcd9d1AfC" + } + }, + "network": "42161", + "addresses": [ + "0x9d1AD258e43d6547Bd8176469Fd4E910dBeB8246", + "0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11", + "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", + "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", + "0x946232eA875bf2C3FD52DefA76B442f3AC2dBfc5", + "0xc1a17F2fd7DB9adf67De8a8F331d682923090Feb", + "0x2E2BE8E35537e66c5Cc34A99Aab01ebb374C8FDF", + "0x939C88325Be283b9D7a4365988624C28e82973b7", + "0x29C3e6eDc2385c4F85248b8B7E43CcE8dCD6bd78", + "0x011a4E314429E97D7056a71c6fea32392b474A42", + "0xb7d49ADB031d6DBDF3E8e28F21C6Dd3b6f231cD5" + ], + "snapshot": 218605485 + } +] diff --git a/src/strategies/garden-stakes/index.ts b/src/strategies/garden-stakes/index.ts new file mode 100644 index 000000000..ce4e4eac0 --- /dev/null +++ b/src/strategies/garden-stakes/index.ts @@ -0,0 +1,74 @@ +import { keccak256 } from '@ethersproject/keccak256'; +import { pack } from '@ethersproject/solidity'; +import { Multicaller } from '../../utils'; +import { BigNumber } from '@ethersproject/bignumber'; + +export const author = 'gardenfi'; +export const version = '0.0.1'; + +const abi = [ + 'function delegateNonce(address) external view returns (uint256)', + 'function stakes(bytes32) external view returns (address owner, uint256 stake, uint256 units, uint256 votes, address filler, uint256 expiry)' +]; + +type Vote = { + votes: { _hex: string; _isBigNumber: boolean }; +}; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multi = new Multicaller(network, provider, abi, { blockTag }); + + for (const address of addresses) { + multi.call(address, options.gardenStakerAddress, 'delegateNonce', [ + address + ]); + } + const nonces = await multi.execute(); + + for (const address of addresses) { + for (let i = 0; i < nonces[address]; i++) { + const stakeId = keccak256(pack(['address', 'uint256'], [address, i])); + // Append i to address to avoid collisions from multiple stakes + multi.call(address + i, options.gardenStakerAddress, 'stakes', [stakeId]); + } + } + + const stakes: Record = await multi.execute(); + + const usersToVotes: Record = {}; + + for (const userAddrWithStakeNumber of Object.keys(stakes)) { + // remove the appended number from the address + const address = userAddrWithStakeNumber.substring(0, 42); + usersToVotes[address] = calculateVotes( + stakes[userAddrWithStakeNumber], + usersToVotes[address] + ); + } + + for (const address of addresses) { + if (!usersToVotes[address]) { + usersToVotes[address] = 0; + } + } + + return usersToVotes; +} + +/** + * Calculate the total votes for a user given their stake and existing votes + */ +function calculateVotes(stake: Vote, existingVotes: number | undefined) { + return ( + (existingVotes ?? 0) + (BigNumber.from(stake.votes._hex).toNumber() ?? 0) + ); +} diff --git a/src/strategies/garden-stakes/schema.json b/src/strategies/garden-stakes/schema.json new file mode 100644 index 000000000..a991b6431 --- /dev/null +++ b/src/strategies/garden-stakes/schema.json @@ -0,0 +1,22 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "gardenStakerAddress": { + "type": "string", + "title": "Garden's staking address", + "examples": ["e.g. 0xe2239938Ce088148b3Ab398b2b77Eedfcd9d1AfC"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } + }, + "required": ["gardenStakerAddress"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index f77c9cfd6..6d2f8e335 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -429,6 +429,7 @@ import * as a51VaultBalance from './a51-vault-balance'; import * as quickswapv3 from './quickswap-v3'; import * as balanceOfWithBazaarBatchAuctionLinearVestingPower from './balance-of-with-bazaar-batch-auction-linear-vesting-power'; import * as stakingBalanceOfV1 from './staking-balance-of-v1'; +import * as gardenStakes from './garden-stakes'; const strategies = { 'giveth-balances-supply-weighted': givethBalancesSupplyWeighted, @@ -869,6 +870,7 @@ const strategies = { balanceOfWithBazaarBatchAuctionLinearVestingPower, 'staking-balance-of-v1': stakingBalanceOfV1, 'staking-balance-of-v2': stakingBalanceOfV2, + 'garden-stakes': gardenStakes }; Object.keys(strategies).forEach(function (strategyName) { From e7c91dc9e7837952d9327d322c257429afa71e26 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 8 Jun 2024 19:27:47 +0530 Subject: [PATCH 667/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.30 (#1493) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index d5285b4aa..57e8bef16 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.28", + "@snapshot-labs/snapshot.js": "^0.11.30", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 017b0669e..44b689486 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.28": - version "0.11.28" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.28.tgz#e9e180b0bb6fb43801862cade524ab7cb269d830" - integrity sha512-kcs5gyO84i1ybneH2V0RxwHDb/9aHy0hmYKoUQcrt46EMH0ItY3SBRVqxW/Sdb4vteuo5fRlfcLApWJqA2IG9w== +"@snapshot-labs/snapshot.js@^0.11.30": + version "0.11.30" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.30.tgz#1e9c7e2f3cdee33892ec0ab9e2bd2be243774803" + integrity sha512-BsKNOVKQ2VVbiTOTTsxXtF+1+VCKeayRBBXcVh8Na1RErAM3/XWaQvrS34xBimxaAHAQEZl7/4O/gaJnWCQk+w== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 1da292df3b588063ce116daab6cac79765c47e23 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 9 Jun 2024 17:07:35 +0530 Subject: [PATCH 668/815] Automated lint (#1494) Co-authored-by: ChaituVR --- src/strategies/staking-balance-of-v1/index.ts | 66 +++++++++---------- src/strategies/staking-balance-of-v2/index.ts | 60 ++++++++--------- 2 files changed, 59 insertions(+), 67 deletions(-) diff --git a/src/strategies/staking-balance-of-v1/index.ts b/src/strategies/staking-balance-of-v1/index.ts index fee1eff1f..47d29c955 100644 --- a/src/strategies/staking-balance-of-v1/index.ts +++ b/src/strategies/staking-balance-of-v1/index.ts @@ -1,6 +1,6 @@ import { formatUnits } from '@ethersproject/units'; import { Multicaller } from '../../utils'; -import {BigNumber, BigNumberish} from "@ethersproject/bignumber"; +import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; export const author = 'propchain-development'; export const version = '0.1.0'; @@ -21,22 +21,22 @@ interface Options { interface PoolInfo { startTime: BigNumberish; - rewardsToken: string - penaltyWallet: string, - apyPercent: BigNumberish, - totalStaked: BigNumberish, - active: boolean, - claimTimeLimit: BigNumberish, - penaltyFee: BigNumberish, - penaltyTimeLimit: BigNumberish - isVIPPool: boolean + rewardsToken: string; + penaltyWallet: string; + apyPercent: BigNumberish; + totalStaked: BigNumberish; + active: boolean; + claimTimeLimit: BigNumberish; + penaltyFee: BigNumberish; + penaltyTimeLimit: BigNumberish; + isVIPPool: boolean; } interface UserProperties { - amount: BigNumberish, - totalRedeemed: BigNumberish, - lastClaimTimestamp: BigNumberish, - depositTimestamp: BigNumberish + amount: BigNumberish; + totalRedeemed: BigNumberish; + lastClaimTimestamp: BigNumberish; + depositTimestamp: BigNumberish; } export async function strategy( @@ -51,24 +51,19 @@ export async function strategy( const multi = new Multicaller(network, provider, vestingABI, { blockTag }); - multi.call(options.pid_1, options.staking_contract, 'getPoolInfo', [options.pid_1]); + multi.call(options.pid_1, options.staking_contract, 'getPoolInfo', [ + options.pid_1 + ]); if (options.pid_2) - multi.call( - options.pid_2, - options.staking_contract, - 'getPoolInfo', - [options.pid_2] - ); + multi.call(options.pid_2, options.staking_contract, 'getPoolInfo', [ + options.pid_2 + ]); if (options.pid_3) - multi.call( - options.pid_3, - options.staking_contract, - 'getPoolInfo', - [options.pid_3] - ); + multi.call(options.pid_3, options.staking_contract, 'getPoolInfo', [ + options.pid_3 + ]); - - const poolRecords : Record = await multi.execute(); + const poolRecords: Record = await multi.execute(); addresses.forEach((address: string) => { if (poolRecords[options.pid_1].active) { @@ -103,15 +98,16 @@ export async function strategy( if (!filteredRecords[addr]) filteredRecords[addr] = 0; - if(!poolInfo.active) return; + if (!poolInfo.active) return; if (parseInt(pid) === 0) return; - const weight = BigNumber.from(poolInfo.penaltyTimeLimit).toNumber() / BigNumber.from(options.maxTimeInPool).toNumber(); - const votingPower = parseFloat( - formatUnits(user.amount, options.decimals) - ) * weight; + const weight = + BigNumber.from(poolInfo.penaltyTimeLimit).toNumber() / + BigNumber.from(options.maxTimeInPool).toNumber(); + const votingPower = + parseFloat(formatUnits(user.amount, options.decimals)) * weight; - filteredRecords[addr] += votingPower + filteredRecords[addr] += votingPower; }); return filteredRecords; diff --git a/src/strategies/staking-balance-of-v2/index.ts b/src/strategies/staking-balance-of-v2/index.ts index 97b4a298e..4bb0b225f 100644 --- a/src/strategies/staking-balance-of-v2/index.ts +++ b/src/strategies/staking-balance-of-v2/index.ts @@ -1,6 +1,6 @@ import { formatUnits } from '@ethersproject/units'; import { Multicaller } from '../../utils'; -import {BigNumber, BigNumberish} from "@ethersproject/bignumber"; +import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; export const author = 'propchain-development'; export const version = '0.1.0'; @@ -21,16 +21,16 @@ interface Options { interface PoolInfo { startTime: BigNumberish; - rewardsToken: string - penaltyWallet: string, - apyPercent: BigNumberish, - totalStaked: BigNumberish, - active: boolean, - claimTimeLimit: BigNumberish, - minStakeAmount: BigNumberish, - penaltyFee: BigNumberish, - penaltyTimeLimit: BigNumberish - isVIPPool: boolean + rewardsToken: string; + penaltyWallet: string; + apyPercent: BigNumberish; + totalStaked: BigNumberish; + active: boolean; + claimTimeLimit: BigNumberish; + minStakeAmount: BigNumberish; + penaltyFee: BigNumberish; + penaltyTimeLimit: BigNumberish; + isVIPPool: boolean; } export async function strategy( @@ -45,24 +45,19 @@ export async function strategy( const multi = new Multicaller(network, provider, vestingABI, { blockTag }); - multi.call(options.pid_1, options.staking_contract, 'getPoolInfo', [options.pid_1]); + multi.call(options.pid_1, options.staking_contract, 'getPoolInfo', [ + options.pid_1 + ]); if (options.pid_2) - multi.call( - options.pid_2, - options.staking_contract, - 'getPoolInfo', - [options.pid_2] - ); + multi.call(options.pid_2, options.staking_contract, 'getPoolInfo', [ + options.pid_2 + ]); if (options.pid_3) - multi.call( - options.pid_3, - options.staking_contract, - 'getPoolInfo', - [options.pid_3] - ); + multi.call(options.pid_3, options.staking_contract, 'getPoolInfo', [ + options.pid_3 + ]); - - const poolRecords : Record = await multi.execute(); + const poolRecords: Record = await multi.execute(); addresses.forEach((address: string) => { if (poolRecords[options.pid_1].active) { @@ -97,15 +92,16 @@ export async function strategy( if (!filteredRecords[addr]) filteredRecords[addr] = 0; - if(!poolInfo.active) return; + if (!poolInfo.active) return; if (parseInt(pid) === 0) return; - const weight = BigNumber.from(poolInfo.penaltyTimeLimit).toNumber() / BigNumber.from(options.maxTimeInPool).toNumber(); - const votingPower = parseFloat( - formatUnits(userAmount, options.decimals) - ) * weight; + const weight = + BigNumber.from(poolInfo.penaltyTimeLimit).toNumber() / + BigNumber.from(options.maxTimeInPool).toNumber(); + const votingPower = + parseFloat(formatUnits(userAmount, options.decimals)) * weight; - filteredRecords[addr] += votingPower + filteredRecords[addr] += votingPower; }); return filteredRecords; From 014489bb158e1e90536c57ba10acb889ed5bc88d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 11 Jun 2024 00:01:13 +0530 Subject: [PATCH 669/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.31 (#1495) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 57e8bef16..ff0b8d39f 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.30", + "@snapshot-labs/snapshot.js": "^0.11.31", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 44b689486..abba81e88 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.30": - version "0.11.30" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.30.tgz#1e9c7e2f3cdee33892ec0ab9e2bd2be243774803" - integrity sha512-BsKNOVKQ2VVbiTOTTsxXtF+1+VCKeayRBBXcVh8Na1RErAM3/XWaQvrS34xBimxaAHAQEZl7/4O/gaJnWCQk+w== +"@snapshot-labs/snapshot.js@^0.11.31": + version "0.11.31" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.31.tgz#7e91069e1c1ed116c77e7aa642c69e87d9176f31" + integrity sha512-AovoHVggA74s/i6h/NVmvry1IeQs3+LWvz9Bj3wspiSgFubcmv20aTaQjUdJ7/Pt4ed2pAoRt7vZlwjhmPNp8g== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 088dd14e5a981e78b31ae8da37b216c9e24c0131 Mon Sep 17 00:00:00 2001 From: Andy Espagnolo Date: Tue, 11 Jun 2024 13:36:47 -0300 Subject: [PATCH 670/815] chore: update decentraland urls (#1498) * chore: update decentraland urls * fix: linting * fix: update network from example --- src/strategies/decentraland-estate-size/index.ts | 3 +-- src/strategies/decentraland-rental-lessors/README.md | 4 ++-- .../decentraland-rental-lessors/examples.json | 6 +++--- src/strategies/decentraland-wearable-rarity/index.ts | 11 +++++------ 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/strategies/decentraland-estate-size/index.ts b/src/strategies/decentraland-estate-size/index.ts index 57b6956ac..6d4e402db 100644 --- a/src/strategies/decentraland-estate-size/index.ts +++ b/src/strategies/decentraland-estate-size/index.ts @@ -6,8 +6,7 @@ export const version = '0.1.0'; const SUBGRAPH_QUERY_ADDRESSES_LIMIT = 2000; const DECENTRALAND_MARKETPLACE_SUBGRAPH_URL = { - '1': 'https://api.thegraph.com/subgraphs/name/decentraland/marketplace', - '3': 'https://api.thegraph.com/subgraphs/name/decentraland/marketplaceropsten' + '1': 'https://subgraph.decentraland.org/marketplace' }; function chunk(_array: string[], pageSize: number): string[][] { diff --git a/src/strategies/decentraland-rental-lessors/README.md b/src/strategies/decentraland-rental-lessors/README.md index 678ec1e7f..39472221d 100644 --- a/src/strategies/decentraland-rental-lessors/README.md +++ b/src/strategies/decentraland-rental-lessors/README.md @@ -11,8 +11,8 @@ The following example params are for obtaining the VP users have after sending t ```json { "subgraphs": { - "rentals": "https://api.thegraph.com/subgraphs/name/decentraland/rentals-ethereum-goerli", - "marketplace": "https://api.thegraph.com/subgraphs/name/decentraland/marketplace-goerli" + "rentals": "https://api.studio.thegraph.com/query/49472/rentals-ethereum-sepolia/version/latest", + "marketplace": "https://api.studio.thegraph.com/query/49472/marketplace-sepolia/version/latest" }, "addresses": { "estate": "0xc9a46712e6913c24d15b46ff12221a79c4e251dc", diff --git a/src/strategies/decentraland-rental-lessors/examples.json b/src/strategies/decentraland-rental-lessors/examples.json index e2f8512e8..9d5f7e9e8 100644 --- a/src/strategies/decentraland-rental-lessors/examples.json +++ b/src/strategies/decentraland-rental-lessors/examples.json @@ -5,8 +5,8 @@ "name": "decentraland-rental-lessors", "params": { "subgraphs": { - "rentals": "https://api.thegraph.com/subgraphs/name/decentraland/rentals-ethereum-goerli", - "marketplace": "https://api.thegraph.com/subgraphs/name/decentraland/marketplace-goerli" + "rentals": "https://api.studio.thegraph.com/query/49472/rentals-ethereum-sepolia/version/latest", + "marketplace": "https://api.studio.thegraph.com/query/49472/marketplace-sepolia/version/latest" }, "addresses": { "estate": "0xc9a46712e6913c24d15b46ff12221a79c4e251dc", @@ -18,7 +18,7 @@ } } }, - "network": "5", + "network": "11155111", "addresses": [ "0x747c6f502272129bf1ba872a1903045b837ee86c", "0xbad79d832671d91b4bba85f600932faec0e5fd7c", diff --git a/src/strategies/decentraland-wearable-rarity/index.ts b/src/strategies/decentraland-wearable-rarity/index.ts index 4baaf43d5..efa50e365 100644 --- a/src/strategies/decentraland-wearable-rarity/index.ts +++ b/src/strategies/decentraland-wearable-rarity/index.ts @@ -6,12 +6,11 @@ export const version = '0.1.0'; const SUBGRAPH_QUERY_ADDRESSES_LIMIT = 2000; const DECENTRALAND_COLLECTIONS_SUBGRAPH_URL = { - '1': 'https://api.thegraph.com/subgraphs/name/decentraland/collections-ethereum-mainnet', - '3': 'https://api.thegraph.com/subgraphs/name/decentraland/collections-ethereum-ropsten', - '137': - 'https://api.thegraph.com/subgraphs/name/decentraland/collections-matic-mainnet', - '80001': - 'https://api.thegraph.com/subgraphs/name/decentraland/collections-matic-mumbai' + '1': 'https://subgraph.decentraland.org/collections-ethereum-mainnet', + '11155111': + 'https://api.studio.thegraph.com/query/49472/marketplace-sepolia/version/latest', + '137': 'https://subgraph.decentraland.org/collections-matic-mainnet', + '80002': 'https://subgraph.decentraland.org/collections-matic-amoy' }; function chunk(_array: string[], pageSize: number): string[][] { From 5d70d3f29fed2e23588579e0220c9d8c815a3daa Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Thu, 13 Jun 2024 00:40:58 +0530 Subject: [PATCH 671/815] fix: Change subgraph URLs to upgraded ones (#1500) * fix: Change subgraph URLs to upgraded ones * lint --- src/strategies/a51-farming/index.ts | 2 +- src/strategies/a51-vault-balance/index.ts | 2 +- src/strategies/aelin-council/index.ts | 3 +- src/strategies/balance-of-subgraph/README.md | 2 +- .../balance-of-subgraph/examples.json | 2 +- src/strategies/balance-of-subgraph/index.ts | 4 +- .../index.ts | 2 +- src/strategies/balancer-poolid/index.ts | 2 +- src/strategies/balancer/index.ts | 2 +- .../battlefly-vgfly-and-staked-gfly/README.md | 2 +- .../examples.json | 2 +- src/strategies/cake/index.ts | 2 +- src/strategies/ctsi-staking-pool/index.ts | 3 +- src/strategies/darkforest-score/examples.json | 2 +- src/strategies/dfyn-staked-in-farms/index.ts | 2 +- src/strategies/dgenesis/index.ts | 3 +- src/strategies/dogs-unchained/index.ts | 2 +- src/strategies/dps-nft-strategy/index.ts | 2 +- src/strategies/eco-voting-power/index.ts | 4 +- src/strategies/ens-10k-club/index.ts | 5 +-- src/strategies/ens-all-club-digits/index.ts | 2 +- src/strategies/ens-domains-owned/index.ts | 2 +- .../erc20-balance-of-top-holders/README.md | 2 +- .../examples.json | 2 +- src/strategies/flashstake/index.ts | 2 +- .../giveth-balancer-balance/index.ts | 4 +- .../index.ts | 4 +- .../giveth-gnosis-balance-v2/index.ts | 4 +- src/strategies/h2o/index.ts | 2 +- .../index.ts | 10 ++--- src/strategies/honeyswap/index.ts | 3 +- src/strategies/hopr-bridged-balance/index.ts | 4 +- .../hopr-staking-by-season/index.ts | 2 +- src/strategies/hopr-staking-s2/index.ts | 2 +- src/strategies/hopr-uni-lp-farm/index.ts | 2 +- .../README.md | 2 +- .../infinityprotocol-liquidity-pools/index.ts | 2 +- src/strategies/jpegd-locked-jpeg-of/index.ts | 2 +- .../liquidity-token-provide/README.md | 2 +- .../liquidity-token-provide/index.ts | 4 +- .../lrc-l2-nft-balance-of/README.md | 2 +- .../lrc-l2-nft-balance-of/examples.json | 2 +- src/strategies/lrc-nft-search-mult/README.md | 2 +- .../lrc-nft-search-mult/examples.json | 2 +- src/strategies/masterchef/index.ts | 4 +- src/strategies/meebitsdao-delegation/index.ts | 2 +- .../index.ts | 2 +- src/strategies/nexon-army-nft/index.ts | 3 +- src/strategies/otterspace-badges/index.ts | 9 ++-- src/strategies/poap-with-weight-v2/index.ts | 5 ++- src/strategies/poap-with-weight/index.ts | 5 ++- src/strategies/poap/index.ts | 5 ++- src/strategies/pob-hash/index.ts | 2 +- src/strategies/push-voting-power/index.ts | 2 +- src/strategies/ren-nodes/index.ts | 2 +- src/strategies/rep3-badges/index.ts | 3 +- .../sablier-v1-deposit/examples.json | 8 ++-- src/strategies/sablier-v1-deposit/index.ts | 17 +++----- src/strategies/sablier-v2/configuration.ts | 43 ++++++++++++------- .../skale-delegation-weighted/index.ts | 2 +- src/strategies/spaceid/index.ts | 2 +- src/strategies/spacey2025/index.ts | 2 +- src/strategies/staked-balancer/index.ts | 2 +- .../starcatchers-top-window/index.ts | 2 +- .../synthetix-non-quadratic_1/index.ts | 2 +- src/strategies/synthetix-quadratic_1/index.ts | 2 +- src/strategies/thales/index.ts | 4 +- src/strategies/the-graph/graphUtils.ts | 2 +- src/strategies/the-graph/tokenLockWallets.ts | 2 +- src/strategies/tranche-staking-lp/index.ts | 2 +- src/strategies/uniswap-v3-staking/index.ts | 2 +- src/strategies/uniswap-v3/index.ts | 2 +- src/strategies/uniswap/index.ts | 2 +- src/strategies/wagdie-subgraph/README.md | 2 +- src/strategies/wagdie-subgraph/examples.json | 2 +- src/strategies/wagdie-subgraph/index.ts | 2 +- src/strategies/xdai-easy-staking/index.ts | 2 +- 77 files changed, 139 insertions(+), 128 deletions(-) diff --git a/src/strategies/a51-farming/index.ts b/src/strategies/a51-farming/index.ts index f037ea9d5..9bf4d0c40 100644 --- a/src/strategies/a51-farming/index.ts +++ b/src/strategies/a51-farming/index.ts @@ -6,7 +6,7 @@ export const version = '0.1.0'; const A51_STAKING_SUBGRAPH_URL = { '137': - 'https://api.thegraph.com/subgraphs/name/hamzabhatti125/farming-polygon' + 'https://subgrapher.snapshot.org/subgraph/arbitrum/mr29ZjZSuNs6iNhD8YmNnEg3JB17muNbGp1PCYxusr7' }; const vaultABI = { diff --git a/src/strategies/a51-vault-balance/index.ts b/src/strategies/a51-vault-balance/index.ts index cbbb20d74..2a21b2dff 100644 --- a/src/strategies/a51-vault-balance/index.ts +++ b/src/strategies/a51-vault-balance/index.ts @@ -6,7 +6,7 @@ export const version = '0.1.0'; const A51_VAULT_SUBGRAPH_URL = { '137': - 'https://api.thegraph.com/subgraphs/name/hamzabhatti125/unipilot-quickswap-stats' + 'https://subgrapher.snapshot.org/subgraph/arbitrum/GXc2d1wMCbyKq2F2qRo8zcCad6tXsmXubEA5F8jGKBTG' }; const vaultABI = { diff --git a/src/strategies/aelin-council/index.ts b/src/strategies/aelin-council/index.ts index 5778b8015..9da2de011 100644 --- a/src/strategies/aelin-council/index.ts +++ b/src/strategies/aelin-council/index.ts @@ -9,7 +9,8 @@ export const version = '1.0.0'; const GRAPH_API_URL = { uniswap: { - mainnet: 'https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2' + mainnet: + 'https://subgrapher.snapshot.org/subgraph/arbitrum/EYCKATKGBKLWvSfwvBjzfCBmGwYNdVkduYXVivCsLRFu' }, aelin: { mainnet: 'https://api.thegraph.com/subgraphs/name/0xcdb/aelin-governance', diff --git a/src/strategies/balance-of-subgraph/README.md b/src/strategies/balance-of-subgraph/README.md index 86275dbce..e65b07f10 100644 --- a/src/strategies/balance-of-subgraph/README.md +++ b/src/strategies/balance-of-subgraph/README.md @@ -17,7 +17,7 @@ The space config will look like this: ```JSON { // subgraphURL for the request - "subGraphURL": "https://api.thegraph.com/subgraphs/name/dinngodev/furucombo-tokenomics-mainnet", + "subGraphURL": "https://subgrapher.snapshot.org/subgraph/arbitrum/4RGbQCKV1NNoEJcK3shwgTvn65zsHaFdqG9RPvv28qJU", // scoreMultiplier can be used to increase users' scores by a certain magnitude "scoreMultiplier": 1, } diff --git a/src/strategies/balance-of-subgraph/examples.json b/src/strategies/balance-of-subgraph/examples.json index c97beb9c8..5e2f2d49e 100644 --- a/src/strategies/balance-of-subgraph/examples.json +++ b/src/strategies/balance-of-subgraph/examples.json @@ -4,7 +4,7 @@ "strategy": { "name": "balance-of-subgraph", "params": { - "subGraphURL": "https://api.thegraph.com/subgraphs/name/dinngodev/furucombo-tokenomics-mainnet" + "subGraphURL": "https://subgrapher.snapshot.org/subgraph/arbitrum/4RGbQCKV1NNoEJcK3shwgTvn65zsHaFdqG9RPvv28qJU" } }, "network": "1", diff --git a/src/strategies/balance-of-subgraph/index.ts b/src/strategies/balance-of-subgraph/index.ts index 0761ec0d3..9f701e3aa 100644 --- a/src/strategies/balance-of-subgraph/index.ts +++ b/src/strategies/balance-of-subgraph/index.ts @@ -2,9 +2,9 @@ import { getAddress } from '@ethersproject/address'; import { subgraphRequest } from '../../utils'; const SUBGRAPH_URL = { - '1': 'https://api.thegraph.com/subgraphs/name/dinngodev/furucombo-tokenomics-mainnet', + '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/4RGbQCKV1NNoEJcK3shwgTvn65zsHaFdqG9RPvv28qJU', '137': - 'https://api.thegraph.com/subgraphs/name/dinngodev/furucombo-tokenomics-polygon' + 'https://subgrapher.snapshot.org/subgraph/arbitrum/HHNWub5axWTGR1no6yrqVurT8Ak9skEFAwnw3YcqkD8G' }; export const author = 'weizard'; diff --git a/src/strategies/balance-of-with-bazaar-batch-auction-linear-vesting-power/index.ts b/src/strategies/balance-of-with-bazaar-batch-auction-linear-vesting-power/index.ts index 95caedfa1..9687230c1 100644 --- a/src/strategies/balance-of-with-bazaar-batch-auction-linear-vesting-power/index.ts +++ b/src/strategies/balance-of-with-bazaar-batch-auction-linear-vesting-power/index.ts @@ -14,7 +14,7 @@ const abi = [ ]; const GRAPH_BLOCK_API_URL = - 'https://api.thegraph.com/subgraphs/name/blocklytics/ethereum-blocks'; + 'https://subgrapher.snapshot.org/subgraph/arbitrum/9A6bkprqEG2XsZUYJ5B2XXp6ymz9fNcn4tVPxMWDztYC'; async function getNearestBlockNumberBeforeTimestamp(timestamp: number) { const rawData = await subgraphRequest(GRAPH_BLOCK_API_URL, { diff --git a/src/strategies/balancer-poolid/index.ts b/src/strategies/balancer-poolid/index.ts index 58a6ee933..01e5746ce 100644 --- a/src/strategies/balancer-poolid/index.ts +++ b/src/strategies/balancer-poolid/index.ts @@ -8,7 +8,7 @@ export const version = '0.1.0'; const PAGE_SIZE = 1000; const BALANCER_SUBGRAPH_URL_ROOT = - 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer'; + 'https://subgrapher.snapshot.org/subgraph/arbitrum/93yusydMYauh7cfe9jEfoGABmwnX4GffHd7in8KJi1XB'; const NETWORK_KEY = { '1': '', diff --git a/src/strategies/balancer/index.ts b/src/strategies/balancer/index.ts index 15635acf8..1c45ae9fd 100644 --- a/src/strategies/balancer/index.ts +++ b/src/strategies/balancer/index.ts @@ -5,7 +5,7 @@ export const author = 'bonustrack'; export const version = '0.2.0'; const BALANCER_SUBGRAPH_URL_ROOT = - 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer'; + 'https://subgrapher.snapshot.org/subgraph/arbitrum/93yusydMYauh7cfe9jEfoGABmwnX4GffHd7in8KJi1XB'; const NETWORK_KEY = { '1': '', diff --git a/src/strategies/battlefly-vgfly-and-staked-gfly/README.md b/src/strategies/battlefly-vgfly-and-staked-gfly/README.md index 9e6ac679e..ec912effe 100644 --- a/src/strategies/battlefly-vgfly-and-staked-gfly/README.md +++ b/src/strategies/battlefly-vgfly-and-staked-gfly/README.md @@ -12,7 +12,7 @@ Additionally, the gFLY, magic vgFLY and LP token addresses are required for some ```json { - "graphUrl": "https://api.thegraph.com/subgraphs/name/battlefly-game/gfly-main", + "graphUrl": "https://subgrapher.snapshot.org/subgraph/arbitrum/EaWD4rchSZT7qMtRd4z5J89xMMHLdhPRhskYKQvPznMS", "gFLYAddress": "0x872bAD41CFc8BA731f811fEa8B2d0b9fd6369585", "magicAddress": "0x539bdE0d7Dbd336b79148AA742883198BBF60342", "lpAddress": "0x088F2Bd3667F385427d9289C28725D43d4b74AB4", diff --git a/src/strategies/battlefly-vgfly-and-staked-gfly/examples.json b/src/strategies/battlefly-vgfly-and-staked-gfly/examples.json index 40c0cf4c8..69b781c08 100644 --- a/src/strategies/battlefly-vgfly-and-staked-gfly/examples.json +++ b/src/strategies/battlefly-vgfly-and-staked-gfly/examples.json @@ -4,7 +4,7 @@ "strategy": { "name": "battlefly-vgfly-and-staked-gfly", "params": { - "graphUrl": "https://api.thegraph.com/subgraphs/name/battlefly-game/gfly-main", + "graphUrl": "https://subgrapher.snapshot.org/subgraph/arbitrum/EaWD4rchSZT7qMtRd4z5J89xMMHLdhPRhskYKQvPznMS", "gFLYAddress": "0x872bAD41CFc8BA731f811fEa8B2d0b9fd6369585", "magicAddress": "0x539bdE0d7Dbd336b79148AA742883198BBF60342", "lpAddress": "0x088F2Bd3667F385427d9289C28725D43d4b74AB4", diff --git a/src/strategies/cake/index.ts b/src/strategies/cake/index.ts index 68d51ff29..303434159 100644 --- a/src/strategies/cake/index.ts +++ b/src/strategies/cake/index.ts @@ -48,7 +48,7 @@ const vaultAbi = [ ]; const smartChefUrl = - 'https://api.thegraph.com/subgraphs/name/pancakeswap/smartchef'; + 'https://subgrapher.snapshot.org/subgraph/arbitrum/Gr629imGYJckFywitY1bndE4LhVaLF7pFJPEtHMw6EBr'; async function getPools(provider, snapshot: any) { let blockNumber = snapshot; diff --git a/src/strategies/ctsi-staking-pool/index.ts b/src/strategies/ctsi-staking-pool/index.ts index 4e541dac7..bff8476a3 100644 --- a/src/strategies/ctsi-staking-pool/index.ts +++ b/src/strategies/ctsi-staking-pool/index.ts @@ -6,7 +6,8 @@ import { subgraphRequest } from '../../utils'; export const author = 'cartesi'; export const version = '0.1.0'; -const SUBGRAPH_URL_ROOT = 'https://api.thegraph.com/subgraphs/name/cartesi/pos'; +const SUBGRAPH_URL_ROOT = + 'https://subgrapher.snapshot.org/subgraph/arbitrum/8BCdnuKC96Gzv2XyEfy4MQyLEjL5E47bmBtFDnBtM3KD'; const NETWORK_KEY = { '1': '', diff --git a/src/strategies/darkforest-score/examples.json b/src/strategies/darkforest-score/examples.json index 414738cad..8aeb21522 100644 --- a/src/strategies/darkforest-score/examples.json +++ b/src/strategies/darkforest-score/examples.json @@ -4,7 +4,7 @@ "strategy": { "name": "darkforest-score", "params": { - "graph_url": "https://api.thegraph.com/subgraphs/name/darkforest-eth/dark-forest-v06-round-4", + "graph_url": "https://subgrapher.snapshot.org/subgraph/arbitrum/FKhgrqfpKxN5rhYeHpC4wM9BFmKz8rsmStr9LMSbZznA", "symbol": "log2(score)" } }, diff --git a/src/strategies/dfyn-staked-in-farms/index.ts b/src/strategies/dfyn-staked-in-farms/index.ts index 91c63ab5e..27608ca6d 100644 --- a/src/strategies/dfyn-staked-in-farms/index.ts +++ b/src/strategies/dfyn-staked-in-farms/index.ts @@ -6,7 +6,7 @@ export const author = 'vatsalgupta13'; export const version = '0.1.0'; const DFYN_SUBGRAPH_URL = - 'https://api.thegraph.com/subgraphs/name/ss-sonic/dfyn-v5'; + 'https://subgrapher.snapshot.org/subgraph/arbitrum/FuxKHMLaziLFcQi5c4y3p1JY1ZGLA81rFqBfZfbQZDpo'; const getAllLP = async (skip, stakedLP, snapshot) => { const params = { diff --git a/src/strategies/dgenesis/index.ts b/src/strategies/dgenesis/index.ts index bc48ea8c0..240981e02 100644 --- a/src/strategies/dgenesis/index.ts +++ b/src/strategies/dgenesis/index.ts @@ -4,7 +4,8 @@ import { formatUnits } from '@ethersproject/units'; import { subgraphRequest } from '../../utils'; const DGENESIS_SUBGRAPH_URL = { - '42161': 'https://api.thegraph.com/subgraphs/name/callikai/dgenesisarbitrum' + '42161': + 'https://subgrapher.snapshot.org/subgraph/arbitrum/5muLDbVvE371id5FfiS4Zn3DjuZvA2n5M1cvskN3ARGV' }; export const author = 'callikai'; diff --git a/src/strategies/dogs-unchained/index.ts b/src/strategies/dogs-unchained/index.ts index e26b7cb92..f5fb1441f 100644 --- a/src/strategies/dogs-unchained/index.ts +++ b/src/strategies/dogs-unchained/index.ts @@ -11,7 +11,7 @@ const abi721or20 = [ ]; const SUBGRAPH_URL = - 'https://api.thegraph.com/subgraphs/name/dogsunchained/dogs-unchained'; + 'https://subgrapher.snapshot.org/subgraph/arbitrum/BhWDi1iaaH34qM1XsfiZRMRTd6DYvFushCN237LNVNTk'; export async function strategy( space, diff --git a/src/strategies/dps-nft-strategy/index.ts b/src/strategies/dps-nft-strategy/index.ts index 6eda761e4..11f70b16e 100644 --- a/src/strategies/dps-nft-strategy/index.ts +++ b/src/strategies/dps-nft-strategy/index.ts @@ -6,7 +6,7 @@ export const version = '0.3.1'; const DPS_SUBGRAPH_URL_MOONBEAM = { '1284': - 'https://api.thegraph.com/subgraphs/name/andreibadea20/dps-holders-moonbeam' + 'https://subgrapher.snapshot.org/subgraph/arbitrum/G2ysJgNidntuiBVzHtbdcyxeRX1Q6EB5vxVAG1x5Rs2C' }; const PAGE_SIZE = 1000; diff --git a/src/strategies/eco-voting-power/index.ts b/src/strategies/eco-voting-power/index.ts index 2191d91c9..03581ad3f 100644 --- a/src/strategies/eco-voting-power/index.ts +++ b/src/strategies/eco-voting-power/index.ts @@ -10,8 +10,8 @@ export const author = 'carlosfebres'; export const version = '1.0.1'; const ECO_SUBGRAPH_BY_CHAIN_ID = { - '1': 'https://api.thegraph.com/subgraphs/name/ecographs/the-eco-currency-subgraphs', - '5': 'https://api.thegraph.com/subgraphs/name/ecographs/staging-subgraphs' + '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/6Ff7vyzHA1vaiTE5jnHcdUuwpWrxrbr1KwJs9yKKEEzc', + '5': 'https://subgrapher.snapshot.org/subgraph/arbitrum/H3xZUx4ZRoThHeDGbaqMRxuS2HK8FeeDqzYsDo9yjbTr' }; const TOKEN_DELEGATEES_FIELDS = { diff --git a/src/strategies/ens-10k-club/index.ts b/src/strategies/ens-10k-club/index.ts index 4720800bc..89087f378 100644 --- a/src/strategies/ens-10k-club/index.ts +++ b/src/strategies/ens-10k-club/index.ts @@ -2,10 +2,7 @@ import { subgraphRequest } from '../../utils'; import { getAddress } from '@ethersproject/address'; const ENS_SUBGRAPH_URL = { - '1': 'https://api.thegraph.com/subgraphs/name/ensdomains/ens', - '3': 'https://api.thegraph.com/subgraphs/name/ensdomains/ensropsten', - '4': 'https://api.thegraph.com/subgraphs/name/ensdomains/ensrinkeby', - '5': 'https://api.thegraph.com/subgraphs/name/ensdomains/ensgoerli' + '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/5XqPmWe6gjyrJtFn9cLy237i4cWw2j9HcUJEXsP5qGtH' }; // 999 Club: 000-999 as strings, 1000 total diff --git a/src/strategies/ens-all-club-digits/index.ts b/src/strategies/ens-all-club-digits/index.ts index d1885ba41..5d2c9f35d 100644 --- a/src/strategies/ens-all-club-digits/index.ts +++ b/src/strategies/ens-all-club-digits/index.ts @@ -2,7 +2,7 @@ import { subgraphRequest } from '../../utils'; import { getAddress } from '@ethersproject/address'; const ENS_SUBGRAPH_URL = { - '1': 'https://api.thegraph.com/subgraphs/name/ensdomains/ens', + '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/5XqPmWe6gjyrJtFn9cLy237i4cWw2j9HcUJEXsP5qGtH', '3': 'https://api.thegraph.com/subgraphs/name/ensdomains/ensropsten', '4': 'https://api.thegraph.com/subgraphs/name/ensdomains/ensrinkeby', '5': 'https://api.thegraph.com/subgraphs/name/ensdomains/ensgoerli' diff --git a/src/strategies/ens-domains-owned/index.ts b/src/strategies/ens-domains-owned/index.ts index 985bf0577..b1086827f 100644 --- a/src/strategies/ens-domains-owned/index.ts +++ b/src/strategies/ens-domains-owned/index.ts @@ -2,7 +2,7 @@ import { getAddress } from '@ethersproject/address'; import { subgraphRequest } from '../../utils'; const ENS_SUBGRAPH_URL = { - '1': 'https://api.thegraph.com/subgraphs/name/ensdomains/ens', + '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/5XqPmWe6gjyrJtFn9cLy237i4cWw2j9HcUJEXsP5qGtH', '3': 'https://api.thegraph.com/subgraphs/name/ensdomains/ensropsten', '4': 'https://api.thegraph.com/subgraphs/name/ensdomains/ensrinkeby', '5': 'https://api.thegraph.com/subgraphs/name/ensdomains/ensgoerli' diff --git a/src/strategies/erc20-balance-of-top-holders/README.md b/src/strategies/erc20-balance-of-top-holders/README.md index 211310382..2089f0171 100644 --- a/src/strategies/erc20-balance-of-top-holders/README.md +++ b/src/strategies/erc20-balance-of-top-holders/README.md @@ -11,7 +11,7 @@ Here is an example of parameters: "address": "0x8494Aee22e0DB34daA1e8D6829d85710357be9F7", "symbol": "HANDZ", "decimals": 18, - "subgraphUrl": "https://api.thegraph.com/subgraphs/name/kostyamospan/handz-token", + "subgraphUrl": "https://subgrapher.snapshot.org/subgraph/arbitrum/9kfJit8geYDR4fcLr8xUediS1N3UeEkFPPDJAvCdtFJj", "topHolders": 5 } ``` diff --git a/src/strategies/erc20-balance-of-top-holders/examples.json b/src/strategies/erc20-balance-of-top-holders/examples.json index fda35a613..bad140ede 100644 --- a/src/strategies/erc20-balance-of-top-holders/examples.json +++ b/src/strategies/erc20-balance-of-top-holders/examples.json @@ -7,7 +7,7 @@ "address": "0x8494Aee22e0DB34daA1e8D6829d85710357be9F7", "symbol": "HANDZ", "decimals": 18, - "subgraphUrl": "https://api.thegraph.com/subgraphs/name/kostyamospan/handz-token", + "subgraphUrl": "https://subgrapher.snapshot.org/subgraph/arbitrum/9kfJit8geYDR4fcLr8xUediS1N3UeEkFPPDJAvCdtFJj", "topHolders": 5 } }, diff --git a/src/strategies/flashstake/index.ts b/src/strategies/flashstake/index.ts index e6e0e0fd9..e3cb562b5 100644 --- a/src/strategies/flashstake/index.ts +++ b/src/strategies/flashstake/index.ts @@ -2,7 +2,7 @@ import { getAddress } from '@ethersproject/address'; import { subgraphRequest } from '../../utils'; const FLASHSTAKE_SUBGRAPH_URL = { - '1': 'https://api.thegraph.com/subgraphs/name/blockzerohello/flash-stake-stats-v2-subgraph' + '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/4RQRar5ZKWVVZABSaCugWBCJC1GW9Nx3eFUtQ5vyYc9F' }; export const author = 'anassohail99'; diff --git a/src/strategies/giveth-balancer-balance/index.ts b/src/strategies/giveth-balancer-balance/index.ts index 3e15cbfdc..2bd19b70b 100644 --- a/src/strategies/giveth-balancer-balance/index.ts +++ b/src/strategies/giveth-balancer-balance/index.ts @@ -7,10 +7,10 @@ export const author = 'pkretzschmar'; export const version = '0.1.0'; const GIVETH_SUBGRAPH_API = - 'https://api.thegraph.com/subgraphs/name/giveth/giveth-economy-mainnet'; + 'https://subgrapher.snapshot.org/subgraph/arbitrum/D1nWhEyZsWmsuqUJTzZZXfpxDXht5WKte7nDdDV6Ah7Y'; const BALANCER_SUBGRAPH_API = - 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-v2'; + 'https://subgrapher.snapshot.org/subgraph/arbitrum/93yusydMYauh7cfe9jEfoGABmwnX4GffHd7in8KJi1XB-v2'; const poolParams = { pool: { diff --git a/src/strategies/giveth-gnosis-balance-supply-weighted-v3/index.ts b/src/strategies/giveth-gnosis-balance-supply-weighted-v3/index.ts index 0f965b1e6..5e35d77cc 100644 --- a/src/strategies/giveth-gnosis-balance-supply-weighted-v3/index.ts +++ b/src/strategies/giveth-gnosis-balance-supply-weighted-v3/index.ts @@ -6,9 +6,9 @@ export const author = 'divine-comedian'; export const version = '0.1.0'; const GIVETH_SUBGRAPH_API = - 'https://api.thegraph.com/subgraphs/name/giveth/giveth-economy-second-xdai'; + 'https://subgrapher.snapshot.org/subgraph/arbitrum/7UFA1vv3cXNKzzaSVWt6Fe4EhU8B71G97XwWWkN4kxAW'; const XDAI_BLOCKS_API = - 'https://api.thegraph.com/subgraphs/name/elkfinance/xdai-blocks'; + 'https://subgrapher.snapshot.org/subgraph/arbitrum/HTGgWawRHBKr6tDe6umPoVNkYDoUpBEsJSGtX6A7N8MG'; const CIRUCLATING_SUPPLY_API = 'https://circulating.giveth.io/token-supply'; // "supplyField" : "circulating", diff --git a/src/strategies/giveth-gnosis-balance-v2/index.ts b/src/strategies/giveth-gnosis-balance-v2/index.ts index ca3efc5c3..4020093f3 100644 --- a/src/strategies/giveth-gnosis-balance-v2/index.ts +++ b/src/strategies/giveth-gnosis-balance-v2/index.ts @@ -6,9 +6,9 @@ export const author = 'mateodaza'; export const version = '0.1.0'; const GIVETH_SUBGRAPH_API = - 'https://api.thegraph.com/subgraphs/name/giveth/giveth-economy-second-xdai'; + 'https://subgrapher.snapshot.org/subgraph/arbitrum/7UFA1vv3cXNKzzaSVWt6Fe4EhU8B71G97XwWWkN4kxAW'; const XDAI_BLOCKS_API = - 'https://api.thegraph.com/subgraphs/name/elkfinance/xdai-blocks'; + 'https://subgrapher.snapshot.org/subgraph/arbitrum/HTGgWawRHBKr6tDe6umPoVNkYDoUpBEsJSGtX6A7N8MG'; const blockParams = { blocks: { diff --git a/src/strategies/h2o/index.ts b/src/strategies/h2o/index.ts index 07e5122da..c7f250d9a 100644 --- a/src/strategies/h2o/index.ts +++ b/src/strategies/h2o/index.ts @@ -5,7 +5,7 @@ export const author = 'MantisClone'; export const version = '0.1.0'; const SUBGRAPH_URL = { - '1': 'https://api.thegraph.com/subgraphs/name/h2odata/h2o-mainnet' + '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/Djs1i3j3XpSqkieuQAULxTp2cA2j4V8wxWo6XUqgJte7' }; export async function strategy( diff --git a/src/strategies/hats-protocol-single-vote-per-org/index.ts b/src/strategies/hats-protocol-single-vote-per-org/index.ts index 80c2f2eeb..37caa161c 100644 --- a/src/strategies/hats-protocol-single-vote-per-org/index.ts +++ b/src/strategies/hats-protocol-single-vote-per-org/index.ts @@ -71,14 +71,14 @@ export async function strategy( switch (network) { case '1': result = await subgraphRequestHats( - 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-ethereum', + 'https://subgrapher.snapshot.org/subgraph/arbitrum/D1kbQSGSt165189Vh1CoQWjk33mSYyi5aLc3Dvb92gX7', snapshot, options.humanReadableTreeId ); break; case '10': result = await subgraphRequestHats( - 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-optimism', + 'https://subgrapher.snapshot.org/subgraph/arbitrum/8iG8KCsAjgogxp6GvxXWLYwSgKXZsLRCeg9y4ysm5AkK', snapshot, options.humanReadableTreeId ); @@ -92,21 +92,21 @@ export async function strategy( break; case '137': result = await subgraphRequestHats( - 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-polygon', + 'https://subgrapher.snapshot.org/subgraph/arbitrum/4rNc2eosDbwiXPEY74NY7Nvdr1svikoSS7cLF5cCB5Dd', snapshot, options.humanReadableTreeId ); break; case '100': result = await subgraphRequestHats( - 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-gnosis-chain', + 'https://subgrapher.snapshot.org/subgraph/arbitrum/7XiPq3eW6qnxZ6pKGyq9ubE5Lb9XRqg5dZrhY7DGkBhd', snapshot, options.humanReadableTreeId ); break; case '42161': result = await subgraphRequestHats( - 'https://api.thegraph.com/subgraphs/name/hats-protocol/hats-v1-arbitrum', + 'https://subgrapher.snapshot.org/subgraph/arbitrum/EtmBkCiM4fVeRXrNukUhtNWxBL4w582ifWMgAurtdQeQ', snapshot, options.humanReadableTreeId ); diff --git a/src/strategies/honeyswap/index.ts b/src/strategies/honeyswap/index.ts index f77387f7c..53c4b3dbc 100644 --- a/src/strategies/honeyswap/index.ts +++ b/src/strategies/honeyswap/index.ts @@ -7,7 +7,8 @@ export const version = '0.2.0'; const HONEYSWAP_SUBGRAPH_URL = { '100': { - exchange: 'https://api.thegraph.com/subgraphs/name/1hive/uniswap-v2', + exchange: + 'https://subgrapher.snapshot.org/subgraph/arbitrum/F5u74NSaLF92s1qUSacQU4fmWizmK9yqDhXAq6RPtgky', farm: 'https://api.thegraph.com/subgraphs/name/1hive/honeyfarm-xdai' } }; diff --git a/src/strategies/hopr-bridged-balance/index.ts b/src/strategies/hopr-bridged-balance/index.ts index e9e2f3f64..862e6bb4a 100644 --- a/src/strategies/hopr-bridged-balance/index.ts +++ b/src/strategies/hopr-bridged-balance/index.ts @@ -10,9 +10,9 @@ const tokenAbi = ['function balanceOf(address) view returns (uint256)']; const XDAI_BLOCK_SUBGRAPH_URL = 'https://api.thegraph.com/subgraphs/name/1hive/xdai-blocks'; const MAINNET_BLOCK_SUBGRAPH_URL = - 'https://api.thegraph.com/subgraphs/name/blocklytics/ethereum-blocks'; + 'https://subgrapher.snapshot.org/subgraph/arbitrum/9A6bkprqEG2XsZUYJ5B2XXp6ymz9fNcn4tVPxMWDztYC'; const HOPR_XDAI_SUBGRAPH_URL = - 'https://api.thegraph.com/subgraphs/name/hoprnet/hopr-on-xdai'; + 'https://subgrapher.snapshot.org/subgraph/arbitrum/9EEKrJnzerBVeNfqDCziQx1hCLdrcPnnehu8rKME25g9'; const HOPR_MAINNET_SUBGRAPH_URL = 'https://api.thegraph.com/subgraphs/name/hoprnet/hopr-on-mainnet'; const LIMIT = 1000; // 1000 addresses per query in Subgraph diff --git a/src/strategies/hopr-staking-by-season/index.ts b/src/strategies/hopr-staking-by-season/index.ts index b0305398d..ba1565dc3 100644 --- a/src/strategies/hopr-staking-by-season/index.ts +++ b/src/strategies/hopr-staking-by-season/index.ts @@ -10,7 +10,7 @@ const XDAI_BLOCK_SUBGRAPH_URL = const HOPR_STAKING_SUBGRAPH_ROOT = 'https://api.thegraph.com/subgraphs/name/hoprnet/'; const DEFAULT_HOPR_STAKING_SUBGRAPH_URL = - 'https://api.thegraph.com/subgraphs/name/hoprnet/staking-season3'; + 'https://subgrapher.snapshot.org/subgraph/arbitrum/GboRvnV9xikDA488gyRTmtTzHg1kEpXQiqFKGkJMEK8u'; const LIMIT = 1000; // 1000 addresses per query in Subgraph function buildHoprStakeSubgraphUrl(variant: string, seasonNumber: number) { diff --git a/src/strategies/hopr-staking-s2/index.ts b/src/strategies/hopr-staking-s2/index.ts index 58b5df33c..391934e49 100644 --- a/src/strategies/hopr-staking-s2/index.ts +++ b/src/strategies/hopr-staking-s2/index.ts @@ -8,7 +8,7 @@ export const version = '0.1.0'; const XDAI_BLOCK_SUBGRAPH_URL = 'https://api.thegraph.com/subgraphs/name/1hive/xdai-blocks'; const HOPR_STAKING_SUBGRAPH_URL = - 'https://api.thegraph.com/subgraphs/name/hoprnet/staking-season2'; + 'https://subgrapher.snapshot.org/subgraph/arbitrum/94LBxbmmR2t3CujsDFhaFPSAVipUqHSvq4Zos3GNcbZg'; const LIMIT = 1000; // 1000 addresses per query in Subgraph async function getXdaiBlockNumber(timestamp: number): Promise { diff --git a/src/strategies/hopr-uni-lp-farm/index.ts b/src/strategies/hopr-uni-lp-farm/index.ts index fd334a1ca..181a771bb 100644 --- a/src/strategies/hopr-uni-lp-farm/index.ts +++ b/src/strategies/hopr-uni-lp-farm/index.ts @@ -71,7 +71,7 @@ const tokenAndPoolAbi = [ const XDAI_BLOCK_SUBGRAPH_URL = 'https://api.thegraph.com/subgraphs/name/1hive/xdai-blocks'; const HOPR_XDAI_SUBGRAPH_URL = - 'https://api.thegraph.com/subgraphs/name/hoprnet/hopr-on-xdai'; + 'https://subgrapher.snapshot.org/subgraph/arbitrum/9EEKrJnzerBVeNfqDCziQx1hCLdrcPnnehu8rKME25g9'; const LIMIT = 1000; // 1000 addresses per query in Subgraph async function getXdaiBlockNumber(timestamp: number): Promise { diff --git a/src/strategies/infinityprotocol-liquidity-pools/README.md b/src/strategies/infinityprotocol-liquidity-pools/README.md index cce3450da..4916d7c44 100644 --- a/src/strategies/infinityprotocol-liquidity-pools/README.md +++ b/src/strategies/infinityprotocol-liquidity-pools/README.md @@ -16,7 +16,7 @@ The space config will look like this: "address": "0xc168e40227e4ebd8c1cae80f7a55a4f0e6d66c97", "symbol": "DFYN" // subgraphURL for the request - "subGraphURL": "https://api.thegraph.com/subgraphs/name/ss-sonic/dfyn-v5", + "subGraphURL": "https://subgrapher.snapshot.org/subgraph/arbitrum/FuxKHMLaziLFcQi5c4y3p1JY1ZGLA81rFqBfZfbQZDpo", // scoreMultiplier can be used to increase users' scores by a certain magnitude "scoreMultiplier": 1, }, diff --git a/src/strategies/infinityprotocol-liquidity-pools/index.ts b/src/strategies/infinityprotocol-liquidity-pools/index.ts index 14982f5b0..3459b3cf4 100644 --- a/src/strategies/infinityprotocol-liquidity-pools/index.ts +++ b/src/strategies/infinityprotocol-liquidity-pools/index.ts @@ -2,7 +2,7 @@ import { getAddress } from '@ethersproject/address'; import { subgraphRequest } from '../../utils'; const INFINITYPROTOCOL_SUBGRAPH_URL = { - '56': 'https://api.thegraph.com/subgraphs/name/infinitywallet/infinity-protocol' + '56': 'https://subgrapher.snapshot.org/subgraph/arbitrum/5bvBvmThMNxZiioc5qkfE3s43YWMVsvLCgFstr1nDfiH' }; export const author = 'vfatouros'; diff --git a/src/strategies/jpegd-locked-jpeg-of/index.ts b/src/strategies/jpegd-locked-jpeg-of/index.ts index 8a9bdad01..be5033087 100644 --- a/src/strategies/jpegd-locked-jpeg-of/index.ts +++ b/src/strategies/jpegd-locked-jpeg-of/index.ts @@ -7,7 +7,7 @@ export const author = '0xleez'; export const version = '0.1.1'; const SUBGRAPH_URL = { - '1': 'https://api.thegraph.com/subgraphs/name/jpegd/jpegd-core-mainnet' + '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/9CyfknHXr1cJrxraayn37zEmu1v4BS69i9NjLQW9XJT4' }; const abi = [ diff --git a/src/strategies/liquidity-token-provide/README.md b/src/strategies/liquidity-token-provide/README.md index 558a4b0de..5af313f83 100644 --- a/src/strategies/liquidity-token-provide/README.md +++ b/src/strategies/liquidity-token-provide/README.md @@ -15,7 +15,7 @@ The space config will look like this: "address": "0xffffffff2ba8f66d4e51811c5190992176930278", "symbol": "COMBO" // subgraphURL for the request - "subGraphURL": "https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2", + "subGraphURL": "https://subgrapher.snapshot.org/subgraph/arbitrum/EYCKATKGBKLWvSfwvBjzfCBmGwYNdVkduYXVivCsLRFu", // scoreMultiplier can be used to increase users' scores by a certain magnitude "scoreMultiplier": 1, } diff --git a/src/strategies/liquidity-token-provide/index.ts b/src/strategies/liquidity-token-provide/index.ts index 800b30d08..fcbe170b5 100644 --- a/src/strategies/liquidity-token-provide/index.ts +++ b/src/strategies/liquidity-token-provide/index.ts @@ -2,9 +2,9 @@ import { getAddress } from '@ethersproject/address'; import { subgraphRequest } from '../../utils'; const SUBGRAPH_URL = { - '1': 'https://api.thegraph.com/subgraphs/name/dinngodev/furucombo-tokenomics-mainnet', + '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/4RGbQCKV1NNoEJcK3shwgTvn65zsHaFdqG9RPvv28qJU', '137': - 'https://api.thegraph.com/subgraphs/name/dinngodev/furucombo-tokenomics-polygon' + 'https://subgrapher.snapshot.org/subgraph/arbitrum/HHNWub5axWTGR1no6yrqVurT8Ak9skEFAwnw3YcqkD8G' }; export const author = 'weizard'; diff --git a/src/strategies/lrc-l2-nft-balance-of/README.md b/src/strategies/lrc-l2-nft-balance-of/README.md index e031a59b4..b270e3bda 100644 --- a/src/strategies/lrc-l2-nft-balance-of/README.md +++ b/src/strategies/lrc-l2-nft-balance-of/README.md @@ -6,7 +6,7 @@ Here is an example of parameters: ```json { - "graph": "https://api.thegraph.com/subgraphs/name/loopring/loopring", + "graph": "https://subgrapher.snapshot.org/subgraph/arbitrum/8Z15oyPLRCYzVdNbjKSU2iD8BE6Sj8PZRV4KddDuvuk2", "minter_account_id": "74447", "tokens": ["token (Collection) id's to include"], "blacklisted_account_ids": ["38482"], diff --git a/src/strategies/lrc-l2-nft-balance-of/examples.json b/src/strategies/lrc-l2-nft-balance-of/examples.json index e7e7d1c49..76a7eb7c7 100644 --- a/src/strategies/lrc-l2-nft-balance-of/examples.json +++ b/src/strategies/lrc-l2-nft-balance-of/examples.json @@ -4,7 +4,7 @@ "strategy": { "name": "lrc-l2-nft-balance-of", "params": { - "graph": "https://api.thegraph.com/subgraphs/name/loopring/loopring", + "graph": "https://subgrapher.snapshot.org/subgraph/arbitrum/8Z15oyPLRCYzVdNbjKSU2iD8BE6Sj8PZRV4KddDuvuk2", "minter_account_id": "74447", "tokens": ["0xc76eca2937b006606ebe717621409e4c2df906f1"], "blacklisted_account_ids": ["38482"], diff --git a/src/strategies/lrc-nft-search-mult/README.md b/src/strategies/lrc-nft-search-mult/README.md index 00d5a9ba6..74301122c 100644 --- a/src/strategies/lrc-nft-search-mult/README.md +++ b/src/strategies/lrc-nft-search-mult/README.md @@ -12,7 +12,7 @@ Here is an example of parameters: ```json { - "graph": "https://api.thegraph.com/subgraphs/name/loopring/loopring", + "graph": "https://subgrapher.snapshot.org/subgraph/arbitrum/8Z15oyPLRCYzVdNbjKSU2iD8BE6Sj8PZRV4KddDuvuk2", "minter_account_id": "74447", "tokens": ["token (Collection contract address) to include"], "nft_ids": ["nftIDs, unique to every nft, even those under the same token contract"], diff --git a/src/strategies/lrc-nft-search-mult/examples.json b/src/strategies/lrc-nft-search-mult/examples.json index 21b3f111f..5bb175f9f 100644 --- a/src/strategies/lrc-nft-search-mult/examples.json +++ b/src/strategies/lrc-nft-search-mult/examples.json @@ -4,7 +4,7 @@ "strategy": { "name": "lrc-nft-search-mult", "params": { - "graph": "https://api.thegraph.com/subgraphs/name/loopring/loopring", + "graph": "https://subgrapher.snapshot.org/subgraph/arbitrum/8Z15oyPLRCYzVdNbjKSU2iD8BE6Sj8PZRV4KddDuvuk2", "minter_account_id": "157510", "tokens": ["0xb6d91e38e4ac53c9f8952c6c6b1c7aee66c8b6f0"], "nft_ids": [ diff --git a/src/strategies/masterchef/index.ts b/src/strategies/masterchef/index.ts index b018295d4..674be6249 100644 --- a/src/strategies/masterchef/index.ts +++ b/src/strategies/masterchef/index.ts @@ -3,11 +3,11 @@ import { BigNumber } from '@ethersproject/bignumber'; import { subgraphRequest } from '../../utils'; const MASTERCHEF_SUBGRAPH_URL = { - '1': 'https://api.thegraph.com/subgraphs/name/sushiswap/master-chef' + '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/AkCK7BgZJHVwjDdxbnaER1e2XPpywnXVkVZV4p7QGnua' }; const SUSHISWAP_SUBGRAPH_URL = { - '1': 'https://api.thegraph.com/subgraphs/name/sushiswap/exchange' + '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/6NUtT5mGjZ1tSshKLf5Q3uEEJtjBZJo1TpL5MXsUBqrT' }; export const author = '0xKiwi'; diff --git a/src/strategies/meebitsdao-delegation/index.ts b/src/strategies/meebitsdao-delegation/index.ts index eca3299ee..7c18accf7 100644 --- a/src/strategies/meebitsdao-delegation/index.ts +++ b/src/strategies/meebitsdao-delegation/index.ts @@ -8,7 +8,7 @@ export const author = 'maikir'; export const version = '0.2.0'; const MEEBITSDAO_DELEGATION_SUBGRAPH_URL = - 'https://api.thegraph.com/subgraphs/name/maikir/meebitsdao-delegation'; + 'https://subgrapher.snapshot.org/subgraph/arbitrum/6ZRqJohQ1nJ9a3mESbFudJSmnuCmo3n1LCz4BbRqzNRt'; export async function strategy( space, diff --git a/src/strategies/nation3-passport-coop-with-delegations/index.ts b/src/strategies/nation3-passport-coop-with-delegations/index.ts index 8975d3967..337f04d2c 100644 --- a/src/strategies/nation3-passport-coop-with-delegations/index.ts +++ b/src/strategies/nation3-passport-coop-with-delegations/index.ts @@ -51,7 +51,7 @@ export async function strategy( }); const passportIssuanceSubgrgraph = - 'https://api.thegraph.com/subgraphs/name/nation3/passportissuance'; + 'https://subgrapher.snapshot.org/subgraph/arbitrum/5N2XQNjiSJEBQzEp5XAZQY7M7tNqXnd87HCysHC1rdQ7'; const revokedQuery: Query = { revokes: { diff --git a/src/strategies/nexon-army-nft/index.ts b/src/strategies/nexon-army-nft/index.ts index ae91b0741..ab39776f7 100644 --- a/src/strategies/nexon-army-nft/index.ts +++ b/src/strategies/nexon-army-nft/index.ts @@ -7,7 +7,8 @@ export const version = '0.1.0'; const LIMIT = 1000; export const SUBGRAPH_URL = { - '137': 'https://api.thegraph.com/subgraphs/name/nexon-finance/nexon-army-nft' + '137': + 'https://subgrapher.snapshot.org/subgraph/arbitrum/3Z8NRcpP7t2p4Lsi5iKBKgNqTrzf5ivthCEUCKAhH8NV' }; export async function strategy( diff --git a/src/strategies/otterspace-badges/index.ts b/src/strategies/otterspace-badges/index.ts index 224a2079b..02ab58e54 100644 --- a/src/strategies/otterspace-badges/index.ts +++ b/src/strategies/otterspace-badges/index.ts @@ -5,13 +5,10 @@ export const author = 'otterspace-xyz'; export const version = '1.0.1'; const OTTERSPACE_SUBGRAPH_API_URLS_BY_CHAIN_ID = { - '1': 'https://api.thegraph.com/subgraphs/name/otterspace-xyz/badges-mainnet', - '5': 'https://api.thegraph.com/subgraphs/name/otterspace-xyz/badges-goerli', - '10': 'https://api.thegraph.com/subgraphs/name/otterspace-xyz/badges-optimism-alpha', - '420': - 'https://api.thegraph.com/subgraphs/name/otterspace-xyz/badges-optimism-goerli', + '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/6ihhxkTaxozNgrvyKbyTc7BDvwA9mByhDXXTJzW3E6gw', + '10': 'https://subgrapher.snapshot.org/subgraph/arbitrum/DvWYwk9KfxGRE8AH9bNgtSxwGvjgTYXYnHyajQpNWLQB', '137': - 'https://api.thegraph.com/subgraphs/name/otterspace-xyz/badges-polygon', + 'https://subgrapher.snapshot.org/subgraph/arbitrum/8fxbcfCYxZutSysQto4TxPYGzGUuiZCsaVc6SXkDRuS1', '11155111': 'https://api.studio.thegraph.com/query/44988/badges-sepolia/version/latest' }; diff --git a/src/strategies/poap-with-weight-v2/index.ts b/src/strategies/poap-with-weight-v2/index.ts index 74cc8a4a5..dab946128 100644 --- a/src/strategies/poap-with-weight-v2/index.ts +++ b/src/strategies/poap-with-weight-v2/index.ts @@ -5,8 +5,9 @@ export const author = 'gawainb'; export const version = '2.1.0'; 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' + '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/HuioMeA9oSgs2vkBUQvhfxN9jhkBayadi1tmvKN3KG4s', + '100': + 'https://subgrapher.snapshot.org/subgraph/arbitrum/HuioMeA9oSgs2vkBUQvhfxN9jhkBayadi1tmvKN3KG4s-xdai' }; // subgraph query in filter has max length of 500 const EVENT_IDS_LIMIT = 500; diff --git a/src/strategies/poap-with-weight/index.ts b/src/strategies/poap-with-weight/index.ts index 3fca2933f..389b9fbd3 100644 --- a/src/strategies/poap-with-weight/index.ts +++ b/src/strategies/poap-with-weight/index.ts @@ -7,8 +7,9 @@ export const version = '1.1.0'; export const examples = examplesFile; 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' + '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/HuioMeA9oSgs2vkBUQvhfxN9jhkBayadi1tmvKN3KG4s', + '100': + 'https://subgrapher.snapshot.org/subgraph/arbitrum/HuioMeA9oSgs2vkBUQvhfxN9jhkBayadi1tmvKN3KG4s-xdai' }; const getTokenSupply = { diff --git a/src/strategies/poap/index.ts b/src/strategies/poap/index.ts index f088b83d3..f6ed33f3f 100644 --- a/src/strategies/poap/index.ts +++ b/src/strategies/poap/index.ts @@ -8,8 +8,9 @@ export const version = '1.2.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' + '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/HuioMeA9oSgs2vkBUQvhfxN9jhkBayadi1tmvKN3KG4s', + '100': + 'https://subgrapher.snapshot.org/subgraph/arbitrum/HuioMeA9oSgs2vkBUQvhfxN9jhkBayadi1tmvKN3KG4s-xdai' }; // subgraph query in filter has max length of 500 const MAX_ACCOUNTS_IN_QUERY = 500; diff --git a/src/strategies/pob-hash/index.ts b/src/strategies/pob-hash/index.ts index 9931089a6..165aeada9 100644 --- a/src/strategies/pob-hash/index.ts +++ b/src/strategies/pob-hash/index.ts @@ -4,7 +4,7 @@ export const author = 'dave4506'; export const version = '0.1.1'; export const SUBGRAPH_URL = { - '1': 'https://api.thegraph.com/subgraphs/name/proofofbeauty/hash' + '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/N1nKhGBh1yB48pBBDmZAmPWg7pDBSy9EhirZn4yg9pB' }; export async function strategy( diff --git a/src/strategies/push-voting-power/index.ts b/src/strategies/push-voting-power/index.ts index c126616ba..7acd857ef 100644 --- a/src/strategies/push-voting-power/index.ts +++ b/src/strategies/push-voting-power/index.ts @@ -107,7 +107,7 @@ export async function strategy( const responseStakedPUSH = responseStaked.slice(0, addresses.length); let responseStakedPUSHV2 = responseStakedV2.slice(0, addresses.length); - responseStakedPUSHV2 = responseStakedPUSHV2.map((value, i) => { + responseStakedPUSHV2 = responseStakedPUSHV2.map((value) => { return value[0].toString(); }); const responseStakedLP = responseStaked.slice(addresses.length); diff --git a/src/strategies/ren-nodes/index.ts b/src/strategies/ren-nodes/index.ts index e9e36b532..e706a8893 100644 --- a/src/strategies/ren-nodes/index.ts +++ b/src/strategies/ren-nodes/index.ts @@ -10,7 +10,7 @@ export const version = '0.1.0'; */ const RENVM_SUBGRAPH_URL = { - '1': 'https://api.thegraph.com/subgraphs/name/renproject/renvm', + '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/HnW1Q9iWqojVLqHpyB5wBSSngmo9L9Smu3BQd2tGcEAs', '42': 'https://api.thegraph.com/subgraphs/name/renproject/renvm-testnet' }; diff --git a/src/strategies/rep3-badges/index.ts b/src/strategies/rep3-badges/index.ts index b36ed2d28..f2524b436 100644 --- a/src/strategies/rep3-badges/index.ts +++ b/src/strategies/rep3-badges/index.ts @@ -9,7 +9,8 @@ export const version = '1.0.0'; const REP3_SUBGRAPH_API_URLS_BY_CHAIN_ID = { '80001': 'https://api.thegraph.com/subgraphs/name/eth-jashan/rep3-mumbai', - '137': 'https://api.thegraph.com/subgraphs/name/eth-jashan/rep3-matic' + '137': + 'https://subgrapher.snapshot.org/subgraph/arbitrum/5q79qNXTXCAR9TrGAyExYCvBhD8LcAZ6WhTHqn2zh2wf' }; const abi = [ diff --git a/src/strategies/sablier-v1-deposit/examples.json b/src/strategies/sablier-v1-deposit/examples.json index c52b59ad3..b1ac2fb0f 100644 --- a/src/strategies/sablier-v1-deposit/examples.json +++ b/src/strategies/sablier-v1-deposit/examples.json @@ -4,11 +4,11 @@ "strategy": { "name": "sablier-v1-deposit", "params": { - "sender": "0xcCe2CbDcD0eee72984c58A84678F0D49a95257ae", - "token": "0x97cb342Cf2F6EcF48c1285Fb8668f5a4237BF862" + "sender": "0x2752c1d587c56d919e17a4f42374d336ea116004", + "token": "0x350a791bfc2c21f9ed5d10980dad2e2638ffa7f6" } }, - "network": "5", + "network": "10", "addresses": [ "0x06255FA39EBD18796eCCCc17DB8153Ef58DBA0a8", "0xf976aF93B0A5A9F55A7f285a3B5355B8575Eb5bc", @@ -25,7 +25,7 @@ "token": "0x97cb342Cf2F6EcF48c1285Fb8668f5a4237BF862" } }, - "network": "5", + "network": "10", "addresses": [ "0x06255FA39EBD18796eCCCc17DB8153Ef58DBA0a8", "0xf976aF93B0A5A9F55A7f285a3B5355B8575Eb5bc", diff --git a/src/strategies/sablier-v1-deposit/index.ts b/src/strategies/sablier-v1-deposit/index.ts index e83febe47..13cba23ee 100644 --- a/src/strategies/sablier-v1-deposit/index.ts +++ b/src/strategies/sablier-v1-deposit/index.ts @@ -3,18 +3,15 @@ import { formatUnits } from '@ethersproject/units'; import { subgraphRequest } from '../../utils'; const SUBGRAPH_URL = { - '1': 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier', // mainnet - '3': 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-ropsten', // ropsten - '4': 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-rinkeby', // rinkeby - '5': 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-goerli', // goerli - '10': 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-optimism', // optimism - '42': 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-kovan', // kovan - '56': 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-bsc', // bsc - '137': 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-matic', // polygon + '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/DkSXWkgJD5qVqfsrfzkLC5WELVX3Dbj3ByWcYjDJieCh', // mainnet + '10': 'https://subgrapher.snapshot.org/subgraph/arbitrum/BEnQbvBdXnohC1DpM9rSb47C1FbowK39HfPNCEHjgrBt', // optimism + '56': 'https://subgrapher.snapshot.org/subgraph/arbitrum/3Gyy7of99oBRqHcCMGJXpHw2xxxZgXxVmFPFR1vL6YhT', // bsc + '137': + 'https://subgrapher.snapshot.org/subgraph/arbitrum/6UMNQfMeh3pV5Qmn2NDX2UKNeUk9kh4oZhzzzn5e8rSz', // polygon '42161': - 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-arbitrum', // arbitrum + 'https://subgrapher.snapshot.org/subgraph/arbitrum/94SP9QVcxmGV9e2fxuTxUGcZfcv4tjpPCGyyPVyMfLP', // arbitrum '43114': - 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-avalanche' // avalanche + 'https://subgrapher.snapshot.org/subgraph/arbitrum/DK2gHCprwVaytwzwb5fUrkFS9xy7wh66NX6AFcDzMyF9' // avalanche }; export const author = 'sablier-labs'; diff --git a/src/strategies/sablier-v2/configuration.ts b/src/strategies/sablier-v2/configuration.ts index d2ef5bcf9..a78e12fa4 100644 --- a/src/strategies/sablier-v2/configuration.ts +++ b/src/strategies/sablier-v2/configuration.ts @@ -6,50 +6,57 @@ const chains = { arbitrum: '42161', + arbitrumSepolia: '421614', avalanche: '43114', base: '8453', + blast: '81457', bsc: '56', ethereum: '1', - goerli: '5', gnosis: '100', optimism: '10', optimismSepolia: '11155420', polygon: '137', scroll: '534352', - sepolia: '11155111' + sepolia: '11155111', + zkSync: '324' }; const deployments = { + [chains.ethereum]: { + subgraph: + 'https://subgrapher.snapshot.org/subgraph/arbitrum/EuZZnhFtdCGqN2Zt7EMGYDqQKNrVuhJL63KAfwvF35bL' + }, + [chains.arbitrumSepolia]: { + subgraph: + 'https://api.studio.thegraph.com/query/57079/sablier-v2-arbitrum-sepolia/version/latest' + }, [chains.arbitrum]: { subgraph: - 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2-arbitrum' + 'https://subgrapher.snapshot.org/subgraph/arbitrum/AR77w8PwmkAG7c9DJSsfW6yTrC5UdvdQ1Hz5ZTCuaUWz' }, [chains.avalanche]: { subgraph: - 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2-avalanche' + 'https://subgrapher.snapshot.org/subgraph/arbitrum/FdVwZuMV43yCb1nPmjnLQwmzS58wvKuLMPzcZ4UWgWAc' }, [chains.base]: { subgraph: - 'https://api.studio.thegraph.com/query/57079/sablier-v2-base/version/latest' + 'https://subgrapher.snapshot.org/subgraph/arbitrum/3pxjsW9rbDjmZpoQWzc5CAo4vzcyYE9YQyTghntmnb1K' }, - [chains.bsc]: { + [chains.blast]: { subgraph: - 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2-bsc' + 'https://subgrapher.snapshot.org/subgraph/arbitrum/BXoC2ToMZXnTmCjWftQRPh9zMyM7ysijMN54Nxzb2CEY' }, - [chains.ethereum]: { - subgraph: 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2' - }, - [chains.goerli]: { + [chains.bsc]: { subgraph: - 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2-goerli' + 'https://subgrapher.snapshot.org/subgraph/arbitrum/BVyi15zcH5eUg5PPKfRDDesezMezh6cAkn8LPvh7MVAF' }, [chains.gnosis]: { subgraph: - 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2-gnosis' + 'https://subgrapher.snapshot.org/subgraph/arbitrum/EXhNLbhCbsewJPx4jx5tutNXpxwdgng2kmX1J7w1bFyu' }, [chains.optimism]: { subgraph: - 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2-optimism' + 'https://subgrapher.snapshot.org/subgraph/arbitrum/6e6Dvs1yDpsWDDREZRqxGi54SVdvTNzUdKpKJxniKVrp' }, [chains.optimismSepolia]: { subgraph: @@ -57,7 +64,7 @@ const deployments = { }, [chains.polygon]: { subgraph: - 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2-polygon' + 'https://subgrapher.snapshot.org/subgraph/arbitrum/CsDNYv9XPUMP8vufuwDVKQrVhsxhzzRHezjLFFKZZbrx' }, [chains.scroll]: { subgraph: @@ -65,7 +72,11 @@ const deployments = { }, [chains.sepolia]: { subgraph: - 'https://api.thegraph.com/subgraphs/name/sablier-labs/sablier-v2-sepolia' + 'https://api.studio.thegraph.com/query/57079/sablier-v2-sepolia/version/latest' + }, + [chains.zkSync]: { + subgraph: + 'https://subgrapher.snapshot.org/subgraph/arbitrum/GY2fGozmfZiZ3xF2MfevohLR4YGnyxGxAyxzi9zmU5bY' } }; diff --git a/src/strategies/skale-delegation-weighted/index.ts b/src/strategies/skale-delegation-weighted/index.ts index 9453cbc9f..81690ff07 100644 --- a/src/strategies/skale-delegation-weighted/index.ts +++ b/src/strategies/skale-delegation-weighted/index.ts @@ -12,7 +12,7 @@ const abi = [ ]; const GRAPH_API_URL = - 'https://api.thegraph.com/subgraphs/name/ministry-of-decentralization/skale-manager-subgraph'; + 'https://subgrapher.snapshot.org/subgraph/arbitrum/3o81KDCm8mHXDB69KvmGsh4sdVCcxhQwQdwE74bTHi4r'; function returnGraphParamsValidatorPower( snapshot: number | string, diff --git a/src/strategies/spaceid/index.ts b/src/strategies/spaceid/index.ts index 60a64ae7b..d41395c6e 100644 --- a/src/strategies/spaceid/index.ts +++ b/src/strategies/spaceid/index.ts @@ -8,7 +8,7 @@ export const author = 'SID-Marcus'; export const version = '0.0.1'; const pancakeV3Subgraph = - 'https://api.thegraph.com/subgraphs/name/messari/pancakeswap-v3-bsc'; + 'https://subgrapher.snapshot.org/subgraph/arbitrum/78EUqzJmEVJsAKvWghn7qotf9LVGqcTQxJhT5z84ZmgJ'; const UNISWAP_ID_USDC_PAIR = '0x6ac6b053a2858bea8ad758db680198c16e523184'; const PANCAKE_ID_USDT_PAIR = '0x4e1f9aDf96dBA6Dc09c973228c286568F1315ea8'; diff --git a/src/strategies/spacey2025/index.ts b/src/strategies/spacey2025/index.ts index 50579c5be..5c8ebf22f 100644 --- a/src/strategies/spacey2025/index.ts +++ b/src/strategies/spacey2025/index.ts @@ -5,7 +5,7 @@ export const author = 'chuang39'; export const version = '0.1.0'; const SPACEY2025_MARKETPLACE_SUBGRAPH_URL = { - '56': 'https://api.thegraph.com/subgraphs/name/blockfishio/marketplacebsc' + '56': 'https://subgrapher.snapshot.org/subgraph/arbitrum/3zrj6YV8ZAHr1pcn5Vuqz2py2zbBiHFerFQJnH7dvmxJ' }; enum Category { diff --git a/src/strategies/staked-balancer/index.ts b/src/strategies/staked-balancer/index.ts index 9818bde21..94438092c 100644 --- a/src/strategies/staked-balancer/index.ts +++ b/src/strategies/staked-balancer/index.ts @@ -11,7 +11,7 @@ const erc20ABI = [ ]; const BALANCER_SUBGRAPH_URL_ROOT = - 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer'; + 'https://subgrapher.snapshot.org/subgraph/arbitrum/93yusydMYauh7cfe9jEfoGABmwnX4GffHd7in8KJi1XB'; const NETWORK_KEY = { '1': '', diff --git a/src/strategies/starcatchers-top-window/index.ts b/src/strategies/starcatchers-top-window/index.ts index ab8ffe43a..07b0cf928 100644 --- a/src/strategies/starcatchers-top-window/index.ts +++ b/src/strategies/starcatchers-top-window/index.ts @@ -4,7 +4,7 @@ export const author = 'sunshinekitty'; export const version = '0.0.1'; const SC_GRAPH_URL = - 'https://api.thegraph.com/subgraphs/name/sunshinekitty/starcatchers-ia1'; + 'https://subgrapher.snapshot.org/subgraph/arbitrum/AdLbReMZHHHhoKH1s2EcBQ4QrHPTaKqYyriKFJxSxwKm'; export async function strategy( space, diff --git a/src/strategies/synthetix-non-quadratic_1/index.ts b/src/strategies/synthetix-non-quadratic_1/index.ts index 5bd81ab85..cf9ac198d 100644 --- a/src/strategies/synthetix-non-quadratic_1/index.ts +++ b/src/strategies/synthetix-non-quadratic_1/index.ts @@ -25,7 +25,7 @@ const DebtCacheContractAddress = '0x9D5551Cd3425Dd4585c3E7Eb7E4B98902222521E'; const defaultGraphs = { '1': 'https://api.thegraph.com/subgraphs/name/synthetixio-team/synthetix', - '10': 'https://api.thegraph.com/subgraphs/name/synthetixio-team/optimism-main' + '10': 'https://subgrapher.snapshot.org/subgraph/arbitrum/39nXvA89wrgSz7vRAq6uxmvYn2CTNDuSfXJue3m7PVKA' }; const loadLastDebtLedgerEntry = async ( diff --git a/src/strategies/synthetix-quadratic_1/index.ts b/src/strategies/synthetix-quadratic_1/index.ts index 4806cabc4..7144d77bd 100644 --- a/src/strategies/synthetix-quadratic_1/index.ts +++ b/src/strategies/synthetix-quadratic_1/index.ts @@ -25,7 +25,7 @@ const DebtCacheContractAddress = '0x9D5551Cd3425Dd4585c3E7Eb7E4B98902222521E'; const defaultGraphs = { '1': 'https://api.thegraph.com/subgraphs/name/synthetixio-team/synthetix', - '10': 'https://api.thegraph.com/subgraphs/name/synthetixio-team/optimism-main' + '10': 'https://subgrapher.snapshot.org/subgraph/arbitrum/39nXvA89wrgSz7vRAq6uxmvYn2CTNDuSfXJue3m7PVKA' }; const loadLastDebtLedgerEntry = async ( diff --git a/src/strategies/thales/index.ts b/src/strategies/thales/index.ts index 05ef5a460..30b963540 100644 --- a/src/strategies/thales/index.ts +++ b/src/strategies/thales/index.ts @@ -13,9 +13,9 @@ enum NetworkId { const THALES_SUBGRAPH_URL = { optimism: - 'https://api.thegraph.com/subgraphs/name/thales-markets/thales-token', + 'https://subgrapher.snapshot.org/subgraph/arbitrum/2WQ9TKJt96NUxuS2DbR7B4aAwcU9CMiaBH7fwZZfjpn1', arbitrum: - 'https://api.thegraph.com/subgraphs/name/thales-markets/thales-token-arbitrum', + 'https://subgrapher.snapshot.org/subgraph/arbitrum/GRHJHjVRzHrQoN86VyjXMDTDiw9pHNB9NqQJxQmnZcwb', base: 'https://api.studio.thegraph.com/query/11948/thales-token-base/version/latest' }; diff --git a/src/strategies/the-graph/graphUtils.ts b/src/strategies/the-graph/graphUtils.ts index 9470d2644..0fd6cc697 100644 --- a/src/strategies/the-graph/graphUtils.ts +++ b/src/strategies/the-graph/graphUtils.ts @@ -3,7 +3,7 @@ import { BigNumber } from '@ethersproject/bignumber'; import { Provider } from '@ethersproject/providers'; export const GRAPH_NETWORK_SUBGRAPH_URL = { - '1': 'https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-mainnet', + '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/GgwLf9BTFBJi6Z5iYHssMAGEE4w5dR3Jox2dMLrBxnCT', '4': 'https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-testnet' }; export const bnWEI = BigNumber.from('1000000000000000000'); diff --git a/src/strategies/the-graph/tokenLockWallets.ts b/src/strategies/the-graph/tokenLockWallets.ts index aa523ddbe..eae0b0641 100644 --- a/src/strategies/the-graph/tokenLockWallets.ts +++ b/src/strategies/the-graph/tokenLockWallets.ts @@ -3,7 +3,7 @@ import { subgraphRequest } from '../../utils'; import { verifyResults } from './graphUtils'; export const TOKEN_DISTRIBUTION_SUBGRAPH_URL = { - '1': 'https://api.thegraph.com/subgraphs/name/graphprotocol/token-distribution', + '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/ChfAJn6jQEBjVqtdUiThfG6sWy2Sr5XQPNucE9DkgXSN', '4': 'https://api.thegraph.com/subgraphs/name/davekaj/token-distribution-rinkeby' }; interface TokenLockWallets { diff --git a/src/strategies/tranche-staking-lp/index.ts b/src/strategies/tranche-staking-lp/index.ts index 57591ddf4..c3df214fd 100644 --- a/src/strategies/tranche-staking-lp/index.ts +++ b/src/strategies/tranche-staking-lp/index.ts @@ -7,7 +7,7 @@ export const author = 'ayush-jibrel'; export const version = '0.1.0'; const UNISWAP_SUBGRAPH_URL = { - '1': 'https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2' + '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/EYCKATKGBKLWvSfwvBjzfCBmGwYNdVkduYXVivCsLRFu' }; const abi = [ diff --git a/src/strategies/uniswap-v3-staking/index.ts b/src/strategies/uniswap-v3-staking/index.ts index c20514be3..eca230469 100644 --- a/src/strategies/uniswap-v3-staking/index.ts +++ b/src/strategies/uniswap-v3-staking/index.ts @@ -4,7 +4,7 @@ import { subgraphRequest } from '../../utils'; import { getAllReserves, getStakeInfo, UNISWAP_V3_STAKER } from './helper'; const UNISWAP_V3_SUBGRAPH_URL = { - '1': 'https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v3' + '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/5zvR82QoaXYFyDEKLZ9t6v9adgnptxYpKpSbxtgVENFV' }; export const author = 'ribbon-finance'; diff --git a/src/strategies/uniswap-v3/index.ts b/src/strategies/uniswap-v3/index.ts index 5ffbd6a8a..2224dacdf 100644 --- a/src/strategies/uniswap-v3/index.ts +++ b/src/strategies/uniswap-v3/index.ts @@ -2,7 +2,7 @@ import { subgraphRequest } from '../../utils'; import { getAllReserves } from './helper'; const UNISWAP_V3_SUBGRAPH_URL = { - '1': 'https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v3' + '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/5zvR82QoaXYFyDEKLZ9t6v9adgnptxYpKpSbxtgVENFV' }; export const author = 'anassohail99'; diff --git a/src/strategies/uniswap/index.ts b/src/strategies/uniswap/index.ts index 52acbe540..38c0d2952 100644 --- a/src/strategies/uniswap/index.ts +++ b/src/strategies/uniswap/index.ts @@ -2,7 +2,7 @@ import { getAddress } from '@ethersproject/address'; import { subgraphRequest } from '../../utils'; const UNISWAP_SUBGRAPH_URL = { - '1': 'https://api.thegraph.com/subgraphs/name/ianlapham/uniswap-v2-dev' + '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/FEtpnfQ1aqF8um2YktEkfzFD11ZKrfurvBLPeQzv9JB1' }; export const author = 'snapshot-labs'; diff --git a/src/strategies/wagdie-subgraph/README.md b/src/strategies/wagdie-subgraph/README.md index b8552f6f4..94ed4c2c4 100644 --- a/src/strategies/wagdie-subgraph/README.md +++ b/src/strategies/wagdie-subgraph/README.md @@ -19,7 +19,7 @@ The space config will look like this: ```JSON { // subgraphURL for the request - "subGraphURL": "https://api.thegraph.com/subgraphs/name/wagdie/wagdieworld-mainnet", + "subGraphURL": "https://subgrapher.snapshot.org/subgraph/arbitrum/CiuchCqNbcNs88KkbQqs7PwuaD2DrPqHqxuDVKrJ5ESM", // scoreMultiplier can be used to increase users' scores by a certain magnitude "scoreMultiplier": 1, // Array of location IDs to limit votes to specific locations. Can be set to ["all"] to include all locations. diff --git a/src/strategies/wagdie-subgraph/examples.json b/src/strategies/wagdie-subgraph/examples.json index 8ba202c75..4368103b9 100644 --- a/src/strategies/wagdie-subgraph/examples.json +++ b/src/strategies/wagdie-subgraph/examples.json @@ -4,7 +4,7 @@ "strategy": { "name": "wagdie-subgraph", "params": { - "subGraphURL": "https://api.thegraph.com/subgraphs/name/wagdie/wagdieworld-mainnet", + "subGraphURL": "https://subgrapher.snapshot.org/subgraph/arbitrum/CiuchCqNbcNs88KkbQqs7PwuaD2DrPqHqxuDVKrJ5ESM", "scoreMultiplier": 1, "location": ["all"] } diff --git a/src/strategies/wagdie-subgraph/index.ts b/src/strategies/wagdie-subgraph/index.ts index 6f970f6af..10780396d 100644 --- a/src/strategies/wagdie-subgraph/index.ts +++ b/src/strategies/wagdie-subgraph/index.ts @@ -2,7 +2,7 @@ import { getAddress } from '@ethersproject/address'; import { subgraphRequest } from '../../utils'; const SUBGRAPH_URL = { - '1': 'https://api.thegraph.com/subgraphs/name/wagdie/wagdieworld-mainnet' + '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/CiuchCqNbcNs88KkbQqs7PwuaD2DrPqHqxuDVKrJ5ESM' }; export const author = 'IcculusHerEmissary'; diff --git a/src/strategies/xdai-easy-staking/index.ts b/src/strategies/xdai-easy-staking/index.ts index 78745e2db..665557ae8 100644 --- a/src/strategies/xdai-easy-staking/index.ts +++ b/src/strategies/xdai-easy-staking/index.ts @@ -7,7 +7,7 @@ export const author = 'maxaleks'; export const version = '0.1.0'; const EASY_STAKING_SUBGRAPH_URL = - 'https://api.thegraph.com/subgraphs/name/maxaleks/easy-staking'; + 'https://subgrapher.snapshot.org/subgraph/arbitrum/3jhMxbXh6Ua3WXfa7BuFHdh4nUDZaVgLVrvoouhUNPfT'; const ercABI = [ { From ebf2b105c7b914fd07c61d3300f8bdcb38996f91 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Mon, 17 Jun 2024 17:43:30 +0530 Subject: [PATCH 672/815] fix: Wrong subgraph URLs (#1501) --- src/strategies/giveth-balancer-balance/index.ts | 2 +- src/strategies/poap-with-weight-v2/index.ts | 3 +-- src/strategies/poap-with-weight/index.ts | 3 +-- src/strategies/poap/index.ts | 3 +-- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/strategies/giveth-balancer-balance/index.ts b/src/strategies/giveth-balancer-balance/index.ts index 2bd19b70b..1e864f9ab 100644 --- a/src/strategies/giveth-balancer-balance/index.ts +++ b/src/strategies/giveth-balancer-balance/index.ts @@ -10,7 +10,7 @@ const GIVETH_SUBGRAPH_API = 'https://subgrapher.snapshot.org/subgraph/arbitrum/D1nWhEyZsWmsuqUJTzZZXfpxDXht5WKte7nDdDV6Ah7Y'; const BALANCER_SUBGRAPH_API = - 'https://subgrapher.snapshot.org/subgraph/arbitrum/93yusydMYauh7cfe9jEfoGABmwnX4GffHd7in8KJi1XB-v2'; + 'https://subgrapher.snapshot.org/subgraph/arbitrum/C4ayEZP2yTXRAB8vSaTrgN4m9anTe9Mdm2ViyiAuV9TV'; const poolParams = { pool: { diff --git a/src/strategies/poap-with-weight-v2/index.ts b/src/strategies/poap-with-weight-v2/index.ts index dab946128..c4cef7b60 100644 --- a/src/strategies/poap-with-weight-v2/index.ts +++ b/src/strategies/poap-with-weight-v2/index.ts @@ -6,8 +6,7 @@ export const version = '2.1.0'; const POAP_API_ENDPOINT_URL = { '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/HuioMeA9oSgs2vkBUQvhfxN9jhkBayadi1tmvKN3KG4s', - '100': - 'https://subgrapher.snapshot.org/subgraph/arbitrum/HuioMeA9oSgs2vkBUQvhfxN9jhkBayadi1tmvKN3KG4s-xdai' + '100': 'https://api.thegraph.com/subgraphs/name/poap-xyz/poap-xdai' }; // subgraph query in filter has max length of 500 const EVENT_IDS_LIMIT = 500; diff --git a/src/strategies/poap-with-weight/index.ts b/src/strategies/poap-with-weight/index.ts index 389b9fbd3..0beb0009c 100644 --- a/src/strategies/poap-with-weight/index.ts +++ b/src/strategies/poap-with-weight/index.ts @@ -8,8 +8,7 @@ export const examples = examplesFile; const POAP_API_ENDPOINT_URL = { '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/HuioMeA9oSgs2vkBUQvhfxN9jhkBayadi1tmvKN3KG4s', - '100': - 'https://subgrapher.snapshot.org/subgraph/arbitrum/HuioMeA9oSgs2vkBUQvhfxN9jhkBayadi1tmvKN3KG4s-xdai' + '100': 'https://api.thegraph.com/subgraphs/name/poap-xyz/poap-xdai' }; const getTokenSupply = { diff --git a/src/strategies/poap/index.ts b/src/strategies/poap/index.ts index f6ed33f3f..5b6b99f02 100644 --- a/src/strategies/poap/index.ts +++ b/src/strategies/poap/index.ts @@ -9,8 +9,7 @@ export const version = '1.2.0'; const EVENT_IDS_LIMIT = 500; const POAP_API_ENDPOINT_URL = { '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/HuioMeA9oSgs2vkBUQvhfxN9jhkBayadi1tmvKN3KG4s', - '100': - 'https://subgrapher.snapshot.org/subgraph/arbitrum/HuioMeA9oSgs2vkBUQvhfxN9jhkBayadi1tmvKN3KG4s-xdai' + '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; From 36a6a7fdbec54c371547a7b061d481de7c25d814 Mon Sep 17 00:00:00 2001 From: Alex Karolis Date: Tue, 18 Jun 2024 18:13:41 +1200 Subject: [PATCH 673/815] [immutable-x] remove immutable x from snapshot strategies (#1497) Co-authored-by: Chaitanya --- src/strategies/immutable-x/examples.json | 48 ------- src/strategies/immutable-x/index.ts | 158 ----------------------- src/strategies/index.ts | 2 - 3 files changed, 208 deletions(-) delete mode 100644 src/strategies/immutable-x/examples.json delete mode 100644 src/strategies/immutable-x/index.ts diff --git a/src/strategies/immutable-x/examples.json b/src/strategies/immutable-x/examples.json deleted file mode 100644 index dd797aaec..000000000 --- a/src/strategies/immutable-x/examples.json +++ /dev/null @@ -1,48 +0,0 @@ -[ - { - "name": "Immutable X (L1 + L2) vote weighting strategy", - "strategy": { - "name": "immutable-x", - "params": { - "symbol": "imx", - "address": "0x26b81657e09d3a6a18ff1c6d776fd09f4bb9ee80", - "decimals": 18, - "pageSize": 100 - } - }, - "network": "3", - "addresses": [ - "0x6f78046c7441c9ae8063f78af53ef29b47871a3e", - "0xed6f74e896e6853959a02f27634d4ff0b58286ff", - "0x9f797c209fa19627cb4cb52232b5a615dd04f3f8", - "0x60bdc16bd3b001a4c7fb3ef598f4b075ad586d5d", - "0xc8714f989ce817e5d21349888077aa5db4a9bcf6", - "0x49632a466ee268ebb756fc4d963af98143f259d0", - "0x6b32a7add2673a3bc84bd7c5f3bccfb3e96fd611", - "0xca65c6c80562163d49bd12690c2c7ae7d005c6fb", - "0x2d7e665acb06d5907b0b169bbea61ddf5e206b95", - "0x2915f444dca40cf23e0050e12e30e35d864fb451", - "0x973eb49bbdd2754609ba5f3da0b7836948636e62", - "0xdb0d4032c8e03f946477eca6336fac87d1e8ef2f", - "0xed6f74e896e6853959a02f27634d4ff0b58286ff", - "0xdb0d4032c8e03f946477eca6336fac87d1e8ef2f", - "0xca65c6c80562163d49bd12690c2c7ae7d005c6fb", - "0xc8714f989ce817e5d21349888077aa5db4a9bcf6", - "0x9f797c209fa19627cb4cb52232b5a615dd04f3f8", - "0x973eb49bbdd2754609ba5f3da0b7836948636e62", - "0x6f78046c7441c9ae8063f78af53ef29b47871a3e", - "0x6b32a7add2673a3bc84bd7c5f3bccfb3e96fd611", - "0x60bdc16bd3b001a4c7fb3ef598f4b075ad586d5d", - "0x49632a466ee268ebb756fc4d963af98143f259d0", - "0x2d7e665acb06d5907b0b169bbea61ddf5e206b95", - "0x2915f444dca40cf23e0050e12e30e35d864fb451", - "0xed6f74e896e6853959a02f27634d4ff0b58286ff", - "0xdb0d4032c8e03f946477eca6336fac87d1e8ef2f", - "0xca65c6c80562163d49bd12690c2c7ae7d005c6fb", - "0xc8714f989ce817e5d21349888077aa5db4a9bcf6", - "0x9f797c209fa19627cb4cb52232b5a615dd04f3f8", - "0x973eb49bbdd2754609ba5f3da0b7836948636e62" - ], - "snapshot": 11850372 - } -] diff --git a/src/strategies/immutable-x/index.ts b/src/strategies/immutable-x/index.ts deleted file mode 100644 index 1cfdd4e61..000000000 --- a/src/strategies/immutable-x/index.ts +++ /dev/null @@ -1,158 +0,0 @@ -import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; - -import { StaticJsonRpcProvider } from '@ethersproject/providers'; -import fetch from 'cross-fetch'; -import { formatUnits } from '@ethersproject/units'; -import { strategy as getL1Balances } from '../erc20-balance-of'; - -export const author = 'immutable'; -export const version = '1.0.0'; - -export const name = 'immutable-x'; - -const snapshotPath = '/v1/snapshots/balances'; - -const networkMapping = { - 1: 'https://api.x.immutable.com', - 3: 'https://api.ropsten.x.immutable.com' -}; - -const defaultPageSize = 1000; - -interface Response { - records: Score[]; - cursor: string; -} - -interface Score { - ether_key: string; - balance: string; -} - -interface Options { - address: string; - decimals: number; - pageSize?: number; -} - -export async function strategy( - _space: unknown, - network: string, - provider: StaticJsonRpcProvider, - addresses: string[], - options: Options, - block: number | string = 'latest' -): Promise> { - return combineBalanceScores([ - await getL2Balances(network, options, addresses, block), - await getL1Balances(null, network, provider, addresses, options, block) - ]); -} - -async function getL2Balances( - network: string, - options: Options, - addresses: string[], - block: number | string -): Promise> { - const records: Record = {}; - - // Sanitize pageSize - options.pageSize = options.pageSize || defaultPageSize; - - // Loop variables - let cursor = '', - receivedLen = 0; - - // Until all records are returned - // This loop handles both: - // 1. server-side paginated requests for all addresses available; and - // 2. client-side paginated requests (addresses in json body of requests). - // There are separate completion conditions for 1. and 2. - while (true) { - // Build URL - const apiUrl = buildURL(network, options, block, cursor); - - // Send request - const response = await fetch(apiUrl, { - method: 'POST', - body: JSON.stringify({ - ether_keys: addresses.slice(receivedLen, receivedLen + options.pageSize) - }), - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json' - } - }); - - // Decode response - const resJson = await response.json(); - - // Empty response indicates end of results - // for requests without specified address in json body - const respLen = (resJson as Response).records.length; - if (respLen === 0) { - break; - } - // Store result - Object.assign(records, mapL2Response(resJson, options)); - // Iterate - receivedLen += respLen; - // This indicates we have received all results for - // the addresses we asked for - if (receivedLen >= addresses.length) { - break; - } - // For paginated requests, continue w/ cursor - cursor = resJson.cursor; - } - return records; -} - -function buildURL( - network: string, - options: Options, - block: number | string, - cursor?: string -): string { - let apiUrl = networkMapping[network] + snapshotPath; - apiUrl += '/' + options.address.toLowerCase(); - apiUrl += `?page_size=${options.pageSize}`; - apiUrl += typeof block === 'number' ? `&block=${block}` : ''; - apiUrl += cursor || cursor != '' ? `&cursor=${cursor}` : ''; - return apiUrl; -} - -function mapL2Response( - data: Response, - options: Options -): Record { - return Object.fromEntries( - data.records.map((value: Score) => [ - value.ether_key, - formatBalance(value.balance, options.decimals) - ]) - ); -} - -function formatBalance( - balance: BigNumber | string, - decimals: BigNumberish -): number { - return parseFloat(formatUnits(balance, decimals)); -} - -function combineBalanceScores( - records: Record[] -): Record { - return records.reduce((aggScore, currScore) => { - for (const [address, balance] of Object.entries(currScore)) { - if (!aggScore[address]) { - aggScore[address] = balance; - } else { - aggScore[address] += balance; // sum(L1, L2) - } - } - return aggScore; - }, {}); -} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 6d2f8e335..3a627312b 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -153,7 +153,6 @@ import * as aaveGovernancePower from './aave-governance-power'; import * as cake from './cake'; import * as aks from './aks'; import * as impossibleFinance from './impossible-finance'; -import * as immutableX from './immutable-x'; import * as ogn from './ogn'; import * as oolongswap from './oolongswap'; import * as zrxVotingPower from './zrx-voting-power'; @@ -601,7 +600,6 @@ const strategies = { ogn, oolongswap, 'impossible-finance': impossibleFinance, - 'immutable-x': immutableX, 'zrx-voting-power': zrxVotingPower, 'tomb-finance': tombFinance, 'tranche-staking-slice': trancheStakingSLICE, From 968f935ea0ad3274eddb25631ebb788c3d7e4830 Mon Sep 17 00:00:00 2001 From: thomasscovell Date: Tue, 18 Jun 2024 18:54:10 +1200 Subject: [PATCH 674/815] [balance-of-with-max] Added balance-of-with-max (#1503) * Added balance-of-with-max New strategy to cap votes at a max * Update index.ts * Update index.ts * Update index.ts --------- Co-authored-by: Chaitanya --- .../balance-of-with-max/examples.json | 22 ++++++++++++ src/strategies/balance-of-with-max/index.ts | 35 +++++++++++++++++++ src/strategies/index.ts | 2 ++ 3 files changed, 59 insertions(+) create mode 100644 src/strategies/balance-of-with-max/examples.json create mode 100644 src/strategies/balance-of-with-max/index.ts diff --git a/src/strategies/balance-of-with-max/examples.json b/src/strategies/balance-of-with-max/examples.json new file mode 100644 index 000000000..ef59a94fd --- /dev/null +++ b/src/strategies/balance-of-with-max/examples.json @@ -0,0 +1,22 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "balance-of-with-max", + "params": { + "address": "0x6b175474e89094c44da98b954eedeac495271d0f", + "symbol": "DAI", + "decimals": 18, + "maxBalance": 200000 + } + }, + "network": "1", + "addresses": [ + "0xa478c2975ab1ea89e8196811f51a7b7ade33eb11", + "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", + "0x9B8e8dD9151260c21CB6D7cc59067cd8DF306D58", + "0x38C0039247A31F3939baE65e953612125cB88268" + ], + "snapshot": 11437846 + } +] diff --git a/src/strategies/balance-of-with-max/index.ts b/src/strategies/balance-of-with-max/index.ts new file mode 100644 index 000000000..c8648e9b9 --- /dev/null +++ b/src/strategies/balance-of-with-max/index.ts @@ -0,0 +1,35 @@ +import { getAddress } from '@ethersproject/address'; +import { strategy as erc20BalanceOfStrategy } from '../erc20-balance-of'; + +export const author = 'thomasscovell'; +export const version = '0.1.0'; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const score = await erc20BalanceOfStrategy( + space, + network, + provider, + addresses, + options, + snapshot + ); + + Object.keys(score).forEach((key) => { + if (score[key] <= (options.maxBalance || 0)) score[key] = score[key]; + else score[key] = options.maxBalance; + }); + + return Object.fromEntries( + Object.entries(score).map(([address, balance]) => [ + getAddress(address), + balance + ]) + ); +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 3a627312b..a0d1981ab 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -37,6 +37,7 @@ import * as erc20BalanceOfIndexed from './erc20-balance-of-indexed'; import * as revest from './revest'; import * as erc20Price from './erc20-price'; import * as balanceOfWithMin from './balance-of-with-min'; +import * as balanceOfWithMax from './balance-of-with-max'; import * as balanceOfWithThresholds from './balance-of-with-thresholds'; import * as balanceOfWithLinearVestingPower from './balance-of-with-linear-vesting-power'; import * as linearVestingPower from './linear-vesting-power'; @@ -482,6 +483,7 @@ const strategies = { 'erc20-price': erc20Price, 'ethalend-balance-of': ethalendBalanceOf, 'balance-of-with-min': balanceOfWithMin, + 'balance-of-with-max': balanceOfWithMax, 'balance-of-with-thresholds': balanceOfWithThresholds, thresholds, 'eth-balance': ethBalance, From 8dbeb612660a870c3b62410c6c1c161766886b48 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 18 Jun 2024 15:16:17 +0530 Subject: [PATCH 675/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.33 (#1499) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index ff0b8d39f..05c322123 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.31", + "@snapshot-labs/snapshot.js": "^0.11.33", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index abba81e88..cc0c810da 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.31": - version "0.11.31" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.31.tgz#7e91069e1c1ed116c77e7aa642c69e87d9176f31" - integrity sha512-AovoHVggA74s/i6h/NVmvry1IeQs3+LWvz9Bj3wspiSgFubcmv20aTaQjUdJ7/Pt4ed2pAoRt7vZlwjhmPNp8g== +"@snapshot-labs/snapshot.js@^0.11.33": + version "0.11.33" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.33.tgz#6379f67a36ec713321074b271298a32aaffaad51" + integrity sha512-W6VhJ0AO1vdi7NaywtOq477MXvphdlqBasonooP24HRj+7eMe7GZJn8vXfWn8mAVXKK4KEOp+hvLpr0nV16PtQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From df6aa4bf4367eb0277d69b68555576adb0afaf8a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 18 Jun 2024 18:34:40 +0530 Subject: [PATCH 676/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.34 (#1504) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 05c322123..e9814f33f 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.33", + "@snapshot-labs/snapshot.js": "^0.11.34", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index cc0c810da..ab306589c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.33": - version "0.11.33" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.33.tgz#6379f67a36ec713321074b271298a32aaffaad51" - integrity sha512-W6VhJ0AO1vdi7NaywtOq477MXvphdlqBasonooP24HRj+7eMe7GZJn8vXfWn8mAVXKK4KEOp+hvLpr0nV16PtQ== +"@snapshot-labs/snapshot.js@^0.11.34": + version "0.11.34" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.34.tgz#f3cccf2127ee81d102b657db01785fdbcc5d6c5d" + integrity sha512-lcM/aZnVtUtt3oGA+MWTDxcTaGDhbc5YNU4XwhRWYQfaU+dfLFLCeKUc+VgvOp8ehuqv4msAYv/c+1PDctmcrQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From d8874ca80168218526fd50fc6fd4e458e39f6f73 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 18 Jun 2024 20:39:25 +0530 Subject: [PATCH 677/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.35 (#1505) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index e9814f33f..33c51cd77 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.34", + "@snapshot-labs/snapshot.js": "^0.11.35", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index ab306589c..3135463ab 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.34": - version "0.11.34" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.34.tgz#f3cccf2127ee81d102b657db01785fdbcc5d6c5d" - integrity sha512-lcM/aZnVtUtt3oGA+MWTDxcTaGDhbc5YNU4XwhRWYQfaU+dfLFLCeKUc+VgvOp8ehuqv4msAYv/c+1PDctmcrQ== +"@snapshot-labs/snapshot.js@^0.11.35": + version "0.11.35" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.35.tgz#5ed5853dcb68d813c5fdbd20835f40266e0fd353" + integrity sha512-vMp5RUORQjY+joZEq9nsTEaW2qeMAA/ZSgOZRS6mt5fIUbt7PlaCY4p7gk31CVtva5TTfrsLi2VnZ0V8c5faug== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 3c909d0e7fab16903ee6857c0417268b82ef5a6f Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Wed, 19 Jun 2024 00:44:27 +0530 Subject: [PATCH 678/815] [balancer-poolid] Fix subgraph URLs (#1506) --- src/strategies/balancer-poolid/index.ts | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/strategies/balancer-poolid/index.ts b/src/strategies/balancer-poolid/index.ts index 01e5746ce..0dc8ca5c9 100644 --- a/src/strategies/balancer-poolid/index.ts +++ b/src/strategies/balancer-poolid/index.ts @@ -7,20 +7,19 @@ export const author = 'jo-chemla'; export const version = '0.1.0'; const PAGE_SIZE = 1000; -const BALANCER_SUBGRAPH_URL_ROOT = - 'https://subgrapher.snapshot.org/subgraph/arbitrum/93yusydMYauh7cfe9jEfoGABmwnX4GffHd7in8KJi1XB'; -const NETWORK_KEY = { - '1': '', - '42': '-kovan', - '137': '-polygon', - '42161': '-arbitrum' +const BALANCER_SUBGRAPHS = { + '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/93yusydMYauh7cfe9jEfoGABmwnX4GffHd7in8KJi1XB', + '1-v2': + 'https://subgrapher.snapshot.org/subgraph/arbitrum/C4ayEZP2yTXRAB8vSaTrgN4m9anTe9Mdm2ViyiAuV9TV', + '137-v2': + 'https://subgrapher.snapshot.org/subgraph/arbitrum/H9oPAbXnobBRq1cB3HDmbZ1E8MWQyJYQjT1QDJMrdbNp', + '42161-v2': + 'https://subgrapher.snapshot.org/subgraph/arbitrum/98cQDy6tufTJtshDCuhh9z2kWXsQWBHVh2bqnLHsGAeS' }; function buildBalancerSubgraphUrl(chainId, version) { - const networkString = NETWORK_KEY[chainId]; - const versionString = version == 2 ? '-v2' : ''; - return `${BALANCER_SUBGRAPH_URL_ROOT}${networkString}${versionString}`; + return BALANCER_SUBGRAPHS[`${chainId}${version === 2 ? '-v2' : ''}`]; } const params = { From d9d09558b21b2d2eff970d99f684bed9e834d1b5 Mon Sep 17 00:00:00 2001 From: thomasscovell Date: Wed, 19 Jun 2024 21:52:10 +1200 Subject: [PATCH 679/815] [balance-of-with-max] Updated balance-of-with-max to add weight (#1509) * added balance-of-with-max-weighted strategy * Updated balance-of-with-max Adding weight to options. --- src/strategies/balance-of-with-max/examples.json | 3 ++- src/strategies/balance-of-with-max/index.ts | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/strategies/balance-of-with-max/examples.json b/src/strategies/balance-of-with-max/examples.json index ef59a94fd..077b281ec 100644 --- a/src/strategies/balance-of-with-max/examples.json +++ b/src/strategies/balance-of-with-max/examples.json @@ -7,7 +7,8 @@ "address": "0x6b175474e89094c44da98b954eedeac495271d0f", "symbol": "DAI", "decimals": 18, - "maxBalance": 200000 + "maxBalance": 200000, + "weight": 1 } }, "network": "1", diff --git a/src/strategies/balance-of-with-max/index.ts b/src/strategies/balance-of-with-max/index.ts index c8648e9b9..bac5fb0d2 100644 --- a/src/strategies/balance-of-with-max/index.ts +++ b/src/strategies/balance-of-with-max/index.ts @@ -2,7 +2,7 @@ import { getAddress } from '@ethersproject/address'; import { strategy as erc20BalanceOfStrategy } from '../erc20-balance-of'; export const author = 'thomasscovell'; -export const version = '0.1.0'; +export const version = '0.1.1'; export async function strategy( space, @@ -22,7 +22,7 @@ export async function strategy( ); Object.keys(score).forEach((key) => { - if (score[key] <= (options.maxBalance || 0)) score[key] = score[key]; + if ((score[key]* options.weight) <= (options.maxBalance || 0)) score[key] = (score[key]* options.weight); else score[key] = options.maxBalance; }); From e9f4e4fe44e4bdaf43ae8ad1fd800c125952e5d7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 19 Jun 2024 15:29:53 +0530 Subject: [PATCH 680/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.36 (#1508) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 33c51cd77..e1b235a10 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.35", + "@snapshot-labs/snapshot.js": "^0.11.36", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 3135463ab..c6d726e69 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.35": - version "0.11.35" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.35.tgz#5ed5853dcb68d813c5fdbd20835f40266e0fd353" - integrity sha512-vMp5RUORQjY+joZEq9nsTEaW2qeMAA/ZSgOZRS6mt5fIUbt7PlaCY4p7gk31CVtva5TTfrsLi2VnZ0V8c5faug== +"@snapshot-labs/snapshot.js@^0.11.36": + version "0.11.36" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.36.tgz#77f87a5315bf43043b0f64bb45c83def90682379" + integrity sha512-X2Q3WvEEctDSIdmachEXdOq1f6fhmmE4WYlxjZjbpuVPeR8ZfDzevnaGV4mzVSC1U8AHS4z/M2Ndtyl0LE7Cdg== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From ca38e17680b0fbbd440f6e154ce7bcc7ba41a0c5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 24 Jun 2024 10:51:31 +0530 Subject: [PATCH 681/815] Automated lint (#1511) Co-authored-by: ChaituVR --- src/strategies/balance-of-with-max/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/strategies/balance-of-with-max/index.ts b/src/strategies/balance-of-with-max/index.ts index bac5fb0d2..2c5bd5402 100644 --- a/src/strategies/balance-of-with-max/index.ts +++ b/src/strategies/balance-of-with-max/index.ts @@ -22,7 +22,8 @@ export async function strategy( ); Object.keys(score).forEach((key) => { - if ((score[key]* options.weight) <= (options.maxBalance || 0)) score[key] = (score[key]* options.weight); + if (score[key] * options.weight <= (options.maxBalance || 0)) + score[key] = score[key] * options.weight; else score[key] = options.maxBalance; }); From 9f6c845f83c8e7f9a72e9d6c9bbc4175cf2e9d3a Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Mon, 24 Jun 2024 11:01:23 +0530 Subject: [PATCH 682/815] fix: balancer subgraphs (#1512) --- src/strategies/balancer/index.ts | 20 +++++++++----------- src/strategies/staked-balancer/index.ts | 20 +++++++++----------- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/src/strategies/balancer/index.ts b/src/strategies/balancer/index.ts index 1c45ae9fd..986fe1fab 100644 --- a/src/strategies/balancer/index.ts +++ b/src/strategies/balancer/index.ts @@ -4,20 +4,18 @@ import { subgraphRequest } from '../../utils'; export const author = 'bonustrack'; export const version = '0.2.0'; -const BALANCER_SUBGRAPH_URL_ROOT = - 'https://subgrapher.snapshot.org/subgraph/arbitrum/93yusydMYauh7cfe9jEfoGABmwnX4GffHd7in8KJi1XB'; - -const NETWORK_KEY = { - '1': '', - '42': '-kovan', - '137': '-polygon', - '42161': '-arbitrum' +const BALANCER_SUBGRAPHS = { + '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/93yusydMYauh7cfe9jEfoGABmwnX4GffHd7in8KJi1XB', + '1-v2': + 'https://subgrapher.snapshot.org/subgraph/arbitrum/C4ayEZP2yTXRAB8vSaTrgN4m9anTe9Mdm2ViyiAuV9TV', + '137-v2': + 'https://subgrapher.snapshot.org/subgraph/arbitrum/H9oPAbXnobBRq1cB3HDmbZ1E8MWQyJYQjT1QDJMrdbNp', + '42161-v2': + 'https://subgrapher.snapshot.org/subgraph/arbitrum/98cQDy6tufTJtshDCuhh9z2kWXsQWBHVh2bqnLHsGAeS' }; function buildBalancerSubgraphUrl(chainId, version) { - const networkString = NETWORK_KEY[chainId]; - const versionString = version == 2 ? '-v2' : ''; - return `${BALANCER_SUBGRAPH_URL_ROOT}${networkString}${versionString}`; + return BALANCER_SUBGRAPHS[`${chainId}${version === 2 ? '-v2' : ''}`]; } async function subgraphRequestWithPagination(subgraphURL, addresses, snapshot) { diff --git a/src/strategies/staked-balancer/index.ts b/src/strategies/staked-balancer/index.ts index 94438092c..826d0415c 100644 --- a/src/strategies/staked-balancer/index.ts +++ b/src/strategies/staked-balancer/index.ts @@ -10,20 +10,18 @@ const erc20ABI = [ 'function totalSupply() external view returns (uint256)' ]; -const BALANCER_SUBGRAPH_URL_ROOT = - 'https://subgrapher.snapshot.org/subgraph/arbitrum/93yusydMYauh7cfe9jEfoGABmwnX4GffHd7in8KJi1XB'; - -const NETWORK_KEY = { - '1': '', - '42': '-kovan', - '137': '-polygon', - '42161': '-arbitrum' +const BALANCER_SUBGRAPHS = { + '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/93yusydMYauh7cfe9jEfoGABmwnX4GffHd7in8KJi1XB', + '1-v2': + 'https://subgrapher.snapshot.org/subgraph/arbitrum/C4ayEZP2yTXRAB8vSaTrgN4m9anTe9Mdm2ViyiAuV9TV', + '137-v2': + 'https://subgrapher.snapshot.org/subgraph/arbitrum/H9oPAbXnobBRq1cB3HDmbZ1E8MWQyJYQjT1QDJMrdbNp', + '42161-v2': + 'https://subgrapher.snapshot.org/subgraph/arbitrum/98cQDy6tufTJtshDCuhh9z2kWXsQWBHVh2bqnLHsGAeS' }; function buildBalancerSubgraphUrl(chainId, version) { - const networkString = NETWORK_KEY[chainId]; - const versionString = version == 2 ? '-v2' : ''; - return `${BALANCER_SUBGRAPH_URL_ROOT}${networkString}${versionString}`; + return BALANCER_SUBGRAPHS[`${chainId}${version === 2 ? '-v2' : ''}`]; } const params = { From cfc8825bf2e6da0a3f0466e4443c5c466b5130ff Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Tue, 25 Jun 2024 16:39:23 +0530 Subject: [PATCH 683/815] fix: Change the graph network subgraphs (#1514) --- src/strategies/the-graph/graphUtils.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/strategies/the-graph/graphUtils.ts b/src/strategies/the-graph/graphUtils.ts index 0fd6cc697..d4a0e06f8 100644 --- a/src/strategies/the-graph/graphUtils.ts +++ b/src/strategies/the-graph/graphUtils.ts @@ -3,8 +3,9 @@ import { BigNumber } from '@ethersproject/bignumber'; import { Provider } from '@ethersproject/providers'; export const GRAPH_NETWORK_SUBGRAPH_URL = { - '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/GgwLf9BTFBJi6Z5iYHssMAGEE4w5dR3Jox2dMLrBxnCT', - '4': 'https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-testnet' + '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/9Co7EQe5PgW3ugCUJrJgRv4u9zdEuDJf8NvMWftNsBH8', + '42161': + 'https://subgrapher.snapshot.org/subgraph/arbitrum/DZz4kDTdmzWLWsV373w2bSmoar3umKKH9y82SUKr5qmp' }; export const bnWEI = BigNumber.from('1000000000000000000'); From 3eb851c2a8e6623d6ad78883695060f1c7e50571 Mon Sep 17 00:00:00 2001 From: Less Date: Wed, 26 Jun 2024 07:50:58 +0700 Subject: [PATCH 684/815] [csv] add strategy CSV (#1515) * feat: add strategy CSV * improve readme --- src/strategies/csv/README.md | 16 +++++++++ src/strategies/csv/examples.json | 28 +++++++++++++++ src/strategies/csv/index.ts | 62 ++++++++++++++++++++++++++++++++ src/strategies/csv/schema.json | 33 +++++++++++++++++ src/strategies/index.ts | 4 ++- 5 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 src/strategies/csv/README.md create mode 100644 src/strategies/csv/examples.json create mode 100644 src/strategies/csv/index.ts create mode 100644 src/strategies/csv/schema.json diff --git a/src/strategies/csv/README.md b/src/strategies/csv/README.md new file mode 100644 index 000000000..ef6d03684 --- /dev/null +++ b/src/strategies/csv/README.md @@ -0,0 +1,16 @@ +# CSV + +The CSV strategy allows you to fetch token balances from a CSV external file. + +Here is an example of parameters for the strategy: +```csv +```json +{ + "csv": "ipfs://bafkreig3xgt2j7mtcukqy5jglmxwlyy7unrqi2ncplgfnpq32aqomzbo4m", + "symbol": "ABC", + "decimals": 0 +} +``` + +Here is an example of CSV file: +https://gateway.pinata.cloud/ipfs/bafkreig3xgt2j7mtcukqy5jglmxwlyy7unrqi2ncplgfnpq32aqomzbo4m diff --git a/src/strategies/csv/examples.json b/src/strategies/csv/examples.json new file mode 100644 index 000000000..7c4d41ec6 --- /dev/null +++ b/src/strategies/csv/examples.json @@ -0,0 +1,28 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "csv", + "params": { + "csv": "ipfs://bafkreig3xgt2j7mtcukqy5jglmxwlyy7unrqi2ncplgfnpq32aqomzbo4m", + "symbol": "ABC", + "decimals": 0 + } + }, + "network": "1", + "addresses": [ + "0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11", + "0xef8305e140ac520225daf050e2f71d5fbcc543e7", + "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", + "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", + "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e", + "0x1d5E65a087eBc3d03a294412E46CE5D6882969f4", + "0x1f254336E5c46639A851b9CfC165697150a6c327", + "0x2ec3F80BeDA63Ede96BA20375032CDD3aAfb3030", + "0x4AcBcA6BE2f8D2540bBF4CA77E45dA0A4a095Fa2", + "0x4F3D348a6D09837Ae7961B1E0cEe2cc118cec777", + "0x8C28Cf33d9Fd3D0293f963b1cd27e3FF422B425c" + ], + "snapshot": 20172180 + } +] diff --git a/src/strategies/csv/index.ts b/src/strategies/csv/index.ts new file mode 100644 index 000000000..952a0dba7 --- /dev/null +++ b/src/strategies/csv/index.ts @@ -0,0 +1,62 @@ +import { formatUnits } from '@ethersproject/units'; +import { getAddress } from '@ethersproject/address'; + +export const author = 'bonustrack'; +export const version = '0.1.0'; + +interface Items { + [address: string]: string; +} + +async function parseCSV( + url: string, + lineSeparator = '\n', + fieldSeparator = ',' +): Promise { + if (url.startsWith('ipfs://')) { + url = url.replace('ipfs://', 'https://gateway.pinata.cloud/ipfs/'); + } + + const response = await fetch(url); + const text = await response.text(); + + const lines = text.split(lineSeparator); + const items: Items = {}; + + for (let i = 0; i < lines.length; i++) { + const [address, value] = lines[i].split(fieldSeparator); + + if (address && value) { + items[getAddress(address.trim())] = value.trim(); + } + } + + return items; +} + +export async function strategy( + _space, + _network, + _provider, + addresses, + options +): Promise> { + const result = await parseCSV( + options.csv, + options.lineSeparator, + options.fieldSeparator + ); + + return Object.fromEntries( + addresses + .map((address) => { + const checksum = getAddress(address); + + return [ + checksum, + parseFloat(formatUnits(result[checksum] || 0, options.decimals)) + ]; + }) + .filter((address) => address[1] > 0) + ); +} diff --git a/src/strategies/csv/schema.json b/src/strategies/csv/schema.json new file mode 100644 index 000000000..05e0e19e6 --- /dev/null +++ b/src/strategies/csv/schema.json @@ -0,0 +1,33 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "csv": { + "type": "string", + "title": "CSV file", + "examples": [ + "e.g. ipfs://bafkreig3xgt2j7mtcukqy5jglmxwlyy7unrqi2ncplgfnpq32aqomzbo4m" + ] + }, + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. UNI"], + "maxLength": 16 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 18"], + "minimum": 0 + } + }, + "required": ["csv", "decimals"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index a0d1981ab..abb8762c6 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -430,6 +430,7 @@ import * as quickswapv3 from './quickswap-v3'; import * as balanceOfWithBazaarBatchAuctionLinearVestingPower from './balance-of-with-bazaar-batch-auction-linear-vesting-power'; import * as stakingBalanceOfV1 from './staking-balance-of-v1'; import * as gardenStakes from './garden-stakes'; +import * as csv from './csv'; const strategies = { 'giveth-balances-supply-weighted': givethBalancesSupplyWeighted, @@ -870,7 +871,8 @@ const strategies = { balanceOfWithBazaarBatchAuctionLinearVestingPower, 'staking-balance-of-v1': stakingBalanceOfV1, 'staking-balance-of-v2': stakingBalanceOfV2, - 'garden-stakes': gardenStakes + 'garden-stakes': gardenStakes, + csv }; Object.keys(strategies).forEach(function (strategyName) { From 28bd4e1d574c59f8e5f409984549fc649aeb623c Mon Sep 17 00:00:00 2001 From: Nick Doherty Date: Wed, 26 Jun 2024 15:03:30 +1000 Subject: [PATCH 685/815] added the rocket-pool-node-operator-v4 strategy (#1516) --- src/strategies/index.ts | 2 + .../rocketpool-node-operator-v4/README.md | 13 ++++ .../rocketpool-node-operator-v4/examples.json | 24 ++++++++ .../rocketpool-node-operator-v4/index.ts | 61 +++++++++++++++++++ 4 files changed, 100 insertions(+) create mode 100644 src/strategies/rocketpool-node-operator-v4/README.md create mode 100644 src/strategies/rocketpool-node-operator-v4/examples.json create mode 100644 src/strategies/rocketpool-node-operator-v4/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index abb8762c6..c42c0a030 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -293,6 +293,7 @@ import * as auraBalanceOfSingleAsset from './aura-vault-balance-of-single-asset' import * as rocketpoolNodeOperator from './rocketpool-node-operator'; import * as rocketpoolNodeOperatorv2 from './rocketpool-node-operator-v2'; import * as rocketpoolNodeOperatorv3 from './rocketpool-node-operator-v3'; +import * as rocketpoolNodeOperatorv4 from './rocketpool-node-operator-v4'; import * as earthfundChildDaoStakingBalance from './earthfund-child-dao-staking-balance'; import * as unipilotVaultPilotBalance from './unipilot-vault-pilot-balance'; import * as sdBoostTWAVP from './sd-boost-twavp'; @@ -736,6 +737,7 @@ const strategies = { 'rocketpool-node-operator': rocketpoolNodeOperator, 'rocketpool-node-operator-v2': rocketpoolNodeOperatorv2, 'rocketpool-node-operator-v3': rocketpoolNodeOperatorv3, + 'rocketpool-node-operator-v4': rocketpoolNodeOperatorv4, 'earthfund-child-dao-staking-balance': earthfundChildDaoStakingBalance, 'sd-boost-twavp': sdBoostTWAVP, 'unipilot-vault-pilot-balance': unipilotVaultPilotBalance, diff --git a/src/strategies/rocketpool-node-operator-v4/README.md b/src/strategies/rocketpool-node-operator-v4/README.md new file mode 100644 index 000000000..de6248ff9 --- /dev/null +++ b/src/strategies/rocketpool-node-operator-v4/README.md @@ -0,0 +1,13 @@ +# rocketpool-node-operator-delegate-v4 + +This is a strategy for staking node operators, it returns the vote power for a node address. + +Here is an example of parameters: + +```json +{ + "address": "0xD33526068D116cE69F19A9ee46F0bd304F21A51f", + "symbol": "RPL", + "decimals": 18 +} +``` diff --git a/src/strategies/rocketpool-node-operator-v4/examples.json b/src/strategies/rocketpool-node-operator-v4/examples.json new file mode 100644 index 000000000..7764a225f --- /dev/null +++ b/src/strategies/rocketpool-node-operator-v4/examples.json @@ -0,0 +1,24 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "rocketpool-node-operator-v4", + "params": { + "address": "0xD33526068D116cE69F19A9ee46F0bd304F21A51f", + "symbol": "RPL", + "decimals": 18 + } + }, + "network": "1", + "addresses": [ + "0x7ba728C1D84c2313F319D267fD9847F2CEA8D758", + "0xC76DCF5ed10555C417d3c85aF987F2b7D2f63415", + "0xb74006917f66E4b7f005713f061d1f20Ef2A029C", + "0x3b6d43E181BeFCE59732De6098cADF7f35b97b1e", + "0xB0De8cB8Dcc8c5382c4b7F3E978b491140B2bC55", + "0x4F44C1226eb9d13ae5941dEd9cC1e6a4E099a68f", + "0x2d2BfE2389B7b3779fa04d101f75a89F6A62DcD6" + ], + "snapshot": 20172818 + } +] diff --git a/src/strategies/rocketpool-node-operator-v4/index.ts b/src/strategies/rocketpool-node-operator-v4/index.ts new file mode 100644 index 000000000..a8250cd26 --- /dev/null +++ b/src/strategies/rocketpool-node-operator-v4/index.ts @@ -0,0 +1,61 @@ +import { Multicaller } from '../../utils'; +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; + +export const author = 'rocket-pool'; +export const version = '0.1.4'; + +const rocketNetworkVoting = '0xA9d27E1952f742d659143a544d3e535fFf3Eebe1'; +const rocketNetworkVotingAbi = [ + 'function getVotingPower(address _nodeAddress, uint32 _block) external view returns (uint256)' +]; + + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + + const blockTag = typeof snapshot === 'number' ? snapshot : await provider.getBlockNumber(); + + const nodeVotingPower = new Multicaller( + network, + provider, + rocketNetworkVotingAbi, + { blockTag } + ); + + addresses.forEach((address) => { + nodeVotingPower.call(address, rocketNetworkVoting, 'getVotingPower', [ + address, + blockTag + ]); + }); + + const nodeVotingPowerResponse: Record = + await nodeVotingPower.execute(); + + const merged = addresses.map((address) => { + const votePower = nodeVotingPowerResponse[address]; + return { + address: address, + votePower: votePower, + }; + }); + + const reduced: Record = merged.reduce((acc, obj) => { + acc[obj.address] = obj.votePower; + return acc; + }, {}); + + return Object.fromEntries( + Object.entries(reduced).map(([address, votePower]) => [ + address, + parseFloat(formatUnits(votePower, options.decimals)) + ]) + ); +} From 0caa60089ff937de4c53c476a7cb9a2d4dc8ecd1 Mon Sep 17 00:00:00 2001 From: Nick Doherty Date: Wed, 26 Jun 2024 16:07:35 +1000 Subject: [PATCH 686/815] added the rocket-pool-node-operator-delegate-v4 strategy (#1518) --- src/strategies/index.ts | 2 + .../README.md | 13 ++++++ .../examples.json | 24 +++++++++++ .../index.ts | 43 +++++++++++++++++++ 4 files changed, 82 insertions(+) create mode 100644 src/strategies/rocketpool-node-operator-delegate-v4/README.md create mode 100644 src/strategies/rocketpool-node-operator-delegate-v4/examples.json create mode 100644 src/strategies/rocketpool-node-operator-delegate-v4/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index c42c0a030..86af2b48c 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -294,6 +294,7 @@ import * as rocketpoolNodeOperator from './rocketpool-node-operator'; import * as rocketpoolNodeOperatorv2 from './rocketpool-node-operator-v2'; import * as rocketpoolNodeOperatorv3 from './rocketpool-node-operator-v3'; import * as rocketpoolNodeOperatorv4 from './rocketpool-node-operator-v4'; +import * as rocketpoolNodeOperatorDelegatev4 from './rocketpool-node-operator-delegate-v4'; import * as earthfundChildDaoStakingBalance from './earthfund-child-dao-staking-balance'; import * as unipilotVaultPilotBalance from './unipilot-vault-pilot-balance'; import * as sdBoostTWAVP from './sd-boost-twavp'; @@ -738,6 +739,7 @@ const strategies = { 'rocketpool-node-operator-v2': rocketpoolNodeOperatorv2, 'rocketpool-node-operator-v3': rocketpoolNodeOperatorv3, 'rocketpool-node-operator-v4': rocketpoolNodeOperatorv4, + 'rocketpool-node-operator-delegate-v4': rocketpoolNodeOperatorDelegatev4, 'earthfund-child-dao-staking-balance': earthfundChildDaoStakingBalance, 'sd-boost-twavp': sdBoostTWAVP, 'unipilot-vault-pilot-balance': unipilotVaultPilotBalance, diff --git a/src/strategies/rocketpool-node-operator-delegate-v4/README.md b/src/strategies/rocketpool-node-operator-delegate-v4/README.md new file mode 100644 index 000000000..34216345c --- /dev/null +++ b/src/strategies/rocketpool-node-operator-delegate-v4/README.md @@ -0,0 +1,13 @@ +# rocketpool-node-operator-v4 + +This is a strategy for delegate node operators, it returns the delegated vote power for a node address. + +Here is an example of parameters: + +```json +{ + "address": "0xD33526068D116cE69F19A9ee46F0bd304F21A51f", + "symbol": "RPL", + "decimals": 18 +} +``` diff --git a/src/strategies/rocketpool-node-operator-delegate-v4/examples.json b/src/strategies/rocketpool-node-operator-delegate-v4/examples.json new file mode 100644 index 000000000..e904a601a --- /dev/null +++ b/src/strategies/rocketpool-node-operator-delegate-v4/examples.json @@ -0,0 +1,24 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "rocketpool-node-operator-delegate-v4", + "params": { + "address": "0xD33526068D116cE69F19A9ee46F0bd304F21A51f", + "symbol": "RPL", + "decimals": 18 + } + }, + "network": "1", + "addresses": [ + "0x7ba728C1D84c2313F319D267fD9847F2CEA8D758", + "0xC76DCF5ed10555C417d3c85aF987F2b7D2f63415", + "0xb74006917f66E4b7f005713f061d1f20Ef2A029C", + "0x3b6d43E181BeFCE59732De6098cADF7f35b97b1e", + "0xB0De8cB8Dcc8c5382c4b7F3E978b491140B2bC55", + "0x4F44C1226eb9d13ae5941dEd9cC1e6a4E099a68f", + "0x2d2BfE2389B7b3779fa04d101f75a89F6A62DcD6" + ], + "snapshot": 20172818 + } +] diff --git a/src/strategies/rocketpool-node-operator-delegate-v4/index.ts b/src/strategies/rocketpool-node-operator-delegate-v4/index.ts new file mode 100644 index 000000000..992700ee9 --- /dev/null +++ b/src/strategies/rocketpool-node-operator-delegate-v4/index.ts @@ -0,0 +1,43 @@ +import fetch from 'cross-fetch'; +import { getAddress } from '@ethersproject/address'; + +export const author = 'rocket-pool'; +export const version = '0.1.4'; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + console.log(blockTag); + + const req = await fetch( + 'https://api.rocketpool.net/mainnet/delegates/block/' + blockTag + ); + const resp = await req.json(); + + const reduced: Record = resp.reduce((acc, obj) => { + const address = getAddress(obj.address) + if (addresses.includes(address)) { + if (obj.delegators.length > 0) { + acc[address] = obj.votingPower; + } else { + acc[address] = '0'; + } + } + return acc; + }, {}); + + return Object.fromEntries( + Object.entries(reduced).map(([address, votePower]) => [ + address, + parseFloat(String(votePower)) + ]) + ); +} From 53d3e6de0ab43ff764ef08b054f190f37f4e3a53 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Thu, 27 Jun 2024 14:19:27 +0530 Subject: [PATCH 687/815] fix: Sushiswap subgraphs (#1519) * fix: Sushiswap subgraphs * fix lint --- .../index.ts | 3 +- .../rocketpool-node-operator-v4/index.ts | 7 ++- src/strategies/safe-vested/index.ts | 1 + src/strategies/sushiswap/index.ts | 48 +++++++++---------- 4 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/strategies/rocketpool-node-operator-delegate-v4/index.ts b/src/strategies/rocketpool-node-operator-delegate-v4/index.ts index 992700ee9..21673078d 100644 --- a/src/strategies/rocketpool-node-operator-delegate-v4/index.ts +++ b/src/strategies/rocketpool-node-operator-delegate-v4/index.ts @@ -12,7 +12,6 @@ export async function strategy( options, snapshot ): Promise> { - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; console.log(blockTag); @@ -23,7 +22,7 @@ export async function strategy( const resp = await req.json(); const reduced: Record = resp.reduce((acc, obj) => { - const address = getAddress(obj.address) + const address = getAddress(obj.address); if (addresses.includes(address)) { if (obj.delegators.length > 0) { acc[address] = obj.votingPower; diff --git a/src/strategies/rocketpool-node-operator-v4/index.ts b/src/strategies/rocketpool-node-operator-v4/index.ts index a8250cd26..7348e56c9 100644 --- a/src/strategies/rocketpool-node-operator-v4/index.ts +++ b/src/strategies/rocketpool-node-operator-v4/index.ts @@ -10,7 +10,6 @@ const rocketNetworkVotingAbi = [ 'function getVotingPower(address _nodeAddress, uint32 _block) external view returns (uint256)' ]; - export async function strategy( space, network, @@ -19,8 +18,8 @@ export async function strategy( options, snapshot ): Promise> { - - const blockTag = typeof snapshot === 'number' ? snapshot : await provider.getBlockNumber(); + const blockTag = + typeof snapshot === 'number' ? snapshot : await provider.getBlockNumber(); const nodeVotingPower = new Multicaller( network, @@ -43,7 +42,7 @@ export async function strategy( const votePower = nodeVotingPowerResponse[address]; return { address: address, - votePower: votePower, + votePower: votePower }; }); diff --git a/src/strategies/safe-vested/index.ts b/src/strategies/safe-vested/index.ts index 16673ffe6..129f4ce2a 100644 --- a/src/strategies/safe-vested/index.ts +++ b/src/strategies/safe-vested/index.ts @@ -88,6 +88,7 @@ export async function strategy( // Check vesting state, consider only unclaimed amounts and group allocations to the same account return Object.keys(vestings).reduce((result, key) => { // get it from the map by vestingId. A entry is guaranteed to exist + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const [{ account, amount }] = allocationMap[key]!; const hasAlreadyClaimed = vestings[key].account === account; diff --git a/src/strategies/sushiswap/index.ts b/src/strategies/sushiswap/index.ts index c840f3fad..83446e921 100644 --- a/src/strategies/sushiswap/index.ts +++ b/src/strategies/sushiswap/index.ts @@ -5,36 +5,36 @@ import { subgraphRequest } from '../../utils'; // Minichef: https://github.com/sushiswap/sushiswap-interface/blob/master/src/services/graph/fetchers/masterchef.ts // Exchange: https://github.com/sushiswap/sushiswap-interface/blob/master/src/services/graph/fetchers/exchange.ts -const theGraph_baseUrl = 'https://api.thegraph.com/subgraphs/name/'; +const theGraph_baseUrl = 'https://subgrapher.snapshot.org/subgraph/arbitrum/'; const SUSHISWAP_SUBGRAPH_URL = { exchange: { - '1': 'sushiswap/exchange', - '100': 'sushiswap/xdai-exchange', - '137': 'sushiswap/matic-exchange', - '250': 'sushiswap/fantom-exchange', - '42161': 'sushiswap/arbitrum-exchange', - '1285': 'sushiswap/moonriver-exchange', - '42220': 'jiro-ono/sushitestsubgraph', - '122': 'sushiswap/fuse-exchange', - '1666600000': 'sushiswap/harmony-exchange', - '56': 'sushiswap/bsc-exchange', - '43114': 'sushiswap/avalanche-exchange', - '66': 'okex-exchange/oec', - '128': 'heco-exchange/heco' + '1': '6NUtT5mGjZ1tSshKLf5Q3uEEJtjBZJo1TpL5MXsUBqrT', + '100': '4a8hcsttqsmycmmeFcpffGMZhBDU4NhHfyHH6YNcnu7b', + '137': '8NiXkxLRT3R22vpwLB4DXttpEf3X1LrKhe4T1tQ3jjbP', + '250': '3nozHyFKUhxnEvekFg5G57bxPC5V63eiWbwmgA35N5VK', + '42161': '8nFDCAhdnJQEhQF3ZRnfWkJ6FkRsfAiiVabVn4eGoAZH', + '1285': '5skUrJzgVm6vXAmdKN7gw4CjYx3pgLDeUeUqVzqLXkWT', + // '42220': 'jiro-ono/sushitestsubgraph', no upgraded subgraph + '122': 'BumyXJR9Cnzoy7nj4tbCsDwVe59e7ktXR1ELNjhEvimp', + '1666600000': 'FrcJBCCKCYGTLLXJmhppXfPKsNoyod4zqNLjHfXj1KHg', + '56': 'GPRigpbNuPkxkwpSbDuYXbikodNJfurc1LCENLzboWer', + '43114': '6VAhbtW5u2sPYkJKAcMsxgqTBu4a1rqmbiVQWgtNjrvT' + // '66': 'okex-exchange/oec', No subgraph + // '128': 'heco-exchange/heco' No subgraph }, masterChef: { - '1': 'sushiswap/master-chef', - '100': 'matthewlilley/xdai-minichef', // Could be replaced by 'sushiswap/xdai-minichef' - '137': 'sushiswap/matic-minichef', - '250': 'sushiswap/fantom-minichef', - '42161': 'matthewlilley/arbitrum-minichef', - '1285': 'sushiswap/moonriver-minichef', - '42220': 'sushiswap/celo-minichef-v2', - '122': 'sushiswap/fuse-minichef', - '1666600000': 'sushiswap/harmony-minichef' + '1': 'AkCK7BgZJHVwjDdxbnaER1e2XPpywnXVkVZV4p7QGnua', + // '100': 'matthewlilley/xdai-minichef', // Could be replaced by 'sushiswap/xdai-minichef' No upgraded subgraph + // '137': 'sushiswap/matic-minichef', No upgraded subgraph + '250': 'GJXdaT5S7BHvGNxJSLJsMH36tB4w3Z7eES6jSDJuqddg', + // '42161': 'matthewlilley/arbitrum-minichef', No upgraded subgraph + '1285': 'ExyevfNrFJ7EhTK74MDJ823h6oKkqUpwnVP1h3EuN8oa', + '42220': 'Aodb24RhU4p1p6p4ooq1Rwu5aVXhULAvXEGg8QEaPBvg', + '122': 'GdVirDDQ2fg43pjt2cZiH9Uar7bhGfySvm4jiQ9fVD4u' + // '1666600000': 'sushiswap/harmony-minichef' No Subgraph }, masterChefV2: { - '1': 'sushiswap/master-chefv2' + '1': 'FAa1YU79pPDUKj8vtkUPZGzCcPVS6Edg1md5LsRHSKWb' } }; From 3f72a900bc5b6d2cc7922ce2fc8f79b0319e953b Mon Sep 17 00:00:00 2001 From: Nick Doherty Date: Fri, 28 Jun 2024 16:49:34 +1000 Subject: [PATCH 688/815] added the rocket-pool-node-operator-delegate-v5 strategy (#1520) --- src/strategies/index.ts | 2 ++ .../README.md | 13 +++++++ .../examples.json | 25 ++++++++++++++ .../index.ts | 34 +++++++++++++++++++ 4 files changed, 74 insertions(+) create mode 100644 src/strategies/rocketpool-node-operator-delegate-v5/README.md create mode 100644 src/strategies/rocketpool-node-operator-delegate-v5/examples.json create mode 100644 src/strategies/rocketpool-node-operator-delegate-v5/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 86af2b48c..bc65c6828 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -295,6 +295,7 @@ import * as rocketpoolNodeOperatorv2 from './rocketpool-node-operator-v2'; import * as rocketpoolNodeOperatorv3 from './rocketpool-node-operator-v3'; import * as rocketpoolNodeOperatorv4 from './rocketpool-node-operator-v4'; import * as rocketpoolNodeOperatorDelegatev4 from './rocketpool-node-operator-delegate-v4'; +import * as rocketpoolNodeOperatorDelegatev5 from './rocketpool-node-operator-delegate-v5'; import * as earthfundChildDaoStakingBalance from './earthfund-child-dao-staking-balance'; import * as unipilotVaultPilotBalance from './unipilot-vault-pilot-balance'; import * as sdBoostTWAVP from './sd-boost-twavp'; @@ -740,6 +741,7 @@ const strategies = { 'rocketpool-node-operator-v3': rocketpoolNodeOperatorv3, 'rocketpool-node-operator-v4': rocketpoolNodeOperatorv4, 'rocketpool-node-operator-delegate-v4': rocketpoolNodeOperatorDelegatev4, + 'rocketpool-node-operator-delegate-v5': rocketpoolNodeOperatorDelegatev5, 'earthfund-child-dao-staking-balance': earthfundChildDaoStakingBalance, 'sd-boost-twavp': sdBoostTWAVP, 'unipilot-vault-pilot-balance': unipilotVaultPilotBalance, diff --git a/src/strategies/rocketpool-node-operator-delegate-v5/README.md b/src/strategies/rocketpool-node-operator-delegate-v5/README.md new file mode 100644 index 000000000..f6d09387e --- /dev/null +++ b/src/strategies/rocketpool-node-operator-delegate-v5/README.md @@ -0,0 +1,13 @@ +# rocketpool-node-operator-v5 + +This is a strategy for delegate node operators, it returns the delegated vote power for a node address. + +Here is an example of parameters: + +```json +{ + "address": "0xD33526068D116cE69F19A9ee46F0bd304F21A51f", + "symbol": "RPL", + "decimals": 18 +} +``` diff --git a/src/strategies/rocketpool-node-operator-delegate-v5/examples.json b/src/strategies/rocketpool-node-operator-delegate-v5/examples.json new file mode 100644 index 000000000..132bec866 --- /dev/null +++ b/src/strategies/rocketpool-node-operator-delegate-v5/examples.json @@ -0,0 +1,25 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "rocketpool-node-operator-delegate-v5", + "params": { + "address": "0xD33526068D116cE69F19A9ee46F0bd304F21A51f", + "symbol": "RPL", + "decimals": 18 + } + }, + "network": "1", + "addresses": [ + "0x7ba728C1D84c2313F319D267fD9847F2CEA8D758", + "0xC76DCF5ed10555C417d3c85aF987F2b7D2f63415", + "0xb74006917f66E4b7f005713f061d1f20Ef2A029C", + "0x3b6d43E181BeFCE59732De6098cADF7f35b97b1e", + "0xB0De8cB8Dcc8c5382c4b7F3E978b491140B2bC55", + "0x4F44C1226eb9d13ae5941dEd9cC1e6a4E099a68f", + "0x2d2BfE2389B7b3779fa04d101f75a89F6A62DcD6", + "0x0c60ee56a4cd2df657fe5387b5c2f468bb9abfff" + ], + "snapshot": 20187335 + } +] diff --git a/src/strategies/rocketpool-node-operator-delegate-v5/index.ts b/src/strategies/rocketpool-node-operator-delegate-v5/index.ts new file mode 100644 index 000000000..a3e93fbf6 --- /dev/null +++ b/src/strategies/rocketpool-node-operator-delegate-v5/index.ts @@ -0,0 +1,34 @@ +import fetch from 'cross-fetch'; +import { getAddress } from '@ethersproject/address'; + +export const author = 'rocket-pool'; +export const version = '0.1.4'; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const req = await fetch( + 'https://api.rocketpool.net/mainnet/delegates/block/' + blockTag + ); + const resp = await req.json(); + + const reduced: Record = resp.reduce((acc, obj) => { + const address = getAddress(obj.address); + acc[address] = obj.votingPower; + return acc; + }, {}); + + return Object.fromEntries( + Object.entries(reduced).map(([address, votePower]) => [ + address, + parseFloat(String(votePower)) + ]) + ); +} From f02b6730e34e7cd0bd857e38c6834f69f4dfc3cb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 29 Jun 2024 12:41:19 +0530 Subject: [PATCH 689/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.38 (#1510) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index e1b235a10..1b5bef425 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.36", + "@snapshot-labs/snapshot.js": "^0.11.38", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index c6d726e69..a90c8f490 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.36": - version "0.11.36" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.36.tgz#77f87a5315bf43043b0f64bb45c83def90682379" - integrity sha512-X2Q3WvEEctDSIdmachEXdOq1f6fhmmE4WYlxjZjbpuVPeR8ZfDzevnaGV4mzVSC1U8AHS4z/M2Ndtyl0LE7Cdg== +"@snapshot-labs/snapshot.js@^0.11.38": + version "0.11.38" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.38.tgz#bc7e35b6cf5df056ebdb474ef77e851a209b1bab" + integrity sha512-Pkiz+7uo5WAGKKJryT1ZyDY5we3QRVGLwQQGV6RDYLto1EmHGu1pEUX2AN/UUXnRzu7b+SPOynjBkAbJLZZq3A== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 3ddcca382f545c877f2a3e4cae2665b77c772450 Mon Sep 17 00:00:00 2001 From: Nick Doherty Date: Fri, 5 Jul 2024 14:50:15 +1000 Subject: [PATCH 690/815] added the rocket-pool-node-operator-delegate-v6 strategy (#1521) --- src/strategies/index.ts | 2 + .../README.md | 13 ++++ .../examples.json | 25 ++++++++ .../index.ts | 63 +++++++++++++++++++ 4 files changed, 103 insertions(+) create mode 100644 src/strategies/rocketpool-node-operator-delegate-v6/README.md create mode 100644 src/strategies/rocketpool-node-operator-delegate-v6/examples.json create mode 100644 src/strategies/rocketpool-node-operator-delegate-v6/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index bc65c6828..f59629afa 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -296,6 +296,7 @@ import * as rocketpoolNodeOperatorv3 from './rocketpool-node-operator-v3'; import * as rocketpoolNodeOperatorv4 from './rocketpool-node-operator-v4'; import * as rocketpoolNodeOperatorDelegatev4 from './rocketpool-node-operator-delegate-v4'; import * as rocketpoolNodeOperatorDelegatev5 from './rocketpool-node-operator-delegate-v5'; +import * as rocketpoolNodeOperatorDelegatev6 from './rocketpool-node-operator-delegate-v6'; import * as earthfundChildDaoStakingBalance from './earthfund-child-dao-staking-balance'; import * as unipilotVaultPilotBalance from './unipilot-vault-pilot-balance'; import * as sdBoostTWAVP from './sd-boost-twavp'; @@ -742,6 +743,7 @@ const strategies = { 'rocketpool-node-operator-v4': rocketpoolNodeOperatorv4, 'rocketpool-node-operator-delegate-v4': rocketpoolNodeOperatorDelegatev4, 'rocketpool-node-operator-delegate-v5': rocketpoolNodeOperatorDelegatev5, + 'rocketpool-node-operator-delegate-v6': rocketpoolNodeOperatorDelegatev6, 'earthfund-child-dao-staking-balance': earthfundChildDaoStakingBalance, 'sd-boost-twavp': sdBoostTWAVP, 'unipilot-vault-pilot-balance': unipilotVaultPilotBalance, diff --git a/src/strategies/rocketpool-node-operator-delegate-v6/README.md b/src/strategies/rocketpool-node-operator-delegate-v6/README.md new file mode 100644 index 000000000..29002562b --- /dev/null +++ b/src/strategies/rocketpool-node-operator-delegate-v6/README.md @@ -0,0 +1,13 @@ +# rocketpool-node-operator-v5 + +This is a strategy for delegate node operators, it returns the delegated vote power for a node address given a signalling address. + +Here is an example of parameters: + +```json +{ + "address": "0xD33526068D116cE69F19A9ee46F0bd304F21A51f", + "symbol": "RPL", + "decimals": 18 +} +``` diff --git a/src/strategies/rocketpool-node-operator-delegate-v6/examples.json b/src/strategies/rocketpool-node-operator-delegate-v6/examples.json new file mode 100644 index 000000000..b2357829b --- /dev/null +++ b/src/strategies/rocketpool-node-operator-delegate-v6/examples.json @@ -0,0 +1,25 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "rocketpool-node-operator-delegate-v6", + "params": { + "address": "0xD33526068D116cE69F19A9ee46F0bd304F21A51f", + "symbol": "RPL", + "decimals": 18 + } + }, + "network": "1", + "addresses": [ + "0x6212Ee7822265cE44B56C943bFd4bCcc03AeC42A", + "0x291BFc5E578aEdFBE4b4A86d6188E99391BC30Fa", + "0x27108a00Aa686c79fB15c79Fca4B312030cEFb24", + "0xB0De8cB8Dcc8c5382c4b7F3E978b491140B2bC55", + "0x439B5eEa6dD4745d575ADa1ED7d682c723829b7D", + "0x9ec255F1AF4D3e4a813AadAB8ff0497398037d56", + "0x9Be85faBd144bCa1aCdF2b5E074cFbFBEB2855a3", + "0x166C58AC1907e2c4b24717DD52683A88E7123AbA" + ], + "snapshot": 20210904 + } +] diff --git a/src/strategies/rocketpool-node-operator-delegate-v6/index.ts b/src/strategies/rocketpool-node-operator-delegate-v6/index.ts new file mode 100644 index 000000000..e13317a12 --- /dev/null +++ b/src/strategies/rocketpool-node-operator-delegate-v6/index.ts @@ -0,0 +1,63 @@ +import fetch from 'cross-fetch'; +import { getAddress } from '@ethersproject/address'; +import { Multicaller } from '../../utils'; + +export const author = 'rocket-pool'; +export const version = '0.1.4'; + +const signerRegistryContractAddress = '0xc1062617d10Ae99E09D941b60746182A87eAB38F'; +const signerRegistryAbi = [ + 'function signerToNode(address) external view returns (address)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const req = await fetch( + 'https://api.rocketpool.net/mainnet/delegates/block/' + blockTag + ); + const resp = await req.json(); + + const signerRegistry = new Multicaller( + network, + provider, + signerRegistryAbi, + { blockTag } + ); + + addresses.forEach((address) => { + signerRegistry.call(address, signerRegistryContractAddress, 'signerToNode', [address]); + }); + + const signerRegistryResponse: Record = + await signerRegistry.execute(); + + const nodeData = addresses.map((address) => { + const nodeAddress = getAddress(signerRegistryResponse[address]); + const node = resp.find((obj) => getAddress(obj.address) === getAddress(nodeAddress)); + return { + address: address, + votingPower: node ? node.votingPower : 0 + }; + }); + + const reduced: Record = nodeData.reduce((acc, obj) => { + const address = getAddress(obj.address); + acc[address] = obj.votingPower; + return acc; + }, {}); + + return Object.fromEntries( + Object.entries(reduced).map(([address, votePower]) => [ + address, + parseFloat(String(votePower)) + ]) + ); +} From 9017fedc433c32f2f6d7ac58a446dbfb63fcfa9e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 7 Jul 2024 19:30:18 +0530 Subject: [PATCH 691/815] Automated lint (#1522) Co-authored-by: ChaituVR --- .../index.ts | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/strategies/rocketpool-node-operator-delegate-v6/index.ts b/src/strategies/rocketpool-node-operator-delegate-v6/index.ts index e13317a12..397946d4f 100644 --- a/src/strategies/rocketpool-node-operator-delegate-v6/index.ts +++ b/src/strategies/rocketpool-node-operator-delegate-v6/index.ts @@ -5,7 +5,8 @@ import { Multicaller } from '../../utils'; export const author = 'rocket-pool'; export const version = '0.1.4'; -const signerRegistryContractAddress = '0xc1062617d10Ae99E09D941b60746182A87eAB38F'; +const signerRegistryContractAddress = + '0xc1062617d10Ae99E09D941b60746182A87eAB38F'; const signerRegistryAbi = [ 'function signerToNode(address) external view returns (address)' ]; @@ -25,15 +26,17 @@ export async function strategy( ); const resp = await req.json(); - const signerRegistry = new Multicaller( - network, - provider, - signerRegistryAbi, - { blockTag } - ); + const signerRegistry = new Multicaller(network, provider, signerRegistryAbi, { + blockTag + }); addresses.forEach((address) => { - signerRegistry.call(address, signerRegistryContractAddress, 'signerToNode', [address]); + signerRegistry.call( + address, + signerRegistryContractAddress, + 'signerToNode', + [address] + ); }); const signerRegistryResponse: Record = @@ -41,7 +44,9 @@ export async function strategy( const nodeData = addresses.map((address) => { const nodeAddress = getAddress(signerRegistryResponse[address]); - const node = resp.find((obj) => getAddress(obj.address) === getAddress(nodeAddress)); + const node = resp.find( + (obj) => getAddress(obj.address) === getAddress(nodeAddress) + ); return { address: address, votingPower: node ? node.votingPower : 0 From 94f425eeccef58d8a50b9c558839a03f56cace2a Mon Sep 17 00:00:00 2001 From: bogdan <35818861+UnnaturalCabbage@users.noreply.github.com> Date: Mon, 8 Jul 2024 19:44:02 +0200 Subject: [PATCH 692/815] [swarm-stacking] new strategy (#1523) * [swarm-stacking] new strategy * [swarm-stacking] refact: readme, rename vars * [swarm-stacking] fix: increase graph limit * [swarm-stacking] fix: unnecessary map * [swarm-stacking] refact: rename author * [swarm-stacking] fix: lint errors --- src/strategies/index.ts | 4 +- src/strategies/swarm-stacking/README.md | 5 ++ src/strategies/swarm-stacking/examples.json | 22 ++++++ src/strategies/swarm-stacking/index.ts | 88 +++++++++++++++++++++ src/strategies/swarm-stacking/schema.json | 13 +++ 5 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 src/strategies/swarm-stacking/README.md create mode 100644 src/strategies/swarm-stacking/examples.json create mode 100644 src/strategies/swarm-stacking/index.ts create mode 100644 src/strategies/swarm-stacking/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index f59629afa..216ec8fa9 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -435,6 +435,7 @@ import * as balanceOfWithBazaarBatchAuctionLinearVestingPower from './balance-of import * as stakingBalanceOfV1 from './staking-balance-of-v1'; import * as gardenStakes from './garden-stakes'; import * as csv from './csv'; +import * as swarmStacking from './swarm-stacking'; const strategies = { 'giveth-balances-supply-weighted': givethBalancesSupplyWeighted, @@ -880,7 +881,8 @@ const strategies = { 'staking-balance-of-v1': stakingBalanceOfV1, 'staking-balance-of-v2': stakingBalanceOfV2, 'garden-stakes': gardenStakes, - csv + csv, + 'swarm-stacking': swarmStacking }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/swarm-stacking/README.md b/src/strategies/swarm-stacking/README.md new file mode 100644 index 000000000..3f5a097dd --- /dev/null +++ b/src/strategies/swarm-stacking/README.md @@ -0,0 +1,5 @@ +# swarm-stacking + +This a strategory for counting SMT tokens per user inside Swarm Stacking platform + +No parameters required, works specifically for Swarm Stacking so network (polygon) and decimals (18) are hardcoded diff --git a/src/strategies/swarm-stacking/examples.json b/src/strategies/swarm-stacking/examples.json new file mode 100644 index 000000000..04806eabb --- /dev/null +++ b/src/strategies/swarm-stacking/examples.json @@ -0,0 +1,22 @@ +[ + { + "name": "Swarm Stacking", + "strategy": { + "name": "swarm-stacking", + "params": {} + }, + "network": "137", + "addresses": [ + "0x3DF51013b9080786A374E2980dd1dA88B0B99177", + "0x3d17ca0f85d8c83a9daaae8ce4c8ecd7b6f5120e", + "0xe8b4a59067e510d67e72f6fac29620fea03c5c8b", + "0x8668936dc604bbbdd30600dd78623e64fdc1577b", + "0xb6a2efec3ac82531355dc0256a53f0d2c183e01f", + "0xc98cc732a8ad9735cfdbf594f50207b92c694466", + "0x720b587e8759f9310d973faee853af5b34ab01e6", + "0x993627ca9fd5a926c08414e1a24ee81910ec4e6c", + "0x993627ca9fd5a926c08414e1a24ee81910ec4e6c" + ], + "snapshot": 59108341 + } +] diff --git a/src/strategies/swarm-stacking/index.ts b/src/strategies/swarm-stacking/index.ts new file mode 100644 index 000000000..d49c7d76c --- /dev/null +++ b/src/strategies/swarm-stacking/index.ts @@ -0,0 +1,88 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { subgraphRequest } from '../../utils'; +import { getAddress } from '@ethersproject/address'; + +export const author = 'SwarmMarkets'; +export const version = '1.0.0'; + +// 137 - Polygon network number +const SUBGRAPH_URL = { + 137: 'https://gateway-arbitrum.network.thegraph.com/api/2e2730968289f9eb3287cd3f1991a957/deployments/id/QmbcvkW34SqmJLCaUB1GHkx61bFV7bSy2BHhzb3xuNTJhN' +}; +const SMT_TOKEN_DECIMALS = 18; + +interface SwarmStake { + id: string; + maker: string; + stakedAmount: string; +} +async function getSwarmStakes( + network: number | string, + snapshot: number | string, + addresses: string[] +): Promise { + const url = SUBGRAPH_URL[network]; + const query = { + swarmStakes: { + __args: { + first: 1000, + where: { + maker_in: addresses, + unstaked: false + }, + // target specific snapshot of the network + ...(typeof snapshot === 'number' && { + block: { + number: snapshot + } + }) + }, + id: true, + maker: true, + stakedAmount: true + } + }; + const res = await subgraphRequest(url, query); + return res.swarmStakes; +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const allStakes = await getSwarmStakes(network, snapshot, addresses); + + const stakesByMaker = allStakes.reduce>( + (acc, stake) => { + const makerStakes = acc.get(stake.maker) || []; + makerStakes.push(stake); + acc.set(stake.maker, makerStakes); + return acc; + }, + new Map() + ); + + const makersTokenAmount: Map = new Map(); + stakesByMaker.forEach((stakes, maker) => { + const bigTotalAmount: BigNumber = stakes.reduce( + (acc, stake) => acc.add(BigNumber.from(stake.stakedAmount)), + BigNumber.from(0) + ); + const totalAmount = parseFloat( + formatUnits(bigTotalAmount, SMT_TOKEN_DECIMALS) + ); + makersTokenAmount.set(maker, totalAmount); + }); + + const results = Object.fromEntries( + [...makersTokenAmount.entries()].map(([maker, amount]) => { + return [getAddress(maker), amount]; // checksum all addresses + }) + ); + return results; +} diff --git a/src/strategies/swarm-stacking/schema.json b/src/strategies/swarm-stacking/schema.json new file mode 100644 index 000000000..8eb7ce143 --- /dev/null +++ b/src/strategies/swarm-stacking/schema.json @@ -0,0 +1,13 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + } + } +} From 6d5d5e8f3b585d0b706b402ff8419a670bac5d13 Mon Sep 17 00:00:00 2001 From: bogdan <35818861+UnnaturalCabbage@users.noreply.github.com> Date: Tue, 9 Jul 2024 13:13:45 +0200 Subject: [PATCH 693/815] [swarm-staking] Fix type "staCking" -> (#1524) * [swarm-stacking] new strategy * [swarm-stacking] refact: readme, rename vars * [swarm-stacking] fix: increase graph limit * [swarm-stacking] fix: unnecessary map * [swarm-stacking] refact: rename author * [swarm-stacking] fix: lint errors * [swarm-staking] refact: fix typo stack->stak * [swarm-staking] remove unsued files --- src/strategies/index.ts | 4 ++-- src/strategies/swarm-stacking/README.md | 5 ----- src/strategies/swarm-staking/README.md | 5 +++++ .../{swarm-stacking => swarm-staking}/examples.json | 4 ++-- src/strategies/{swarm-stacking => swarm-staking}/index.ts | 0 src/strategies/{swarm-stacking => swarm-staking}/schema.json | 0 6 files changed, 9 insertions(+), 9 deletions(-) delete mode 100644 src/strategies/swarm-stacking/README.md create mode 100644 src/strategies/swarm-staking/README.md rename src/strategies/{swarm-stacking => swarm-staking}/examples.json (90%) rename src/strategies/{swarm-stacking => swarm-staking}/index.ts (100%) rename src/strategies/{swarm-stacking => swarm-staking}/schema.json (100%) diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 216ec8fa9..ff09c6696 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -435,7 +435,7 @@ import * as balanceOfWithBazaarBatchAuctionLinearVestingPower from './balance-of import * as stakingBalanceOfV1 from './staking-balance-of-v1'; import * as gardenStakes from './garden-stakes'; import * as csv from './csv'; -import * as swarmStacking from './swarm-stacking'; +import * as swarmStaking from './swarm-staking'; const strategies = { 'giveth-balances-supply-weighted': givethBalancesSupplyWeighted, @@ -882,7 +882,7 @@ const strategies = { 'staking-balance-of-v2': stakingBalanceOfV2, 'garden-stakes': gardenStakes, csv, - 'swarm-stacking': swarmStacking + 'swarm-staking': swarmStaking }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/swarm-stacking/README.md b/src/strategies/swarm-stacking/README.md deleted file mode 100644 index 3f5a097dd..000000000 --- a/src/strategies/swarm-stacking/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# swarm-stacking - -This a strategory for counting SMT tokens per user inside Swarm Stacking platform - -No parameters required, works specifically for Swarm Stacking so network (polygon) and decimals (18) are hardcoded diff --git a/src/strategies/swarm-staking/README.md b/src/strategies/swarm-staking/README.md new file mode 100644 index 000000000..72f28953d --- /dev/null +++ b/src/strategies/swarm-staking/README.md @@ -0,0 +1,5 @@ +# swarm-staking + +This a strategory for counting SMT tokens per user inside Swarm Staking platform + +No parameters required, works specifically for Swarm Staking so network (polygon) and decimals (18) are hardcoded diff --git a/src/strategies/swarm-stacking/examples.json b/src/strategies/swarm-staking/examples.json similarity index 90% rename from src/strategies/swarm-stacking/examples.json rename to src/strategies/swarm-staking/examples.json index 04806eabb..dc484fe95 100644 --- a/src/strategies/swarm-stacking/examples.json +++ b/src/strategies/swarm-staking/examples.json @@ -1,8 +1,8 @@ [ { - "name": "Swarm Stacking", + "name": "Swarm Staking", "strategy": { - "name": "swarm-stacking", + "name": "swarm-staking", "params": {} }, "network": "137", diff --git a/src/strategies/swarm-stacking/index.ts b/src/strategies/swarm-staking/index.ts similarity index 100% rename from src/strategies/swarm-stacking/index.ts rename to src/strategies/swarm-staking/index.ts diff --git a/src/strategies/swarm-stacking/schema.json b/src/strategies/swarm-staking/schema.json similarity index 100% rename from src/strategies/swarm-stacking/schema.json rename to src/strategies/swarm-staking/schema.json From 413a6d833c53ff1c0b4da4841e8037b9c5a70dfe Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 11 Jul 2024 19:30:42 +0530 Subject: [PATCH 694/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.39 (#1525) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 1b5bef425..6e7a84d52 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.38", + "@snapshot-labs/snapshot.js": "^0.11.39", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index a90c8f490..1ba8403df 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.38": - version "0.11.38" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.38.tgz#bc7e35b6cf5df056ebdb474ef77e851a209b1bab" - integrity sha512-Pkiz+7uo5WAGKKJryT1ZyDY5we3QRVGLwQQGV6RDYLto1EmHGu1pEUX2AN/UUXnRzu7b+SPOynjBkAbJLZZq3A== +"@snapshot-labs/snapshot.js@^0.11.39": + version "0.11.39" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.39.tgz#23ed63f17c0eaf79ce99cc9817dfac7c2ad41cfc" + integrity sha512-Wy2v75f7g1IOn0d75hBnqRmekUzlWO+6ijGPyLSyQSnlsHlRIaqP+su1C/g9otkjCGq2dEFPp0PvTEGmCcT3kA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 8f935995bec41b56bceb5b7e21af0c85c95b11ef Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 12 Jul 2024 08:54:01 +0530 Subject: [PATCH 695/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.40 (#1526) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 6e7a84d52..6cceafbdb 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.39", + "@snapshot-labs/snapshot.js": "^0.11.40", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 1ba8403df..fcf4c71fe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.39": - version "0.11.39" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.39.tgz#23ed63f17c0eaf79ce99cc9817dfac7c2ad41cfc" - integrity sha512-Wy2v75f7g1IOn0d75hBnqRmekUzlWO+6ijGPyLSyQSnlsHlRIaqP+su1C/g9otkjCGq2dEFPp0PvTEGmCcT3kA== +"@snapshot-labs/snapshot.js@^0.11.40": + version "0.11.40" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.40.tgz#549be4207b5bd34d4d4164726ca3d7a119fa21ad" + integrity sha512-sleGyY4yrdB2rZ9Wq2U/q5oqlUZsMXjynG3ALRTYGIai6j9d9V4yKk4jxst2HONFIUYqd/W6YkqBzJ1FhXZl8w== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 5ec57b8a2dbf3dac6339ce9687b730e819544801 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 12 Jul 2024 12:19:29 +0530 Subject: [PATCH 696/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.11.41 (#1527) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 6cceafbdb..d3471a6b9 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.40", + "@snapshot-labs/snapshot.js": "^0.11.41", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index fcf4c71fe..51f594765 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,10 +1184,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.40": - version "0.11.40" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.40.tgz#549be4207b5bd34d4d4164726ca3d7a119fa21ad" - integrity sha512-sleGyY4yrdB2rZ9Wq2U/q5oqlUZsMXjynG3ALRTYGIai6j9d9V4yKk4jxst2HONFIUYqd/W6YkqBzJ1FhXZl8w== +"@snapshot-labs/snapshot.js@^0.11.41": + version "0.11.41" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.41.tgz#9a19b815d7880bab9008fba595cac707116cb256" + integrity sha512-R9aTHvHcHqLPkkf6Yi+5uHVf/wxgmwvUviWG92zlosZ62uXudhtJ8nlWhcUEjrDrnIZIEbaJ0Ge3vXyyvGc4tQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From f66466251cd11c871260965d7514fdf56491f867 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Mon, 15 Jul 2024 09:57:23 +0530 Subject: [PATCH 697/815] fix: Poap xdai subgraph (#1528) --- src/strategies/poap/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/strategies/poap/index.ts b/src/strategies/poap/index.ts index 5b6b99f02..f350889c7 100644 --- a/src/strategies/poap/index.ts +++ b/src/strategies/poap/index.ts @@ -9,7 +9,8 @@ export const version = '1.2.0'; const EVENT_IDS_LIMIT = 500; const POAP_API_ENDPOINT_URL = { '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/HuioMeA9oSgs2vkBUQvhfxN9jhkBayadi1tmvKN3KG4s', - '100': 'https://api.thegraph.com/subgraphs/name/poap-xyz/poap-xdai' + '100': + 'https://subgrapher.snapshot.org/subgraph/arbitrum/DWkA5Rpw4z11TXr6DawquZJeXasF4CfyeQy1S2jxCXLH' }; // subgraph query in filter has max length of 500 const MAX_ACCOUNTS_IN_QUERY = 500; From 040663209137776911bdd7dc052f47ddcefa5d41 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 15 Jul 2024 18:24:09 +0530 Subject: [PATCH 698/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.0 (#1530) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 240 +++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 236 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index d3471a6b9..1d7839930 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.11.41", + "@snapshot-labs/snapshot.js": "^0.12.0", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 51f594765..db316b78e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1134,6 +1134,18 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@noble/curves@~1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.3.0.tgz#01be46da4fd195822dab821e72f71bf4aeec635e" + integrity sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA== + dependencies: + "@noble/hashes" "1.3.3" + +"@noble/hashes@1.3.3", "@noble/hashes@~1.3.3": + version "1.3.3" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699" + integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA== + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -1165,6 +1177,49 @@ resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.4.2-solc-0.7.tgz#38f4dbab672631034076ccdf2f3201fab1726635" integrity sha512-W6QmqgkADuFcTLzHL8vVoNBtkwjvQRpYIAom7KiUNoLKghyx3FgH0GBjt8NRvigV1ZmMOBllvE1By1C+bi8WpA== +"@rometools/cli-darwin-arm64@12.1.3": + version "12.1.3" + resolved "https://registry.yarnpkg.com/@rometools/cli-darwin-arm64/-/cli-darwin-arm64-12.1.3.tgz#b00fe225e34047c4dac63588e237b11ebec47694" + integrity sha512-AmFTUDYjBuEGQp/Wwps+2cqUr+qhR7gyXAUnkL5psCuNCz3807TrUq/ecOoct5MIavGJTH6R4aaSL6+f+VlBEg== + +"@rometools/cli-darwin-x64@12.1.3": + version "12.1.3" + resolved "https://registry.yarnpkg.com/@rometools/cli-darwin-x64/-/cli-darwin-x64-12.1.3.tgz#e5bbf02afb1aab7447e743092245dea992b4b29f" + integrity sha512-k8MbWna8q4LRlb005N2X+JS1UQ+s3ZLBBvwk4fP8TBxlAJXUz17jLLu/Fi+7DTTEmMhM84TWj4FDKW+rNar28g== + +"@rometools/cli-linux-arm64@12.1.3": + version "12.1.3" + resolved "https://registry.yarnpkg.com/@rometools/cli-linux-arm64/-/cli-linux-arm64-12.1.3.tgz#e75b01b74c134edc811e21fa7e1e440602930d59" + integrity sha512-X/uLhJ2/FNA3nu5TiyeNPqiD3OZoFfNfRvw6a3ut0jEREPvEn72NI7WPijH/gxSz55znfQ7UQ6iM4DZumUknJg== + +"@rometools/cli-linux-x64@12.1.3": + version "12.1.3" + resolved "https://registry.yarnpkg.com/@rometools/cli-linux-x64/-/cli-linux-x64-12.1.3.tgz#2b9f4a68079783f275d4d27df83e4fa2220ec6fc" + integrity sha512-csP17q1eWiUXx9z6Jr/JJPibkplyKIwiWPYNzvPCGE8pHlKhwZj3YHRuu7Dm/4EOqx0XFIuqqWZUYm9bkIC8xg== + +"@rometools/cli-win32-arm64@12.1.3": + version "12.1.3" + resolved "https://registry.yarnpkg.com/@rometools/cli-win32-arm64/-/cli-win32-arm64-12.1.3.tgz#714acb67ac4ea4c15e2bc6aea4dd290c76c8efc6" + integrity sha512-RymHWeod57EBOJY4P636CgUwYA6BQdkQjh56XKk4pLEHO6X1bFyMet2XL7KlHw5qOTalzuzf5jJqUs+vf3jdXQ== + +"@rometools/cli-win32-x64@12.1.3": + version "12.1.3" + resolved "https://registry.yarnpkg.com/@rometools/cli-win32-x64/-/cli-win32-x64-12.1.3.tgz#b4f53491d2ca8f1234b3613b7cc73418ad8d76bb" + integrity sha512-yHSKYidqJMV9nADqg78GYA+cZ0hS1twANAjiFibQdXj9aGzD+s/IzIFEIi/U/OBLvWYg/SCw0QVozi2vTlKFDQ== + +"@scure/base@~1.1.3": + version "1.1.7" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.7.tgz#fe973311a5c6267846aa131bc72e96c5d40d2b30" + integrity sha512-PPNYBslrLNNUQ/Yad37MHYsNQtK67EhWb6WtSvNLLPo7SdVZgkUjD6Dg+5On7zNwmskf8OX7I7Nx5oN+MIWE0g== + +"@scure/starknet@~1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@scure/starknet/-/starknet-1.0.0.tgz#4419bc2fdf70f3dd6cb461d36c878c9ef4419f8c" + integrity sha512-o5J57zY0f+2IL/mq8+AYJJ4Xpc1fOtDhr+mFQKbHnYFmm3WQrC+8zj2HEgxak1a+x86mhmBC1Kq305KUpVf0wg== + dependencies: + "@noble/curves" "~1.3.0" + "@noble/hashes" "~1.3.3" + "@sinclair/typebox@^0.25.16": version "0.25.24" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.24.tgz#8c7688559979f7079aacaf31aa881c3aa410b718" @@ -1184,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.11.41": - version "0.11.41" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.11.41.tgz#9a19b815d7880bab9008fba595cac707116cb256" - integrity sha512-R9aTHvHcHqLPkkf6Yi+5uHVf/wxgmwvUviWG92zlosZ62uXudhtJ8nlWhcUEjrDrnIZIEbaJ0Ge3vXyyvGc4tQ== +"@snapshot-labs/snapshot.js@^0.12.0": + version "0.12.0" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.0.tgz#f68b701cd6806fc4d0fa207d31f1c5491dc9ba6e" + integrity sha512-DYgF0oXTz51Gh9tHXXT9mLUzuuYYmhCIVMV/1imu7RH/Cnm7Nmx2BvuBdyjHsCg8nhLrMw7hgVCibIcBWjYdBQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" @@ -1204,6 +1259,7 @@ cross-fetch "^3.1.6" json-to-graphql-query "^2.2.4" lodash.set "^4.3.2" + starknet "^5.24.3" "@spruceid/didkit-wasm-node@^0.2.1": version "0.2.1" @@ -1473,6 +1529,38 @@ "@uniswap/v3-core" "1.0.0" "@uniswap/v3-periphery" "^1.0.1" +"abi-wan-kanabi-v1@npm:abi-wan-kanabi@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/abi-wan-kanabi/-/abi-wan-kanabi-1.0.3.tgz#0d8607f2a2ccb2151a69debea1c3bb68b76c5aa2" + integrity sha512-Xwva0AnhXx/IVlzo3/kwkI7Oa7ZX7codtcSn+Gmoa2PmjGPF/0jeVud9puasIPtB7V50+uBdUj4Mh3iATqtBvg== + dependencies: + abi-wan-kanabi "^1.0.1" + fs-extra "^10.0.0" + rome "^12.1.3" + typescript "^4.9.5" + yargs "^17.7.2" + +"abi-wan-kanabi-v2@npm:abi-wan-kanabi@^2.1.1": + version "2.2.2" + resolved "https://registry.yarnpkg.com/abi-wan-kanabi/-/abi-wan-kanabi-2.2.2.tgz#82c48e8fa08d9016cf92d3d81d494cc60e934693" + integrity sha512-sTCv2HyNIj1x2WFUoc9oL8ZT9liosrL+GoqEGZJK1kDND096CfA7lwx06vLxLWMocQ41FQXO3oliwoh/UZHYdQ== + dependencies: + ansicolors "^0.3.2" + cardinal "^2.1.1" + fs-extra "^10.0.0" + yargs "^17.7.2" + +abi-wan-kanabi@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/abi-wan-kanabi/-/abi-wan-kanabi-1.0.3.tgz#0d8607f2a2ccb2151a69debea1c3bb68b76c5aa2" + integrity sha512-Xwva0AnhXx/IVlzo3/kwkI7Oa7ZX7codtcSn+Gmoa2PmjGPF/0jeVud9puasIPtB7V50+uBdUj4Mh3iATqtBvg== + dependencies: + abi-wan-kanabi "^1.0.1" + fs-extra "^10.0.0" + rome "^12.1.3" + typescript "^4.9.5" + yargs "^17.7.2" + acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" @@ -1551,6 +1639,11 @@ ansi-styles@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== +ansicolors@^0.3.2, ansicolors@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" + integrity sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg== + anymatch@^3.0.3, anymatch@~3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" @@ -1787,6 +1880,14 @@ caniuse-lite@^1.0.30001349: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001357.tgz#dec7fc4158ef6ad24690d0eec7b91f32b8cb1b5d" integrity sha512-b+KbWHdHePp+ZpNj+RDHFChZmuN+J5EvuQUlee9jOQIUAdhv9uvAZeEtUeLAknXbkiu1uxjQ9NLp1ie894CuWg== +cardinal@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/cardinal/-/cardinal-2.1.1.tgz#7cc1055d822d212954d07b085dea251cc7bc5505" + integrity sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw== + dependencies: + ansicolors "~0.3.2" + redeyed "~2.1.0" + chalk@^2.0.0: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -1843,6 +1944,15 @@ cliui@^7.0.2: strip-ansi "^6.0.0" wrap-ansi "^7.0.0" +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -2259,7 +2369,7 @@ espree@^9.3.2: acorn-jsx "^5.3.2" eslint-visitor-keys "^3.3.0" -esprima@^4.0.0: +esprima@^4.0.0, esprima@~4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== @@ -2433,6 +2543,15 @@ form-data@^4.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" +fs-extra@^10.0.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" + integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -2552,6 +2671,11 @@ globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" +graceful-fs@^4.1.6, graceful-fs@^4.2.0: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + graceful-fs@^4.2.9: version "4.2.10" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" @@ -2819,6 +2943,14 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== +isomorphic-fetch@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz#0267b005049046d2421207215d45d6a262b8b8b4" + integrity sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA== + dependencies: + node-fetch "^2.6.1" + whatwg-fetch "^3.4.1" + istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" @@ -3304,6 +3436,15 @@ json5@^2.2.3: resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + kleur@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" @@ -3357,6 +3498,11 @@ lodash.set@^4.3.2: resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23" integrity sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM= +lossless-json@^2.0.8: + version "2.0.11" + resolved "https://registry.yarnpkg.com/lossless-json/-/lossless-json-2.0.11.tgz#3137684c93fd99481c6f99c985efc9c9c5cc76a5" + integrity sha512-BP0vn+NGYvzDielvBZaFain/wgeJ1hTvURCqtKvhr1SCPePdaaTanmmcplrHfEJSJOUql7hk4FHwToNJjWRY3g== + lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -3472,6 +3618,13 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== +node-fetch@^2.6.1: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + node-fetch@^2.6.11: version "2.6.11" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.11.tgz#cde7fc71deef3131ef80a738919f999e6edfff25" @@ -3618,6 +3771,11 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +pako@^2.0.4: + version "2.1.0" + resolved "https://registry.yarnpkg.com/pako/-/pako-2.1.0.tgz#266cc37f98c7d883545d11335c00fbd4062c9a86" + integrity sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug== + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -3781,6 +3939,13 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" +redeyed@~2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/redeyed/-/redeyed-2.1.1.tgz#8984b5815d99cb220469c99eeeffe38913e6cc0b" + integrity sha512-FNpGGo1DycYAdnrKFxCMmKYgo/mILAqtRYbkdQD8Ep/Hk2PQ5+aEAEx+IU713RTDmuBaH0c8P5ZozurNu5ObRQ== + dependencies: + esprima "~4.0.0" + regexpp@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" @@ -3848,6 +4013,18 @@ rimraf@^3.0.2: dependencies: glob "^7.1.3" +rome@^12.1.3: + version "12.1.3" + resolved "https://registry.yarnpkg.com/rome/-/rome-12.1.3.tgz#4d4d62cad16216843680bd3ca11a4c248134902a" + integrity sha512-e+ff72hxDpe/t5/Us7YRBVw3PBET7SeczTQNn6tvrWdrCaAw3qOukQQ+tDCkyFtS4yGsnhjrJbm43ctNbz27Yg== + optionalDependencies: + "@rometools/cli-darwin-arm64" "12.1.3" + "@rometools/cli-darwin-x64" "12.1.3" + "@rometools/cli-linux-arm64" "12.1.3" + "@rometools/cli-linux-x64" "12.1.3" + "@rometools/cli-win32-arm64" "12.1.3" + "@rometools/cli-win32-x64" "12.1.3" + run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -3945,6 +4122,21 @@ stack-utils@^2.0.3: dependencies: escape-string-regexp "^2.0.0" +starknet@^5.24.3: + version "5.29.0" + resolved "https://registry.yarnpkg.com/starknet/-/starknet-5.29.0.tgz#26d8074340f26a2da4bc373169a1a5ed6dc9bedf" + integrity sha512-eEcd6uiYIwGvl8MtHOsXGBhREqjJk84M/qUkvPLQ3n/JAMkbKBGnygDlh+HAsvXJsGlMQfwrcVlm6KpDoPha7w== + dependencies: + "@noble/curves" "~1.3.0" + "@scure/base" "~1.1.3" + "@scure/starknet" "~1.0.0" + abi-wan-kanabi-v1 "npm:abi-wan-kanabi@^1.0.3" + abi-wan-kanabi-v2 "npm:abi-wan-kanabi@^2.1.1" + isomorphic-fetch "^3.0.0" + lossless-json "^2.0.8" + pako "^2.0.4" + url-join "^4.0.1" + string-length@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" @@ -4172,6 +4364,11 @@ typescript@^4.7.4: resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235" integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== +typescript@^4.9.5: + version "4.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" + integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== + unbox-primitive@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" @@ -4182,6 +4379,11 @@ unbox-primitive@^1.0.1: has-symbols "^1.0.2" which-boxed-primitive "^1.0.2" +universalify@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" + integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== + untildify@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" @@ -4194,6 +4396,11 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +url-join@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/url-join/-/url-join-4.0.1.tgz#b642e21a2646808ffa178c4c5fda39844e12cde7" + integrity sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA== + util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -4225,6 +4432,11 @@ webidl-conversions@^3.0.0: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== +whatwg-fetch@^3.4.1: + version "3.6.20" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz#580ce6d791facec91d37c72890995a0b48d31c70" + integrity sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg== + whatwg-url@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" @@ -4308,6 +4520,11 @@ yargs-parser@^21.0.0, yargs-parser@^21.0.1: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.1.tgz#0267f286c877a4f0f728fceb6f8a3e4cb95c6e35" integrity sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg== +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + yargs@^16.1.0: version "16.2.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" @@ -4334,6 +4551,19 @@ yargs@^17.3.1: y18n "^5.0.5" yargs-parser "^21.0.0" +yargs@^17.7.2: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" From a867f38110b9bec5db74e97b77fff9c10888e77c Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Tue, 16 Jul 2024 10:14:47 +0530 Subject: [PATCH 699/815] fix: Change path of types import (#1531) --- src/strategies/delegate-registry-v2/index.ts | 2 +- src/strategies/split-delegation/index.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/strategies/delegate-registry-v2/index.ts b/src/strategies/delegate-registry-v2/index.ts index e22fb4805..7e4b8bfe7 100644 --- a/src/strategies/delegate-registry-v2/index.ts +++ b/src/strategies/delegate-registry-v2/index.ts @@ -1,6 +1,6 @@ import fetch from 'cross-fetch'; import { StaticJsonRpcProvider } from '@ethersproject/providers'; -import { Strategy } from '@snapshot-labs/snapshot.js/dist/voting/types'; +import { Strategy } from '@snapshot-labs/snapshot.js/dist/src/voting/types'; import { getScoresDirect } from '../../utils'; import { getAddress } from '@ethersproject/address'; diff --git a/src/strategies/split-delegation/index.ts b/src/strategies/split-delegation/index.ts index ecd2dd9ee..7db9bb2d4 100644 --- a/src/strategies/split-delegation/index.ts +++ b/src/strategies/split-delegation/index.ts @@ -1,6 +1,6 @@ import fetch from 'cross-fetch'; import { StaticJsonRpcProvider } from '@ethersproject/providers'; -import { Strategy } from '@snapshot-labs/snapshot.js/dist/voting/types'; +import { Strategy } from '@snapshot-labs/snapshot.js/dist/src/voting/types'; export const author = 'gnosisguild'; export const version = '1.0.0'; From def4606d1ef0e66814b262358140f29d58dedc52 Mon Sep 17 00:00:00 2001 From: Nick Doherty Date: Tue, 16 Jul 2024 18:39:52 +1000 Subject: [PATCH 700/815] added the rocket-pool-node-operator-v7 strategy (#1532) --- src/strategies/index.ts | 2 + .../rocketpool-node-operator-v7/README.md | 13 ++++ .../rocketpool-node-operator-v7/examples.json | 27 +++++++++ .../rocketpool-node-operator-v7/index.ts | 60 +++++++++++++++++++ 4 files changed, 102 insertions(+) create mode 100644 src/strategies/rocketpool-node-operator-v7/README.md create mode 100644 src/strategies/rocketpool-node-operator-v7/examples.json create mode 100644 src/strategies/rocketpool-node-operator-v7/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index ff09c6696..d9c22bd96 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -294,6 +294,7 @@ import * as rocketpoolNodeOperator from './rocketpool-node-operator'; import * as rocketpoolNodeOperatorv2 from './rocketpool-node-operator-v2'; import * as rocketpoolNodeOperatorv3 from './rocketpool-node-operator-v3'; import * as rocketpoolNodeOperatorv4 from './rocketpool-node-operator-v4'; +import * as rocketpoolNodeOperatorv7 from './rocketpool-node-operator-v7'; import * as rocketpoolNodeOperatorDelegatev4 from './rocketpool-node-operator-delegate-v4'; import * as rocketpoolNodeOperatorDelegatev5 from './rocketpool-node-operator-delegate-v5'; import * as rocketpoolNodeOperatorDelegatev6 from './rocketpool-node-operator-delegate-v6'; @@ -742,6 +743,7 @@ const strategies = { 'rocketpool-node-operator-v2': rocketpoolNodeOperatorv2, 'rocketpool-node-operator-v3': rocketpoolNodeOperatorv3, 'rocketpool-node-operator-v4': rocketpoolNodeOperatorv4, + 'rocketpool-node-operator-v7': rocketpoolNodeOperatorv7, 'rocketpool-node-operator-delegate-v4': rocketpoolNodeOperatorDelegatev4, 'rocketpool-node-operator-delegate-v5': rocketpoolNodeOperatorDelegatev5, 'rocketpool-node-operator-delegate-v6': rocketpoolNodeOperatorDelegatev6, diff --git a/src/strategies/rocketpool-node-operator-v7/README.md b/src/strategies/rocketpool-node-operator-v7/README.md new file mode 100644 index 000000000..11849dfc6 --- /dev/null +++ b/src/strategies/rocketpool-node-operator-v7/README.md @@ -0,0 +1,13 @@ +# rocketpool-node-operator-delegate-v7 + +This is a strategy for node operators, it returns the vote power for a node address. + +Here is an example of parameters: + +```json +{ + "address": "0xD33526068D116cE69F19A9ee46F0bd304F21A51f", + "symbol": "RPL", + "decimals": 18 +} +``` diff --git a/src/strategies/rocketpool-node-operator-v7/examples.json b/src/strategies/rocketpool-node-operator-v7/examples.json new file mode 100644 index 000000000..bd83e2e82 --- /dev/null +++ b/src/strategies/rocketpool-node-operator-v7/examples.json @@ -0,0 +1,27 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "rocketpool-node-operator-v7", + "params": { + "address": "0xD33526068D116cE69F19A9ee46F0bd304F21A51f", + "symbol": "RPL", + "decimals": 18 + } + }, + "network": "1", + "addresses": [ + "0xc942B5aA63A3410a13358a7a3aEdF33d9e9D3AC3", + "0x9Fe9FfbfD57ab78D4d01973482258bfC4BB70bE3", + "0x57767D8000859535431Fbc57EBFEc43FD0515902", + "0x8fBfD009C4B6a99EDD7a1b9561e696A98b6E48dC", + "0xDe506279b3704064Ee5ED2Fcf5515b7629eDAB1D", + "0x48ee0aBAe316499E6d9375671c4B6AE406bd288B", + "0x07f771B6C79b3F86E12585580654A946448A9020", + "0xF912051684b910FFA7972aDa6E8c1EC46CBBE075", + "0x0e973A3757ed841EfbBE4139a7d52a5EebDa03DB", + "0x427d42983CC65d27e83A2Df5815b46F1F55e6445" + ], + "snapshot": 20309057 + } +] diff --git a/src/strategies/rocketpool-node-operator-v7/index.ts b/src/strategies/rocketpool-node-operator-v7/index.ts new file mode 100644 index 000000000..3bdb096ce --- /dev/null +++ b/src/strategies/rocketpool-node-operator-v7/index.ts @@ -0,0 +1,60 @@ +import { Multicaller } from '../../utils'; +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; + +export const author = 'rocket-pool'; +export const version = '0.1.7'; + +const rocketNetworkVoting = '0xA9d27E1952f742d659143a544d3e535fFf3Eebe1'; +const rocketNetworkVotingAbi = [ + 'function getVotingPower(address _nodeAddress, uint32 _block) external view returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = + typeof snapshot === 'number' ? snapshot : await provider.getBlockNumber(); + + const nodeVotingPower = new Multicaller( + network, + provider, + rocketNetworkVotingAbi, + { blockTag } + ); + + addresses.forEach((address) => { + nodeVotingPower.call(address, rocketNetworkVoting, 'getVotingPower', [ + address, + blockTag + ]); + }); + + const nodeVotingPowerResponse: Record = + await nodeVotingPower.execute(); + + const merged = addresses.map((address) => { + const votePower = nodeVotingPowerResponse[address]; + return { + address: address, + votePower: votePower + }; + }); + + const reduced: Record = merged.reduce((acc, obj) => { + acc[obj.address] = obj.votePower; + return acc; + }, {}); + + return Object.fromEntries( + Object.entries(reduced).map(([address, votePower]) => [ + address, + parseFloat(formatUnits(votePower, options.decimals)) + ]) + ); +} From 66d50fded28a79a377452419d5539c51fb734c7f Mon Sep 17 00:00:00 2001 From: Nick Doherty Date: Tue, 16 Jul 2024 21:03:12 +1000 Subject: [PATCH 701/815] [rocketpool-node-operator-delegate-v7] Added the rocket-pool-node-operator-delegate-v7 strategy (#1533) * added the rocket-pool-node-operator-delegate-v7 strategy * added faster lookup method to fix more than 500 address test --- src/strategies/index.ts | 2 + .../README.md | 13 +++ .../examples.json | 47 ++++++++++ .../index.ts | 89 +++++++++++++++++++ 4 files changed, 151 insertions(+) create mode 100644 src/strategies/rocketpool-node-operator-delegate-v7/README.md create mode 100644 src/strategies/rocketpool-node-operator-delegate-v7/examples.json create mode 100644 src/strategies/rocketpool-node-operator-delegate-v7/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index d9c22bd96..e849a3eb2 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -298,6 +298,7 @@ import * as rocketpoolNodeOperatorv7 from './rocketpool-node-operator-v7'; import * as rocketpoolNodeOperatorDelegatev4 from './rocketpool-node-operator-delegate-v4'; import * as rocketpoolNodeOperatorDelegatev5 from './rocketpool-node-operator-delegate-v5'; import * as rocketpoolNodeOperatorDelegatev6 from './rocketpool-node-operator-delegate-v6'; +import * as rocketpoolNodeOperatorDelegatev7 from './rocketpool-node-operator-delegate-v7'; import * as earthfundChildDaoStakingBalance from './earthfund-child-dao-staking-balance'; import * as unipilotVaultPilotBalance from './unipilot-vault-pilot-balance'; import * as sdBoostTWAVP from './sd-boost-twavp'; @@ -747,6 +748,7 @@ const strategies = { 'rocketpool-node-operator-delegate-v4': rocketpoolNodeOperatorDelegatev4, 'rocketpool-node-operator-delegate-v5': rocketpoolNodeOperatorDelegatev5, 'rocketpool-node-operator-delegate-v6': rocketpoolNodeOperatorDelegatev6, + 'rocketpool-node-operator-delegate-v7': rocketpoolNodeOperatorDelegatev7, 'earthfund-child-dao-staking-balance': earthfundChildDaoStakingBalance, 'sd-boost-twavp': sdBoostTWAVP, 'unipilot-vault-pilot-balance': unipilotVaultPilotBalance, diff --git a/src/strategies/rocketpool-node-operator-delegate-v7/README.md b/src/strategies/rocketpool-node-operator-delegate-v7/README.md new file mode 100644 index 000000000..fe90384ed --- /dev/null +++ b/src/strategies/rocketpool-node-operator-delegate-v7/README.md @@ -0,0 +1,13 @@ +# rocketpool-node-operator-delegate-v7 + +This is a strategy for delegate node operators, it returns the delegated vote power for a node address given a signalling address. + +Here is an example of parameters: + +```json +{ + "address": "0xD33526068D116cE69F19A9ee46F0bd304F21A51f", + "symbol": "RPL", + "decimals": 18 +} +``` diff --git a/src/strategies/rocketpool-node-operator-delegate-v7/examples.json b/src/strategies/rocketpool-node-operator-delegate-v7/examples.json new file mode 100644 index 000000000..322be00d7 --- /dev/null +++ b/src/strategies/rocketpool-node-operator-delegate-v7/examples.json @@ -0,0 +1,47 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "rocketpool-node-operator-delegate-v7", + "params": { + "address": "0xD33526068D116cE69F19A9ee46F0bd304F21A51f", + "symbol": "RPL", + "decimals": 18, + "strategies": [ + { + "name": "rocketpool-node-operator-v7", + "params": { + "address": "0xD33526068D116cE69F19A9ee46F0bd304F21A51f", + "symbol": "RPL", + "decimals": 18 + } + } + ] + } + }, + "network": "1", + "addresses": [ + "0x6212Ee7822265cE44B56C943bFd4bCcc03AeC42A", + "0x291BFc5E578aEdFBE4b4A86d6188E99391BC30Fa", + "0x27108a00Aa686c79fB15c79Fca4B312030cEFb24", + "0xB0De8cB8Dcc8c5382c4b7F3E978b491140B2bC55", + "0x439B5eEa6dD4745d575ADa1ED7d682c723829b7D", + "0x9Be85faBd144bCa1aCdF2b5E074cFbFBEB2855a3", + "0x166C58AC1907e2c4b24717DD52683A88E7123AbA", + "0xf8bFf17a1C9dfC632F6C905d12C404AfE451B16c", + "0x2600846F4401aE10CA760604036A891bb896649E", + "0x38857Ed3a8fC5951289E58e20fB56A00e88f0BBD", + "0xd0Fa32A950fb860501E8e3C0712B9fF847AD6f71", + "0x8de90ADBd431Dfdae0cd81937fc1156031D50f19", + "0xBb2b1CA23afCB616837F2966eb26C4C50ec8D080", + "0x5061845415d2B9f279016Ba819510f2F44908086", + "0x71c1B6562556B2b7fC9929cB1D4c949248036320", + "0xaC643357BBdA44E46896Dcfb195A09cb8C6AE279", + "0x220576274Cd2561a1cc396B023A36631862604f0", + "0x0226e3174a45F3d97d853B8f3fe5DAd1006B9294", + "0xD16dbc40479D572e19da7B671bb6C230aF41643d", + "0x16d9de20adfb6ed1790a2e618063e5b3d1d07ba6" + ], + "snapshot": 20309057 + } +] diff --git a/src/strategies/rocketpool-node-operator-delegate-v7/index.ts b/src/strategies/rocketpool-node-operator-delegate-v7/index.ts new file mode 100644 index 000000000..9806c34f8 --- /dev/null +++ b/src/strategies/rocketpool-node-operator-delegate-v7/index.ts @@ -0,0 +1,89 @@ +import fetch from 'cross-fetch'; +import { getAddress } from '@ethersproject/address'; +import { getScoresDirect, Multicaller } from '../../utils'; + +export const author = 'rocket-pool'; +export const version = '0.1.7'; + +const signerRegistryContractAddress = + '0xc1062617d10Ae99E09D941b60746182A87eAB38F'; +const signerRegistryAbi = [ + 'function signerToNode(address) external view returns (address)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = + typeof snapshot === 'number' ? snapshot : await provider.getBlockNumber(); + + const req = await fetch( + 'https://api.rocketpool.net/mainnet/delegates/block/' + blockTag + ); + const resp = await req.json(); + + const signerRegistry = new Multicaller(network, provider, signerRegistryAbi, { + blockTag + }); + + addresses.forEach((address) => { + signerRegistry.call( + address, + signerRegistryContractAddress, + 'signerToNode', + [address] + ); + }); + + const signerRegistryResponse: Record = + await signerRegistry.execute(); + + const addressMap: Map = new Map(resp.map(obj => [getAddress(obj.address), obj])); + + const nodeData = addresses.map((address) => { + const nodeAddress = getAddress(signerRegistryResponse[address]); + const node = addressMap.get(nodeAddress); + return { + signallingAddress: address, + nodeAddress: nodeAddress, + delegators: node && node.delegators.length > 0 ? node.delegators.map((d) => getAddress(d.address)) : [nodeAddress], + } + }); + + const delegations: Record = Object.fromEntries( + nodeData.map((node) => [node.nodeAddress, node.delegators]) + ); + + const scores = ( + await getScoresDirect( + space, + options.strategies, + network, + provider, + Object.values(delegations).reduce((a: string[], b: string[]) => + a.concat(b) + ), + snapshot + ) + ).filter((score) => Object.keys(score).length !== 0); + + return Object.fromEntries( + addresses.map((address) => { + const addressData = nodeData.find((node) => node.signallingAddress === address); + if (addressData.nodeAddress === "0x0000000000000000000000000000000000000000") { + return [address, 0]; + } + const delegators = addressData.delegators; + const addressScore = delegators.reduce( + (a, b) => a + scores.reduce((x, y) => (y[b] ? x + y[b] : x), 0), + 0 + ); + return [address, addressScore]; + }) + ); +} From 117cab8be0c43909c8a2ee75aff49cfe45231aff Mon Sep 17 00:00:00 2001 From: m1ngshum <140998506+m1ngshum@users.noreply.github.com> Date: Thu, 18 Jul 2024 12:58:38 +0800 Subject: [PATCH 702/815] [moca-staking] add new strategy (#1534) * [moca-staking] add new strategy * fix: author name * Update src/strategies/moca-staking/index.ts * Update src/strategies/moca-staking/examples.json * Update src/strategies/moca-staking/examples.json --------- Co-authored-by: Chaitanya --- src/strategies/index.ts | 4 +- src/strategies/moca-staking/README.md | 28 ++++++++++++++ src/strategies/moca-staking/examples.json | 20 ++++++++++ src/strategies/moca-staking/index.ts | 45 +++++++++++++++++++++++ 4 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 src/strategies/moca-staking/README.md create mode 100644 src/strategies/moca-staking/examples.json create mode 100644 src/strategies/moca-staking/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index e849a3eb2..962015540 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -438,6 +438,7 @@ import * as stakingBalanceOfV1 from './staking-balance-of-v1'; import * as gardenStakes from './garden-stakes'; import * as csv from './csv'; import * as swarmStaking from './swarm-staking'; +import * as mocaStaking from './moca-staking'; const strategies = { 'giveth-balances-supply-weighted': givethBalancesSupplyWeighted, @@ -886,7 +887,8 @@ const strategies = { 'staking-balance-of-v2': stakingBalanceOfV2, 'garden-stakes': gardenStakes, csv, - 'swarm-staking': swarmStaking + 'swarm-staking': swarmStaking, + 'moca-staking': mocaStaking }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/moca-staking/README.md b/src/strategies/moca-staking/README.md new file mode 100644 index 000000000..75a2f0809 --- /dev/null +++ b/src/strategies/moca-staking/README.md @@ -0,0 +1,28 @@ +# MOCA Staking Strategy + +MOCA staking strategy is designed to determine voting power based on number of MOCA staked. + +## Example + +```json +[ + { + "name": "MOCA Staking", + "strategy": { + "name": "moca-staking", + "params": { + "address": "0x9a98e6b60784634ae273f2fb84519c7f1885aed2", + "symbol": "MOCA", + "decimals": 18 + } + }, + "network": "1", + "addresses": [ + "0x95c3017d268BE2d2Cc0dFf162CB1CDA8399497A5", + "0xA9c22753222B1eD97E70aB092EDcD3D74e5d7954", + "0x838587FbC0b10aEc692E5b6a1efCB46B88549df2" + ], + "snapshot": 20324268 + } +] +``` diff --git a/src/strategies/moca-staking/examples.json b/src/strategies/moca-staking/examples.json new file mode 100644 index 000000000..ad4d7aae9 --- /dev/null +++ b/src/strategies/moca-staking/examples.json @@ -0,0 +1,20 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "moca-staking", + "params": { + "address": "0x9a98e6b60784634ae273f2fb84519c7f1885aed2", + "symbol": "MOCA", + "decimals": 18 + } + }, + "network": "1", + "addresses": [ + "0x95c3017d268BE2d2Cc0dFf162CB1CDA8399497A5", + "0xA9c22753222B1eD97E70aB092EDcD3D74e5d7954", + "0x838587FbC0b10aEc692E5b6a1efCB46B88549df2" + ], + "snapshot": 20324268 + } +] diff --git a/src/strategies/moca-staking/index.ts b/src/strategies/moca-staking/index.ts new file mode 100644 index 000000000..15c68ba6a --- /dev/null +++ b/src/strategies/moca-staking/index.ts @@ -0,0 +1,45 @@ +import { formatUnits } from '@ethersproject/units'; +import { multicall } from '../../utils'; + +export const author = 'mocaverse'; +export const version = '0.1.0'; + +const abi = [ + 'function getUser(address user) view returns (tuple(uint256 amount, uint256 cumulativeWeight, uint256 lastUpdateTimestamp))' +]; + +function getArgs(options, address: string) { + const args: Array = options.args || ['%{address}']; + return args.map((arg) => + typeof arg === 'string' ? arg.replace(/%{address}/g, address) : arg + ); +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const response = await multicall( + network, + provider, + abi, + addresses.map((address: any) => [ + options.address, + 'getUser', + getArgs(options, address) + ]), + { blockTag } + ); + + return Object.fromEntries( + response.map(([value], i) => [ + addresses[i], + parseFloat(formatUnits(value.amount, options.decimals)) + ]) + ); +} From bf10b1ed9bfcaad945fcc888800369f84b5687ca Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 18 Jul 2024 12:28:51 +0530 Subject: [PATCH 703/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.1 (#1535) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 1d7839930..abdd7a6fc 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.0", + "@snapshot-labs/snapshot.js": "^0.12.1", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index db316b78e..c16890551 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.0": - version "0.12.0" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.0.tgz#f68b701cd6806fc4d0fa207d31f1c5491dc9ba6e" - integrity sha512-DYgF0oXTz51Gh9tHXXT9mLUzuuYYmhCIVMV/1imu7RH/Cnm7Nmx2BvuBdyjHsCg8nhLrMw7hgVCibIcBWjYdBQ== +"@snapshot-labs/snapshot.js@^0.12.1": + version "0.12.1" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.1.tgz#4ab9edddea886ffb1687e368ce9386e4a93d049f" + integrity sha512-NlSCndyeHdWlQ9eiAiORGjE9XSHhb1CPWrWEXW6BamtRHpJhErT8ebkrM7/7nPKmmVDheZs+G7YqQSU/yelHLw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From ecf77ad0112e83bd9bb964d45a25483c6355f573 Mon Sep 17 00:00:00 2001 From: lemu Date: Fri, 19 Jul 2024 13:50:35 -0300 Subject: [PATCH 704/815] chore: ratelimit decentraland strategies [decentraland-wearable-rarity] (#1536) * chore: add delay between subgraphs requests so that they don't exceed 30 per second between the three strategies * chore: update decentraland-rental-lessors example addresses and contracts * chore: remove sepolia marketplace subgraph --- src/strategies/decentraland-estate-size/index.ts | 7 +++++++ .../decentraland-rental-lessors/examples.json | 13 ++++++------- src/strategies/decentraland-rental-lessors/index.ts | 9 +++++++++ .../decentraland-wearable-rarity/index.ts | 9 +++++++-- 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/strategies/decentraland-estate-size/index.ts b/src/strategies/decentraland-estate-size/index.ts index 6d4e402db..7e3c4c7d8 100644 --- a/src/strategies/decentraland-estate-size/index.ts +++ b/src/strategies/decentraland-estate-size/index.ts @@ -5,6 +5,7 @@ export const author = '2fd'; export const version = '0.1.0'; const SUBGRAPH_QUERY_ADDRESSES_LIMIT = 2000; +const REQUEST_DELAY_MS = 1000 / 10; // 10 requests per second const DECENTRALAND_MARKETPLACE_SUBGRAPH_URL = { '1': 'https://subgraph.decentraland.org/marketplace' }; @@ -17,6 +18,10 @@ function chunk(_array: string[], pageSize: number): string[][] { return chunks; } +async function delay(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + export async function strategy( space, network, @@ -65,6 +70,8 @@ export async function strategy( let hasNext = true; while (hasNext) { + await delay(REQUEST_DELAY_MS); + const result = await subgraphRequest( DECENTRALAND_MARKETPLACE_SUBGRAPH_URL[network], params diff --git a/src/strategies/decentraland-rental-lessors/examples.json b/src/strategies/decentraland-rental-lessors/examples.json index 9d5f7e9e8..def6e2b4e 100644 --- a/src/strategies/decentraland-rental-lessors/examples.json +++ b/src/strategies/decentraland-rental-lessors/examples.json @@ -9,8 +9,8 @@ "marketplace": "https://api.studio.thegraph.com/query/49472/marketplace-sepolia/version/latest" }, "addresses": { - "estate": "0xc9a46712e6913c24d15b46ff12221a79c4e251dc", - "land": "0x25b6b4bac4adb582a0abd475439da6730777fbf7" + "estate": "0x369a7fbe718c870c79f99fb423882e8dd8b20486", + "land": "0x42f4ba48791e2de32f5fbf553441c2672864bb33" }, "multipliers": { "estateSize": 2000, @@ -20,11 +20,10 @@ }, "network": "11155111", "addresses": [ - "0x747c6f502272129bf1ba872a1903045b837ee86c", - "0xbad79d832671d91b4bba85f600932faec0e5fd7c", - "0x24e5f44999c151f08609f8e27b2238c773c4d020", - "0x2f89ec84e0413950d9adf8e56dd56c2b2f5066cb" + "0x69d30b1875d39e13a01af73ccfed6d84839e84f2", + "0xa87d168717538e86d71ac48baccaeb84162de602", + "0x747c6f502272129bf1ba872a1903045b837ee86c" ], - "snapshot": 7866054 + "snapshot": 6339835 } ] diff --git a/src/strategies/decentraland-rental-lessors/index.ts b/src/strategies/decentraland-rental-lessors/index.ts index 72b77efee..83900dffa 100644 --- a/src/strategies/decentraland-rental-lessors/index.ts +++ b/src/strategies/decentraland-rental-lessors/index.ts @@ -6,6 +6,11 @@ export const author = 'fzavalia'; export const version = '0.1.0'; const SUBGRAPH_QUERY_IN_FILTER_MAX_LENGTH = 500; +const REQUEST_DELAY_MS = 1000 / 10; // 10 requests per second + +async function delay(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} export async function strategy( space, @@ -109,6 +114,8 @@ async function fetchLandsAndEstatesInRentalsContract( let hasMoreResults = true; while (hasMoreResults) { + await delay(REQUEST_DELAY_MS); + const result = await subgraphRequest(options.subgraphs.rentals, query); const rentalLandsAndEstates: RentalsLandOrEstate[] = result.rentalAssets; @@ -181,6 +188,8 @@ async function fetchMarketplaceEstatesForProvidedRentalAssets( let hasMoreResults = true; while (hasMoreResults) { + await delay(REQUEST_DELAY_MS); + const result = await subgraphRequest( options.subgraphs.marketplace, query diff --git a/src/strategies/decentraland-wearable-rarity/index.ts b/src/strategies/decentraland-wearable-rarity/index.ts index efa50e365..ce800ea82 100644 --- a/src/strategies/decentraland-wearable-rarity/index.ts +++ b/src/strategies/decentraland-wearable-rarity/index.ts @@ -5,10 +5,9 @@ export const author = '2fd'; export const version = '0.1.0'; const SUBGRAPH_QUERY_ADDRESSES_LIMIT = 2000; +const REQUEST_DELAY_MS = 1000 / 10; // 10 requests per second const DECENTRALAND_COLLECTIONS_SUBGRAPH_URL = { '1': 'https://subgraph.decentraland.org/collections-ethereum-mainnet', - '11155111': - 'https://api.studio.thegraph.com/query/49472/marketplace-sepolia/version/latest', '137': 'https://subgraph.decentraland.org/collections-matic-mainnet', '80002': 'https://subgraph.decentraland.org/collections-matic-amoy' }; @@ -21,6 +20,10 @@ function chunk(_array: string[], pageSize: number): string[][] { return chunks; } +async function delay(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + export async function strategy( space, network, @@ -83,6 +86,8 @@ export async function strategy( // load and add each wearable by rarity let hasNext = true; while (hasNext) { + await delay(REQUEST_DELAY_MS); + const result = await subgraphRequest( DECENTRALAND_COLLECTIONS_SUBGRAPH_URL[network], params From 1ee51d7bd3fd16a2791d2e5265d57e5cb135d7a0 Mon Sep 17 00:00:00 2001 From: jtakalai Date: Sat, 20 Jul 2024 07:35:56 +0300 Subject: [PATCH 705/815] [streamr] added customizable symbol to strategy (#1537) --- src/strategies/streamr/README.md | 3 ++- src/strategies/streamr/examples.json | 1 + src/strategies/streamr/schema.json | 6 ++++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/strategies/streamr/README.md b/src/strategies/streamr/README.md index 861a0d8e1..ba2ebc7f3 100644 --- a/src/strategies/streamr/README.md +++ b/src/strategies/streamr/README.md @@ -6,12 +6,13 @@ Operators are the node running "miners" in the Streamr Network. They run Streamr This is why part of the Operators' DATA tokens are staked in Sponsorships (through an Operator contract that they control). Only a small portion of DATA is expected to be in the Streamr Network participants' wallets, the rest is staked or delegated into the Streamr Network. -'''The point of the Streamr snapshot strategy''' is to allocate voting power not only according to DATA token holding (as in the plain erc-20-balance-of strategy), but also counting in the DATA tokens the token holders control via staking and delegation (NOTE: at first, only implemented for stakers. Counting delegated DATA may be added later). +The point of the Streamr snapshot strategy is to allocate voting power not only according to DATA token holding (as in the plain erc-20-balance-of strategy), but also counting in the DATA tokens the token holders control via staking and delegation. ## Parameters ```json { + "symbol": "DATA (operator)", "tokenAddress": "0x3a9A81d576d83FF21f26f325066054540720fC34", "operatorFactoryAddress": "0x935734e66729b69260543Cf6e5EfeB42AC962183" } diff --git a/src/strategies/streamr/examples.json b/src/strategies/streamr/examples.json index 7e0c62765..b14b6f52f 100644 --- a/src/strategies/streamr/examples.json +++ b/src/strategies/streamr/examples.json @@ -4,6 +4,7 @@ "strategy": { "name": "streamr", "params": { + "symbol": "DATA (operator)", "tokenAddress": "0x3a9A81d576d83FF21f26f325066054540720fC34", "operatorFactoryAddress": "0x935734e66729b69260543Cf6e5EfeB42AC962183" } diff --git a/src/strategies/streamr/schema.json b/src/strategies/streamr/schema.json index 781cc5ac2..2dd54443b 100644 --- a/src/strategies/streamr/schema.json +++ b/src/strategies/streamr/schema.json @@ -6,6 +6,12 @@ "title": "Strategy", "type": "object", "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. DATA (operator)"], + "maxLength": 16 + }, "tokenAddress": { "type": "string", "title": "DATA token address", From 9ea86b77cc7129f383cdf9af9a1d7e240c38f127 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 21 Jul 2024 17:06:14 +0530 Subject: [PATCH 706/815] Automated lint (#1538) Co-authored-by: ChaituVR --- .../index.ts | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/strategies/rocketpool-node-operator-delegate-v7/index.ts b/src/strategies/rocketpool-node-operator-delegate-v7/index.ts index 9806c34f8..4e851d2bf 100644 --- a/src/strategies/rocketpool-node-operator-delegate-v7/index.ts +++ b/src/strategies/rocketpool-node-operator-delegate-v7/index.ts @@ -43,7 +43,9 @@ export async function strategy( const signerRegistryResponse: Record = await signerRegistry.execute(); - const addressMap: Map = new Map(resp.map(obj => [getAddress(obj.address), obj])); + const addressMap: Map = new Map( + resp.map((obj) => [getAddress(obj.address), obj]) + ); const nodeData = addresses.map((address) => { const nodeAddress = getAddress(signerRegistryResponse[address]); @@ -51,8 +53,11 @@ export async function strategy( return { signallingAddress: address, nodeAddress: nodeAddress, - delegators: node && node.delegators.length > 0 ? node.delegators.map((d) => getAddress(d.address)) : [nodeAddress], - } + delegators: + node && node.delegators.length > 0 + ? node.delegators.map((d) => getAddress(d.address)) + : [nodeAddress] + }; }); const delegations: Record = Object.fromEntries( @@ -74,8 +79,12 @@ export async function strategy( return Object.fromEntries( addresses.map((address) => { - const addressData = nodeData.find((node) => node.signallingAddress === address); - if (addressData.nodeAddress === "0x0000000000000000000000000000000000000000") { + const addressData = nodeData.find( + (node) => node.signallingAddress === address + ); + if ( + addressData.nodeAddress === '0x0000000000000000000000000000000000000000' + ) { return [address, 0]; } const delegators = addressData.delegators; From 7dfece6754b1435a1c242ee9739c2717bfc7b1f2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 25 Jul 2024 16:34:23 +0530 Subject: [PATCH 707/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.2 (#1540) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index abdd7a6fc..a7221efa0 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.1", + "@snapshot-labs/snapshot.js": "^0.12.2", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index c16890551..5ccce931e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,14 +1239,15 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.1": - version "0.12.1" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.1.tgz#4ab9edddea886ffb1687e368ce9386e4a93d049f" - integrity sha512-NlSCndyeHdWlQ9eiAiORGjE9XSHhb1CPWrWEXW6BamtRHpJhErT8ebkrM7/7nPKmmVDheZs+G7YqQSU/yelHLw== +"@snapshot-labs/snapshot.js@^0.12.2": + version "0.12.2" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.2.tgz#52e4bb57ba01cb19dadb66d6c76a08a00620dac9" + integrity sha512-FpaeefRC9Yb/BZRGFIP9LJlXfx/MdoxxVrtWEHvlfIkcI9Byv6eFvcXSOKJY6gU4UtHCFp77g+LJklTaJxxaXw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" "@ethersproject/address" "^5.6.1" + "@ethersproject/bignumber" "^5.7.0" "@ethersproject/bytes" "^5.6.1" "@ethersproject/contracts" "^5.6.2" "@ethersproject/hash" "^5.7.0" From 9f65b21ee940f3df3593662ad29dfcb7daa31575 Mon Sep 17 00:00:00 2001 From: Nick Doherty Date: Thu, 25 Jul 2024 23:28:45 +1000 Subject: [PATCH 708/815] [rocketpool-node-operator-delegate-v8] Added rocket-pool-node-operator-delegate-v8-strategy (#1539) * added rocket-pool-node-operator-delegate-v8-strategy * added check for valid strategies based on prefix --- src/strategies/index.ts | 2 + .../README.md | 13 ++ .../examples.json | 36 +++++ .../index.ts | 136 ++++++++++++++++++ 4 files changed, 187 insertions(+) create mode 100644 src/strategies/rocketpool-node-operator-delegate-v8/README.md create mode 100644 src/strategies/rocketpool-node-operator-delegate-v8/examples.json create mode 100644 src/strategies/rocketpool-node-operator-delegate-v8/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 962015540..49ec99860 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -299,6 +299,7 @@ import * as rocketpoolNodeOperatorDelegatev4 from './rocketpool-node-operator-de import * as rocketpoolNodeOperatorDelegatev5 from './rocketpool-node-operator-delegate-v5'; import * as rocketpoolNodeOperatorDelegatev6 from './rocketpool-node-operator-delegate-v6'; import * as rocketpoolNodeOperatorDelegatev7 from './rocketpool-node-operator-delegate-v7'; +import * as rocketpoolNodeOperatorDelegatev8 from './rocketpool-node-operator-delegate-v8'; import * as earthfundChildDaoStakingBalance from './earthfund-child-dao-staking-balance'; import * as unipilotVaultPilotBalance from './unipilot-vault-pilot-balance'; import * as sdBoostTWAVP from './sd-boost-twavp'; @@ -750,6 +751,7 @@ const strategies = { 'rocketpool-node-operator-delegate-v5': rocketpoolNodeOperatorDelegatev5, 'rocketpool-node-operator-delegate-v6': rocketpoolNodeOperatorDelegatev6, 'rocketpool-node-operator-delegate-v7': rocketpoolNodeOperatorDelegatev7, + 'rocketpool-node-operator-delegate-v8': rocketpoolNodeOperatorDelegatev8, 'earthfund-child-dao-staking-balance': earthfundChildDaoStakingBalance, 'sd-boost-twavp': sdBoostTWAVP, 'unipilot-vault-pilot-balance': unipilotVaultPilotBalance, diff --git a/src/strategies/rocketpool-node-operator-delegate-v8/README.md b/src/strategies/rocketpool-node-operator-delegate-v8/README.md new file mode 100644 index 000000000..27363243d --- /dev/null +++ b/src/strategies/rocketpool-node-operator-delegate-v8/README.md @@ -0,0 +1,13 @@ +# rocketpool-node-operator-delegate-v8 + +This is a strategy for delegate node operators, it returns the delegated vote power for a node address given a signalling address. + +Here is an example of parameters: + +```json +{ + "address": "0xD33526068D116cE69F19A9ee46F0bd304F21A51f", + "symbol": "RPL", + "decimals": 18 +} +``` diff --git a/src/strategies/rocketpool-node-operator-delegate-v8/examples.json b/src/strategies/rocketpool-node-operator-delegate-v8/examples.json new file mode 100644 index 000000000..638acb4c9 --- /dev/null +++ b/src/strategies/rocketpool-node-operator-delegate-v8/examples.json @@ -0,0 +1,36 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "rocketpool-node-operator-delegate-v8", + "params": { + "address": "0xD33526068D116cE69F19A9ee46F0bd304F21A51f", + "symbol": "RPL", + "decimals": 18, + "strategies": [ + { + "name": "rocketpool-node-operator-v7", + "params": { + "address": "0xD33526068D116cE69F19A9ee46F0bd304F21A51f", + "symbol": "RPL", + "decimals": 18 + } + } + ] + } + }, + "network": "1", + "addresses": [ + "0xAc69b72672aBb00Ab51837F74a4F28B45296b09E", + "0x519f4cC0994aA03b2174f732c658e778458BC650", + "0xDA5e3CE712D019C1D3c628c20bf50D2494198C8E", + "0x16d9de20adfb6ed1790a2e618063e5b3d1d07ba6", + "0x2600846F4401aE10CA760604036A891bb896649E", + "0xD16dbc40479D572e19da7B671bb6C230aF41643d", + "0xf131c4db1d11a19765d4336b6cd68772aabe79fd", + "0xfaA0967947243A96F949E9D021dD8c603098721B", + "0xf8bFf17a1C9dfC632F6C905d12C404AfE451B16c" + ], + "snapshot": 20367212 + } +] diff --git a/src/strategies/rocketpool-node-operator-delegate-v8/index.ts b/src/strategies/rocketpool-node-operator-delegate-v8/index.ts new file mode 100644 index 000000000..8bd68edac --- /dev/null +++ b/src/strategies/rocketpool-node-operator-delegate-v8/index.ts @@ -0,0 +1,136 @@ +import fetch from 'cross-fetch'; +import { getScoresDirect, Multicaller } from '../../utils'; +import { getAddress } from '@ethersproject/address'; + +export const author = 'rocket-pool'; +export const version = '0.1.8'; +export const dependOnOtherAddress = true; + +const signerRegistryContractAddress = + '0xc1062617d10Ae99E09D941b60746182A87eAB38F'; +const signerRegistryAbi = [ + 'function signerToNode(address) external view returns (address)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = + typeof snapshot === 'number' ? snapshot : 'latest'; + + const validPrefix = 'rocketpool-node-operator-v'; + if ( + !options.strategies.some((s) => { + const parsedStrategy = JSON.parse(JSON.stringify(s)); + return parsedStrategy.name.startsWith(validPrefix); + }) + ) { + return {}; + } + + const req = await fetch( + 'https://api.rocketpool.net/mainnet/delegates/block/' + blockTag + ); + const resp = await req.json(); + + const signerRegistry = new Multicaller(network, provider, signerRegistryAbi, { + blockTag + }); + + addresses.forEach((address) => { + signerRegistry.call( + address, + signerRegistryContractAddress, + 'signerToNode', + [address] + ); + }); + + const signerRegistryResponse: Record = + await signerRegistry.execute(); + + const nodeAddressMap: Map = new Map( + resp.map((obj) => [getAddress(obj.address), obj]) + ); + + const nodeData = addresses.map((address) => { + const nodeAddress = getAddress(signerRegistryResponse[address]); + const node = nodeAddressMap.get(nodeAddress); + const signallingAddress = address; + const delegatesTo = node && node.delegatesTo ? getAddress(node.delegatesTo) : ''; + const delegators = node && node.delegators.length > 0 ? node.delegators.map((d) => getAddress(d.address)) : [nodeAddress]; + return { + signallingAddress: signallingAddress, + nodeAddress: nodeAddress, + delegatesTo: delegatesTo, + delegators: delegators + }; + }); + + const nodeDataMap: Map = new Map( + nodeData.map((obj) => [getAddress(obj.nodeAddress), obj]) + ); + + const overrides = nodeData.map((node) => { + if (node.delegatesTo !== node.nodeAddress) { + return { + nodeAddress: node.nodeAddress, + delegatesTo: node.delegatesTo + }; + } + return {}; + }).filter((override) => Object.keys(override).length !== 0); + + if (Object.keys(overrides).length !== 0) { + overrides.map((override) => { + const delegate = nodeDataMap.get(override.delegatesTo); + if (!delegate) return; + const delegators = delegate ? delegate.delegators.filter((d) => d !== override.nodeAddress) : []; + delegate.delegators = delegators; + nodeDataMap.set(override.delegatesTo, delegate); + const nodeToUpdate = nodeData.find((node) => node.nodeAddress === delegate.nodeAddress); + nodeToUpdate.delegators = delegators; + }); + } + + const delegations: Record = Object.fromEntries( + nodeData.map((node) => [node.nodeAddress, node.delegators]) + ); + + if (Object.keys(delegations).length === 0) return {}; + + const scores = ( + await getScoresDirect( + space, + options.strategies, + network, + provider, + Object.values(delegations).reduce((a: string[], b: string[]) => + a.concat(b) + ), + snapshot + ) + ).filter((score) => Object.keys(score).length !== 0); + + const signallingAddressMap: Map = new Map( + nodeData.map((obj) => [getAddress(obj.signallingAddress), obj]) + ); + + return Object.fromEntries( + addresses.map((address) => { + const data = signallingAddressMap.get(getAddress(address)); + if (!data) return [address, 0]; + const delegators = data.delegators; + const addressScore = delegators.reduce( + (a, b) => a + scores.reduce((x, y) => (y[b] ? x + y[b] : x), 0), + 0 + ); + return [address, addressScore]; + }) + ); +} From 230cebcee1f9e7cf53b294f955e72593863474bb Mon Sep 17 00:00:00 2001 From: 0xAlchemist <0xalchemist@proton.me> Date: Thu, 25 Jul 2024 20:25:43 -0700 Subject: [PATCH 709/815] [delegatexyz-erc721-balance-of] Delegatexyz erc721 balance of (#1541) * passing tests; prepare to submit * fix checksum address issue * cleanup and comments * add schema * cleanup * add README * Update src/strategies/delegatexyz-erc721-balance-of/constants.ts Co-authored-by: Chaitanya --------- Co-authored-by: Chaitanya --- .../delegatexyz-erc721-balance-of/README.md | 9 ++ .../constants.ts | 6 ++ .../examples.json | 24 +++++ .../delegatexyz-erc721-balance-of/index.ts | 94 +++++++++++++++++++ .../delegatexyz-erc721-balance-of/schema.json | 28 ++++++ .../delegatexyz-erc721-balance-of/types.ts | 36 +++++++ .../delegatexyz-erc721-balance-of/utils.ts | 20 ++++ src/strategies/index.ts | 2 + 8 files changed, 219 insertions(+) create mode 100644 src/strategies/delegatexyz-erc721-balance-of/README.md create mode 100644 src/strategies/delegatexyz-erc721-balance-of/constants.ts create mode 100644 src/strategies/delegatexyz-erc721-balance-of/examples.json create mode 100644 src/strategies/delegatexyz-erc721-balance-of/index.ts create mode 100644 src/strategies/delegatexyz-erc721-balance-of/schema.json create mode 100644 src/strategies/delegatexyz-erc721-balance-of/types.ts create mode 100644 src/strategies/delegatexyz-erc721-balance-of/utils.ts diff --git a/src/strategies/delegatexyz-erc721-balance-of/README.md b/src/strategies/delegatexyz-erc721-balance-of/README.md new file mode 100644 index 000000000..921c4d62d --- /dev/null +++ b/src/strategies/delegatexyz-erc721-balance-of/README.md @@ -0,0 +1,9 @@ +# ERC-721 with Delegate.xyz (V2) support + +This enables Delegate.xyz users to vote from their delegate wallet while using ERC-721 NFTs from their cold wallet. Users can safely vote without the need to connect or sign using their cold wallet. + +Delegate.xyz (V2) Full wallet and smart contract level delegation are both supported. + +This strategy uses the same parameters as erc721-balance-of, but the signing wallet is now the delegate wallet. + +-- Made with Love by ApesPlus diff --git a/src/strategies/delegatexyz-erc721-balance-of/constants.ts b/src/strategies/delegatexyz-erc721-balance-of/constants.ts new file mode 100644 index 000000000..93963f1d9 --- /dev/null +++ b/src/strategies/delegatexyz-erc721-balance-of/constants.ts @@ -0,0 +1,6 @@ +export const abi = [ + 'function getIncomingDelegations(address to) view returns (tuple(uint8 type_, address to, address from, bytes32 rights, address contract_, uint256 tokenId, uint256 amount)[] delegations_)' +]; + +export const delegatexyzV2ContractAddress = + '0x00000000000000447e69651d841bd8d104bed493'; diff --git a/src/strategies/delegatexyz-erc721-balance-of/examples.json b/src/strategies/delegatexyz-erc721-balance-of/examples.json new file mode 100644 index 000000000..5bb77a603 --- /dev/null +++ b/src/strategies/delegatexyz-erc721-balance-of/examples.json @@ -0,0 +1,24 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "delegatexyz-erc721-balance-of", + "params": { + "address": "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D", + "symbol": "BAYC" + } + }, + "network": "1", + "addresses": [ + "0x9fBDD6437840641B5dEDE244B084D31e109A0F23", + "0xdA6A58741EaEf21eb455811F3421705cF7AF9dc8", + "0x6AE06aD5CFEf7575B31933a18c263013CCFd3be1", + "0x51688cd36c18891167e8036bde2a8fb10ec80c43", + "0x3e17fac953de2cd729b0ace7f6d4353387717e9e", + "0x23f67feb67a3aa1e376d23beaa3f241217e427c9", + "0x54685c62db8e16b1484768db8e0daf3c644d50bf", + "0x766bc61d3150232f6f4e1d81633d68f3a94879e3" + ], + "snapshot": 20042069 + } +] diff --git a/src/strategies/delegatexyz-erc721-balance-of/index.ts b/src/strategies/delegatexyz-erc721-balance-of/index.ts new file mode 100644 index 000000000..612789713 --- /dev/null +++ b/src/strategies/delegatexyz-erc721-balance-of/index.ts @@ -0,0 +1,94 @@ +import { multicall } from '../../utils'; +import { strategy as erc721BalanceOfStrategy } from '../erc721'; +import { abi, delegatexyzV2ContractAddress } from './constants'; +import { lowerCaseAddress, calculateVotingPower } from './utils'; +import { + Address, + DelegationType, + Delegation, + DelegationStruct, + DelegatedMapping, + AddressScore +} from './types'; + +export const author = 'apesplus'; +export const version = '0.1.0'; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const mappedDelegations: DelegatedMapping = {}; + + // Use the provided addresses as the keys for our mapping + addresses.map((address: Address) => { + mappedDelegations[lowerCaseAddress(address)] = []; + }); + + // Get the wallet mapping from delegate wallets to vault wallets + const response = await multicall( + network, + provider, + abi, + addresses.map((address: Address) => [ + delegatexyzV2ContractAddress, + 'getIncomingDelegations', + [address] + ]), + { blockTag } + ); + + // complete the mapping from the results of + // the multicall to getIncomingDelegations + if (response.length) { + response.map((data: DelegationStruct) => { + data.delegations_.map((delegation: Delegation) => { + const { to, from, type_, contract_ } = delegation; + + // Check for full wallet delegation first and + // add the vault to the mapping + if (type_ === DelegationType.ALL) { + mappedDelegations[lowerCaseAddress(to)].push(from); + } + + // Check for contract level delegation and add + // to the mapping if contract is correct and the + // vault address is not already mapped + if (type_ === DelegationType.CONTRACT) { + if (contract_ !== options.address) return; + if (mappedDelegations[lowerCaseAddress(to)].includes(from)) return; + + mappedDelegations[lowerCaseAddress(to)].push(from); + } + }); + }); + } + + // Flatten mapped wallets so we can check vault wallets directly + const delegateWallets: Address[] = Object.keys(mappedDelegations).map( + (key) => mappedDelegations[key] + ); + + const flattenedAddresses: Address[] = ([] as Address[]).concat.apply( + [], + delegateWallets + ); + + // Check balance of vault wallets + const addressScores: AddressScore = await erc721BalanceOfStrategy( + space, + network, + provider, + flattenedAddresses, + options, + snapshot + ); + + // Sum voting power of vault wallets and map the score back to delegate wallet + return calculateVotingPower(addresses, addressScores, mappedDelegations); +} diff --git a/src/strategies/delegatexyz-erc721-balance-of/schema.json b/src/strategies/delegatexyz-erc721-balance-of/schema.json new file mode 100644 index 000000000..fa75f7b66 --- /dev/null +++ b/src/strategies/delegatexyz-erc721-balance-of/schema.json @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. BAYC"], + "maxLength": 16 + }, + "address": { + "type": "string", + "title": "Contract address", + "examples": ["e.g. 0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } + }, + "required": ["address"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/delegatexyz-erc721-balance-of/types.ts b/src/strategies/delegatexyz-erc721-balance-of/types.ts new file mode 100644 index 000000000..1bfe5a1c6 --- /dev/null +++ b/src/strategies/delegatexyz-erc721-balance-of/types.ts @@ -0,0 +1,36 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import { Bytes } from '@ethersproject/bytes'; + +export type Address = `0x${string}`; + +export enum DelegationType { + NONE, + ALL, + CONTRACT, + ERC721, + ERC20, + ERC1155 +} + +export interface Delegation { + type_: DelegationType; + to: Address; + from: Address; + rights: Bytes; + contract_: Address; + tokenId: BigNumber; + amount: BigNumber; +} + +export interface DelegationStruct { + _: Delegation[]; + delegations_: Delegation[]; +} + +export interface DelegatedMapping { + [key: Address]: Address[]; +} + +export interface AddressScore { + [key: Address]: number; +} diff --git a/src/strategies/delegatexyz-erc721-balance-of/utils.ts b/src/strategies/delegatexyz-erc721-balance-of/utils.ts new file mode 100644 index 000000000..f7a9f3f83 --- /dev/null +++ b/src/strategies/delegatexyz-erc721-balance-of/utils.ts @@ -0,0 +1,20 @@ +import { Address, DelegatedMapping, AddressScore } from './types'; + +export const lowerCaseAddress = (address: Address) => + address.toLowerCase() as Address; + +export const calculateVotingPower = ( + inputAddresses: Address[], + addressScores: AddressScore, + walletMapping: DelegatedMapping +) => { + const userVotingPower = {}; + inputAddresses.map((address: Address) => { + let count = 0.0; + walletMapping[lowerCaseAddress(address)].map((address: Address) => { + count += addressScores[address]; + }); + userVotingPower[address] = count; + }); + return userVotingPower; +}; diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 49ec99860..0690f875c 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -1,6 +1,7 @@ import { readFileSync } from 'fs'; import path from 'path'; +import * as delegatexyzErc721BalanceOf from './delegatexyz-erc721-balance-of'; import * as urbitGalaxies from './urbit-galaxies/index'; import * as ecoVotingPower from './eco-voting-power'; import * as dpsNFTStrategy from './dps-nft-strategy'; @@ -442,6 +443,7 @@ import * as swarmStaking from './swarm-staking'; import * as mocaStaking from './moca-staking'; const strategies = { + 'delegatexyz-erc721-balance-of': delegatexyzErc721BalanceOf, 'giveth-balances-supply-weighted': givethBalancesSupplyWeighted, 'giveth-gnosis-balance-supply-weighted-v3': givethGnosisBalanceSupplyWeightedV3, From 3aceca930a62280b09597026477936d55a1cf802 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 26 Jul 2024 15:40:11 +0530 Subject: [PATCH 710/815] Automated lint (#1542) Co-authored-by: ChaituVR --- .../index.ts | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/strategies/rocketpool-node-operator-delegate-v8/index.ts b/src/strategies/rocketpool-node-operator-delegate-v8/index.ts index 8bd68edac..506d97c82 100644 --- a/src/strategies/rocketpool-node-operator-delegate-v8/index.ts +++ b/src/strategies/rocketpool-node-operator-delegate-v8/index.ts @@ -20,8 +20,7 @@ export async function strategy( options, snapshot ): Promise> { - const blockTag = - typeof snapshot === 'number' ? snapshot : 'latest'; + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; const validPrefix = 'rocketpool-node-operator-v'; if ( @@ -62,8 +61,12 @@ export async function strategy( const nodeAddress = getAddress(signerRegistryResponse[address]); const node = nodeAddressMap.get(nodeAddress); const signallingAddress = address; - const delegatesTo = node && node.delegatesTo ? getAddress(node.delegatesTo) : ''; - const delegators = node && node.delegators.length > 0 ? node.delegators.map((d) => getAddress(d.address)) : [nodeAddress]; + const delegatesTo = + node && node.delegatesTo ? getAddress(node.delegatesTo) : ''; + const delegators = + node && node.delegators.length > 0 + ? node.delegators.map((d) => getAddress(d.address)) + : [nodeAddress]; return { signallingAddress: signallingAddress, nodeAddress: nodeAddress, @@ -76,24 +79,30 @@ export async function strategy( nodeData.map((obj) => [getAddress(obj.nodeAddress), obj]) ); - const overrides = nodeData.map((node) => { - if (node.delegatesTo !== node.nodeAddress) { - return { - nodeAddress: node.nodeAddress, - delegatesTo: node.delegatesTo - }; - } - return {}; - }).filter((override) => Object.keys(override).length !== 0); + const overrides = nodeData + .map((node) => { + if (node.delegatesTo !== node.nodeAddress) { + return { + nodeAddress: node.nodeAddress, + delegatesTo: node.delegatesTo + }; + } + return {}; + }) + .filter((override) => Object.keys(override).length !== 0); if (Object.keys(overrides).length !== 0) { overrides.map((override) => { const delegate = nodeDataMap.get(override.delegatesTo); if (!delegate) return; - const delegators = delegate ? delegate.delegators.filter((d) => d !== override.nodeAddress) : []; + const delegators = delegate + ? delegate.delegators.filter((d) => d !== override.nodeAddress) + : []; delegate.delegators = delegators; nodeDataMap.set(override.delegatesTo, delegate); - const nodeToUpdate = nodeData.find((node) => node.nodeAddress === delegate.nodeAddress); + const nodeToUpdate = nodeData.find( + (node) => node.nodeAddress === delegate.nodeAddress + ); nodeToUpdate.delegators = delegators; }); } From 960324597f63f0bf7326b8aa00c732639d778328 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 2 Aug 2024 17:46:37 +0530 Subject: [PATCH 711/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.3 (#1543) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index a7221efa0..a13216fed 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.2", + "@snapshot-labs/snapshot.js": "^0.12.3", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 5ccce931e..b2378e55a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.2": - version "0.12.2" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.2.tgz#52e4bb57ba01cb19dadb66d6c76a08a00620dac9" - integrity sha512-FpaeefRC9Yb/BZRGFIP9LJlXfx/MdoxxVrtWEHvlfIkcI9Byv6eFvcXSOKJY6gU4UtHCFp77g+LJklTaJxxaXw== +"@snapshot-labs/snapshot.js@^0.12.3": + version "0.12.3" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.3.tgz#049b4c342d5386810c1d675329d5a24637e84bc2" + integrity sha512-9i0xkAfaQzvxV6oDLoHTrFRch2ta/9zZtqbn85JVEKFXa7y8/dQHa4sPkgyIGXdaeHNYj27gKDP6ofZqVYlN0Q== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From f23583a13999813381ab2e820ba03c9e28bc33a0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 2 Aug 2024 18:44:03 +0530 Subject: [PATCH 712/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.4 (#1544) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index a13216fed..6f505e504 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.3", + "@snapshot-labs/snapshot.js": "^0.12.4", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index b2378e55a..2b2100081 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.3": - version "0.12.3" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.3.tgz#049b4c342d5386810c1d675329d5a24637e84bc2" - integrity sha512-9i0xkAfaQzvxV6oDLoHTrFRch2ta/9zZtqbn85JVEKFXa7y8/dQHa4sPkgyIGXdaeHNYj27gKDP6ofZqVYlN0Q== +"@snapshot-labs/snapshot.js@^0.12.4": + version "0.12.4" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.4.tgz#d2cf1e2bb04714638f3b746bb212f9d93d2ab624" + integrity sha512-O9qxZ3qzH2CDBiMDGX4orQIFYKLKJMvpoF8uMsRhWVnp/CiH1eu5obxJCzys2n4o6KvvgtDQjS45b+7mh/85gA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 2067352d020f66770199c392f1ca1b977b5d5606 Mon Sep 17 00:00:00 2001 From: JD <103535732+JD0x2e@users.noreply.github.com> Date: Sat, 3 Aug 2024 18:21:57 +0100 Subject: [PATCH 713/815] [rdnt-capital-voting] Add base chain to rdnt-capital-voting (#1545) * [rdnt-capital-dlp] added total dlp check strategy * Create README.md * Added rdnt-capital-locked-dlp strategy * Reverted strategy back to lockedBalances as uint * Updated strategy which returns rdnt amount in locked dLP * added BSC functionality * RDNT in LP strat * Updated name * Update examples.json * Update src/strategies/rdnt-capital-voting/README.md Co-authored-by: Chaitanya * Update README.md * Add ethereum to rdnt-capital-voting * feat(radiant): add base to radiant-capital-voting * chore(radiant): examples json file * chore(radiant): lint files * fix(radiant): linting and add 3 tests to example base chain * fix(radiant): missing locking contract for base chain --------- Co-authored-by: TomBrandy <103236817+TomBrandy@users.noreply.github.com> Co-authored-by: JD <103535732+JDoy99@users.noreply.github.com> Co-authored-by: Chaitanya Co-authored-by: dcota <32775237+DaigaroCota@users.noreply.github.com> Co-authored-by: 0xdcota <32775237+0xdcota@users.noreply.github.com> --- .../rdnt-capital-voting/examples.json | 18 ++++++++++ src/strategies/rdnt-capital-voting/index.ts | 34 +++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/src/strategies/rdnt-capital-voting/examples.json b/src/strategies/rdnt-capital-voting/examples.json index a5805037b..02c5c44dc 100644 --- a/src/strategies/rdnt-capital-voting/examples.json +++ b/src/strategies/rdnt-capital-voting/examples.json @@ -56,5 +56,23 @@ "0x4011091Dbe57bd4521F598616fe4BB3978ea3005" ], "snapshot": 18483999 + }, + { + "name": "RDNT in dLP - Base", + "strategy": { + "name": "rdnt-capital-voting", + "params": { + "rdnt": "0xd722E55C1d9D9fA0021A5215Cbb904b92B3dC5d4", + "lpToken": "0x8A76639FE8e390Ed16eA88f87BEB46d6A5328254", + "lockingContract": "0xD87F8a52a91680c993ece968B281bf92505A3741" + } + }, + "network": "8453", + "addresses": [ + "0xD87F8a52a91680c993ece968B281bf92505A3741", + "0x4011091Dbe57bd4521F598616fe4BB3978ea3005", + "0x2eAA7327e9B5Ff46bc2B7452acE9e44A1528eb84" + ], + "snapshot": 17844635 } ] diff --git a/src/strategies/rdnt-capital-voting/index.ts b/src/strategies/rdnt-capital-voting/index.ts index 57a64cd9a..568a1e2a1 100644 --- a/src/strategies/rdnt-capital-voting/index.ts +++ b/src/strategies/rdnt-capital-voting/index.ts @@ -20,10 +20,42 @@ const balancerVaultAbi = [ 'function getPoolTokenInfo(bytes32,address) view returns (uint256)' ]; +const uniV3TokenizedLpAbi = [ + 'function getTotalAmounts() view returns (uint256, uint256)', + 'function token0() view returns (address)', + 'function totalSupply() view returns (uint256)' +]; + const toJsNum = (bn: BigNumberish) => { return parseFloat(formatUnits(bn)); }; +const rdntPerUniV3LpToken = async (network, provider, options, blockTag) => { + const [token0Bal, token1Bal] = await call(provider, uniV3TokenizedLpAbi, [ + options.lpToken, + 'getTotalAmounts', + [], + { blockTag } + ]); + + const [token0, totalSupplyBN] = await multicall( + network, + provider, + uniV3TokenizedLpAbi, + [ + [options.lpToken, 'token0'], + [options.lpToken, 'totalSupply'] + ], + { blockTag } + ); + const totalSupply = toJsNum(totalSupplyBN[0]); + const rdntInLp = + Number(token0) == Number(options.rdnt) + ? toJsNum(token0Bal) + : toJsNum(token1Bal); + return rdntInLp / totalSupply; +}; + const rdntPerBalancerLpToken = async (network, provider, options, blockTag) => { const rdntInVault = await call(provider, balancerVaultAbi, [ options.balancerVault, @@ -93,6 +125,8 @@ export async function strategy( ); } else if (network === '56') { rdntPerLp = await rdntPerUniLpToken(network, provider, options, blockTag); + } else if (network === '8453') { + rdntPerLp = await rdntPerUniV3LpToken(network, provider, options, blockTag); } // console.log(`RDNT per LP token: ${rdntPerLp}`); From 83764b6da7cd22c610f4fe831c041c700188bb25 Mon Sep 17 00:00:00 2001 From: PineCrypto <51626000+DramaCrypto@users.noreply.github.com> Date: Wed, 14 Aug 2024 01:49:40 +0800 Subject: [PATCH 714/815] [candy-lockv1-token] feat: Add candy-lockv1-strategy (#1547) * feat: Add candy-lockv1-strategy * Update src/strategies/candy-lockv1-token/index.ts --------- Co-authored-by: Chaitanya --- src/strategies/candy-lockv1-token/README.md | 12 ++++ .../candy-lockv1-token/examples.json | 22 +++++++ src/strategies/candy-lockv1-token/index.ts | 65 +++++++++++++++++++ src/strategies/candy-lockv1-token/schema.json | 22 +++++++ src/strategies/index.ts | 4 +- 5 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 src/strategies/candy-lockv1-token/README.md create mode 100644 src/strategies/candy-lockv1-token/examples.json create mode 100644 src/strategies/candy-lockv1-token/index.ts create mode 100644 src/strategies/candy-lockv1-token/schema.json diff --git a/src/strategies/candy-lockv1-token/README.md b/src/strategies/candy-lockv1-token/README.md new file mode 100644 index 000000000..8bc2e1b51 --- /dev/null +++ b/src/strategies/candy-lockv1-token/README.md @@ -0,0 +1,12 @@ +# candy-lockv1-token strategy + +This is the strategy for the Candy token lock v1 contracts in the Candy Defi , it returns the balances of the locked Candy tokens. + +Here is an example of parameters: + +```json +{ + "address": "0x7CeA583ea310b3A8a72Ed42B3364aff16d24B3A2", + "decimals": 18 +} +``` diff --git a/src/strategies/candy-lockv1-token/examples.json b/src/strategies/candy-lockv1-token/examples.json new file mode 100644 index 000000000..bd91e4a7a --- /dev/null +++ b/src/strategies/candy-lockv1-token/examples.json @@ -0,0 +1,22 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "candy-lockv1-token", + "params": { + "address": "0x7CeA583ea310b3A8a72Ed42B3364aff16d24B3A2" + } + }, + "network": "25", + "addresses": [ + "0x46B94710620d3E5626c5192aA80d2b362781997a", + "0x0f55730B5E34167aAf418050c0A1e52556041E55", + "0xc0Ee01A64d0466b2f500F6CAB92c553f913Db10A", + "0x5Abbf6aB860577E89C0483cF141e300bF8B74250", + "0x1d448201d3B781d8fFb00E1F9Ee99e0db212F3aC", + "0x88788e2c2d5f3362A8aB63E6a2e00a742fA946a2", + "0x34cfa46732692Ab062F0453036cd5a4f5B771473" + ], + "snapshot": 15303354 + } +] diff --git a/src/strategies/candy-lockv1-token/index.ts b/src/strategies/candy-lockv1-token/index.ts new file mode 100644 index 000000000..002b1642c --- /dev/null +++ b/src/strategies/candy-lockv1-token/index.ts @@ -0,0 +1,65 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'dramacrypto'; +export const version = '0.1.0'; + +const abi = [ + 'function lockCount(address account_) external view returns (uint256)', + 'function viewLocks(address account_, uint256 offset_, uint256 count_) external view returns (tuple(uint256 lid, uint256 amount, uint256 lockAt, uint256 duration, uint256 lastRewardAt, bool unlocked, uint256[] nfts)[])' +]; + +interface LockData { + lid: BigNumber; + unlocked: boolean; + amount: BigNumber; + lockAt: BigNumber; + duration: BigNumber; + lastRewardAt: BigNumber; + nfts: BigNumber[]; +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const lockCountMulti = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => + lockCountMulti.call(address, options.address, 'lockCount', [address]) + ); + const lockCountsResult: Record = + await lockCountMulti.execute(); + const lockCounts = Object.entries(lockCountsResult).map( + ([address, lockCount]) => [address, parseFloat(formatUnits(lockCount, 0))] + ); + + const lockDataMulti = new Multicaller(network, provider, abi, { blockTag }); + lockCounts.forEach(([address, lockCount]) => + lockDataMulti.call(address, options.address, 'viewLocks', [ + address, + 0, + lockCount + ]) + ); + const lockDatasMulti: Record = await lockDataMulti.execute(); + + return Object.fromEntries( + Object.entries(lockDatasMulti).map(([address, userLocks]) => { + const userLockedTokenAmount = userLocks + .filter((userLock: LockData) => !userLock.unlocked) + .reduce( + (cur, acc: LockData) => + cur + parseFloat(formatUnits(acc.amount, options.decimals)), + 0 + ); + return [address, userLockedTokenAmount]; + }) + ); +} diff --git a/src/strategies/candy-lockv1-token/schema.json b/src/strategies/candy-lockv1-token/schema.json new file mode 100644 index 000000000..32a5131a9 --- /dev/null +++ b/src/strategies/candy-lockv1-token/schema.json @@ -0,0 +1,22 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "address": { + "type": "string", + "title": "CandyLock contract address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } + }, + "required": ["address"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 0690f875c..6001a6f7a 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -441,6 +441,7 @@ import * as gardenStakes from './garden-stakes'; import * as csv from './csv'; import * as swarmStaking from './swarm-staking'; import * as mocaStaking from './moca-staking'; +import * as candyLockV1Token from './candy-lockv1-token'; const strategies = { 'delegatexyz-erc721-balance-of': delegatexyzErc721BalanceOf, @@ -892,7 +893,8 @@ const strategies = { 'garden-stakes': gardenStakes, csv, 'swarm-staking': swarmStaking, - 'moca-staking': mocaStaking + 'moca-staking': mocaStaking, + 'candy-lockv1-token': candyLockV1Token }; Object.keys(strategies).forEach(function (strategyName) { From 7604184aaac842da412ae3cbca11c1b4fa1e33e6 Mon Sep 17 00:00:00 2001 From: 0xAlchemist <0xalchemist@proton.me> Date: Tue, 13 Aug 2024 21:28:55 -0700 Subject: [PATCH 715/815] patch [delegatexyz-erc721-balance-of] delegatexyz-erc721-balance-of (#1546) * prevent exploiting voting power by restricting to latest delegation per 'from' address * cleanup * Update src/strategies/delegatexyz-erc721-balance-of/constants.ts Co-authored-by: Chaitanya * avoid exploiting voting power by restricting to latest delegation * update readme --------- Co-authored-by: Chaitanya --- .../delegatexyz-erc721-balance-of/README.md | 2 + .../constants.ts | 3 +- .../delegatexyz-erc721-balance-of/index.ts | 45 ++++++++++++++++--- 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/src/strategies/delegatexyz-erc721-balance-of/README.md b/src/strategies/delegatexyz-erc721-balance-of/README.md index 921c4d62d..7655e14e0 100644 --- a/src/strategies/delegatexyz-erc721-balance-of/README.md +++ b/src/strategies/delegatexyz-erc721-balance-of/README.md @@ -4,6 +4,8 @@ This enables Delegate.xyz users to vote from their delegate wallet while using E Delegate.xyz (V2) Full wallet and smart contract level delegation are both supported. +If a user has delegated access to multiple wallets, the most recent delegation will be calculated. + This strategy uses the same parameters as erc721-balance-of, but the signing wallet is now the delegate wallet. -- Made with Love by ApesPlus diff --git a/src/strategies/delegatexyz-erc721-balance-of/constants.ts b/src/strategies/delegatexyz-erc721-balance-of/constants.ts index 93963f1d9..f615059f8 100644 --- a/src/strategies/delegatexyz-erc721-balance-of/constants.ts +++ b/src/strategies/delegatexyz-erc721-balance-of/constants.ts @@ -1,5 +1,6 @@ export const abi = [ - 'function getIncomingDelegations(address to) view returns (tuple(uint8 type_, address to, address from, bytes32 rights, address contract_, uint256 tokenId, uint256 amount)[] delegations_)' + 'function getIncomingDelegations(address to) view returns (tuple(uint8 type_, address to, address from, bytes32 rights, address contract_, uint256 tokenId, uint256 amount)[] delegations_)', + 'function getOutgoingDelegations(address from) view returns (tuple(uint8 type_, address to, address from, bytes32 rights, address contract_, uint256 tokenId, uint256 amount)[] delegations_)' ]; export const delegatexyzV2ContractAddress = diff --git a/src/strategies/delegatexyz-erc721-balance-of/index.ts b/src/strategies/delegatexyz-erc721-balance-of/index.ts index 612789713..7c2511d85 100644 --- a/src/strategies/delegatexyz-erc721-balance-of/index.ts +++ b/src/strategies/delegatexyz-erc721-balance-of/index.ts @@ -12,7 +12,7 @@ import { } from './types'; export const author = 'apesplus'; -export const version = '0.1.0'; +export const version = '0.1.1'; export async function strategy( space, @@ -24,6 +24,8 @@ export async function strategy( ) { const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; const mappedDelegations: DelegatedMapping = {}; + const delegators: Address[] = []; + const allowlist: Address[] = []; // Use the provided addresses as the keys for our mapping addresses.map((address: Address) => { @@ -43,23 +45,56 @@ export async function strategy( { blockTag } ); + // build a list of delegators (from addresses) so we can check + // outgoing delegations + response.forEach((data: DelegationStruct) => { + data.delegations_.forEach((delegation: Delegation) => { + if (!delegators.includes(delegation.from)) { + delegators.push(delegation.from); + } + }); + }); + + // check outgoing delegations for each delegator + const outgoing = await multicall( + network, + provider, + abi, + delegators.map((address: Address) => [ + delegatexyzV2ContractAddress, + 'getOutgoingDelegations', + [address] + ]), + { blockTag } + ); + + outgoing.forEach((data: DelegationStruct) => { + const latest: Delegation = data.delegations_.slice(-1)[0]; + // whitelist the most recent outgoing delegation (to) address + // to prevent users from voting multiple times for each asset + // stored in the vault + if (!allowlist.includes(latest.to)) { + allowlist.push(latest.to); + } + }); + // complete the mapping from the results of // the multicall to getIncomingDelegations if (response.length) { - response.map((data: DelegationStruct) => { - data.delegations_.map((delegation: Delegation) => { + response.forEach((data: DelegationStruct) => { + data.delegations_.forEach((delegation: Delegation) => { const { to, from, type_, contract_ } = delegation; // Check for full wallet delegation first and // add the vault to the mapping - if (type_ === DelegationType.ALL) { + if (type_ === DelegationType.ALL && allowlist.includes(to)) { mappedDelegations[lowerCaseAddress(to)].push(from); } // Check for contract level delegation and add // to the mapping if contract is correct and the // vault address is not already mapped - if (type_ === DelegationType.CONTRACT) { + if (type_ === DelegationType.CONTRACT && allowlist.includes(to)) { if (contract_ !== options.address) return; if (mappedDelegations[lowerCaseAddress(to)].includes(from)) return; From 0ddf9d7c13632109c3417fd2de31848d7f95e5ff Mon Sep 17 00:00:00 2001 From: PineCrypto <51626000+DramaCrypto@users.noreply.github.com> Date: Wed, 14 Aug 2024 20:10:49 +0800 Subject: [PATCH 716/815] [candy-lock-token] feat: Add new strategy "candy-lock-token" (#1550) * feat: Add new strategy "candy-lock-token" * feat: Update to have limited multicall --- src/strategies/candy-lock-token/README.md | 14 ++ src/strategies/candy-lock-token/examples.json | 28 ++++ src/strategies/candy-lock-token/index.ts | 140 ++++++++++++++++++ src/strategies/candy-lock-token/schema.json | 44 ++++++ src/strategies/index.ts | 4 +- 5 files changed, 229 insertions(+), 1 deletion(-) create mode 100644 src/strategies/candy-lock-token/README.md create mode 100644 src/strategies/candy-lock-token/examples.json create mode 100644 src/strategies/candy-lock-token/index.ts create mode 100644 src/strategies/candy-lock-token/schema.json diff --git a/src/strategies/candy-lock-token/README.md b/src/strategies/candy-lock-token/README.md new file mode 100644 index 000000000..6a471209b --- /dev/null +++ b/src/strategies/candy-lock-token/README.md @@ -0,0 +1,14 @@ +# candy-lock-token strategy + +This is the strategy for the Candy token lock v1 / v2 / v3 contracts in the Candy Defi , it returns the balances of the locked Candy tokens. + +Here is an example of parameters: + +```json +{ + "v1_address": "0x7CeA583ea310b3A8a72Ed42B3364aff16d24B3A2", + "v2_address": "0x094EcA6E834Fbe726f8b7670267244dC3983be73", + "v3_address": "0xbAEe5f69927B995478b05c400E15755217804118", + "decimals": 18 +} +``` diff --git a/src/strategies/candy-lock-token/examples.json b/src/strategies/candy-lock-token/examples.json new file mode 100644 index 000000000..a45173478 --- /dev/null +++ b/src/strategies/candy-lock-token/examples.json @@ -0,0 +1,28 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "candy-lock-token", + "params": { + "v1_address": "0x7CeA583ea310b3A8a72Ed42B3364aff16d24B3A2", + "v2_address": "0x094EcA6E834Fbe726f8b7670267244dC3983be73", + "v3_address": "0xbAEe5f69927B995478b05c400E15755217804118", + "decimals": 18 + } + }, + "network": "25", + "addresses": [ + "0x46B94710620d3E5626c5192aA80d2b362781997a", + "0x0f55730B5E34167aAf418050c0A1e52556041E55", + "0xc0Ee01A64d0466b2f500F6CAB92c553f913Db10A", + "0x5Abbf6aB860577E89C0483cF141e300bF8B74250", + "0x1d448201d3B781d8fFb00E1F9Ee99e0db212F3aC", + "0x88788e2c2d5f3362A8aB63E6a2e00a742fA946a2", + "0x34cfa46732692Ab062F0453036cd5a4f5B771473", + "0x743aAdEBf260f6282a2E1AaC0b9630A3Efaf0F93", + "0x971541C1f8368957411980354ce966dD4A27E0E3", + "0x090fF72fb73b289BB233Fe7d1e8FDd8AdD9Cf534" + ], + "snapshot": 15303354 + } +] diff --git a/src/strategies/candy-lock-token/index.ts b/src/strategies/candy-lock-token/index.ts new file mode 100644 index 000000000..a5e66b808 --- /dev/null +++ b/src/strategies/candy-lock-token/index.ts @@ -0,0 +1,140 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'dramacrypto'; +export const version = '0.1.0'; + +const v1Abi = [ + 'function lockCount(address account_) external view returns (uint256)', + 'function viewLocks(address account_, uint256 offset_, uint256 count_) external view returns (tuple(uint256 lid, uint256 amount, uint256 lockAt, uint256 duration, uint256 lastRewardAt, bool unlocked, uint256[] nfts)[])' +]; +const v2Abi = [ + 'function userAllLockCount(address account) external view returns (uint256)', + 'function userAllLocks(address account, uint256 from, uint256 count) external view returns (tuple(address owner, uint256 id, uint256 tokenAmount, uint256 lockAt, uint256 duration, uint256 lastRewardAt, uint256 listPrice, uint256[] nftIds, uint8[] nftRarities)[])' +]; + +interface V1LockData { + lid: BigNumber; + unlocked: boolean; + amount: BigNumber; + lockAt: BigNumber; + duration: BigNumber; + lastRewardAt: BigNumber; + nfts: BigNumber[]; +} + +interface V2LockData { + owner: string; + id: BigNumber; + tokenAmount: BigNumber; + lockAt: BigNumber; + duration: BigNumber; + lastRewardAt: BigNumber; + listPrice: BigNumber; + nftIds: BigNumber[]; + nftRarities: number[]; +} + +async function v1_scores( + network, + provider, + addresses, + snapshot, + contract_address, + token_decimals +): Promise<[string, number][]> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const lockDataMulti = new Multicaller(network, provider, v1Abi, { blockTag }); + addresses.forEach((address) => + lockDataMulti.call(address, contract_address, 'viewLocks', [ + address, + 0, + 1000 + ]) + ); + const lockDatasMulti: Record = await lockDataMulti.execute(); + + return Object.entries(lockDatasMulti).map(([address, userLocks]) => { + const userLockedTokenAmount = userLocks + .filter((userLock: V1LockData) => !userLock.unlocked) + .reduce( + (cur, acc: V1LockData) => + cur + parseFloat(formatUnits(acc.amount, token_decimals)), + 0 + ); + return [address, userLockedTokenAmount]; + }); +} + +async function v2_3_scores( + network, + provider, + addresses, + snapshot, + contract_address, + token_decimals +): Promise<[string, number][]> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const lockDataMulti = new Multicaller(network, provider, v2Abi, { blockTag }); + addresses.forEach((address) => + lockDataMulti.call(address, contract_address, 'userAllLocks', [ + address, + 0, + 1000 + ]) + ); + const lockDatasMulti: Record = await lockDataMulti.execute(); + + return Object.entries(lockDatasMulti).map(([address, userLocks]) => { + const userLockedTokenAmount = userLocks.reduce( + (cur, acc: V2LockData) => + cur + parseFloat(formatUnits(acc.tokenAmount, token_decimals)), + 0 + ); + return [address, userLockedTokenAmount]; + }); +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const v1Scores = await v1_scores( + network, + provider, + addresses, + snapshot, + options.v1_address, + options.decimals + ); + const v2Scores = await v2_3_scores( + network, + provider, + addresses, + snapshot, + options.v2_address, + options.decimals + ); + const v3Scores = await v2_3_scores( + network, + provider, + addresses, + snapshot, + options.v3_address, + options.decimals + ); + + return Object.fromEntries( + v1Scores.map(([address, v1Score], index) => { + const totalScore = v1Score + v2Scores[index][1] + v3Scores[index][1]; + return [address, totalScore]; + }) + ); +} diff --git a/src/strategies/candy-lock-token/schema.json b/src/strategies/candy-lock-token/schema.json new file mode 100644 index 000000000..c8192d301 --- /dev/null +++ b/src/strategies/candy-lock-token/schema.json @@ -0,0 +1,44 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "v1_address": { + "type": "string", + "title": "CandyLock v1 contract address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "v2_address": { + "type": "string", + "title": "CandyLock v2 contract address", + "examples": ["e.g. 0x094EcA6E834Fbe726f8b7670267244dC3983be73"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "v3_address": { + "type": "string", + "title": "CandyLock v3 contract address", + "examples": ["e.g. 0xbAEe5f69927B995478b05c400E15755217804118"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Candy token decimals", + "examples": ["e.g. 18"], + "minimum": 0 + } + }, + "required": ["v1_address", "v2_address", "v3_address", "decimals"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 6001a6f7a..40b48ecf7 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -442,6 +442,7 @@ import * as csv from './csv'; import * as swarmStaking from './swarm-staking'; import * as mocaStaking from './moca-staking'; import * as candyLockV1Token from './candy-lockv1-token'; +import * as candyLockToken from './candy-lock-token'; const strategies = { 'delegatexyz-erc721-balance-of': delegatexyzErc721BalanceOf, @@ -894,7 +895,8 @@ const strategies = { csv, 'swarm-staking': swarmStaking, 'moca-staking': mocaStaking, - 'candy-lockv1-token': candyLockV1Token + 'candy-lockv1-token': candyLockV1Token, + 'candy-lock-token': candyLockToken }; Object.keys(strategies).forEach(function (strategyName) { From bfc64869582538d625c3a13e6b3242361ee30d14 Mon Sep 17 00:00:00 2001 From: PineCrypto <51626000+DramaCrypto@users.noreply.github.com> Date: Wed, 14 Aug 2024 20:19:17 +0800 Subject: [PATCH 717/815] [candy-lock-nft] feat: Add new strategy "candy-lock-nft" (#1551) * feat: Add new strategy "candy-lock-nft" * feat: Update the strategy to have limited multicall --- src/strategies/candy-lock-nft/README.md | 13 ++ src/strategies/candy-lock-nft/examples.json | 27 ++++ src/strategies/candy-lock-nft/index.ts | 134 ++++++++++++++++++++ src/strategies/candy-lock-nft/schema.json | 38 ++++++ src/strategies/index.ts | 4 +- 5 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 src/strategies/candy-lock-nft/README.md create mode 100644 src/strategies/candy-lock-nft/examples.json create mode 100644 src/strategies/candy-lock-nft/index.ts create mode 100644 src/strategies/candy-lock-nft/schema.json diff --git a/src/strategies/candy-lock-nft/README.md b/src/strategies/candy-lock-nft/README.md new file mode 100644 index 000000000..c3a4d8330 --- /dev/null +++ b/src/strategies/candy-lock-nft/README.md @@ -0,0 +1,13 @@ +# candy-lock-nft strategy + +This is the strategy for the Candy token lock v1 / v2 / v3 contracts in the Candy Defi , it returns the counts of the locked nfts. + +Here is an example of parameters: + +```json +{ + "v1_address": "0x7CeA583ea310b3A8a72Ed42B3364aff16d24B3A2", + "v2_address": "0x094EcA6E834Fbe726f8b7670267244dC3983be73", + "v3_address": "0xbAEe5f69927B995478b05c400E15755217804118" +} +``` diff --git a/src/strategies/candy-lock-nft/examples.json b/src/strategies/candy-lock-nft/examples.json new file mode 100644 index 000000000..12c60feb2 --- /dev/null +++ b/src/strategies/candy-lock-nft/examples.json @@ -0,0 +1,27 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "candy-lock-nft", + "params": { + "v1_address": "0x7CeA583ea310b3A8a72Ed42B3364aff16d24B3A2", + "v2_address": "0x094EcA6E834Fbe726f8b7670267244dC3983be73", + "v3_address": "0xbAEe5f69927B995478b05c400E15755217804118" + } + }, + "network": "25", + "addresses": [ + "0x46B94710620d3E5626c5192aA80d2b362781997a", + "0x0f55730B5E34167aAf418050c0A1e52556041E55", + "0xc0Ee01A64d0466b2f500F6CAB92c553f913Db10A", + "0x5Abbf6aB860577E89C0483cF141e300bF8B74250", + "0x1d448201d3B781d8fFb00E1F9Ee99e0db212F3aC", + "0x88788e2c2d5f3362A8aB63E6a2e00a742fA946a2", + "0x34cfa46732692Ab062F0453036cd5a4f5B771473", + "0x743aAdEBf260f6282a2E1AaC0b9630A3Efaf0F93", + "0x971541C1f8368957411980354ce966dD4A27E0E3", + "0x090fF72fb73b289BB233Fe7d1e8FDd8AdD9Cf534" + ], + "snapshot": 15303354 + } +] diff --git a/src/strategies/candy-lock-nft/index.ts b/src/strategies/candy-lock-nft/index.ts new file mode 100644 index 000000000..49afde1b4 --- /dev/null +++ b/src/strategies/candy-lock-nft/index.ts @@ -0,0 +1,134 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import { Multicaller } from '../../utils'; + +export const author = 'dramacrypto'; +export const version = '0.1.0'; + +const v1Abi = [ + 'function lockCount(address account_) external view returns (uint256)', + 'function viewLocks(address account_, uint256 offset_, uint256 count_) external view returns (tuple(uint256 lid, uint256 amount, uint256 lockAt, uint256 duration, uint256 lastRewardAt, bool unlocked, uint256[] nfts)[])' +]; +const v2Abi = [ + 'function userAllLockCount(address account) external view returns (uint256)', + 'function userAllLocks(address account, uint256 from, uint256 count) external view returns (tuple(address owner, uint256 id, uint256 tokenAmount, uint256 lockAt, uint256 duration, uint256 lastRewardAt, uint256 listPrice, uint256[] nftIds, uint8[] nftRarities)[])' +]; + +interface V1LockData { + lid: BigNumber; + unlocked: boolean; + amount: BigNumber; + lockAt: BigNumber; + duration: BigNumber; + lastRewardAt: BigNumber; + nfts: BigNumber[]; +} + +interface V2LockData { + owner: string; + id: BigNumber; + tokenAmount: BigNumber; + lockAt: BigNumber; + duration: BigNumber; + lastRewardAt: BigNumber; + listPrice: BigNumber; + nftIds: BigNumber[]; + nftRarities: number[]; +} + +async function v1_scores( + network, + provider, + addresses, + snapshot, + contract_address, + token_decimals +): Promise<[string, number][]> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const lockDataMulti = new Multicaller(network, provider, v1Abi, { blockTag }); + addresses.forEach((address) => + lockDataMulti.call(address, contract_address, 'viewLocks', [ + address, + 0, + 1000 + ]) + ); + const lockDatasMulti: Record = await lockDataMulti.execute(); + + return Object.entries(lockDatasMulti).map(([address, userLocks]) => { + const userLockedTokenAmount = userLocks + .filter((userLock: V1LockData) => !userLock.unlocked) + .reduce((cur, acc: V1LockData) => cur + acc.nfts.length, 0); + return [address, userLockedTokenAmount]; + }); +} + +async function v2_3_scores( + network, + provider, + addresses, + snapshot, + contract_address, + token_decimals +): Promise<[string, number][]> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const lockDataMulti = new Multicaller(network, provider, v2Abi, { blockTag }); + addresses.forEach((address) => + lockDataMulti.call(address, contract_address, 'userAllLocks', [ + address, + 0, + 1000 + ]) + ); + const lockDatasMulti: Record = await lockDataMulti.execute(); + + return Object.entries(lockDatasMulti).map(([address, userLocks]) => { + const userLockedTokenAmount = userLocks.reduce( + (cur, acc: V2LockData) => cur + acc.nftIds.length, + 0 + ); + return [address, userLockedTokenAmount]; + }); +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const v1Scores = await v1_scores( + network, + provider, + addresses, + snapshot, + options.v1_address, + options.decimals + ); + const v2Scores = await v2_3_scores( + network, + provider, + addresses, + snapshot, + options.v2_address, + options.decimals + ); + const v3Scores = await v2_3_scores( + network, + provider, + addresses, + snapshot, + options.v3_address, + options.decimals + ); + + return Object.fromEntries( + v1Scores.map(([address, v1Score], index) => { + const totalScore = v1Score + v2Scores[index][1] + v3Scores[index][1]; + return [address, totalScore]; + }) + ); +} diff --git a/src/strategies/candy-lock-nft/schema.json b/src/strategies/candy-lock-nft/schema.json new file mode 100644 index 000000000..56e8150c6 --- /dev/null +++ b/src/strategies/candy-lock-nft/schema.json @@ -0,0 +1,38 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "v1_address": { + "type": "string", + "title": "CandyLock v1 contract address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "v2_address": { + "type": "string", + "title": "CandyLock v2 contract address", + "examples": ["e.g. 0x094EcA6E834Fbe726f8b7670267244dC3983be73"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "v3_address": { + "type": "string", + "title": "CandyLock v3 contract address", + "examples": ["e.g. 0xbAEe5f69927B995478b05c400E15755217804118"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } + }, + "required": ["v1_address", "v2_address", "v3_address"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 40b48ecf7..2e95d95e9 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -443,6 +443,7 @@ import * as swarmStaking from './swarm-staking'; import * as mocaStaking from './moca-staking'; import * as candyLockV1Token from './candy-lockv1-token'; import * as candyLockToken from './candy-lock-token'; +import * as candyLockNft from './candy-lock-nft'; const strategies = { 'delegatexyz-erc721-balance-of': delegatexyzErc721BalanceOf, @@ -896,7 +897,8 @@ const strategies = { 'swarm-staking': swarmStaking, 'moca-staking': mocaStaking, 'candy-lockv1-token': candyLockV1Token, - 'candy-lock-token': candyLockToken + 'candy-lock-token': candyLockToken, + 'candy-lock-nft': candyLockNft }; Object.keys(strategies).forEach(function (strategyName) { From 026856902b35b9a528fbeaa65a7260fce7a218f5 Mon Sep 17 00:00:00 2001 From: PineCrypto <51626000+DramaCrypto@users.noreply.github.com> Date: Wed, 14 Aug 2024 20:38:47 +0800 Subject: [PATCH 718/815] [candy-auto-vault] feat: Add new strategy "candy-auto-vault" (#1552) * feat: Add candy-auto-vault strategy * Update index.ts * feat: Update strategy and example --------- Co-authored-by: Chaitanya --- src/strategies/candy-auto-vault/README.md | 12 ++ src/strategies/candy-auto-vault/examples.json | 27 +++++ src/strategies/candy-auto-vault/index.ts | 112 ++++++++++++++++++ src/strategies/candy-auto-vault/schema.json | 28 +++++ src/strategies/index.ts | 2 + 5 files changed, 181 insertions(+) create mode 100644 src/strategies/candy-auto-vault/README.md create mode 100644 src/strategies/candy-auto-vault/examples.json create mode 100644 src/strategies/candy-auto-vault/index.ts create mode 100644 src/strategies/candy-auto-vault/schema.json diff --git a/src/strategies/candy-auto-vault/README.md b/src/strategies/candy-auto-vault/README.md new file mode 100644 index 000000000..1d109114f --- /dev/null +++ b/src/strategies/candy-auto-vault/README.md @@ -0,0 +1,12 @@ +# candy-auto-vault strategy + +This is the strategy for the Candy auto-compounding vault contracts in the Candy Defi, it returns the Candy balances in the auto-compounding vault contract. + +Here is an example of parameters: + +```json +{ + "address": "0x7CeA583ea310b3A8a72Ed42B3364aff16d24B3A2", + "decimals": 18 +} +``` diff --git a/src/strategies/candy-auto-vault/examples.json b/src/strategies/candy-auto-vault/examples.json new file mode 100644 index 000000000..f54888981 --- /dev/null +++ b/src/strategies/candy-auto-vault/examples.json @@ -0,0 +1,27 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "candy-auto-vault", + "params": { + "address": "0x8FEf43b1f3046F8f58A76c64aD01Bc8d82ff0ad1", + "decimals": 18 + } + }, + "network": "25", + "addresses": [ + "0xe63C9580F032047883eac063E3F0b700033B823A", + "0x1152694659bc4a982946fe3e7d7aa26e9c6EB2b7", + "0x5fB141dF98c72F31766E8eE6A4a0f224BBA26777", + "0x5Abbf6aB860577E89C0483cF141e300bF8B74250", + "0x5E54Ea4F4BeeDFdece613a67eB1fCbE06d15F845", + "0x19E53469BdfD70e103B18D9De7627d88c4506DF2", + "0xf0709362bAE2c85A65dD749d1482dC7d576116fe", + "0x12fe999052B5779FE5A8266C363462bbE38626cD", + "0xFc7bB93d64CD48D5754830B70630d9eE89C87C44", + "0x090fF72fb73b289BB233Fe7d1e8FDd8AdD9Cf534", + "0x172A25d57dA59AB86792FB8cED103ad871CBEf34" + ], + "snapshot": 15303354 + } +] diff --git a/src/strategies/candy-auto-vault/index.ts b/src/strategies/candy-auto-vault/index.ts new file mode 100644 index 000000000..ccd38393f --- /dev/null +++ b/src/strategies/candy-auto-vault/index.ts @@ -0,0 +1,112 @@ +import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { multicall, Multicaller } from '../../utils'; + +export const author = 'dramacrypto'; +export const version = '0.1.0'; + +const vaultAbi = [ + 'function getPricePerFullShare() external view returns (uint256)', + 'function calculatePerformanceFee(address _user) public view returns (uint256)', + 'function calculateOverdueFee(address _user) public view returns (uint256)', + 'function userInfo(address account) external view returns (uint256 shares, uint256 lastDepositedTime, uint256 candyAtLastUserAction, uint256 lastUserActionTime, uint256 lockStartTime, uint256 lockEndTime, uint256 userBoostedShare, bool locked, uint256 lockedAmount)' +]; + +interface UserInfo { + shares: BigNumber; + lastDepositedTIme: BigNumber; + candyAtLastUserAction: BigNumber; + lastUserActionTime: BigNumber; + lockStartTime: BigNumber; + lockEndTime: BigNumber; + userBoostedShare: BigNumber; + locked: boolean; + lockedAmount: BigNumber; +} + +function convertSharesToCandy( + shares: BigNumber, + pricePerFullShare: BigNumber, + decimals = 18, + fee?: BigNumber +): number { + const amountCandyBigNumber = shares + .mul(pricePerFullShare) + .div(BigNumber.from(10).pow(decimals)) + .sub(fee || BigNumber.from(0)); + const amountCandyAsNumber = parseFloat( + formatUnits(amountCandyBigNumber, decimals) + ); + return amountCandyAsNumber; +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + // get price per full share + const pricePerFullShare = await multicall( + network, + provider, + vaultAbi, + [[options.address, 'getPricePerFullShare', []]], + { blockTag } + ); + + // get user info + const userInfoMulti = new Multicaller(network, provider, vaultAbi, { + blockTag + }); + addresses.forEach((address) => + userInfoMulti.call(address, options.address, 'userInfo', [address]) + ); + const userInfosResult: Record = + await userInfoMulti.execute(); + + // calculate performance fee + const performanceFeeMulti = new Multicaller(network, provider, vaultAbi, { + blockTag + }); + addresses.forEach((address) => + performanceFeeMulti.call( + address, + options.address, + 'calculatePerformanceFee', + [address] + ) + ); + const performanceFeesResult: Record = + await performanceFeeMulti.execute(); + + // calculate overdue fee + const overdueFeeMulti = new Multicaller(network, provider, vaultAbi, { + blockTag + }); + addresses.forEach((address) => + overdueFeeMulti.call(address, options.address, 'calculateOverdueFee', [ + address + ]) + ); + const overdueFeesResult: Record = + await overdueFeeMulti.execute(); + + return Object.fromEntries( + Object.entries(userInfosResult).map(([address, userInfo]) => { + const userBalance = convertSharesToCandy( + BigNumber.from(userInfo.shares.toString()), + pricePerFullShare[0].toString(), + options.decimals, + BigNumber.from(overdueFeesResult[address]) + .add(performanceFeesResult[address]) + .add(userInfo.userBoostedShare) + ); + return [address, userBalance]; + }) + ); +} diff --git a/src/strategies/candy-auto-vault/schema.json b/src/strategies/candy-auto-vault/schema.json new file mode 100644 index 000000000..78ba56137 --- /dev/null +++ b/src/strategies/candy-auto-vault/schema.json @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "address": { + "type": "string", + "title": "Candy auto-comound vault contract address", + "examples": ["e.g. 0x8FEf43b1f3046F8f58A76c64aD01Bc8d82ff0ad1"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Candy token decimals", + "examples": ["e.g. 18"], + "minimum": 0 + } + }, + "required": ["address", "decimals"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 2e95d95e9..79cac4e3a 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -443,6 +443,7 @@ import * as swarmStaking from './swarm-staking'; import * as mocaStaking from './moca-staking'; import * as candyLockV1Token from './candy-lockv1-token'; import * as candyLockToken from './candy-lock-token'; +import * as candyAutoVault from './candy-auto-vault'; import * as candyLockNft from './candy-lock-nft'; const strategies = { @@ -898,6 +899,7 @@ const strategies = { 'moca-staking': mocaStaking, 'candy-lockv1-token': candyLockV1Token, 'candy-lock-token': candyLockToken, + 'candy-auto-vault': candyAutoVault, 'candy-lock-nft': candyLockNft }; From ad1e32793e8426360a7f12926254c748a36902af Mon Sep 17 00:00:00 2001 From: PineCrypto <51626000+DramaCrypto@users.noreply.github.com> Date: Wed, 14 Aug 2024 22:55:03 +0800 Subject: [PATCH 719/815] feat: Add new strategy "candy-nft-staking" (#1553) --- src/strategies/candy-nft-staking/README.md | 12 ++++ .../candy-nft-staking/examples.json | 29 ++++++++++ src/strategies/candy-nft-staking/index.ts | 55 +++++++++++++++++++ src/strategies/candy-nft-staking/schema.json | 30 ++++++++++ src/strategies/index.ts | 4 +- 5 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 src/strategies/candy-nft-staking/README.md create mode 100644 src/strategies/candy-nft-staking/examples.json create mode 100644 src/strategies/candy-nft-staking/index.ts create mode 100644 src/strategies/candy-nft-staking/schema.json diff --git a/src/strategies/candy-nft-staking/README.md b/src/strategies/candy-nft-staking/README.md new file mode 100644 index 000000000..764c6b968 --- /dev/null +++ b/src/strategies/candy-nft-staking/README.md @@ -0,0 +1,12 @@ +# candy-nft-staking strategy + +This is the strategy for the Candy nft fixed / shared staking contracts in the Candy Defi , it returns the counts of the staked nfts. + +Here is an example of parameters: + +```json +{ + "fixed_staking_address": "0xA46C4a3428a5E9B5C84A4457215D98BC8DC17AbB", + "shared_staking_address": "0xCa207941946218126BD7BBe44C5d457753490b4A" +} +``` diff --git a/src/strategies/candy-nft-staking/examples.json b/src/strategies/candy-nft-staking/examples.json new file mode 100644 index 000000000..25c788096 --- /dev/null +++ b/src/strategies/candy-nft-staking/examples.json @@ -0,0 +1,29 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "candy-nft-staking", + "params": { + "fixed_staking_address": "0xA46C4a3428a5E9B5C84A4457215D98BC8DC17AbB", + "shared_staking_address": "0xCa207941946218126BD7BBe44C5d457753490b4A" + } + }, + "network": "25", + "addresses": [ + "0xB45C6BFB18BD516Af6ceB3db34c1CE24852E75b3", + "0xC1B329FC60aB809191566129175d79B979067F21", + "0x229279f27352129B8FeFC4e751D8cB6972482B93", + "0x5Abbf6aB860577E89C0483cF141e300bF8B74250", + "0x0Cf17da8daFaa4925b142dfD6eD46E56FA04DF0A", + "0x88788e2c2d5f3362A8aB63E6a2e00a742fA946a2", + "0x81d9a4A193095f626F9bA3a1185C35377039B138", + "0xB6f737AF7159d7C4711db5564F5238ea7e56908f", + "0x97570Aba03745134f74E2F2c8c302061A20dc480", + "0xe1a7FC20a848eE97D2218a6e9c1ecF11194E017E", + "0xF0F821115D9F3e9A1A579249980a0Ac0FCd7bD0d", + "0x4239E9044CBB5301eb51F3B7dA58e8496B86fdcd", + "0x132EB9222dAE73A24D703e3702608916E5577814" + ], + "snapshot": 15303354 + } +] diff --git a/src/strategies/candy-nft-staking/index.ts b/src/strategies/candy-nft-staking/index.ts new file mode 100644 index 000000000..e8e0bc3d2 --- /dev/null +++ b/src/strategies/candy-nft-staking/index.ts @@ -0,0 +1,55 @@ +import { Multicaller } from '../../utils'; + +export const author = 'dramacrypto'; +export const version = '0.1.0'; + +const stakingAbi = [ + 'function stakedNfts(address _account, uint256 _offset, uint256 _count) external view returns (uint256[])' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const fixedStakingMulti = new Multicaller(network, provider, stakingAbi, { + blockTag + }); + addresses.forEach((address) => + fixedStakingMulti.call( + address, + options.fixed_staking_address, + 'stakedNfts', + [address, 0, 10000] + ) + ); + const fixedStakingResults: Record = + await fixedStakingMulti.execute(); + + const sharedStakingMulti = new Multicaller(network, provider, stakingAbi, { + blockTag + }); + addresses.forEach((address) => + sharedStakingMulti.call( + address, + options.shared_staking_address, + 'stakedNfts', + [address, 0, 10000] + ) + ); + const sharedStakingResults: Record = + await sharedStakingMulti.execute(); + + return Object.fromEntries( + Object.entries(fixedStakingResults).map(([address, fixedStakedNfts]) => { + const stakedNftCount = + fixedStakedNfts.length + sharedStakingResults[address].length; + return [address, stakedNftCount]; + }) + ); +} diff --git a/src/strategies/candy-nft-staking/schema.json b/src/strategies/candy-nft-staking/schema.json new file mode 100644 index 000000000..93ee23053 --- /dev/null +++ b/src/strategies/candy-nft-staking/schema.json @@ -0,0 +1,30 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "fixed_staking_address": { + "type": "string", + "title": "Candy nft fixed staking contract address", + "examples": ["e.g. 0xA46C4a3428a5E9B5C84A4457215D98BC8DC17AbB"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "shared_staking_address": { + "type": "string", + "title": "Candy nft shared staking contract address", + "examples": ["e.g. 0xCa207941946218126BD7BBe44C5d457753490b4A"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } + }, + "required": ["fixed_staking_address", "shared_staking_address"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 79cac4e3a..9956c7ad9 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -445,6 +445,7 @@ import * as candyLockV1Token from './candy-lockv1-token'; import * as candyLockToken from './candy-lock-token'; import * as candyAutoVault from './candy-auto-vault'; import * as candyLockNft from './candy-lock-nft'; +import * as candyNftStaking from './candy-nft-staking'; const strategies = { 'delegatexyz-erc721-balance-of': delegatexyzErc721BalanceOf, @@ -900,7 +901,8 @@ const strategies = { 'candy-lockv1-token': candyLockV1Token, 'candy-lock-token': candyLockToken, 'candy-auto-vault': candyAutoVault, - 'candy-lock-nft': candyLockNft + 'candy-lock-nft': candyLockNft, + 'candy-nft-staking': candyNftStaking }; Object.keys(strategies).forEach(function (strategyName) { From 105de962bb8f3a9cacd825f54e36f812ec3d646c Mon Sep 17 00:00:00 2001 From: PineCrypto <51626000+DramaCrypto@users.noreply.github.com> Date: Thu, 15 Aug 2024 16:32:25 +0800 Subject: [PATCH 720/815] feat: Add multiplier x2500 (#1554) * feat: Add new strategy "candy-nft-staking" * feat: Add multiplier x2500 --- src/strategies/candy-nft-staking/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategies/candy-nft-staking/index.ts b/src/strategies/candy-nft-staking/index.ts index e8e0bc3d2..174b1208c 100644 --- a/src/strategies/candy-nft-staking/index.ts +++ b/src/strategies/candy-nft-staking/index.ts @@ -49,7 +49,7 @@ export async function strategy( Object.entries(fixedStakingResults).map(([address, fixedStakedNfts]) => { const stakedNftCount = fixedStakedNfts.length + sharedStakingResults[address].length; - return [address, stakedNftCount]; + return [address, stakedNftCount * 2500]; }) ); } From a7ba52b68a41af6f6740fe70d25b4a6de8a0eba2 Mon Sep 17 00:00:00 2001 From: PineCrypto <51626000+DramaCrypto@users.noreply.github.com> Date: Thu, 15 Aug 2024 16:32:41 +0800 Subject: [PATCH 721/815] feat: Add multiplier x2500 (#1555) --- src/strategies/candy-lock-nft/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategies/candy-lock-nft/index.ts b/src/strategies/candy-lock-nft/index.ts index 49afde1b4..f731451df 100644 --- a/src/strategies/candy-lock-nft/index.ts +++ b/src/strategies/candy-lock-nft/index.ts @@ -128,7 +128,7 @@ export async function strategy( return Object.fromEntries( v1Scores.map(([address, v1Score], index) => { const totalScore = v1Score + v2Scores[index][1] + v3Scores[index][1]; - return [address, totalScore]; + return [address, totalScore * 2500]; }) ); } From bf3515bf8338eb21fb7f0e3d6d0ec8da1ddb9774 Mon Sep 17 00:00:00 2001 From: bogdan <35818861+UnnaturalCabbage@users.noreply.github.com> Date: Fri, 16 Aug 2024 23:24:16 +0700 Subject: [PATCH 722/815] [swarm-staking] Map proxy contract addresses to the owner addresses (#1556) * [swarm-stacking] new strategy * [swarm-stacking] refact: readme, rename vars * [swarm-stacking] fix: increase graph limit * [swarm-stacking] fix: unnecessary map * [swarm-stacking] refact: rename author * [swarm-stacking] fix: lint errors * [swarm-staking] refact: fix typo stack->stak * [swarm-staking] remove unsued files * [swarm-staking] map proxy adresses smt to the owner adresses --- .../swarm-staking/creator-to-proxy-map.ts | 126 ++++++++++++++++++ src/strategies/swarm-staking/examples.json | 7 +- src/strategies/swarm-staking/index.ts | 54 ++++---- 3 files changed, 157 insertions(+), 30 deletions(-) create mode 100644 src/strategies/swarm-staking/creator-to-proxy-map.ts diff --git a/src/strategies/swarm-staking/creator-to-proxy-map.ts b/src/strategies/swarm-staking/creator-to-proxy-map.ts new file mode 100644 index 000000000..d38876043 --- /dev/null +++ b/src/strategies/swarm-staking/creator-to-proxy-map.ts @@ -0,0 +1,126 @@ +/** + * hardcoded list of all addresses with proxies that have active stakes on our platform + * it won't change cuz it's legacy feature and was removed on 6 Feb 2024 + **/ +export default { + '0x022ddd9e1fa29397905d7e49ed3df96544bd0ea0': + '0x2c55f0b890d9bd273e50d72b359d9968e87c45cc', + '0x022f4d861e2903b53aee85f51d4b7d109b75fe1b': + '0xd5978c85298cecbe348a188e6a74144ba61c4dfd', + '0x0719ba8aa4c70ae42436659df20935096e9d7df4': + '0x8668936dc604bbbdd30600dd78623e64fdc1577b', + '0x119324b9d8d34965b460f9457b80ead79d8fe36a': + '0x07aee47166da31414033b2b566542519edf4ec18', + '0x175676a8a8b20e235ec29e84b536f9dc50e3b17f': + '0x114484db7cc19f98160d5d93bc986206be7d4d80', + '0x1ba014fe8e2bd0440e1803f67e451510e75b8441': + '0x1b9f7c4281dd6bb1f7afc34145e131ea86dbc27e', + '0x24701cc283003caeb83e76f59cd62b38ef3e5754': + '0x720b587e8759f9310d973faee853af5b34ab01e6', + '0x277fb2af5ce837a8e77c5607ef463e1919796d5d': + '0xd092456bfd490ca357dc049636688ab4947dc3ba', + '0x2843aa1c185656b7c2fac572f35eb8f7fc6f7921': + '0x0682270307021438daa95e2c3d7830eab92f84bc', + '0x2a69313cc3ea2d41f5ee97c96663ee1ef3009df7': + '0x18495659f38d990aa5ea01d135ac4ddbde6dbb8f', + '0x2e8c2aa09d6bf6f3c262dacc8ff71f7b29286bee': + '0x7142f6977d3cf62e5395765fd141a664aaacf5db', + '0x2fa4db030d2dc4d36f8c037ed2b3219f82e7b893': + '0x9c6e1d00cc1454d063132070e10df94c53af4cc3', + '0x3471532bba810e477a8cc314e929d92d668a2474': + '0x0578f281ad28d4f0e37795b1e01816628266b98c', + '0x36c15170088e6867fb2d3b14dd7e05dfdd6d7f0f': + '0x951523fe57de1c8014afb5400819d308d2edf7e5', + '0x3733376cb4fa342732e0ab1bc44b9c9be4308d62': + '0x24858a18168bcdb0ddc95251b11f7d9a9b6f2d1a', + '0x3b00fc5e00df2d4543050b81329ed5c36e813dfb': + '0xd2a4a042ac8dc775173634a47ca79139574eecd9', + '0x3da206ed63127d6b0a19f8950fc5b183bf58e7df': + '0xe8b4a59067e510d67e72f6fac29620fea03c5c8b', + '0x424cd658a2ee5679f3e3f315916a9f70c42fea70': + '0x2e1c49d2eb0f51c93ffe27d26741fffb4acdd92d', + '0x4c2c21d5427d1e114531091bb29b2975eeb440c0': + '0x154ef53c059d8f62eebe952b4161f961c6a74563', + '0x4cef35031e86cba5414780cdbb60fd9efd677268': + '0x1037541afa2ca8230791fe9116d66b0cd6ddf7b0', + '0x4dc5cd9f0de75f1b15be4abe4ee6c23e60b722c6': + '0x021e2d17feff0617b58246a44f97fb9179909695', + '0x5c87196bd916c2544c27ca4d41c21346d737eccf': + '0xca6ed8bbf5c736433912a7e50987d30e21a29da1', + '0x6377882b7980f4f9dbecf5a7536167e950b96fb4': + '0x916bbe4774500b4bcdf73e0e8cf0d5b93c3e7f4f', + '0x6b31682a6eec6fcedf0b9628cdfcca958bcadcd8': + '0x958cc9a04e3d81c1902d92ce6e09ac8eeb8b85b6', + '0x6ff5b6aa621ee75192a08685254b1f874a93ee73': + '0x53807334a69c429303d63154806729be617cf08d', + '0x72cf8c26bd2955b379eee6b0adc016671c2778c7': + '0x2bd89eba8e45026af7338df665fb8a210e5c8e2b', + '0x762bf468bd981984ce55af641c817abc089b611a': + '0x110e75c6fed215b7a2201d0ad208f7bb9f879cee', + '0x7b60440260b91a98f7b760c17795c5ff2dba094d': + '0x7ab778e3b6e6b6b9497d7c43256182911874a974', + '0x7f49acb60aa0ada47a763f119012e95f07484a8d': + '0x6688e02cd6ba6e8d7d4b0c939e40748528065c09', + '0x874fa6cd927d748326d5004065636e343df97405': + '0x3ce8db26c40ad44d7654328ff80cf98ab68dcd7f', + '0x8f4b44193e96a75a4cd14ecc73f276f1f8c4c946': + '0x8cddf509fafb26228d7828985ef7e99921253345', + '0x91a4815d131c194c9138970245ed96be2cb8c01c': + '0x8de438f3ee743c8f488612a587216ca5a5c45910', + '0x927ecd3e8995b545dca211ddf4676101e6bc87a1': + '0xa501d55b7d257da67640e6853b61d05578d4d15a', + '0x9c3f4a1f5a5d4a58cf164b392359de6c618461eb': + '0xb63fd041924f2df1ff503c2af3b1a8ac8d7fb763', + '0x9c5779b16e8600492c827373596b8f44deb21cce': + '0x49599516e4537d3f4da4b9217a19ee72b8b73996', + '0x9f73dac1edc5b1e03577a3b7b654ef342002dbdc': + '0xf3d00aaee3e2b2ba773037e8adacf5542c13a755', + '0xa1c7d4ecc193ef9ba3b9fe243c65d08446a74015': + '0xb930c562eb087dd39458cfaa78d964db039338d6', + '0xa2fc9ed9d2983631faccdcaf6799bc4bc64cdfc2': + '0xbdff02da79b664115f5da5ef2a6fa9bebddf03dd', + '0xa69a62e5797c626eea08aeac988e2646c5357b7a': + '0x19b24769f88053e70e2e03037f57054eff84de46', + '0xaa41bb9118afab9abf9481cc753ae8b8dd71f7b4': + '0xe13dd75dbba21acb6440c63eeda49c12cac35d77', + '0xaeeb8a17a59b2e27bf821253a31c3f025994e869': + '0x4f0d2850bd06c8db1b47f4ded6dd670bd5036f29', + '0xaf38756e009f32af4ca87a603503ccbeee0e6688': + '0xc98cc732a8ad9735cfdbf594f50207b92c694466', + '0xb0e86b059ddc05b17f42bc9c2a819b5486378781': + '0x097815bb4c4846258653ba356b01d7c560481933', + '0xb45de2ad8568a2a80eb64c9a4584e235fa88571f': + '0x9169298c3bea731917d14f0d0579d8636a7caa8f', + '0xbc8ca713a71ffbe54446e215ef850f773ec4d5a7': + '0xf9c6ab480b0842cecfd171db67c2d4cfc7fc4ff0', + '0xbe487c37dd4ff70b122a27d93d1495b08de049d2': + '0x3d17ca0f85d8c83a9daaae8ce4c8ecd7b6f5120e', + '0xc58c66c0777a169698b32b16c5a9eddbc6c45d76': + '0xc287804b8a98f7bcb550b59be5d5d08f63482ba2', + '0xc7b77336ebf08a7938b1eb2ede0f392a2568e45a': + '0xc26017ef77e276b4ae0e5d977b9b3ed0f9cb7721', + '0xcab24612be0d7767572a2795201da32b277d8d25': + '0x365d4440fd7e6f88967d6001c52b3837d29dc6ea', + '0xcae1061a7dff2607aa3d22048ff1b7f42a009321': + '0xecdd18c25cd46e0f81358d124c8d46c6172d2ecd', + '0xd3a5e587ff77541e849f85f6dc00abf4080b989a': + '0xcf76f4ca0f0e7b0102dbb0764efb637700003e39', + '0xd47ef90d54b548ebc3c1f1eeb20e291db7e0a0d1': + '0x1362733c64f76afa83d8ed17acd02883a731b902', + '0xd9dc13f3286c15eba48ff55e9f39020a6b1a8591': + '0x20117489ef31ce639a5e4b2c1f2ed7199ff0bb84', + '0xda844e1ec97b0bab57f6d33f59b225ba57f0f0c9': + '0x84037b279a532b885de0de5ba757b9b9a8dc3663', + '0xdbe981a0e21a536caecf8c56b00d890e9a1613ae': + '0x14ae133f222c37d8756f56da81ee727375de6189', + '0xe14a4383ea37ac45cc59f7959078747267c81e76': + '0x3cd4e80c6b54da54fb3a155dfeca402bacf98eb2', + '0xe85a25444e31cf56456129f5610c96fc2f9a319d': + '0xb6c0bf2ba39e7b227a024ffbb90514d2ddeaadeb', + '0xef7f0089e4dbf745d431db07d7807bc2e1e5daa3': + '0x78678c5401ecdeeb5ec7ff4eed7f06d353b24810', + '0xef839c529ba597b97ef73895a8ac2610e4268d81': + '0xf6b6bef0128e070a2a67de54771a59cc91e51744', + '0xf82446768cc19a6f0d226af27faa2b4052f3bfb8': + '0xacb66516f2ea89615699b279b4743e82e820965e' +}; diff --git a/src/strategies/swarm-staking/examples.json b/src/strategies/swarm-staking/examples.json index dc484fe95..028a416ab 100644 --- a/src/strategies/swarm-staking/examples.json +++ b/src/strategies/swarm-staking/examples.json @@ -7,13 +7,14 @@ }, "network": "137", "addresses": [ + "0x022ddd9e1fa29397905d7e49ed3df96544bd0ea0", "0x3DF51013b9080786A374E2980dd1dA88B0B99177", - "0x3d17ca0f85d8c83a9daaae8ce4c8ecd7b6f5120e", - "0xe8b4a59067e510d67e72f6fac29620fea03c5c8b", + "0x3b00fc5e00df2d4543050b81329ed5c36e813dfb", + "0x3da206ed63127d6b0a19f8950fc5b183bf58e7df", "0x8668936dc604bbbdd30600dd78623e64fdc1577b", "0xb6a2efec3ac82531355dc0256a53f0d2c183e01f", "0xc98cc732a8ad9735cfdbf594f50207b92c694466", - "0x720b587e8759f9310d973faee853af5b34ab01e6", + "0x7f49acb60aa0ada47a763f119012e95f07484a8d", "0x993627ca9fd5a926c08414e1a24ee81910ec4e6c", "0x993627ca9fd5a926c08414e1a24ee81910ec4e6c" ], diff --git a/src/strategies/swarm-staking/index.ts b/src/strategies/swarm-staking/index.ts index d49c7d76c..05e77a099 100644 --- a/src/strategies/swarm-staking/index.ts +++ b/src/strategies/swarm-staking/index.ts @@ -2,6 +2,7 @@ import { BigNumber } from '@ethersproject/bignumber'; import { formatUnits } from '@ethersproject/units'; import { subgraphRequest } from '../../utils'; import { getAddress } from '@ethersproject/address'; +import creatorToProxyMap from './creator-to-proxy-map'; export const author = 'SwarmMarkets'; export const version = '1.0.0'; @@ -23,12 +24,19 @@ async function getSwarmStakes( addresses: string[] ): Promise { const url = SUBGRAPH_URL[network]; + // include proxy addresses if there are. so later we can assign it voting power to an actuall ownn + const addressesWithProxy = [...addresses]; + addresses.forEach((address) => { + if (creatorToProxyMap[address.toLowerCase()]) { + addressesWithProxy.push(creatorToProxyMap[address.toLowerCase()]); + } + }); const query = { swarmStakes: { __args: { first: 1000, where: { - maker_in: addresses, + maker_in: addressesWithProxy, unstaked: false }, // target specific snapshot of the network @@ -56,33 +64,25 @@ export async function strategy( snapshot ): Promise> { const allStakes = await getSwarmStakes(network, snapshot, addresses); - - const stakesByMaker = allStakes.reduce>( - (acc, stake) => { - const makerStakes = acc.get(stake.maker) || []; - makerStakes.push(stake); - acc.set(stake.maker, makerStakes); - return acc; - }, - new Map() + const bigScoreMap: Map = new Map(); + const proxyToCreatorMap = Object.fromEntries( + Object.entries(creatorToProxyMap).map(([key, value]) => [value, key]) ); - - const makersTokenAmount: Map = new Map(); - stakesByMaker.forEach((stakes, maker) => { - const bigTotalAmount: BigNumber = stakes.reduce( - (acc, stake) => acc.add(BigNumber.from(stake.stakedAmount)), - BigNumber.from(0) - ); - const totalAmount = parseFloat( - formatUnits(bigTotalAmount, SMT_TOKEN_DECIMALS) - ); - makersTokenAmount.set(maker, totalAmount); + allStakes.forEach(({ maker, stakedAmount }) => { + // if stake address is a proxy contract, assign it's vote power to the owner address + if (proxyToCreatorMap[maker]) { + maker = proxyToCreatorMap[maker]; + } + const currScore = bigScoreMap.get(maker) || BigNumber.from(0); + bigScoreMap.set(maker, currScore.add(BigNumber.from(stakedAmount))); }); - - const results = Object.fromEntries( - [...makersTokenAmount.entries()].map(([maker, amount]) => { - return [getAddress(maker), amount]; // checksum all addresses - }) + // format results by checksuming addresses and parsing tokens amount + const score = Object.fromEntries( + [...bigScoreMap.entries()].map(([maker, amount]) => [ + getAddress(maker), + parseFloat(formatUnits(amount, SMT_TOKEN_DECIMALS)) + ]) ); - return results; + + return score; } From f27f0b3e8ce37b699889161de5c66c4d628f44ca Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 18 Aug 2024 19:49:02 +0530 Subject: [PATCH 723/815] Automated lint (#1557) Co-authored-by: ChaituVR --- src/strategies/candy-lock-nft/examples.json | 2 +- src/strategies/candy-lock-token/examples.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/strategies/candy-lock-nft/examples.json b/src/strategies/candy-lock-nft/examples.json index 12c60feb2..3fb9e84f6 100644 --- a/src/strategies/candy-lock-nft/examples.json +++ b/src/strategies/candy-lock-nft/examples.json @@ -20,7 +20,7 @@ "0x34cfa46732692Ab062F0453036cd5a4f5B771473", "0x743aAdEBf260f6282a2E1AaC0b9630A3Efaf0F93", "0x971541C1f8368957411980354ce966dD4A27E0E3", - "0x090fF72fb73b289BB233Fe7d1e8FDd8AdD9Cf534" + "0x090fF72fb73b289BB233Fe7d1e8FDd8AdD9Cf534" ], "snapshot": 15303354 } diff --git a/src/strategies/candy-lock-token/examples.json b/src/strategies/candy-lock-token/examples.json index a45173478..655a64156 100644 --- a/src/strategies/candy-lock-token/examples.json +++ b/src/strategies/candy-lock-token/examples.json @@ -21,7 +21,7 @@ "0x34cfa46732692Ab062F0453036cd5a4f5B771473", "0x743aAdEBf260f6282a2E1AaC0b9630A3Efaf0F93", "0x971541C1f8368957411980354ce966dD4A27E0E3", - "0x090fF72fb73b289BB233Fe7d1e8FDd8AdD9Cf534" + "0x090fF72fb73b289BB233Fe7d1e8FDd8AdD9Cf534" ], "snapshot": 15303354 } From e44b28cbeba42111b841af8ce2a8b525115db75a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 21 Aug 2024 14:04:07 +0530 Subject: [PATCH 724/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.5 (#1558) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 6f505e504..cdad880f4 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.4", + "@snapshot-labs/snapshot.js": "^0.12.5", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 2b2100081..dba4ad262 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.4": - version "0.12.4" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.4.tgz#d2cf1e2bb04714638f3b746bb212f9d93d2ab624" - integrity sha512-O9qxZ3qzH2CDBiMDGX4orQIFYKLKJMvpoF8uMsRhWVnp/CiH1eu5obxJCzys2n4o6KvvgtDQjS45b+7mh/85gA== +"@snapshot-labs/snapshot.js@^0.12.5": + version "0.12.5" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.5.tgz#7888352ddc0352e20db708efdf46031cd1c9affa" + integrity sha512-oJRVCUR5dVwiniNe76joCV0SuiGJksZGQh2bIfFxmT2jngc24jmlFqVWDbhJOM3HhLcZro5l/irRLcwB+Ki1pA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From eaed17d01589f2e459d9b70e1ea9e49cbd01b584 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 21 Aug 2024 21:12:05 +0530 Subject: [PATCH 725/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.6 (#1559) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index cdad880f4..1288fba0d 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.5", + "@snapshot-labs/snapshot.js": "^0.12.6", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index dba4ad262..92e7061ff 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.5": - version "0.12.5" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.5.tgz#7888352ddc0352e20db708efdf46031cd1c9affa" - integrity sha512-oJRVCUR5dVwiniNe76joCV0SuiGJksZGQh2bIfFxmT2jngc24jmlFqVWDbhJOM3HhLcZro5l/irRLcwB+Ki1pA== +"@snapshot-labs/snapshot.js@^0.12.6": + version "0.12.6" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.6.tgz#c577eb6773f3895a2382dfe343ff1c46d364be2c" + integrity sha512-kxTgL1t0HlmeyHo6W1SvzDcYN9Bu5WTk0FAP7iugAtufam9ogdABFXHxnLJjXJfVfK7Bf9sodL9fS22idxCupQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From f954c5e3ef80c0da4412de95a3a852001ba985a3 Mon Sep 17 00:00:00 2001 From: tracyspacy <42025315+tracyspacy@users.noreply.github.com> Date: Fri, 23 Aug 2024 19:28:14 +0200 Subject: [PATCH 726/815] TG-192 #done (#1560) add strategy pom --- src/strategies/index.ts | 4 +++- src/strategies/pom/README.md | 12 +++++++++++ src/strategies/pom/examples.json | 34 ++++++++++++++++++++++++++++++ src/strategies/pom/index.ts | 36 ++++++++++++++++++++++++++++++++ src/strategies/pom/schema.json | 20 ++++++++++++++++++ 5 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 src/strategies/pom/README.md create mode 100644 src/strategies/pom/examples.json create mode 100644 src/strategies/pom/index.ts create mode 100644 src/strategies/pom/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 9956c7ad9..3ceb293f1 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -446,6 +446,7 @@ import * as candyLockToken from './candy-lock-token'; import * as candyAutoVault from './candy-auto-vault'; import * as candyLockNft from './candy-lock-nft'; import * as candyNftStaking from './candy-nft-staking'; +import * as pom from './pom'; const strategies = { 'delegatexyz-erc721-balance-of': delegatexyzErc721BalanceOf, @@ -902,7 +903,8 @@ const strategies = { 'candy-lock-token': candyLockToken, 'candy-auto-vault': candyAutoVault, 'candy-lock-nft': candyLockNft, - 'candy-nft-staking': candyNftStaking + 'candy-nft-staking': candyNftStaking, + pom }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/pom/README.md b/src/strategies/pom/README.md new file mode 100644 index 000000000..60699e6d8 --- /dev/null +++ b/src/strategies/pom/README.md @@ -0,0 +1,12 @@ + # PoM strategy + + Each Proof Of Membership (PoM) is implemented as a non-transferable soulbound erc721. + An address can have only 1 name in a community. + This is the basic voting strategy for Proof Of Membership (PoM), which allows users with a name in a particular community to have 1 vote. + + Here is an example of parameters: + ```json + { + "community": "beast", + } + ``` diff --git a/src/strategies/pom/examples.json b/src/strategies/pom/examples.json new file mode 100644 index 000000000..b3fa5a2e3 --- /dev/null +++ b/src/strategies/pom/examples.json @@ -0,0 +1,34 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "pom", + "params": { + "community": "beast" + } + }, + "network": "1", + "addresses": [ + "0x75c41548F9a71c267Cf38E8452435EC580d3978E", + "0x6c6234983BCf60d4497cd8EE416bA04600a0a4C2", + "0xeF8305E140ac520225DAf050e2f71d5fBcC543e7", + "0x1E1A51E25f2816335cA436D65e9Af7694BE232ad", + "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", + "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e", + "0x1d5E65a087eBc3d03a294412E46CE5D6882969f4", + "0x1f254336E5c46639A851b9CfC165697150a6c327", + "0x2ec3F80BeDA63Ede96BA20375032CDD3aAfb3030", + "0x4AcBcA6BE2f8D2540bBF4CA77E45dA0A4a095Fa2", + "0x4F3D348a6D09837Ae7961B1E0cEe2cc118cec777", + "0x6D7f23A509E212Ba7773EC1b2505d1A134f54fbe", + "0x07a1f6fc89223c5ebD4e4ddaE89Ac97629856A0f", + "0x8d5F05270da470e015b67Ab5042BDbE2D2FEFB48", + "0x8d07D225a769b7Af3A923481E1FdF49180e6A265", + "0x8f60501dE5b9b01F9EAf1214dbE1924aA97F7fd0", + "0x9B8e8dD9151260c21CB6D7cc59067cd8DF306D58", + "0x17ea92D6FfbAA1c7F6B117c1E9D0c88ABdc8b84C", + "0x38C0039247A31F3939baE65e953612125cB88268" + ], + "snapshot": 20584876 + } +] diff --git a/src/strategies/pom/index.ts b/src/strategies/pom/index.ts new file mode 100644 index 000000000..ee99f7fb6 --- /dev/null +++ b/src/strategies/pom/index.ts @@ -0,0 +1,36 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import { Multicaller } from '../../utils'; + +export const author = 'beastdao'; +export const version = '0.1.0'; + +const namesRegistryAddress = '0xaCeE2CB8Cf92D0d6DC7eB80bEF7dDecf75482819'; +const abi = [ + 'function getNameInCommunityByAddress(address userAddress,string memory community_) public view returns (uint256) ' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const multi = new Multicaller(network, provider, abi, { blockTag }); + + addresses.forEach((address) => + multi.call(address, namesRegistryAddress, 'getNameInCommunityByAddress', [ + address, + options.community + ]) + ); + const result: Record = await multi.execute(); + return Object.fromEntries( + Object.entries(result).map(([address, id]) => [ + address, + id.isZero() ? 0 : 1 + ]) + ); +} diff --git a/src/strategies/pom/schema.json b/src/strategies/pom/schema.json new file mode 100644 index 000000000..327b9ee1a --- /dev/null +++ b/src/strategies/pom/schema.json @@ -0,0 +1,20 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "community": { + "type": "string", + "title": "community name in lowercase", + "examples": ["e.g. beast"], + "maxLength": 10 + } + }, + "required": ["community"], + "additionalProperties": false + } + } +} From 0c7afed6e14012bb42e11d71193d2fa6b36f1587 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 24 Aug 2024 09:49:11 +0530 Subject: [PATCH 727/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.7 (#1561) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 1288fba0d..5e58048dd 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.6", + "@snapshot-labs/snapshot.js": "^0.12.7", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 92e7061ff..ad64ed299 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.6": - version "0.12.6" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.6.tgz#c577eb6773f3895a2382dfe343ff1c46d364be2c" - integrity sha512-kxTgL1t0HlmeyHo6W1SvzDcYN9Bu5WTk0FAP7iugAtufam9ogdABFXHxnLJjXJfVfK7Bf9sodL9fS22idxCupQ== +"@snapshot-labs/snapshot.js@^0.12.7": + version "0.12.7" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.7.tgz#e08899984c012cb680730fa9ed785236a96ef9b3" + integrity sha512-pMNckn709ZTXQcdWRco7RfOKKuTbXa08BPaZA1NLq9NDiWdvOP0UAj4ZQBzmXPPOmM6vkpH7QwX9bzhobJe6yA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 7b8d2288ff5eca88fb38a0dce05c004aff1d3935 Mon Sep 17 00:00:00 2001 From: Travis Moore <33413876+FortisFortuna@users.noreply.github.com> Date: Tue, 27 Aug 2024 21:08:46 -0700 Subject: [PATCH 728/815] Frax Finance Fraxtal [frax-finance-fraxtal] (#1563) * Frax Finance Fraxtal * Update src/strategies/frax-finance-fraxtal/index.ts * Update src/strategies/frax-finance-fraxtal/index.ts * Update src/strategies/frax-finance-fraxtal/index.ts --------- Co-authored-by: Chaitanya --- .../frax-finance-fraxtal/examples.json | 23 +++++ src/strategies/frax-finance-fraxtal/index.ts | 86 +++++++++++++++++++ src/strategies/index.ts | 2 + 3 files changed, 111 insertions(+) create mode 100644 src/strategies/frax-finance-fraxtal/examples.json create mode 100644 src/strategies/frax-finance-fraxtal/index.ts diff --git a/src/strategies/frax-finance-fraxtal/examples.json b/src/strategies/frax-finance-fraxtal/examples.json new file mode 100644 index 000000000..e2c9c9da7 --- /dev/null +++ b/src/strategies/frax-finance-fraxtal/examples.json @@ -0,0 +1,23 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "frax-finance-fraxtal", + "params": { + "symbol": "veFXS", + "decimals": 18, + "FXS": "0xfc00000000000000000000000000000000000002", + "VEFXS_AGGREGATOR": "0x176A4e081653EbB8a2246BAfbfCf663782426531" + } + }, + "network": "252", + "addresses": [ + "0x36A87d1E3200225f881488E4AEedF25303FebcAe", + "0x234D953a9404Bf9DbC3b526271d440cD2870bCd2", + "0x6B175474E89094C44Da98b954EedeAC495271d0F", + "0x22511ffA88433aB56495947b559dfB62B3d47633", + "0x5180db0237291A6449DdA9ed33aD90a38787621c" + ], + "snapshot": 8944368 + } +] diff --git a/src/strategies/frax-finance-fraxtal/index.ts b/src/strategies/frax-finance-fraxtal/index.ts new file mode 100644 index 000000000..6b96caa3b --- /dev/null +++ b/src/strategies/frax-finance-fraxtal/index.ts @@ -0,0 +1,86 @@ +import { formatUnits } from '@ethersproject/units'; +// import { BigNumber } from '@ethersproject/bignumber'; +import { multicall } from '../../utils'; + +// const BIG18 = BigNumber.from('1000000000000000000'); + +export const author = 'FraxFinance'; +export const version = '0.0.1'; + +// 0.0.1: Held FXS + veFXS from the VeFXSAggregator + +const DECIMALS = 18; + +const abi = [ 'function balanceOf(address account) view returns (uint256)' ] + +const chunk = (arr, size) => + Array.from({ length: Math.ceil(arr.length / size) }, (v, i) => + arr.slice(i * size, i * size + size) + ); + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + // Fetch FXS Balance + const fxsQuery = addresses.map((address: any) => [ + options.FXS, + 'balanceOf', + [address] + ]); + + // Fetch veFXS Balance + const vefxsQuery = addresses.map((address: any) => [ + options.VEFXS_AGGREGATOR, + 'balanceOf', + [address] + ]); + + const response = await multicall( + network, + provider, + abi, + [ + ...fxsQuery, + ...vefxsQuery, + ], + { blockTag } + ); + + const chunks = chunk(response, addresses.length); + const fxsBalances = chunks[0]; + const vefxsBalances = chunks[1]; + + return Object.fromEntries( + Array(addresses.length) + .fill('x') + .map((_, i) => { + const free_fxs = fxsBalances[i][0]; + const vefxs = vefxsBalances[i][0]; + + // Print statements + // console.log(`==================${addresses[i]}==================`); + // console.log("Free FXS: ", free_fxs.div(BIG18).toString()); + // console.log("veFXS: ", vefxs.div(BIG18).toString()); + // console.log(``); + + return [ + addresses[i], + parseFloat( + formatUnits( + free_fxs + .add(vefxs) + .toString(), + DECIMALS + ) + ) + ]; + }) + ); +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 3ceb293f1..07a716a8b 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -52,6 +52,7 @@ import * as makerDsChief from './maker-ds-chief'; import * as uni from './uni'; import * as yearnVault from './yearn-vault'; import * as fraxFinance from './frax-finance'; +import * as fraxFinanceFraxtal from './frax-finance-fraxtal'; import * as moloch from './moloch'; import * as uniswap from './uniswap'; import * as faralandStaking from './faraland-staking'; @@ -526,6 +527,7 @@ const strategies = { 'gooddollar-multichain': gooddollarMultichain, uni, 'frax-finance': fraxFinance, + 'frax-finance-fraxtal': fraxFinanceFraxtal, 'yearn-vault': yearnVault, moloch, masterchef, From ba69938e14814572cd7760b808c338aaacee55ee Mon Sep 17 00:00:00 2001 From: Marsot Pierre Date: Wed, 28 Aug 2024 19:12:58 +0200 Subject: [PATCH 729/815] add strategy with working balance (#1564) --- src/strategies/index.ts | 2 + .../sd-gauge-less-vote-boost/README.md | 28 ++ .../sd-gauge-less-vote-boost/examples.json | 32 +++ .../sd-gauge-less-vote-boost/index.ts | 242 ++++++++++++++++++ 4 files changed, 304 insertions(+) create mode 100644 src/strategies/sd-gauge-less-vote-boost/README.md create mode 100644 src/strategies/sd-gauge-less-vote-boost/examples.json create mode 100644 src/strategies/sd-gauge-less-vote-boost/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 07a716a8b..8bf94892f 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -378,6 +378,7 @@ import * as erc4626AssetsOf from './erc4626-assets-of'; import * as sdVoteBoostTWAVPV2 from './sd-vote-boost-twavp-v2'; import * as sdVoteBoostTWAVPV3 from './sd-vote-boost-twavp-v3'; import * as sdVoteBoostTWAVPV4 from './sd-vote-boost-twavp-v4'; +import * as sdGaugeLessVoteBoost from './sd-gauge-less-vote-boost'; import * as sdVoteBoostTWAVPVsdToken from './sd-vote-boost-twavp-vsdtoken'; import * as sdVoteBoostTWAVPVCrossChain from './sd-vote-boost-twavp-vsdcrv-crosschain'; import * as sdVoteBoostTWAVPBalanceof from './sd-vote-boost-twavp-balanceof'; @@ -838,6 +839,7 @@ const strategies = { 'sd-vote-boost-twavp-v2': sdVoteBoostTWAVPV2, 'sd-vote-boost-twavp-v3': sdVoteBoostTWAVPV3, 'sd-vote-boost-twavp-v4': sdVoteBoostTWAVPV4, + 'sd-gauge-less-vote-boost': sdGaugeLessVoteBoost, 'sd-vote-boost-twavp-vsdtoken': sdVoteBoostTWAVPVsdToken, 'sd-vote-boost-twavp-vsdcrv-crosschain': sdVoteBoostTWAVPVCrossChain, 'sd-vote-boost-twavp-balanceof': sdVoteBoostTWAVPBalanceof, diff --git a/src/strategies/sd-gauge-less-vote-boost/README.md b/src/strategies/sd-gauge-less-vote-boost/README.md new file mode 100644 index 000000000..470a65059 --- /dev/null +++ b/src/strategies/sd-gauge-less-vote-boost/README.md @@ -0,0 +1,28 @@ +# sd-vote-boost-twavp-v4 + +This strategy is used by Stake DAO to vote with sdToken using Time Weighted Averaged Voting Power (TWAVP) system and adapted for veSDT boost delegation with possibility to whiteliste address to by pass TWAVP. + +``` +VotingPower(user) = veToken.balanceOf(liquidLocker) * (average.sdTokenGauge.working_balances(user) / sdTokenGauge.working_supply) +``` + +>_sampleSize: in days_ +>_sampleStep: the number of block for `average` calculation (max 5)_ + +Here is an example of parameters: + +```json +{ + "veToken": "0x5f3b5DfEb7B28CDbD7FAba78963EE202a494e2A2", + "liquidLocker": "0x52f541764E6e90eeBc5c21Ff570De0e2D63766B6", + "sdTokenGauge": "0x7f50786A0b15723D741727882ee99a0BF34e3466", + "sdToken": "0xD1b5651E55D4CeeD36251c61c50C889B36F6abB5", + "pools": ["0xca0253a98d16e9c1e3614cafda19318ee69772d0"], + "symbol": "sdToken", + "decimals": 18, + "sampleSize": 10, + "sampleStep": 5, + "botAddress": "", + "whiteListedAddress": ["0x1c0D72a330F2768dAF718DEf8A19BAb019EEAd09"] +} +``` \ No newline at end of file diff --git a/src/strategies/sd-gauge-less-vote-boost/examples.json b/src/strategies/sd-gauge-less-vote-boost/examples.json new file mode 100644 index 000000000..eb6e7786c --- /dev/null +++ b/src/strategies/sd-gauge-less-vote-boost/examples.json @@ -0,0 +1,32 @@ +[ + { + "name": "Stake DAO vote boost using working balance", + "strategy": { + "name": "sd-gauge-less-vote-boost", + "params": { + "sdTokenGaugeDestinationChain": "0x12992595328E52267c95e45B1a97014D6Ddf8683", + "symbol": "sdToken", + "decimals": 18, + "twavpDaysInterval": 10, + "twavpNumberOfBlocks": 2, + "botAddress": "0xb4542526AfeE2FdA1D584213D1521272a398B42a", + "whiteListedAddress": ["0x1c0D72a330F2768dAF718DEf8A19BAb019EEAd09"], + "targetChainId": "252", + "blocksPerDay": 43200 + } + }, + "network": "1", + "addresses": [ + "0x26a5994176d34D128C5e6ab80Fa0882A7df4fF00", + "0xDdB50FfDbA4D89354E1088e4EA402de895562173", + "0xb4542526AfeE2FdA1D584213D1521272a398B42a", + "0xE1F7eaD40d33eeF30dCf15eB5efC45409001aAB8", + "0xb0e83C2D71A991017e0116d58c5765Abc57384af", + "0x1c0D72a330F2768dAF718DEf8A19BAb019EEAd09", + "0xC6625129C9df3314a4dd604845488f4bA62F9dB8", + "0x10c16c7B8b1DDCFE65990ec822DE4379dd8a86dE", + "0x034f978581617FcABB75bfBe697d2230a3285437" + ], + "snapshot": 20619358 + } +] diff --git a/src/strategies/sd-gauge-less-vote-boost/index.ts b/src/strategies/sd-gauge-less-vote-boost/index.ts new file mode 100644 index 000000000..b6d3cc288 --- /dev/null +++ b/src/strategies/sd-gauge-less-vote-boost/index.ts @@ -0,0 +1,242 @@ +import { getProvider, multicall, subgraphRequest } from '../../utils'; +import { BigNumber } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; + +export const author = 'pierremarsotlyon1'; +export const version = '0.0.1'; + +const VE_SDT = "0x0C30476f66034E11782938DF8e4384970B6c9e8a"; +const VE_PROXY_BOOST_SDT = "0xD67bdBefF01Fc492f1864E61756E5FBB3f173506"; +const TOKENLESS_PRODUCTION = 40; + +// Used ABI +const abi = [ + 'function balanceOf(address account) external view returns (uint256)', + 'function working_supply() external view returns (uint256)', + 'function totalSupply() external view returns (uint256)', + 'function working_balances(address account) external view returns (uint256)', + 'function balances(uint256 i) external view returns (uint256)', + 'function adjusted_balance_of(address user) external view returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + // Maximum of 5 multicall! + if (options.twavpNumberOfBlocks > 2) { + throw new Error('maximum of 2 calls'); + } + + // Maximum of 20 whitelisted address + if (options.whiteListedAddress.length > 20) { + throw new Error('maximum of 20 whitelisted address'); + } + + const mainnetCalls: any[] = [ + [VE_SDT, 'totalSupply'] + ]; + + const destinationChainCalls: any[] = [ + [options.sdTokenGaugeDestinationChain, 'totalSupply'] + ]; + + // --- Create block number list for twavp + // Obtain last block number + // Create block tag + let blockTag = 0; + if (typeof snapshot === 'number') { + blockTag = snapshot; + } else { + blockTag = await provider.getBlockNumber(); + } + + const destinationChainProvider = getProvider(options.targetChainId); + + // Get corresponding block number on the destination chain side + const destinationChainBlockTag = await getIDChainBlock( + blockTag, + provider, + options.targetChainId + ); + + // Create block lists + const blockListMainnet = getPreviousBlocks( + blockTag, + options.twavpNumberOfBlocks, + options.twavpDaysInterval, + 7200 + ); + + const blockListDesitnationChain = getPreviousBlocks( + destinationChainBlockTag, + options.twavpNumberOfBlocks, + options.twavpDaysInterval, + options.blocksPerDay + ); + + // Queries + const ajustedBalancesMainnet = addresses.map((address: any) => + [ + VE_PROXY_BOOST_SDT, + 'adjusted_balance_of', + [address] + ]); + + const sdTknGaugeBalanceDestinationChain = addresses.map((address: any) => + [ + options.sdTokenGaugeDestinationChain, + 'balanceOf', + [address] + ]); + + const responsesMainnet: any[] = []; + const responsesDestinationChain: any[] = []; + + let veSDTTotalSupply = 0; + let sdTokenGaugeTotalSupplyDestinationChain = 0; + + for (let i = 0; i < options.twavpNumberOfBlocks; i++) { + const isEnd = i === options.twavpNumberOfBlocks - 1; + + // Mainnet + let calls: any[] = ajustedBalancesMainnet; + if (isEnd) { + calls.push(...mainnetCalls); + } + + let callResp: any[] = await multicall( + network, + provider, + abi, + calls, + { blockTag: blockListMainnet[i] }); + + if (isEnd) { + veSDTTotalSupply = parseFloat(formatUnits(callResp.pop()[0], 18)); + } + + responsesMainnet.push(callResp); + + // Destination chain + calls = sdTknGaugeBalanceDestinationChain; + if (isEnd) { + calls.push(...destinationChainCalls); + } + + callResp = await multicall( + options.targetChainId, + destinationChainProvider, + abi, + calls, + { blockTag: blockListDesitnationChain[i] }); + + if (isEnd) { + sdTokenGaugeTotalSupplyDestinationChain = parseFloat(formatUnits(callResp.pop()[0], 18)); + } + + responsesDestinationChain.push(callResp); + } + + return Object.fromEntries( + Array(addresses.length) + .fill('x') + .map((_, i) => { + // Init array of working balances for user + const userWorkingBalances: number[] = []; + + for (let j = 0; j < options.twavpNumberOfBlocks; j++) { + const voting_balance = parseFloat(formatUnits(BigNumber.from(responsesMainnet[j].shift()[0]), 18)); + const l = parseFloat(formatUnits(BigNumber.from(responsesDestinationChain[j].shift()[0]), 18)); + + let lim = l * TOKENLESS_PRODUCTION / 100 + if (veSDTTotalSupply > 0) { + lim += sdTokenGaugeTotalSupplyDestinationChain * voting_balance / veSDTTotalSupply * (100 - TOKENLESS_PRODUCTION) / 100 + } + + userWorkingBalances.push(Math.min(l, lim)); + } + + // Get average working balance. + const averageWorkingBalance = average( + userWorkingBalances, + addresses[i], + options.whiteListedAddress + ); + + // Return address and voting power + return [addresses[i], Number(averageWorkingBalance)]; + }) + ); +} + +function getPreviousBlocks( + currentBlockNumber: number, + numberOfBlocks: number, + daysInterval: number, + blocksPerDay: number +): number[] { + // Calculate total blocks interval + const totalBlocksInterval = blocksPerDay * daysInterval; + // Calculate block interval + const blockInterval = totalBlocksInterval / (numberOfBlocks - 1); + + // Init array of block numbers + const blockNumbers: number[] = []; + + for (let i = 0; i < numberOfBlocks; i++) { + // Calculate block number + let blockNumber = + currentBlockNumber - totalBlocksInterval + blockInterval * i; + + // Add block number to array + blockNumbers.push(Math.round(blockNumber)); + } + + // Return array of block numbers + return blockNumbers; +} + +function average( + numbers: number[], + address: string, + whiteListedAddress: string[] +): number { + // If no numbers, return 0 to avoid division by 0. + if (numbers.length === 0) return 0; + + // If address is whitelisted, return most recent working balance. i.e. no twavp applied. + if (whiteListedAddress.includes(address)) return numbers[numbers.length - 1]; + + // Init sum + let sum = 0; + // Loop through all elements and add them to sum + for (let i = 0; i < numbers.length; i++) { + sum += numbers[i]; + } + + // Return sum divided by array length to get mean + return sum / numbers.length; +} + +async function getIDChainBlock(snapshot, provider, chainId) { + const ts = (await provider.getBlock(snapshot)).timestamp; + const query = { + blocks: { + __args: { + where: { + ts: ts, + network_in: [chainId] + } + }, + number: true + } + }; + const url = 'https://blockfinder.snapshot.org'; + const data = await subgraphRequest(url, query); + return data.blocks[0].number; +} \ No newline at end of file From 1be3b77857df36b8b79d153e9d78a7a77996e506 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Fri, 30 Aug 2024 00:31:09 +0530 Subject: [PATCH 730/815] [api-v2] Fix: use lowercased addresses to find score from API response (#1565) * [api-v2] Fix: use lowercased addresses to find score from API response * update readme * fix lint --- src/strategies/api-v2/README.md | 19 ++++- src/strategies/api-v2/index.ts | 2 +- src/strategies/candy-lock-nft/index.ts | 15 ++-- src/strategies/frax-finance-fraxtal/index.ts | 16 +--- .../sd-gauge-less-vote-boost/index.ts | 73 ++++++++++--------- 5 files changed, 67 insertions(+), 58 deletions(-) diff --git a/src/strategies/api-v2/README.md b/src/strategies/api-v2/README.md index baf43e591..6ad459a73 100644 --- a/src/strategies/api-v2/README.md +++ b/src/strategies/api-v2/README.md @@ -3,7 +3,7 @@ Voting strategy using a REST API endpoint. Number of votes depends on the return of the API endpoint. (Unlike the `api` strategy, this strategy does not depend on voting power of other addresses) -> Note: Better to use this strategy only if you are not using any override strategies (example: delegation strategy). +> Note: Use this strategy only if you are not using any override strategies (For example using `delegation` strategy). ## Parameters @@ -48,3 +48,20 @@ If you are passing a API url with POST method use following format: "type": "api-post" } ``` + +### Example response from API + +```JSON +{ + "score": [ + { + "address": "0x1234567890abcdef1234567890abcdef12345678", + "score": "100" + }, + { + "address": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd", + "score": "200" + } + ] +} +``` diff --git a/src/strategies/api-v2/index.ts b/src/strategies/api-v2/index.ts index fdf1cb006..b9bbfe34b 100644 --- a/src/strategies/api-v2/index.ts +++ b/src/strategies/api-v2/index.ts @@ -71,7 +71,7 @@ export async function strategy( parseFloat( formatUnits( responseData.score - .find((s) => s.address === address) + .find((s) => s.address?.toLowerCase() === address.toLowerCase()) ?.score?.toString() || '0', options.hasOwnProperty('decimals') ? options.decimals : 0 ) diff --git a/src/strategies/candy-lock-nft/index.ts b/src/strategies/candy-lock-nft/index.ts index f731451df..3835d319e 100644 --- a/src/strategies/candy-lock-nft/index.ts +++ b/src/strategies/candy-lock-nft/index.ts @@ -40,8 +40,7 @@ async function v1_scores( provider, addresses, snapshot, - contract_address, - token_decimals + contract_address ): Promise<[string, number][]> { const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; @@ -68,8 +67,7 @@ async function v2_3_scores( provider, addresses, snapshot, - contract_address, - token_decimals + contract_address ): Promise<[string, number][]> { const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; @@ -105,24 +103,21 @@ export async function strategy( provider, addresses, snapshot, - options.v1_address, - options.decimals + options.v1_address ); const v2Scores = await v2_3_scores( network, provider, addresses, snapshot, - options.v2_address, - options.decimals + options.v2_address ); const v3Scores = await v2_3_scores( network, provider, addresses, snapshot, - options.v3_address, - options.decimals + options.v3_address ); return Object.fromEntries( diff --git a/src/strategies/frax-finance-fraxtal/index.ts b/src/strategies/frax-finance-fraxtal/index.ts index 6b96caa3b..a91f9fdc8 100644 --- a/src/strategies/frax-finance-fraxtal/index.ts +++ b/src/strategies/frax-finance-fraxtal/index.ts @@ -11,7 +11,7 @@ export const version = '0.0.1'; const DECIMALS = 18; -const abi = [ 'function balanceOf(address account) view returns (uint256)' ] +const abi = ['function balanceOf(address account) view returns (uint256)']; const chunk = (arr, size) => Array.from({ length: Math.ceil(arr.length / size) }, (v, i) => @@ -46,10 +46,7 @@ export async function strategy( network, provider, abi, - [ - ...fxsQuery, - ...vefxsQuery, - ], + [...fxsQuery, ...vefxsQuery], { blockTag } ); @@ -72,14 +69,7 @@ export async function strategy( return [ addresses[i], - parseFloat( - formatUnits( - free_fxs - .add(vefxs) - .toString(), - DECIMALS - ) - ) + parseFloat(formatUnits(free_fxs.add(vefxs).toString(), DECIMALS)) ]; }) ); diff --git a/src/strategies/sd-gauge-less-vote-boost/index.ts b/src/strategies/sd-gauge-less-vote-boost/index.ts index b6d3cc288..136ebf7ed 100644 --- a/src/strategies/sd-gauge-less-vote-boost/index.ts +++ b/src/strategies/sd-gauge-less-vote-boost/index.ts @@ -5,8 +5,8 @@ import { formatUnits } from '@ethersproject/units'; export const author = 'pierremarsotlyon1'; export const version = '0.0.1'; -const VE_SDT = "0x0C30476f66034E11782938DF8e4384970B6c9e8a"; -const VE_PROXY_BOOST_SDT = "0xD67bdBefF01Fc492f1864E61756E5FBB3f173506"; +const VE_SDT = '0x0C30476f66034E11782938DF8e4384970B6c9e8a'; +const VE_PROXY_BOOST_SDT = '0xD67bdBefF01Fc492f1864E61756E5FBB3f173506'; const TOKENLESS_PRODUCTION = 40; // Used ABI @@ -37,9 +37,7 @@ export async function strategy( throw new Error('maximum of 20 whitelisted address'); } - const mainnetCalls: any[] = [ - [VE_SDT, 'totalSupply'] - ]; + const mainnetCalls: any[] = [[VE_SDT, 'totalSupply']]; const destinationChainCalls: any[] = [ [options.sdTokenGaugeDestinationChain, 'totalSupply'] @@ -80,19 +78,17 @@ export async function strategy( ); // Queries - const ajustedBalancesMainnet = addresses.map((address: any) => - [ - VE_PROXY_BOOST_SDT, - 'adjusted_balance_of', - [address] - ]); - - const sdTknGaugeBalanceDestinationChain = addresses.map((address: any) => - [ - options.sdTokenGaugeDestinationChain, - 'balanceOf', - [address] - ]); + const ajustedBalancesMainnet = addresses.map((address: any) => [ + VE_PROXY_BOOST_SDT, + 'adjusted_balance_of', + [address] + ]); + + const sdTknGaugeBalanceDestinationChain = addresses.map((address: any) => [ + options.sdTokenGaugeDestinationChain, + 'balanceOf', + [address] + ]); const responsesMainnet: any[] = []; const responsesDestinationChain: any[] = []; @@ -109,12 +105,9 @@ export async function strategy( calls.push(...mainnetCalls); } - let callResp: any[] = await multicall( - network, - provider, - abi, - calls, - { blockTag: blockListMainnet[i] }); + let callResp: any[] = await multicall(network, provider, abi, calls, { + blockTag: blockListMainnet[i] + }); if (isEnd) { veSDTTotalSupply = parseFloat(formatUnits(callResp.pop()[0], 18)); @@ -133,10 +126,13 @@ export async function strategy( destinationChainProvider, abi, calls, - { blockTag: blockListDesitnationChain[i] }); + { blockTag: blockListDesitnationChain[i] } + ); if (isEnd) { - sdTokenGaugeTotalSupplyDestinationChain = parseFloat(formatUnits(callResp.pop()[0], 18)); + sdTokenGaugeTotalSupplyDestinationChain = parseFloat( + formatUnits(callResp.pop()[0], 18) + ); } responsesDestinationChain.push(callResp); @@ -150,12 +146,23 @@ export async function strategy( const userWorkingBalances: number[] = []; for (let j = 0; j < options.twavpNumberOfBlocks; j++) { - const voting_balance = parseFloat(formatUnits(BigNumber.from(responsesMainnet[j].shift()[0]), 18)); - const l = parseFloat(formatUnits(BigNumber.from(responsesDestinationChain[j].shift()[0]), 18)); - - let lim = l * TOKENLESS_PRODUCTION / 100 + const voting_balance = parseFloat( + formatUnits(BigNumber.from(responsesMainnet[j].shift()[0]), 18) + ); + const l = parseFloat( + formatUnits( + BigNumber.from(responsesDestinationChain[j].shift()[0]), + 18 + ) + ); + + let lim = (l * TOKENLESS_PRODUCTION) / 100; if (veSDTTotalSupply > 0) { - lim += sdTokenGaugeTotalSupplyDestinationChain * voting_balance / veSDTTotalSupply * (100 - TOKENLESS_PRODUCTION) / 100 + lim += + (((sdTokenGaugeTotalSupplyDestinationChain * voting_balance) / + veSDTTotalSupply) * + (100 - TOKENLESS_PRODUCTION)) / + 100; } userWorkingBalances.push(Math.min(l, lim)); @@ -190,7 +197,7 @@ function getPreviousBlocks( for (let i = 0; i < numberOfBlocks; i++) { // Calculate block number - let blockNumber = + const blockNumber = currentBlockNumber - totalBlocksInterval + blockInterval * i; // Add block number to array @@ -239,4 +246,4 @@ async function getIDChainBlock(snapshot, provider, chainId) { const url = 'https://blockfinder.snapshot.org'; const data = await subgraphRequest(url, query); return data.blocks[0].number; -} \ No newline at end of file +} From a44c3195f88c577dd8bc0c3881be97726749441f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 4 Sep 2024 15:36:57 +0530 Subject: [PATCH 731/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.8 (#1566) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 5e58048dd..ae38f4858 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.7", + "@snapshot-labs/snapshot.js": "^0.12.8", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index ad64ed299..c86ebff87 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.7": - version "0.12.7" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.7.tgz#e08899984c012cb680730fa9ed785236a96ef9b3" - integrity sha512-pMNckn709ZTXQcdWRco7RfOKKuTbXa08BPaZA1NLq9NDiWdvOP0UAj4ZQBzmXPPOmM6vkpH7QwX9bzhobJe6yA== +"@snapshot-labs/snapshot.js@^0.12.8": + version "0.12.8" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.8.tgz#4923f312f905c3697844d8704c91308c39902a47" + integrity sha512-PZ9NgqC5QKiEw29NiEs5HPHrjmuREroNS8FSJ5hHudY720eLWEuE+8h+/pSxSJB3TlBvZ6LkBj+2fplgmq9+1w== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 74f328bbb58a0dadb528dcf3fddfd837590f587f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 5 Sep 2024 15:15:45 +0530 Subject: [PATCH 732/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.9 (#1567) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index ae38f4858..03cb71d2e 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.8", + "@snapshot-labs/snapshot.js": "^0.12.9", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index c86ebff87..8e32538a0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.8": - version "0.12.8" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.8.tgz#4923f312f905c3697844d8704c91308c39902a47" - integrity sha512-PZ9NgqC5QKiEw29NiEs5HPHrjmuREroNS8FSJ5hHudY720eLWEuE+8h+/pSxSJB3TlBvZ6LkBj+2fplgmq9+1w== +"@snapshot-labs/snapshot.js@^0.12.9": + version "0.12.9" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.9.tgz#76dbb3509c258833fcf1e99ace10135736b8ecf9" + integrity sha512-+rdwjFPLgR1yhXlBmQaD92d9J7x7d8AxoY91s8MgoYWvClfdYrsHvmAH+9uQ4+BvQbFxjNT6mzw3WXjn7dRzEQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 837243bce76bdc87d0f59f9ae929ce14f0bc9a52 Mon Sep 17 00:00:00 2001 From: Marsot Pierre Date: Thu, 5 Sep 2024 16:00:54 +0200 Subject: [PATCH 733/815] sdvote-balanceof-twavp-pool (#1568) --- src/strategies/index.ts | 2 + .../sdvote-balanceof-twavp-pool/README.md | 23 +++ .../sdvote-balanceof-twavp-pool/examples.json | 30 ++++ .../sdvote-balanceof-twavp-pool/index.ts | 162 ++++++++++++++++++ 4 files changed, 217 insertions(+) create mode 100644 src/strategies/sdvote-balanceof-twavp-pool/README.md create mode 100644 src/strategies/sdvote-balanceof-twavp-pool/examples.json create mode 100644 src/strategies/sdvote-balanceof-twavp-pool/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 8bf94892f..d5a58c0ad 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -379,6 +379,7 @@ import * as sdVoteBoostTWAVPV2 from './sd-vote-boost-twavp-v2'; import * as sdVoteBoostTWAVPV3 from './sd-vote-boost-twavp-v3'; import * as sdVoteBoostTWAVPV4 from './sd-vote-boost-twavp-v4'; import * as sdGaugeLessVoteBoost from './sd-gauge-less-vote-boost'; +import * as sdVoteBalanceOfTwavpPool from './sdvote-balanceof-twavp-pool'; import * as sdVoteBoostTWAVPVsdToken from './sd-vote-boost-twavp-vsdtoken'; import * as sdVoteBoostTWAVPVCrossChain from './sd-vote-boost-twavp-vsdcrv-crosschain'; import * as sdVoteBoostTWAVPBalanceof from './sd-vote-boost-twavp-balanceof'; @@ -840,6 +841,7 @@ const strategies = { 'sd-vote-boost-twavp-v3': sdVoteBoostTWAVPV3, 'sd-vote-boost-twavp-v4': sdVoteBoostTWAVPV4, 'sd-gauge-less-vote-boost': sdGaugeLessVoteBoost, + 'sdvote-balanceof-twavp-pool': sdVoteBalanceOfTwavpPool, 'sd-vote-boost-twavp-vsdtoken': sdVoteBoostTWAVPVsdToken, 'sd-vote-boost-twavp-vsdcrv-crosschain': sdVoteBoostTWAVPVCrossChain, 'sd-vote-boost-twavp-balanceof': sdVoteBoostTWAVPBalanceof, diff --git a/src/strategies/sdvote-balanceof-twavp-pool/README.md b/src/strategies/sdvote-balanceof-twavp-pool/README.md new file mode 100644 index 000000000..73d015679 --- /dev/null +++ b/src/strategies/sdvote-balanceof-twavp-pool/README.md @@ -0,0 +1,23 @@ +# sdvote-balanceof-twavp-pool + +This strategy is used by Stake DAO to vote with sdToken using Time Weighted Averaged Voting Power (TWAVP) system based on a balanceOf with possibility to whitelist addresses to by pass TWAVP. +Also, the voting power based on the balance of the specified pools is allocated to a bot + +Here is an example of parameters: + +```json +{ + "sdTokenGauge": "0xE2496134149e6CD3f3A577C2B08A6f54fC23e6e4", + "symbol": "sdToken-gauge", + "decimals": 18, + "twavpDaysInterval": 10, + "twavpNumberOfBlocks": 5, + "blockPerSec": 3, + "whiteListedAddress": [], + "pools": [ + "0xb8204D31379A9B317CD61C833406C972F58ecCbC" + ], + "botAddress": "0xb4542526AfeE2FdA1D584213D1521272a398B42a", + "indexSdTokenInPool": 1 +} +``` \ No newline at end of file diff --git a/src/strategies/sdvote-balanceof-twavp-pool/examples.json b/src/strategies/sdvote-balanceof-twavp-pool/examples.json new file mode 100644 index 000000000..4f9c0f210 --- /dev/null +++ b/src/strategies/sdvote-balanceof-twavp-pool/examples.json @@ -0,0 +1,30 @@ +[ + { + "name": "Stake DAO vote using TWAVP balanceOf and attribute pools voting power to a bot", + "strategy": { + "name": "sdvote-balanceof-twavp-pool", + "params": { + "sdTokenGauge": "0xE2496134149e6CD3f3A577C2B08A6f54fC23e6e4", + "symbol": "sdToken-gauge", + "decimals": 18, + "twavpDaysInterval": 10, + "twavpNumberOfBlocks": 5, + "blockPerSec": 3, + "whiteListedAddress": [], + "pools": [ + "0xb8204D31379A9B317CD61C833406C972F58ecCbC" + ], + "botAddress": "0xb4542526AfeE2FdA1D584213D1521272a398B42a", + "indexSdTokenInPool": 1 + } + }, + "network": "56", + "addresses": [ + "0xb734Ec7A75d65406fde5bcf9156cAB673ba1e1C5", + "0xee439Ee079AC05D9d33a6926A16e0c820fB2713A", + "0xc1133c83D409724727fF6699F14F040746e5AD01", + "0xb4542526AfeE2FdA1D584213D1521272a398B42a" + ], + "snapshot": 41988561 + } +] diff --git a/src/strategies/sdvote-balanceof-twavp-pool/index.ts b/src/strategies/sdvote-balanceof-twavp-pool/index.ts new file mode 100644 index 000000000..90beefedc --- /dev/null +++ b/src/strategies/sdvote-balanceof-twavp-pool/index.ts @@ -0,0 +1,162 @@ +import { multicall } from '../../utils'; +import { BigNumber } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; + +export const author = 'pierremarsotlyon1'; +export const version = '0.0.1'; + +// Used ABI +const abi = [ + 'function balanceOf(address account) external view returns (uint256)', + 'function balances(uint256 i) external view returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + // Maximum of 5 multicall! + if (options.twavpNumberOfBlocks > 5) { + throw new Error('maximum of 5 call'); + } + + // Maximum of 20 whitelisted address + if (options.whiteListedAddress.length > 20) { + throw new Error('maximum of 20 whitelisted address'); + } + + // --- Create block number list for twavp + // Obtain last block number + // Create block tag + let blockTag = 0; + if (typeof snapshot === 'number') { + blockTag = snapshot; + } else { + blockTag = await provider.getBlockNumber(); + } + + // Create block list + const blockList = getPreviousBlocks( + blockTag, + options.twavpNumberOfBlocks, + options.twavpDaysInterval, + options.blockPerSec + ); + + // Query working balance of users + const balanceOfQueries = addresses.map((address: any) => [ + options.sdTokenGauge, + 'balanceOf', + [address] + ]); + + const poolsCalls: any[] = options.pools.map((pool: string) => [pool, 'balances', [options.indexSdTokenInPool]]); + + // Execute multicall `sampleStep` times + const response: any[] = []; + for (let i = 0; i < options.twavpNumberOfBlocks; i++) { + // Use good block number + blockTag = blockList[i]; + + const queries = [ + ...balanceOfQueries + ]; + + if (i === options.twavpNumberOfBlocks - 1) { + queries.push(...poolsCalls); + } + + response.push( + await multicall(network, provider, abi, queries, { blockTag }) + ); + } + + let liquidityVoteFee = 0; + if (options.pools.length > 0) { + liquidityVoteFee = options.pools.map(() => parseFloat(formatUnits(response[response.length - 1].pop()[0], 18))) + .reduce((acc: number, balance: number) => acc + balance, 0); + } + + return Object.fromEntries( + Array(addresses.length) + .fill('x') + .map((_, i) => { + // Init array of working balances for user + const userBalances: BigNumber[] = []; + + for (let j = 0; j < options.twavpNumberOfBlocks; j++) { + const balance = response[j].shift()[0]; + userBalances.push(balance); + } + + if (addresses[i].toLowerCase() === options.botAddress.toLowerCase()) { + return [addresses[i], Number(liquidityVoteFee)]; + } else { + // Get average balance + const averageBalanceOf = parseFloat( + formatUnits( + average(userBalances, addresses[i], options.whiteListedAddress), + options.decimals + ) + ); + + // Return address and voting power + return [addresses[i], Number(averageBalanceOf)]; + } + }) + ); +} + +function getPreviousBlocks( + currentBlockNumber: number, + numberOfBlocks: number, + daysInterval: number, + blockPerSec: number +): number[] { + const blocksPerDay = 86400 / blockPerSec; + + // Calculate total blocks interval + const totalBlocksInterval = blocksPerDay * daysInterval; + // Calculate block interval + const blockInterval = totalBlocksInterval / (numberOfBlocks - 1); + + // Init array of block numbers + const blockNumbers: number[] = []; + + for (let i = 0; i < numberOfBlocks; i++) { + // Calculate block number + const blockNumber = + currentBlockNumber - totalBlocksInterval + blockInterval * i; + // Add block number to array + blockNumbers.push(Math.round(blockNumber)); + } + + // Return array of block numbers + return blockNumbers; +} + +function average( + numbers: BigNumber[], + address: string, + whiteListedAddress: string[] +): BigNumber { + // If no numbers, return 0 to avoid division by 0. + if (numbers.length === 0) return BigNumber.from(0); + + // If address is whitelisted, return most recent working balance. i.e. no twavp applied. + if (whiteListedAddress.includes(address)) return numbers[numbers.length - 1]; + + // Init sum + let sum = BigNumber.from(0); + // Loop through all elements and add them to sum + for (let i = 0; i < numbers.length; i++) { + sum = sum.add(numbers[i]); + } + + // Return sum divided by array length to get mean + return sum.div(numbers.length); +} From c29ef935e30555c102e3bc338831fcca3af4d957 Mon Sep 17 00:00:00 2001 From: benk10 Date: Thu, 5 Sep 2024 19:32:36 +0400 Subject: [PATCH 734/815] [hats-strategy] Hats Finance strategy (hats-finance) (#1569) * Create hats-strategy * Update src/strategies/index.ts Co-authored-by: Chaitanya --------- Co-authored-by: Chaitanya --- src/strategies/hats-strategy/README.md | 13 ++++ src/strategies/hats-strategy/examples.json | 25 +++++++ src/strategies/hats-strategy/index.ts | 87 ++++++++++++++++++++++ src/strategies/hats-strategy/schema.json | 42 +++++++++++ src/strategies/index.ts | 2 + 5 files changed, 169 insertions(+) create mode 100644 src/strategies/hats-strategy/README.md create mode 100644 src/strategies/hats-strategy/examples.json create mode 100644 src/strategies/hats-strategy/index.ts create mode 100644 src/strategies/hats-strategy/schema.json diff --git a/src/strategies/hats-strategy/README.md b/src/strategies/hats-strategy/README.md new file mode 100644 index 000000000..cba078ce5 --- /dev/null +++ b/src/strategies/hats-strategy/README.md @@ -0,0 +1,13 @@ +# hats-strategy + +This strategy for Hats.finance governance allows token holders to vote and delegate, and gives voting power to depositors of an ERC4626 vault + +```json +{ + "address": "0x4D22e37Eb4d71D1acc5f4889a65936D2a44A2f15", + "decimals": 18, + "vaultAddress": "0x1025B2248cB6AEAF93c7E4d10B19F90f5B4ea090", + "vaultDecimals": 18, + "vaultMultiplier": 3 +} +``` diff --git a/src/strategies/hats-strategy/examples.json b/src/strategies/hats-strategy/examples.json new file mode 100644 index 000000000..e0865153e --- /dev/null +++ b/src/strategies/hats-strategy/examples.json @@ -0,0 +1,25 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "hats-strategy", + "params": { + "address": "0x4D22e37Eb4d71D1acc5f4889a65936D2a44A2f15", + "decimals": 18, + "vaultAddress": "0x1025B2248cB6AEAF93c7E4d10B19F90f5B4ea090", + "vaultMultiplier": 3 + } + }, + "network": "42161", + "addresses": [ + "0x307392EDc15A34B3418A0caf27A1e0b057c82EA6", + "0x00B5ADe4ac1fE9cCc08Addc2C10070642335117F", + "0xfaB068e04F887b672AC021340C890E3b3F1e4eB1", + "0x4fdc370Db5f81fb1237F189e036DF937Aaa31092", + "0x410f82a8617dDBa669e9431BD8Bf897b009095C8", + "0xfFB5f28D949B64D05A61826104b25E3a14A5caC5", + "0xB2B1f686833717068d6c8111CE2E0104d4686699" + ], + "snapshot": 240742719 + } +] diff --git a/src/strategies/hats-strategy/index.ts b/src/strategies/hats-strategy/index.ts new file mode 100644 index 000000000..6276ac7d6 --- /dev/null +++ b/src/strategies/hats-strategy/index.ts @@ -0,0 +1,87 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import { formatUnits, parseUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; +import { strategy as erc4626BalanceOfStrategy } from '../erc4626-assets-of'; + +export const author = 'hats-finance'; +export const version = '0.1.0'; + +const abi = [ + 'function delegates(address account) view returns (address)', + 'function balanceOf(address account) view returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multi = new Multicaller(network, provider, abi, { blockTag }); + + // Get the delegate addresses and original balances + addresses.forEach((address) => { + multi.call(`delegates.${address}`, options.address, 'delegates', [address]); + multi.call(`balances.${address}`, options.address, 'balanceOf', [address]); + }); + + const response = await multi.execute(); + + const delegates: Record = {}; + const tokenBalances: Record = {}; + + for (const address of addresses) { + const delegate = response.delegates[address]; + const balance = BigNumber.from(response.balances[address] || 0); + tokenBalances[address] = balance; + if (delegate !== '0x0000000000000000000000000000000000000000' && delegate !== address) { + delegates[address] = delegate; + } + } + + // If ERC4626 vault is provided, calculate the balances and apply multiplier + let vaultBalances: Record = {}; + if (options.vaultAddress) { + const rawVaultBalances = await erc4626BalanceOfStrategy( + space, + network, + provider, + addresses, + { address: options.vaultAddress, decimals: options.decimals }, + snapshot + ); + + // Apply multiplier to vault balances + for (const [address, balance] of Object.entries(rawVaultBalances)) { + vaultBalances[address] = BigNumber.from(parseUnits(balance.toString(), options.decimals)).mul(options.vaultMultiplier || 3); + } + } + + // Handle delegation: add both token and vault balances to the delegate if delegation exists + const adjustedBalances: Record = {}; + for (const address of addresses) { + const tokenBalance = tokenBalances[address] || BigNumber.from(0); + const vaultBalance = vaultBalances[address] || BigNumber.from(0); + const totalBalance = tokenBalance.add(vaultBalance); + + const delegate = delegates[address]; + if (delegate) { + adjustedBalances[delegate] = (adjustedBalances[delegate] || BigNumber.from(0)).add(totalBalance); + adjustedBalances[address] = BigNumber.from(0); // Zero out original balance to avoid double-counting + } else { + adjustedBalances[address] = totalBalance; + } + } + + const finalBalances: Record = {}; + + Object.keys(adjustedBalances).forEach((address) => { + finalBalances[address] = parseFloat(formatUnits(adjustedBalances[address] || BigNumber.from(0), options.decimals)); + }); + + return finalBalances; +} diff --git a/src/strategies/hats-strategy/schema.json b/src/strategies/hats-strategy/schema.json new file mode 100644 index 000000000..1b3107f09 --- /dev/null +++ b/src/strategies/hats-strategy/schema.json @@ -0,0 +1,42 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "address": { + "type": "string", + "title": "ERC20 address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 18"], + "minimum": 0 + }, + "vaultAddress": { + "type": "string", + "title": "ECR4626 vault address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "vaultMultiplier": { + "type": "number", + "title": "Vault voting multiplier", + "examples": ["e.g. 3"], + "minimum": 0 + } + }, + "required": ["address", "decimals"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index d5a58c0ad..cc85ad8bb 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -444,6 +444,7 @@ import * as gardenStakes from './garden-stakes'; import * as csv from './csv'; import * as swarmStaking from './swarm-staking'; import * as mocaStaking from './moca-staking'; +import * as hatsStrategy from './hats-strategy'; import * as candyLockV1Token from './candy-lockv1-token'; import * as candyLockToken from './candy-lock-token'; import * as candyAutoVault from './candy-auto-vault'; @@ -905,6 +906,7 @@ const strategies = { csv, 'swarm-staking': swarmStaking, 'moca-staking': mocaStaking, + 'hats-strategy': hatsStrategy, 'candy-lockv1-token': candyLockV1Token, 'candy-lock-token': candyLockToken, 'candy-auto-vault': candyAutoVault, From 7d40ebe5faa593593d2dfc72685664012eb7b1fa Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 7 Sep 2024 18:30:13 +0530 Subject: [PATCH 735/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.10 (#1570) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 03cb71d2e..5dee73c05 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.9", + "@snapshot-labs/snapshot.js": "^0.12.10", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 8e32538a0..d04191577 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.9": - version "0.12.9" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.9.tgz#76dbb3509c258833fcf1e99ace10135736b8ecf9" - integrity sha512-+rdwjFPLgR1yhXlBmQaD92d9J7x7d8AxoY91s8MgoYWvClfdYrsHvmAH+9uQ4+BvQbFxjNT6mzw3WXjn7dRzEQ== +"@snapshot-labs/snapshot.js@^0.12.10": + version "0.12.10" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.10.tgz#69880cec8546fd271c1ede15134906ab2625e78f" + integrity sha512-NNypHVuNd9xsbAA/oGLntBMfVA7TfT2ARygVJ+zqmmgvkeofkoGi9u0bCXRqXWSyylP8tfvtkPQ9eFVGk4U1RQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From e59b59f689821e3bb86861206918d93108c0120e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 9 Sep 2024 08:13:56 +0530 Subject: [PATCH 736/815] Automated lint (#1571) Co-authored-by: ChaituVR --- src/strategies/hats-strategy/index.ts | 30 +++++++++++++------ .../sdvote-balanceof-twavp-pool/examples.json | 4 +-- .../sdvote-balanceof-twavp-pool/index.ts | 15 ++++++---- 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/strategies/hats-strategy/index.ts b/src/strategies/hats-strategy/index.ts index 6276ac7d6..69ef767cc 100644 --- a/src/strategies/hats-strategy/index.ts +++ b/src/strategies/hats-strategy/index.ts @@ -38,13 +38,16 @@ export async function strategy( const delegate = response.delegates[address]; const balance = BigNumber.from(response.balances[address] || 0); tokenBalances[address] = balance; - if (delegate !== '0x0000000000000000000000000000000000000000' && delegate !== address) { + if ( + delegate !== '0x0000000000000000000000000000000000000000' && + delegate !== address + ) { delegates[address] = delegate; } } // If ERC4626 vault is provided, calculate the balances and apply multiplier - let vaultBalances: Record = {}; + const vaultBalances: Record = {}; if (options.vaultAddress) { const rawVaultBalances = await erc4626BalanceOfStrategy( space, @@ -57,7 +60,9 @@ export async function strategy( // Apply multiplier to vault balances for (const [address, balance] of Object.entries(rawVaultBalances)) { - vaultBalances[address] = BigNumber.from(parseUnits(balance.toString(), options.decimals)).mul(options.vaultMultiplier || 3); + vaultBalances[address] = BigNumber.from( + parseUnits(balance.toString(), options.decimals) + ).mul(options.vaultMultiplier || 3); } } @@ -70,18 +75,25 @@ export async function strategy( const delegate = delegates[address]; if (delegate) { - adjustedBalances[delegate] = (adjustedBalances[delegate] || BigNumber.from(0)).add(totalBalance); + adjustedBalances[delegate] = ( + adjustedBalances[delegate] || BigNumber.from(0) + ).add(totalBalance); adjustedBalances[address] = BigNumber.from(0); // Zero out original balance to avoid double-counting } else { adjustedBalances[address] = totalBalance; } } - const finalBalances: Record = {}; - - Object.keys(adjustedBalances).forEach((address) => { - finalBalances[address] = parseFloat(formatUnits(adjustedBalances[address] || BigNumber.from(0), options.decimals)); - }); + const finalBalances: Record = {}; + + Object.keys(adjustedBalances).forEach((address) => { + finalBalances[address] = parseFloat( + formatUnits( + adjustedBalances[address] || BigNumber.from(0), + options.decimals + ) + ); + }); return finalBalances; } diff --git a/src/strategies/sdvote-balanceof-twavp-pool/examples.json b/src/strategies/sdvote-balanceof-twavp-pool/examples.json index 4f9c0f210..2f5ad7739 100644 --- a/src/strategies/sdvote-balanceof-twavp-pool/examples.json +++ b/src/strategies/sdvote-balanceof-twavp-pool/examples.json @@ -11,9 +11,7 @@ "twavpNumberOfBlocks": 5, "blockPerSec": 3, "whiteListedAddress": [], - "pools": [ - "0xb8204D31379A9B317CD61C833406C972F58ecCbC" - ], + "pools": ["0xb8204D31379A9B317CD61C833406C972F58ecCbC"], "botAddress": "0xb4542526AfeE2FdA1D584213D1521272a398B42a", "indexSdTokenInPool": 1 } diff --git a/src/strategies/sdvote-balanceof-twavp-pool/index.ts b/src/strategies/sdvote-balanceof-twavp-pool/index.ts index 90beefedc..4cfed1bb1 100644 --- a/src/strategies/sdvote-balanceof-twavp-pool/index.ts +++ b/src/strategies/sdvote-balanceof-twavp-pool/index.ts @@ -54,7 +54,11 @@ export async function strategy( [address] ]); - const poolsCalls: any[] = options.pools.map((pool: string) => [pool, 'balances', [options.indexSdTokenInPool]]); + const poolsCalls: any[] = options.pools.map((pool: string) => [ + pool, + 'balances', + [options.indexSdTokenInPool] + ]); // Execute multicall `sampleStep` times const response: any[] = []; @@ -62,9 +66,7 @@ export async function strategy( // Use good block number blockTag = blockList[i]; - const queries = [ - ...balanceOfQueries - ]; + const queries = [...balanceOfQueries]; if (i === options.twavpNumberOfBlocks - 1) { queries.push(...poolsCalls); @@ -77,7 +79,10 @@ export async function strategy( let liquidityVoteFee = 0; if (options.pools.length > 0) { - liquidityVoteFee = options.pools.map(() => parseFloat(formatUnits(response[response.length - 1].pop()[0], 18))) + liquidityVoteFee = options.pools + .map(() => + parseFloat(formatUnits(response[response.length - 1].pop()[0], 18)) + ) .reduce((acc: number, balance: number) => acc + balance, 0); } From bf0ea67752297ea64be79493e5c1694f9bf452c6 Mon Sep 17 00:00:00 2001 From: Marsot Pierre Date: Mon, 9 Sep 2024 16:07:06 +0200 Subject: [PATCH 737/815] [sd-gauge-less-vote-boost] Add veSDT boost for MS (#1572) * sdvote-balanceof-twavp-pool * sd-gauge-less-vote-boost - add veSDT boost for MS --- src/strategies/sd-gauge-less-vote-boost/examples.json | 6 ++++-- src/strategies/sd-gauge-less-vote-boost/index.ts | 8 +++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/strategies/sd-gauge-less-vote-boost/examples.json b/src/strategies/sd-gauge-less-vote-boost/examples.json index eb6e7786c..5109f2023 100644 --- a/src/strategies/sd-gauge-less-vote-boost/examples.json +++ b/src/strategies/sd-gauge-less-vote-boost/examples.json @@ -11,6 +11,7 @@ "twavpNumberOfBlocks": 2, "botAddress": "0xb4542526AfeE2FdA1D584213D1521272a398B42a", "whiteListedAddress": ["0x1c0D72a330F2768dAF718DEf8A19BAb019EEAd09"], + "veSDTUserAddresses": {}, "targetChainId": "252", "blocksPerDay": 43200 } @@ -25,8 +26,9 @@ "0x1c0D72a330F2768dAF718DEf8A19BAb019EEAd09", "0xC6625129C9df3314a4dd604845488f4bA62F9dB8", "0x10c16c7B8b1DDCFE65990ec822DE4379dd8a86dE", - "0x034f978581617FcABB75bfBe697d2230a3285437" + "0x034f978581617FcABB75bfBe697d2230a3285437", + "0xBf911AF95bC5FE348F468b6D6928df7E7fC278e3" ], - "snapshot": 20619358 + "snapshot": 20712893 } ] diff --git a/src/strategies/sd-gauge-less-vote-boost/index.ts b/src/strategies/sd-gauge-less-vote-boost/index.ts index 136ebf7ed..12f833c32 100644 --- a/src/strategies/sd-gauge-less-vote-boost/index.ts +++ b/src/strategies/sd-gauge-less-vote-boost/index.ts @@ -37,6 +37,12 @@ export async function strategy( throw new Error('maximum of 20 whitelisted address'); } + const veSDTUserAddresses = options.veSDTUserAddresses || {}; + const veSDTUserAddressesMap = {}; + for (const address of Object.keys(veSDTUserAddresses)) { + veSDTUserAddressesMap[address.toLowerCase()] = veSDTUserAddresses[address].toLowerCase(); + } + const mainnetCalls: any[] = [[VE_SDT, 'totalSupply']]; const destinationChainCalls: any[] = [ @@ -81,7 +87,7 @@ export async function strategy( const ajustedBalancesMainnet = addresses.map((address: any) => [ VE_PROXY_BOOST_SDT, 'adjusted_balance_of', - [address] + [veSDTUserAddressesMap[address.toLowerCase()] || address] ]); const sdTknGaugeBalanceDestinationChain = addresses.map((address: any) => [ From 8aeadfc78fe6071ef2d9090ab2693678fe61c79e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 12 Sep 2024 15:46:54 +0530 Subject: [PATCH 738/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.11 (#1573) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 5dee73c05..4db226577 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.10", + "@snapshot-labs/snapshot.js": "^0.12.11", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index d04191577..c4c11452d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.10": - version "0.12.10" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.10.tgz#69880cec8546fd271c1ede15134906ab2625e78f" - integrity sha512-NNypHVuNd9xsbAA/oGLntBMfVA7TfT2ARygVJ+zqmmgvkeofkoGi9u0bCXRqXWSyylP8tfvtkPQ9eFVGk4U1RQ== +"@snapshot-labs/snapshot.js@^0.12.11": + version "0.12.11" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.11.tgz#62b3ddd7f3fb87d24a0ceda249015f55302b6799" + integrity sha512-HCToXWBoYOFZs8HzsAIapmgQqF7XUJ3jMxg8eiJayAAotkVO1ckZdcUcpTXCt6sG/aKhrZSIqGLQzNqn90Advw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 8bb93f7b1f056d4608addbbb856cdb471e9d64f6 Mon Sep 17 00:00:00 2001 From: Didi Date: Fri, 13 Sep 2024 09:50:28 +0200 Subject: [PATCH 739/815] Add strategy for SuperBoring [superboring] (#1575) * added superboring strategy * also consider staked amount * updated readme --- src/strategies/index.ts | 4 +- src/strategies/superboring/README.md | 22 ++++ src/strategies/superboring/examples.json | 22 ++++ src/strategies/superboring/index.ts | 123 +++++++++++++++++++++++ src/strategies/superboring/schema.json | 30 ++++++ 5 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 src/strategies/superboring/README.md create mode 100644 src/strategies/superboring/examples.json create mode 100644 src/strategies/superboring/index.ts create mode 100644 src/strategies/superboring/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index cc85ad8bb..3ed65506e 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -451,6 +451,7 @@ import * as candyAutoVault from './candy-auto-vault'; import * as candyLockNft from './candy-lock-nft'; import * as candyNftStaking from './candy-nft-staking'; import * as pom from './pom'; +import * as superboring from './superboring'; const strategies = { 'delegatexyz-erc721-balance-of': delegatexyzErc721BalanceOf, @@ -912,7 +913,8 @@ const strategies = { 'candy-auto-vault': candyAutoVault, 'candy-lock-nft': candyLockNft, 'candy-nft-staking': candyNftStaking, - pom + pom, + superboring }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/superboring/README.md b/src/strategies/superboring/README.md new file mode 100644 index 000000000..80cb12879 --- /dev/null +++ b/src/strategies/superboring/README.md @@ -0,0 +1,22 @@ +# SuperBoring + +Returns the $BORING amount associated to the voter, consisting of 3 components +* tokens directly held +* tokens held by the associated _SleepPod_ +* sum of tokens staked on Torexes controlled by the SuperBoring instance + +The _SleepPod_ is a contract holding tokens on behalf of users. Each account can have zero or one SleepPod associated. + +In order to calculate the amount of staked tokens, the strategy first gets a list of _Torexes_ from the SuperBoring contract, +then queries the stake amount of the voter for each of them, and sums them up. + +Here is an example of parameters for Celo: + +```json +{ + "tokenAddress": "0x6C210F071c7246C452CAC7F8BaA6dA53907BbaE1", + "superBoringAddress": "0xAcA744453C178F3D651e06A3459E2F242aa01789" +} +``` + +For more details about SuperBoring, visit https://docs.superboring.xyz \ No newline at end of file diff --git a/src/strategies/superboring/examples.json b/src/strategies/superboring/examples.json new file mode 100644 index 000000000..7eeb9bb5d --- /dev/null +++ b/src/strategies/superboring/examples.json @@ -0,0 +1,22 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "superboring", + "params": { + "tokenAddress": "0x6C210F071c7246C452CAC7F8BaA6dA53907BbaE1", + "superBoringAddress": "0xAcA744453C178F3D651e06A3459E2F242aa01789" + } + }, + "network": "42220", + "addresses": [ + "0xA6dB8CdC7dED892C6cE2c56a29c3FAa69687CCC4", + "0x7DeF778c74ac7F6E355b277Ba29c0D73142467a8", + "0x1F717Ce8ff07597ee7c408b5623dF40AaAf1787C", + "0xbae4ffDeAF799fd43f7d6d5f378Dd775d1f48f1e", + "0x1c7a9275F2BD5a260A9c31069F77d53473b8ae2e", + "0x4ee5D45eB79aEa04C02961a2e543bbAf5cec81B3" + ], + "snapshot": 27695930 + } +] diff --git a/src/strategies/superboring/index.ts b/src/strategies/superboring/index.ts new file mode 100644 index 000000000..08d96f7d2 --- /dev/null +++ b/src/strategies/superboring/index.ts @@ -0,0 +1,123 @@ +import { BigNumberish, BigNumber } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +/// See https://app.superboring.xyz + +export const author = 'd10r'; +export const version = '0.1.0'; + +// subset of SuperBoring methods we need +const superBoringAbi = [ + 'function getSleepPod(address staker) external view returns (address)', + 'function getAllTorexesMetadata() external view returns ((address, address, address)[])', + 'function getStakedAmountOf(address torex, address staker) public view returns (uint256 stakedAmount)' +]; + +// subset of token methods we need +const tokenAbi = [ + 'function balanceOf(address account) external view returns (uint256)' +]; + +const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"; + +// Super Tokens always have 18 decimals +const DECIMALS = 18; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + // Construct first batch call to SuperBoring contract + const sbMultiCall = new Multicaller(network, provider, superBoringAbi, { blockTag }); + + // Get the sleep pod for each address (will return zero if not exists) + addresses.forEach((address) => + sbMultiCall.call(address, options.superBoringAddress, 'getSleepPod', [ address ]) + ); + + // Get all torexes + sbMultiCall.call('torexes', options.superBoringAddress, 'getAllTorexesMetadata') + + // execute. + // This will return an object with 2 kinds of elements: + // - 1 element with key "torexes" and value an array of tuples with 3 addresses, the first of which is the torex address + // - elements with address as key (one for each user), with the corresponding sleep pod address (zero if not exists) as value + const sbResult: Record = await sbMultiCall.execute(); + + // extract the map from user address to pod address + const podsMap = Object.fromEntries( + Object.entries(sbResult).filter(([key]) => key !== 'torexes') + ); + + // extract the addresses of regitered torexes + const torexAddrs = Array.isArray(sbResult['torexes']) + ? sbResult['torexes'].map(tuple => tuple[0]) + : []; + + // Now we have all torex adresses and can get the staked amounts for each user + + // Construct second batch call to SuperBoring contract + // Since the SuperBoring contract does (corrently) not allow to query the overall staked amount of a user, + // we need to query for each combination of user and torex + const sbMulti2 = new Multicaller(network, provider, superBoringAbi, { blockTag }); + addresses.forEach((address) => + torexAddrs.forEach((torexAddr) => + sbMulti2.call(`${address}-${torexAddr}`, options.superBoringAddress, 'getStakedAmountOf', [ torexAddr, address ]) + ) + ); + + // execute. + // This returns an object with elements with keys of the form "userAddr-torexAddr" and values the staked amount + const sbResult2: Record = await sbMulti2.execute(); + + // Transform to a map from user address to total staked amount + const stakesMap = Object.keys(sbResult2).reduce((acc, key) => { + const [address, ] = key.split('-'); + acc[address] = (acc[address] || BigNumber.from(0)).add(sbResult2[key]); + return acc; + }, {}); + + // In the next multicall, we get the unstaked balances of users and pods, querying the token contract + + const tokenMultiCall = new Multicaller(network, provider, tokenAbi, { blockTag }); + + // Get the balance of each address + addresses.forEach((address) => + tokenMultiCall.call(address, options.tokenAddress, 'balanceOf', [address]) + ); + + // Get the balance of each pod (we filter out the zero addresses which represent non-existing pods) + Object.values(podsMap) + .filter(podAddr => podAddr !== ZERO_ADDRESS) + .forEach((podAddr) => + tokenMultiCall.call(podAddr, options.tokenAddress, 'balanceOf', [podAddr]) + ); + + // execute. + // The returned object will have one element for each user and each pod, with their address as key and the balance as value + const balancesResult: Record = await tokenMultiCall.execute(); + + // Now add up the 3 balance components per user: directly owned + held by pod + staked + const balanceMap: Record = {}; + addresses.forEach((address) => { + balanceMap[address] = + BigNumber.from(balancesResult[address]) // directly owned + .add(BigNumber.from(balancesResult[podsMap[address]] || 0)) // held by pod + .add(BigNumber.from(stakesMap[address])); // staked + }); + + // Return in the required format + return Object.fromEntries( + Object.entries(balanceMap).map(([address, balance]) => [ + address, + parseFloat(formatUnits(balance, DECIMALS)) + ]) + ); +} diff --git a/src/strategies/superboring/schema.json b/src/strategies/superboring/schema.json new file mode 100644 index 000000000..cd773ed63 --- /dev/null +++ b/src/strategies/superboring/schema.json @@ -0,0 +1,30 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "tokenAddress": { + "type": "string", + "title": "Token contract address", + "examples": ["e.g. 0x6C210F071c7246C452CAC7F8BaA6dA53907BbaE1"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "superBoringAddress": { + "type": "string", + "title": "SuperBoring contract address", + "examples": ["e.g. 0xAcA744453C178F3D651e06A3459E2F242aa01789"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } + }, + "required": ["tokenAddress", "superBoringAddress"], + "additionalProperties": false + } + } +} From d1a0ba421ee95336b975c1cee9ff0820b0522daf Mon Sep 17 00:00:00 2001 From: benk10 Date: Fri, 13 Sep 2024 11:52:41 +0400 Subject: [PATCH 740/815] Fix delegation of hats-strategy (#1576) --- src/strategies/hats-strategy/index.ts | 50 +++++++++------------------ 1 file changed, 16 insertions(+), 34 deletions(-) diff --git a/src/strategies/hats-strategy/index.ts b/src/strategies/hats-strategy/index.ts index 69ef767cc..2235a99e2 100644 --- a/src/strategies/hats-strategy/index.ts +++ b/src/strategies/hats-strategy/index.ts @@ -7,6 +7,7 @@ export const author = 'hats-finance'; export const version = '0.1.0'; const abi = [ + 'function getVotes(address account) view returns (uint256)', 'function delegates(address account) view returns (address)', 'function balanceOf(address account) view returns (uint256)' ]; @@ -23,31 +24,31 @@ export async function strategy( const multi = new Multicaller(network, provider, abi, { blockTag }); - // Get the delegate addresses and original balances + // Get the voting power, delegate addresses, and original balances addresses.forEach((address) => { + multi.call(`votes.${address}`, options.address, 'getVotes', [address]); multi.call(`delegates.${address}`, options.address, 'delegates', [address]); multi.call(`balances.${address}`, options.address, 'balanceOf', [address]); }); const response = await multi.execute(); - const delegates: Record = {}; - const tokenBalances: Record = {}; + const adjustedBalances: Record = {}; for (const address of addresses) { + const votes = BigNumber.from(response.votes[address] || 0); const delegate = response.delegates[address]; const balance = BigNumber.from(response.balances[address] || 0); - tokenBalances[address] = balance; - if ( - delegate !== '0x0000000000000000000000000000000000000000' && - delegate !== address - ) { - delegates[address] = delegate; + + if (delegate === '0x0000000000000000000000000000000000000000') { + adjustedBalances[address] = votes.add(balance); + } else { + adjustedBalances[address] = votes; } } // If ERC4626 vault is provided, calculate the balances and apply multiplier - const vaultBalances: Record = {}; + let vaultBalances: Record = {}; if (options.vaultAddress) { const rawVaultBalances = await erc4626BalanceOfStrategy( space, @@ -60,39 +61,20 @@ export async function strategy( // Apply multiplier to vault balances for (const [address, balance] of Object.entries(rawVaultBalances)) { - vaultBalances[address] = BigNumber.from( - parseUnits(balance.toString(), options.decimals) - ).mul(options.vaultMultiplier || 3); + vaultBalances[address] = BigNumber.from(parseUnits(balance.toString(), options.decimals)).mul(options.vaultMultiplier || 3); } } - // Handle delegation: add both token and vault balances to the delegate if delegation exists - const adjustedBalances: Record = {}; + // Add vault balances to adjusted balances for (const address of addresses) { - const tokenBalance = tokenBalances[address] || BigNumber.from(0); const vaultBalance = vaultBalances[address] || BigNumber.from(0); - const totalBalance = tokenBalance.add(vaultBalance); - - const delegate = delegates[address]; - if (delegate) { - adjustedBalances[delegate] = ( - adjustedBalances[delegate] || BigNumber.from(0) - ).add(totalBalance); - adjustedBalances[address] = BigNumber.from(0); // Zero out original balance to avoid double-counting - } else { - adjustedBalances[address] = totalBalance; - } + adjustedBalances[address] = (adjustedBalances[address] || BigNumber.from(0)).add(vaultBalance); } const finalBalances: Record = {}; - + Object.keys(adjustedBalances).forEach((address) => { - finalBalances[address] = parseFloat( - formatUnits( - adjustedBalances[address] || BigNumber.from(0), - options.decimals - ) - ); + finalBalances[address] = parseFloat(formatUnits(adjustedBalances[address] || BigNumber.from(0), options.decimals)); }); return finalBalances; From 6ceed8cbcfd2029a52f7fa87da43b5f072dbd671 Mon Sep 17 00:00:00 2001 From: Marsot Pierre Date: Fri, 13 Sep 2024 16:44:15 +0200 Subject: [PATCH 741/815] [sd-gauge-less-vote-boost] Add delegation (#1577) * sdvote-balanceof-twavp-pool * sd-gauge-less-vote-boost - add veSDT boost for MS * add delegation * fix merge * fix merge * change address * change address --- .../sd-gauge-less-vote-boost/examples.json | 4 +++ .../sd-gauge-less-vote-boost/index.ts | 31 ++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/strategies/sd-gauge-less-vote-boost/examples.json b/src/strategies/sd-gauge-less-vote-boost/examples.json index 5109f2023..b4476c624 100644 --- a/src/strategies/sd-gauge-less-vote-boost/examples.json +++ b/src/strategies/sd-gauge-less-vote-boost/examples.json @@ -12,6 +12,9 @@ "botAddress": "0xb4542526AfeE2FdA1D584213D1521272a398B42a", "whiteListedAddress": ["0x1c0D72a330F2768dAF718DEf8A19BAb019EEAd09"], "veSDTUserAddresses": {}, + "delegation": { + "0xBf911AF95bC5FE348F468b6D6928df7E7fC278e3": "0xF930EBBd05eF8b25B1797b9b2109DDC9B0d43063" + }, "targetChainId": "252", "blocksPerDay": 43200 } @@ -27,6 +30,7 @@ "0xC6625129C9df3314a4dd604845488f4bA62F9dB8", "0x10c16c7B8b1DDCFE65990ec822DE4379dd8a86dE", "0x034f978581617FcABB75bfBe697d2230a3285437", + "0xF930EBBd05eF8b25B1797b9b2109DDC9B0d43063", "0xBf911AF95bC5FE348F468b6D6928df7E7fC278e3" ], "snapshot": 20712893 diff --git a/src/strategies/sd-gauge-less-vote-boost/index.ts b/src/strategies/sd-gauge-less-vote-boost/index.ts index 12f833c32..4617167da 100644 --- a/src/strategies/sd-gauge-less-vote-boost/index.ts +++ b/src/strategies/sd-gauge-less-vote-boost/index.ts @@ -1,3 +1,4 @@ +import { getAddress } from '@ethersproject/address'; import { getProvider, multicall, subgraphRequest } from '../../utils'; import { BigNumber } from '@ethersproject/bignumber'; import { formatUnits } from '@ethersproject/units'; @@ -19,6 +20,11 @@ const abi = [ 'function adjusted_balance_of(address user) external view returns (uint256)' ]; +interface IDelegation { + source: string; + destination: string; +} + export async function strategy( space, network, @@ -37,6 +43,25 @@ export async function strategy( throw new Error('maximum of 20 whitelisted address'); } + // Addresses in tlc + addresses = addresses.map((addr) => addr.toLowerCase()); + + const delegations: IDelegation[] = []; + if (options.delegation) { + for (const addSource of Object.keys(options.delegation)) { + const addrSource = addSource.toLowerCase(); + delegations.push({ + source: addrSource, + destination: options.delegation[addSource].toLowerCase() + }); + + // Add the delegation to addresses list + if (!addresses.find((addr) => addr === addrSource)) { + addresses.push(addrSource); + } + } + } + const veSDTUserAddresses = options.veSDTUserAddresses || {}; const veSDTUserAddressesMap = {}; for (const address of Object.keys(veSDTUserAddresses)) { @@ -181,8 +206,12 @@ export async function strategy( options.whiteListedAddress ); + // Check if we have a delegation, if yes, use the delegated address instead of the current address + const delegation = delegations.find((d) => d.source === addresses[i].toLowerCase()); + const address = delegation ? delegation.destination : addresses[i]; + // Return address and voting power - return [addresses[i], Number(averageWorkingBalance)]; + return [getAddress(address), Number(averageWorkingBalance)]; }) ); } From c9280df08ec22d7cd4c3d0a0cfc11e8b15a1fa10 Mon Sep 17 00:00:00 2001 From: vk4vd Date: Fri, 13 Sep 2024 17:33:49 +0200 Subject: [PATCH 742/815] Add erable-governance-v1 strategy (#1579) --- src/strategies/erable-governance-v1/README.md | 15 +++++ .../erable-governance-v1/examples.json | 22 +++++++ src/strategies/erable-governance-v1/index.ts | 57 +++++++++++++++++++ .../erable-governance-v1/schema.json | 42 ++++++++++++++ src/strategies/index.ts | 4 +- 5 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 src/strategies/erable-governance-v1/README.md create mode 100644 src/strategies/erable-governance-v1/examples.json create mode 100644 src/strategies/erable-governance-v1/index.ts create mode 100644 src/strategies/erable-governance-v1/schema.json diff --git a/src/strategies/erable-governance-v1/README.md b/src/strategies/erable-governance-v1/README.md new file mode 100644 index 000000000..4b5f44a48 --- /dev/null +++ b/src/strategies/erable-governance-v1/README.md @@ -0,0 +1,15 @@ +# erable_governance_v1 + +This strategy calculates the voting power of $ERA token holders. The voting power is based on both tokens held in the wallet and tokens staked in the staking contract, with the following rules: + +1 token in wallet = 1 vote +1 token in staking = 2 votes + +```json +{ + "address": "0xA8bF0B92BE0338794d2e3b180b9643A1f0eB2914", + "stakingAddress": "0xA88729cD1482F4B9A2cF6A9E72E8CD0a26EC3122", + "symbol": "ERA", + "decimals": 18 +} +``` \ No newline at end of file diff --git a/src/strategies/erable-governance-v1/examples.json b/src/strategies/erable-governance-v1/examples.json new file mode 100644 index 000000000..670f102a8 --- /dev/null +++ b/src/strategies/erable-governance-v1/examples.json @@ -0,0 +1,22 @@ +[ + { + "name": "Erable Governance Example", + "strategy": { + "name": "erable-governance-v1", + "params": { + "address": "0xA8bF0B92BE0338794d2e3b180b9643A1f0eB2914", + "stakingAddress": "0xA88729cD1482F4B9A2cF6A9E72E8CD0a26EC3122", + "symbol": "ERA", + "decimals": 18 + } + }, + "network": "137", + "addresses": [ + "0x00Ce97947676F228513dF085F7d678053D482882", + "0x1a52462A47B2BfB51E3912Cd41942ec057BEE228", + "0x8c77e668b3BCbda6E0dA0c83f06D9c80675f85cB", + "0x13B4263dA02e7CE27Efe2cd8170c5DF13C137f88" + ], + "snapshot": 61703618 + } +] \ No newline at end of file diff --git a/src/strategies/erable-governance-v1/index.ts b/src/strategies/erable-governance-v1/index.ts new file mode 100644 index 000000000..f28bb8683 --- /dev/null +++ b/src/strategies/erable-governance-v1/index.ts @@ -0,0 +1,57 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import { multicall } from '../../utils'; + +export const author = 'your-github-username'; +export const version = '0.1.0'; + +// Contracts for token and staking +const ERA_TOKEN_CONTRACT = '0xA8bF0B92BE0338794d2e3b180b9643A1f0eB2914'; +const STAKING_CONTRACT = '0xA88729cD1482F4B9A2cF6A9E72E8CD0a26EC3122'; + +// ABI for balanceOf (ERC-20) and getTotalStakedForUser +const abi = [ + 'function balanceOf(address account) external view returns (uint256)', + 'function getTotalStakedForUser(address user) external view returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + // Multicall to get wallet balances + const walletBalanceCalls = addresses.map((address: any) => [ + ERA_TOKEN_CONTRACT, + 'balanceOf', + [address] + ]); + + // Multicall to get staked balances using getTotalStakedForUser function + const stakingBalanceCalls = addresses.map((address: any) => [ + STAKING_CONTRACT, + 'getTotalStakedForUser', + [address] + ]); + + const [walletBalances, stakedBalances] = await Promise.all([ + multicall(network, provider, abi, walletBalanceCalls, { blockTag }), + multicall(network, provider, abi, stakingBalanceCalls, { blockTag }) + ]); + + return Object.fromEntries( + addresses.map((address: any, index: number) => { + // Accessing the value from the response object + const walletBalance = BigNumber.from(walletBalances[index]?.[0] || '0'); + const stakedBalance = BigNumber.from(stakedBalances[index]?.[0] || '0'); + + // Voting logic: 1 token = 1 vote (wallet), 1 token = 2 votes (staked) + const totalVotes = walletBalance.add(stakedBalance.mul(2)); + return [address, parseFloat(totalVotes.toString())]; + }) + ); +} \ No newline at end of file diff --git a/src/strategies/erable-governance-v1/schema.json b/src/strategies/erable-governance-v1/schema.json new file mode 100644 index 000000000..36070b0c5 --- /dev/null +++ b/src/strategies/erable-governance-v1/schema.json @@ -0,0 +1,42 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. ERA"], + "maxLength": 16 + }, + "address": { + "type": "string", + "title": "Contract address", + "examples": ["e.g. 0xA8bF0B92BE0338794d2e3b180b9643A1f0eB2914"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "stakingAddress": { + "type": "string", + "title": "Staking contract address", + "examples": ["e.g. 0xA88729cD1482F4B9A2cF6A9E72E8CD0a26EC3122"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 18"], + "minimum": 0 + } + }, + "required": ["address", "stakingAddress", "decimals"], + "additionalProperties": false + } + } +} \ No newline at end of file diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 3ed65506e..c9580a225 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -452,6 +452,7 @@ import * as candyLockNft from './candy-lock-nft'; import * as candyNftStaking from './candy-nft-staking'; import * as pom from './pom'; import * as superboring from './superboring'; +import * as erableGovernanceV1 from './erable-governance-v1'; const strategies = { 'delegatexyz-erc721-balance-of': delegatexyzErc721BalanceOf, @@ -914,7 +915,8 @@ const strategies = { 'candy-lock-nft': candyLockNft, 'candy-nft-staking': candyNftStaking, pom, - superboring + superboring, + 'erable-governance-v1': erableGovernanceV1 }; Object.keys(strategies).forEach(function (strategyName) { From 3746739107a5a8300d9a29de8da37ce9d13c2d57 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 15 Sep 2024 15:54:29 +0530 Subject: [PATCH 743/815] Automated lint (#1580) Co-authored-by: ChaituVR --- .../erable-governance-v1/examples.json | 2 +- src/strategies/erable-governance-v1/index.ts | 2 +- .../erable-governance-v1/schema.json | 2 +- src/strategies/hats-strategy/index.ts | 19 +++++--- .../sd-gauge-less-vote-boost/index.ts | 7 ++- src/strategies/superboring/index.ts | 43 +++++++++++++------ 6 files changed, 52 insertions(+), 23 deletions(-) diff --git a/src/strategies/erable-governance-v1/examples.json b/src/strategies/erable-governance-v1/examples.json index 670f102a8..b105f4e8e 100644 --- a/src/strategies/erable-governance-v1/examples.json +++ b/src/strategies/erable-governance-v1/examples.json @@ -19,4 +19,4 @@ ], "snapshot": 61703618 } -] \ No newline at end of file +] diff --git a/src/strategies/erable-governance-v1/index.ts b/src/strategies/erable-governance-v1/index.ts index f28bb8683..71f0b6e6f 100644 --- a/src/strategies/erable-governance-v1/index.ts +++ b/src/strategies/erable-governance-v1/index.ts @@ -54,4 +54,4 @@ export async function strategy( return [address, parseFloat(totalVotes.toString())]; }) ); -} \ No newline at end of file +} diff --git a/src/strategies/erable-governance-v1/schema.json b/src/strategies/erable-governance-v1/schema.json index 36070b0c5..d68c626a5 100644 --- a/src/strategies/erable-governance-v1/schema.json +++ b/src/strategies/erable-governance-v1/schema.json @@ -39,4 +39,4 @@ "additionalProperties": false } } -} \ No newline at end of file +} diff --git a/src/strategies/hats-strategy/index.ts b/src/strategies/hats-strategy/index.ts index 2235a99e2..9825480a9 100644 --- a/src/strategies/hats-strategy/index.ts +++ b/src/strategies/hats-strategy/index.ts @@ -48,7 +48,7 @@ export async function strategy( } // If ERC4626 vault is provided, calculate the balances and apply multiplier - let vaultBalances: Record = {}; + const vaultBalances: Record = {}; if (options.vaultAddress) { const rawVaultBalances = await erc4626BalanceOfStrategy( space, @@ -61,20 +61,29 @@ export async function strategy( // Apply multiplier to vault balances for (const [address, balance] of Object.entries(rawVaultBalances)) { - vaultBalances[address] = BigNumber.from(parseUnits(balance.toString(), options.decimals)).mul(options.vaultMultiplier || 3); + vaultBalances[address] = BigNumber.from( + parseUnits(balance.toString(), options.decimals) + ).mul(options.vaultMultiplier || 3); } } // Add vault balances to adjusted balances for (const address of addresses) { const vaultBalance = vaultBalances[address] || BigNumber.from(0); - adjustedBalances[address] = (adjustedBalances[address] || BigNumber.from(0)).add(vaultBalance); + adjustedBalances[address] = ( + adjustedBalances[address] || BigNumber.from(0) + ).add(vaultBalance); } const finalBalances: Record = {}; - + Object.keys(adjustedBalances).forEach((address) => { - finalBalances[address] = parseFloat(formatUnits(adjustedBalances[address] || BigNumber.from(0), options.decimals)); + finalBalances[address] = parseFloat( + formatUnits( + adjustedBalances[address] || BigNumber.from(0), + options.decimals + ) + ); }); return finalBalances; diff --git a/src/strategies/sd-gauge-less-vote-boost/index.ts b/src/strategies/sd-gauge-less-vote-boost/index.ts index 4617167da..15b624c7c 100644 --- a/src/strategies/sd-gauge-less-vote-boost/index.ts +++ b/src/strategies/sd-gauge-less-vote-boost/index.ts @@ -65,7 +65,8 @@ export async function strategy( const veSDTUserAddresses = options.veSDTUserAddresses || {}; const veSDTUserAddressesMap = {}; for (const address of Object.keys(veSDTUserAddresses)) { - veSDTUserAddressesMap[address.toLowerCase()] = veSDTUserAddresses[address].toLowerCase(); + veSDTUserAddressesMap[address.toLowerCase()] = + veSDTUserAddresses[address].toLowerCase(); } const mainnetCalls: any[] = [[VE_SDT, 'totalSupply']]; @@ -207,7 +208,9 @@ export async function strategy( ); // Check if we have a delegation, if yes, use the delegated address instead of the current address - const delegation = delegations.find((d) => d.source === addresses[i].toLowerCase()); + const delegation = delegations.find( + (d) => d.source === addresses[i].toLowerCase() + ); const address = delegation ? delegation.destination : addresses[i]; // Return address and voting power diff --git a/src/strategies/superboring/index.ts b/src/strategies/superboring/index.ts index 08d96f7d2..374a34d05 100644 --- a/src/strategies/superboring/index.ts +++ b/src/strategies/superboring/index.ts @@ -19,7 +19,7 @@ const tokenAbi = [ 'function balanceOf(address account) external view returns (uint256)' ]; -const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"; +const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; // Super Tokens always have 18 decimals const DECIMALS = 18; @@ -35,15 +35,23 @@ export async function strategy( const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; // Construct first batch call to SuperBoring contract - const sbMultiCall = new Multicaller(network, provider, superBoringAbi, { blockTag }); + const sbMultiCall = new Multicaller(network, provider, superBoringAbi, { + blockTag + }); // Get the sleep pod for each address (will return zero if not exists) addresses.forEach((address) => - sbMultiCall.call(address, options.superBoringAddress, 'getSleepPod', [ address ]) + sbMultiCall.call(address, options.superBoringAddress, 'getSleepPod', [ + address + ]) ); // Get all torexes - sbMultiCall.call('torexes', options.superBoringAddress, 'getAllTorexesMetadata') + sbMultiCall.call( + 'torexes', + options.superBoringAddress, + 'getAllTorexesMetadata' + ); // execute. // This will return an object with 2 kinds of elements: @@ -58,7 +66,7 @@ export async function strategy( // extract the addresses of regitered torexes const torexAddrs = Array.isArray(sbResult['torexes']) - ? sbResult['torexes'].map(tuple => tuple[0]) + ? sbResult['torexes'].map((tuple) => tuple[0]) : []; // Now we have all torex adresses and can get the staked amounts for each user @@ -66,10 +74,17 @@ export async function strategy( // Construct second batch call to SuperBoring contract // Since the SuperBoring contract does (corrently) not allow to query the overall staked amount of a user, // we need to query for each combination of user and torex - const sbMulti2 = new Multicaller(network, provider, superBoringAbi, { blockTag }); + const sbMulti2 = new Multicaller(network, provider, superBoringAbi, { + blockTag + }); addresses.forEach((address) => torexAddrs.forEach((torexAddr) => - sbMulti2.call(`${address}-${torexAddr}`, options.superBoringAddress, 'getStakedAmountOf', [ torexAddr, address ]) + sbMulti2.call( + `${address}-${torexAddr}`, + options.superBoringAddress, + 'getStakedAmountOf', + [torexAddr, address] + ) ) ); @@ -79,14 +94,16 @@ export async function strategy( // Transform to a map from user address to total staked amount const stakesMap = Object.keys(sbResult2).reduce((acc, key) => { - const [address, ] = key.split('-'); + const [address] = key.split('-'); acc[address] = (acc[address] || BigNumber.from(0)).add(sbResult2[key]); return acc; }, {}); // In the next multicall, we get the unstaked balances of users and pods, querying the token contract - const tokenMultiCall = new Multicaller(network, provider, tokenAbi, { blockTag }); + const tokenMultiCall = new Multicaller(network, provider, tokenAbi, { + blockTag + }); // Get the balance of each address addresses.forEach((address) => @@ -95,20 +112,20 @@ export async function strategy( // Get the balance of each pod (we filter out the zero addresses which represent non-existing pods) Object.values(podsMap) - .filter(podAddr => podAddr !== ZERO_ADDRESS) + .filter((podAddr) => podAddr !== ZERO_ADDRESS) .forEach((podAddr) => tokenMultiCall.call(podAddr, options.tokenAddress, 'balanceOf', [podAddr]) ); // execute. // The returned object will have one element for each user and each pod, with their address as key and the balance as value - const balancesResult: Record = await tokenMultiCall.execute(); + const balancesResult: Record = + await tokenMultiCall.execute(); // Now add up the 3 balance components per user: directly owned + held by pod + staked const balanceMap: Record = {}; addresses.forEach((address) => { - balanceMap[address] = - BigNumber.from(balancesResult[address]) // directly owned + balanceMap[address] = BigNumber.from(balancesResult[address]) // directly owned .add(BigNumber.from(balancesResult[podsMap[address]] || 0)) // held by pod .add(BigNumber.from(stakesMap[address])); // staked }); From 53452dfc508d1c315d8490ab1530c3da955de5ef Mon Sep 17 00:00:00 2001 From: Marsot Pierre Date: Mon, 16 Sep 2024 17:15:06 +0200 Subject: [PATCH 744/815] sdFXS delegation [sd-gauge-less-vote-boost] (#1581) * sdvote-balanceof-twavp-pool * sd-gauge-less-vote-boost - add veSDT boost for MS * add delegation * fix merge * fix merge * change address * change address * delegation --- .../sd-gauge-less-vote-boost/examples.json | 4 +-- .../sd-gauge-less-vote-boost/index.ts | 35 +++++++++++++------ 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/strategies/sd-gauge-less-vote-boost/examples.json b/src/strategies/sd-gauge-less-vote-boost/examples.json index b4476c624..70dc6ff0b 100644 --- a/src/strategies/sd-gauge-less-vote-boost/examples.json +++ b/src/strategies/sd-gauge-less-vote-boost/examples.json @@ -13,7 +13,7 @@ "whiteListedAddress": ["0x1c0D72a330F2768dAF718DEf8A19BAb019EEAd09"], "veSDTUserAddresses": {}, "delegation": { - "0xBf911AF95bC5FE348F468b6D6928df7E7fC278e3": "0xF930EBBd05eF8b25B1797b9b2109DDC9B0d43063" + "0xBf911AF95bC5FE348F468b6D6928df7E7fC278e3": "0x20aCB38B9268F694657EbefcD2aC9bCb8A103D2e" }, "targetChainId": "252", "blocksPerDay": 43200 @@ -31,7 +31,7 @@ "0x10c16c7B8b1DDCFE65990ec822DE4379dd8a86dE", "0x034f978581617FcABB75bfBe697d2230a3285437", "0xF930EBBd05eF8b25B1797b9b2109DDC9B0d43063", - "0xBf911AF95bC5FE348F468b6D6928df7E7fC278e3" + "0x20aCB38B9268F694657EbefcD2aC9bCb8A103D2e" ], "snapshot": 20712893 } diff --git a/src/strategies/sd-gauge-less-vote-boost/index.ts b/src/strategies/sd-gauge-less-vote-boost/index.ts index 15b624c7c..c9b7f1e58 100644 --- a/src/strategies/sd-gauge-less-vote-boost/index.ts +++ b/src/strategies/sd-gauge-less-vote-boost/index.ts @@ -65,8 +65,7 @@ export async function strategy( const veSDTUserAddresses = options.veSDTUserAddresses || {}; const veSDTUserAddressesMap = {}; for (const address of Object.keys(veSDTUserAddresses)) { - veSDTUserAddressesMap[address.toLowerCase()] = - veSDTUserAddresses[address].toLowerCase(); + veSDTUserAddressesMap[address.toLowerCase()] = veSDTUserAddresses[address].toLowerCase(); } const mainnetCalls: any[] = [[VE_SDT, 'totalSupply']]; @@ -170,7 +169,7 @@ export async function strategy( responsesDestinationChain.push(callResp); } - return Object.fromEntries( + const vp = Object.fromEntries( Array(addresses.length) .fill('x') .map((_, i) => { @@ -207,16 +206,32 @@ export async function strategy( options.whiteListedAddress ); - // Check if we have a delegation, if yes, use the delegated address instead of the current address - const delegation = delegations.find( - (d) => d.source === addresses[i].toLowerCase() - ); - const address = delegation ? delegation.destination : addresses[i]; - // Return address and voting power - return [getAddress(address), Number(averageWorkingBalance)]; + return [addresses[i], Number(averageWorkingBalance)]; }) ); + + // Manage delegation + for(const addr of Object.keys(vp)) { + for(const delegation of delegations) { + if(addr.toLowerCase() === delegation.destination.toLowerCase()) { + let vpToAdd = 0; + for(const addrTmp of Object.keys(vp)) { + if(addrTmp.toLowerCase() === delegation.source.toLowerCase()) { + vpToAdd = vp[addrTmp] || 0; + break; + } + } + vp[addr] += vpToAdd; + break; + } + } + } + + return Object.keys(vp).reduce((acc, addr) => { + acc[getAddress(addr)] = vp[addr]; + return acc; + } , {}); } function getPreviousBlocks( From d80d8cd5a852f595b5f28c2ea696261ad8ec6db7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 18 Sep 2024 21:29:17 +0530 Subject: [PATCH 745/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.13 (#1574) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 4db226577..fc56f3743 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.11", + "@snapshot-labs/snapshot.js": "^0.12.13", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index c4c11452d..7263cc83e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.11": - version "0.12.11" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.11.tgz#62b3ddd7f3fb87d24a0ceda249015f55302b6799" - integrity sha512-HCToXWBoYOFZs8HzsAIapmgQqF7XUJ3jMxg8eiJayAAotkVO1ckZdcUcpTXCt6sG/aKhrZSIqGLQzNqn90Advw== +"@snapshot-labs/snapshot.js@^0.12.13": + version "0.12.13" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.13.tgz#40b6cbf20ec4f1222bb231d1b3e26e5f702bf912" + integrity sha512-e9pXdQA45tO5+af42PkOYI01WAPPR7IrQDejjUdhz3y98e7m/Na9Foqlbj6nIksnTJ4GubcmOZV7iQzcrNw/kw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 790b7ef0e69df048eca79596a2e811c2681b8a66 Mon Sep 17 00:00:00 2001 From: Javier G Date: Thu, 19 Sep 2024 14:27:39 +0200 Subject: [PATCH 746/815] Add polygon-self-staked-pol (#1584) --- src/strategies/index.ts | 2 + .../polygon-self-staked-pol/README.md | 16 +++ .../polygon-self-staked-pol/examples.json | 20 ++++ .../polygon-self-staked-pol/index.ts | 104 ++++++++++++++++++ .../polygon-self-staked-pol/schema.json | 31 ++++++ 5 files changed, 173 insertions(+) create mode 100644 src/strategies/polygon-self-staked-pol/README.md create mode 100644 src/strategies/polygon-self-staked-pol/examples.json create mode 100644 src/strategies/polygon-self-staked-pol/index.ts create mode 100644 src/strategies/polygon-self-staked-pol/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index c9580a225..c28fc3116 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -1,6 +1,7 @@ import { readFileSync } from 'fs'; import path from 'path'; +import * as polygonSelfStaked from './polygon-self-staked-pol'; import * as delegatexyzErc721BalanceOf from './delegatexyz-erc721-balance-of'; import * as urbitGalaxies from './urbit-galaxies/index'; import * as ecoVotingPower from './eco-voting-power'; @@ -830,6 +831,7 @@ const strategies = { spaceid, 'delegate-registry-v2': delegateRegistryV2, 'split-delegation': splitDelegation, + 'polygon-self-staked-pol': polygonSelfStaked, 'hats-protocol-single-vote-per-org': hatsProtocolSingleVotePerOrg, 'karma-discord-roles': karmaDiscordRoles, 'seedify-cumulative-voting-power-hodl-staking-farming': diff --git a/src/strategies/polygon-self-staked-pol/README.md b/src/strategies/polygon-self-staked-pol/README.md new file mode 100644 index 000000000..cb24b082a --- /dev/null +++ b/src/strategies/polygon-self-staked-pol/README.md @@ -0,0 +1,16 @@ +# Polygon Self Staked POL + +This strategy calculates the voting power based on the active stake of delegators for the Polygon network. + +## Parameters + +- `stakeManagerAddress`: The address of the StakeManager contract +- `decimals`: The number of decimals used for token amounts (18 for POL) + +## Example + +```json +{ + "stakeManagerAddress": "0x5e3Ef299fDDf15eAa0432E6e66473ace8c13D908", + "decimals": 18 +} \ No newline at end of file diff --git a/src/strategies/polygon-self-staked-pol/examples.json b/src/strategies/polygon-self-staked-pol/examples.json new file mode 100644 index 000000000..e199753f3 --- /dev/null +++ b/src/strategies/polygon-self-staked-pol/examples.json @@ -0,0 +1,20 @@ +[ + { + "name": "Polygon Self Staked POL", + "strategy": { + "name": "polygon-self-staked-pol", + "params": { + "stakeManagerAddress": "0x5e3Ef299fDDf15eAa0432E6e66473ace8c13D908", + "decimals": 18 + } + }, + "network": "1", + "addresses": [ + "0x1234567890123456789012345678901234567890", + "0x0987654321098765432109876543210987654321", + "0xf086597e0e155f9e46fbda46d5549697a103ffb4", + "0xd6f8d59f3037c7c021a4e1f88f2413862cde082c" + ], + "snapshot": 20733426 + } +] \ No newline at end of file diff --git a/src/strategies/polygon-self-staked-pol/index.ts b/src/strategies/polygon-self-staked-pol/index.ts new file mode 100644 index 000000000..1574d2a8d --- /dev/null +++ b/src/strategies/polygon-self-staked-pol/index.ts @@ -0,0 +1,104 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; +import { getAddress } from '@ethersproject/address'; + +export const author = 'maticnetwork'; +export const version = '0.1.0'; + +const stakeManagerABI = [ + 'function getValidatorContract(uint256) view returns (address)', + 'function validators(uint256) view returns (uint256 amount, uint256 reward, uint256 activationEpoch, uint256 deactivationEpoch, uint256 jailTime, address signer, address contractAddress, uint8 status, uint256 commissionRate, uint256 lastCommissionUpdate, uint256 delegatorsReward, uint256 delegatedAmount, uint256 initialRewardPerStake)', + 'function currentEpoch() view returns (uint256)', + 'function NFTCounter() view returns (uint256)' +]; + +const validatorShareABI = [ + 'function getTotalStake(address) view returns (uint256, uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multi = new Multicaller(network, provider, stakeManagerABI, { + blockTag + }); + + multi.call('currentEpoch', options.stakeManagerAddress, 'currentEpoch'); + multi.call('nftCounter', options.stakeManagerAddress, 'NFTCounter'); + + const initialResult = await multi.execute(); + const currentEpoch = initialResult.currentEpoch.toNumber(); + const validatorCount = initialResult.nftCounter.toNumber(); + + for (let i = 0; i < validatorCount; i++) { + multi.call( + `validator${i}`, + options.stakeManagerAddress, + 'getValidatorContract', + [i] + ); + multi.call(`validatorInfo${i}`, options.stakeManagerAddress, 'validators', [ + i + ]); + } + + const result = await multi.execute(); + + const votingPower: Record = {}; + for (const address of addresses) { + votingPower[address] = BigNumber.from(0); + } + + const stakesMulti = new Multicaller(network, provider, validatorShareABI, { + blockTag + }); + + for (let i = 1; i < validatorCount; i++) { + const validatorContract = result[`validator${i}`]; + const validatorInfo = result[`validatorInfo${i}`]; + + const isNotDeactivated = + validatorInfo.deactivationEpoch.eq(0) || + validatorInfo.deactivationEpoch.gt(currentEpoch); + + if ( + isNotDeactivated && + validatorContract !== '0x0000000000000000000000000000000000000000' + ) { + for (const address of addresses) { + stakesMulti.call( + `${address}_${i}`, + validatorContract, + 'getTotalStake', + [address] + ); + } + } + } + + const stakes = await stakesMulti.execute(); + + for (const address of addresses) { + for (let i = 0; i < validatorCount; i++) { + const key = `${address}_${i}`; + if (stakes[key]) { + votingPower[address] = votingPower[address].add(stakes[key][0]); + } + } + } + + return Object.fromEntries( + Object.entries(votingPower).map(([address, power]) => [ + getAddress(address), + parseFloat(formatUnits(power, options.decimals)) + ]) + ); +} diff --git a/src/strategies/polygon-self-staked-pol/schema.json b/src/strategies/polygon-self-staked-pol/schema.json new file mode 100644 index 000000000..382829d48 --- /dev/null +++ b/src/strategies/polygon-self-staked-pol/schema.json @@ -0,0 +1,31 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "stakeManagerAddress": { + "type": "string", + "title": "Stake Manager Contract Address", + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": [ + 18 + ] + } + }, + "required": [ + "stakeManagerAddress", + "decimals" + ], + "additionalProperties": false + } + } +} \ No newline at end of file From 3b160af4eb28782b6164e58cceac9df5d0bb0a75 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 23 Sep 2024 08:53:15 +0530 Subject: [PATCH 747/815] Automated lint (#1585) Co-authored-by: ChaituVR --- .../polygon-self-staked-pol/examples.json | 2 +- .../polygon-self-staked-pol/schema.json | 11 +++-------- src/strategies/sd-gauge-less-vote-boost/index.ts | 15 ++++++++------- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/strategies/polygon-self-staked-pol/examples.json b/src/strategies/polygon-self-staked-pol/examples.json index e199753f3..46da6e59b 100644 --- a/src/strategies/polygon-self-staked-pol/examples.json +++ b/src/strategies/polygon-self-staked-pol/examples.json @@ -17,4 +17,4 @@ ], "snapshot": 20733426 } -] \ No newline at end of file +] diff --git a/src/strategies/polygon-self-staked-pol/schema.json b/src/strategies/polygon-self-staked-pol/schema.json index 382829d48..79263844d 100644 --- a/src/strategies/polygon-self-staked-pol/schema.json +++ b/src/strategies/polygon-self-staked-pol/schema.json @@ -16,16 +16,11 @@ "decimals": { "type": "number", "title": "Decimals", - "examples": [ - 18 - ] + "examples": [18] } }, - "required": [ - "stakeManagerAddress", - "decimals" - ], + "required": ["stakeManagerAddress", "decimals"], "additionalProperties": false } } -} \ No newline at end of file +} diff --git a/src/strategies/sd-gauge-less-vote-boost/index.ts b/src/strategies/sd-gauge-less-vote-boost/index.ts index c9b7f1e58..04b6a01f1 100644 --- a/src/strategies/sd-gauge-less-vote-boost/index.ts +++ b/src/strategies/sd-gauge-less-vote-boost/index.ts @@ -65,7 +65,8 @@ export async function strategy( const veSDTUserAddresses = options.veSDTUserAddresses || {}; const veSDTUserAddressesMap = {}; for (const address of Object.keys(veSDTUserAddresses)) { - veSDTUserAddressesMap[address.toLowerCase()] = veSDTUserAddresses[address].toLowerCase(); + veSDTUserAddressesMap[address.toLowerCase()] = + veSDTUserAddresses[address].toLowerCase(); } const mainnetCalls: any[] = [[VE_SDT, 'totalSupply']]; @@ -212,12 +213,12 @@ export async function strategy( ); // Manage delegation - for(const addr of Object.keys(vp)) { - for(const delegation of delegations) { - if(addr.toLowerCase() === delegation.destination.toLowerCase()) { + for (const addr of Object.keys(vp)) { + for (const delegation of delegations) { + if (addr.toLowerCase() === delegation.destination.toLowerCase()) { let vpToAdd = 0; - for(const addrTmp of Object.keys(vp)) { - if(addrTmp.toLowerCase() === delegation.source.toLowerCase()) { + for (const addrTmp of Object.keys(vp)) { + if (addrTmp.toLowerCase() === delegation.source.toLowerCase()) { vpToAdd = vp[addrTmp] || 0; break; } @@ -231,7 +232,7 @@ export async function strategy( return Object.keys(vp).reduce((acc, addr) => { acc[getAddress(addr)] = vp[addr]; return acc; - } , {}); + }, {}); } function getPreviousBlocks( From b7a576aef87ff788b83a7f8c80eb7188af26b377 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Tue, 24 Sep 2024 15:14:33 +0530 Subject: [PATCH 748/815] [erc1155-all-balances-of] Update subgraph URL and disable matic network (#1586) * [erc1155-all-balances-of] Update subgraph URL and disable matic network * limit --- .../erc1155-all-balances-of/README.md | 5 ++-- .../erc1155-all-balances-of/examples.json | 23 ++++--------------- .../erc1155-all-balances-of/index.ts | 4 ++-- 3 files changed, 10 insertions(+), 22 deletions(-) diff --git a/src/strategies/erc1155-all-balances-of/README.md b/src/strategies/erc1155-all-balances-of/README.md index 116339fcc..a0af742dd 100644 --- a/src/strategies/erc1155-all-balances-of/README.md +++ b/src/strategies/erc1155-all-balances-of/README.md @@ -2,5 +2,6 @@ This strategy return the balances of the voters for all tokens in a ERC1155 contract. -### Limit: -On polygon, works only with contracts with total tokenIds less than 6000 \ No newline at end of file +## Limits + +- This strategy is only compatible with ERC1155 contracts on mainnet. diff --git a/src/strategies/erc1155-all-balances-of/examples.json b/src/strategies/erc1155-all-balances-of/examples.json index ed11b31c1..7d102b1cc 100644 --- a/src/strategies/erc1155-all-balances-of/examples.json +++ b/src/strategies/erc1155-all-balances-of/examples.json @@ -9,25 +9,12 @@ } }, "network": "1", - "addresses": ["0x06658Fd70023f527BFAc1A6d9141C56d99c65129"], - "snapshot": 14597922 - }, - { - "name": "Example query", - "strategy": { - "name": "erc1155-all-balances-of", - "params": { - "address": "0x2939b94BDc377e66A377cfc15028DF3Bd6aC6C28", - "symbol": "CORGI" - } - }, - "network": "137", "addresses": [ - "0xb165014c736c50da0638283eac2e19c88eab74f3", - "0x28adbf7bd37c08965746669471a1dcef6dc91009", - "0xe6fecee69a9e3726324498830bb0e898a866eccc", - "0x715c624ff8a8ebae3a2030c0b0868a5b447c956f" + "0x06658Fd70023f527BFAc1A6d9141C56d99c65129", + "0xa745067637CFea3fef6861135fAd57Ad38dF3Bfe", + "0xe616A809F70f0B947331759303286C28Cc304693", + "0xb104371D5a2680fB0d47eA9A3aA2348392454186" ], - "snapshot": 27088229 + "snapshot": 14597922 } ] diff --git a/src/strategies/erc1155-all-balances-of/index.ts b/src/strategies/erc1155-all-balances-of/index.ts index 8bf056aea..1d2708bc6 100644 --- a/src/strategies/erc1155-all-balances-of/index.ts +++ b/src/strategies/erc1155-all-balances-of/index.ts @@ -5,11 +5,11 @@ export const author = 'snapshot-labs'; export const version = '0.2.0'; const SUBGRAPH_URL = { - '1': 'https://gateway.thegraph.com/api/94c3f5dd3947e2f62fc6e0e757549ee7/subgraphs/id/GCQVLurkeZrdMf4t5v5NyeWJY8pHhfE9sinjFMjLYd9C' + '1': 'https://subgrapher.snapshot.org/subgraph/arbitrum/8cDX3UAptW4mvQDpTDyVDvW7cbYC6bgT3yeYrid7FFPA' }; const HOSTED_SUBGRAPH_URL = { - '137': 'https://api.thegraph.com/subgraphs/name/tranchien2002/eip1155-matic' + // '137': 'https://api.thegraph.com/subgraphs/name/tranchien2002/eip1155-matic' // subgraph doesn't exist anymore }; export async function strategy( From 7f1ace3f2483ba1e1ba8dcf06d0d38d8e04269bc Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Wed, 25 Sep 2024 17:03:23 +0530 Subject: [PATCH 749/815] [ens-domains-owned] fix latest block (#1589) --- .../ens-domains-owned/examples.json | 3 +- src/strategies/ens-domains-owned/index.ts | 49 +++++++++++-------- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/src/strategies/ens-domains-owned/examples.json b/src/strategies/ens-domains-owned/examples.json index c2f2842f0..b1f73b304 100644 --- a/src/strategies/ens-domains-owned/examples.json +++ b/src/strategies/ens-domains-owned/examples.json @@ -11,7 +11,8 @@ "network": "1", "addresses": [ "0xaCf4C2950107eF9b1C37faA1F9a866C8F0da88b9", - "0x0239769A1aDF4DeF9f07Da824B80B9C4fCB59593" + "0x0239769A1aDF4DeF9f07Da824B80B9C4fCB59593", + "0x8d2f3a76a76f055D62A931678ab16b042E7BADeb" ], "snapshot": 11414195 } diff --git a/src/strategies/ens-domains-owned/index.ts b/src/strategies/ens-domains-owned/index.ts index b1086827f..a776946e7 100644 --- a/src/strategies/ens-domains-owned/index.ts +++ b/src/strategies/ens-domains-owned/index.ts @@ -27,31 +27,38 @@ export async function strategy( const params = Object.fromEntries( pages .map((page, i) => `_${i}`) - .map((q, i) => [ - q, - { - __aliasFor: 'domains', - __args: { - block: snapshot !== 'latest' ? { number: snapshot } : undefined, - where: { - name: options.domain - }, - first: 1000 + .map((q, i) => { + const args: any = { + where: { + name: options.domain }, - id: true, - labelName: true, - subdomains: { - __args: { - where: { - owner_in: pages[i].map((address) => address.toLowerCase()) + first: 1000 + }; + + if (snapshot !== 'latest') { + args.block = { number: snapshot }; + } + + return [ + q, + { + __aliasFor: 'domains', + __args: args, + id: true, + labelName: true, + subdomains: { + __args: { + where: { + owner_in: pages[i].map((address) => address.toLowerCase()) + } + }, + owner: { + id: true } - }, - owner: { - id: true } } - } - ]) + ]; + }) ); let result = await subgraphRequest(ENS_SUBGRAPH_URL[network], params); From 0de108347838fcb5a7aa8b6abbc4e7079f507d74 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 25 Sep 2024 17:03:55 +0530 Subject: [PATCH 750/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.14 (#1588) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index fc56f3743..6df5a3f4f 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.13", + "@snapshot-labs/snapshot.js": "^0.12.14", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 7263cc83e..a27226f13 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.13": - version "0.12.13" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.13.tgz#40b6cbf20ec4f1222bb231d1b3e26e5f702bf912" - integrity sha512-e9pXdQA45tO5+af42PkOYI01WAPPR7IrQDejjUdhz3y98e7m/Na9Foqlbj6nIksnTJ4GubcmOZV7iQzcrNw/kw== +"@snapshot-labs/snapshot.js@^0.12.14": + version "0.12.14" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.14.tgz#e85091b88f743e80d97d693b04f28b60def251d0" + integrity sha512-aH39M4RaNypmdpr8xb2SSH6njaYx7EerLqQXHve3ZqcGg4hxKKqn4mmrY7GQFFFnBV6D4MxGvgJFCu8VxCmDCA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From f251d898955fd0893c190d12b8a8108034072104 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 25 Sep 2024 22:27:00 +0530 Subject: [PATCH 751/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.15 (#1590) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 6df5a3f4f..f7d5aceca 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.14", + "@snapshot-labs/snapshot.js": "^0.12.15", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index a27226f13..1a5a72f86 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.14": - version "0.12.14" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.14.tgz#e85091b88f743e80d97d693b04f28b60def251d0" - integrity sha512-aH39M4RaNypmdpr8xb2SSH6njaYx7EerLqQXHve3ZqcGg4hxKKqn4mmrY7GQFFFnBV6D4MxGvgJFCu8VxCmDCA== +"@snapshot-labs/snapshot.js@^0.12.15": + version "0.12.15" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.15.tgz#c11a26b582b43e5396f1b45dca86be218e31a3d4" + integrity sha512-sbM7u2n5CtoFo6z7HIFPwYxdQNnkstIWqDxEAvsdVj/ItkC2H1m4m+aH4A44YgKIAysfknNERqpx3BUAyqp6sQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 093d1bf3d780adcc421ae7f189ca4dbca46fe557 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2024 08:46:02 +0530 Subject: [PATCH 752/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.16 (#1591) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f7d5aceca..ba9056649 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.15", + "@snapshot-labs/snapshot.js": "^0.12.16", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 1a5a72f86..0eeded8ba 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.15": - version "0.12.15" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.15.tgz#c11a26b582b43e5396f1b45dca86be218e31a3d4" - integrity sha512-sbM7u2n5CtoFo6z7HIFPwYxdQNnkstIWqDxEAvsdVj/ItkC2H1m4m+aH4A44YgKIAysfknNERqpx3BUAyqp6sQ== +"@snapshot-labs/snapshot.js@^0.12.16": + version "0.12.16" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.16.tgz#643def33ee564f1c9c0379b35165f73eddb148c8" + integrity sha512-TI5cCsQk0eyj/jxzyjrPc6yOT7mnb+Q1GYUYL3g/P1kECyhrVttV7zlilXBwjIB0IscgdfIQUMgA67J1Pcb2zg== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From ae11f201b23113a6045bfbd67f6604100e359094 Mon Sep 17 00:00:00 2001 From: Javier G Date: Thu, 26 Sep 2024 06:52:22 +0200 Subject: [PATCH 753/815] [subgraph-split-delegation] New strategy: Subgraph split delegation (#1583) * Add subgraph-split-delegation * Update example * Paginate subgraph and limit by address_in * Paginate delegations queries --- src/strategies/index.ts | 2 + .../subgraph-split-delegation/README.md | 33 +++ .../subgraph-split-delegation/examples.json | 35 +++ .../subgraph-split-delegation/index.ts | 210 ++++++++++++++++++ .../subgraph-split-delegation/schema.json | 44 ++++ 5 files changed, 324 insertions(+) create mode 100644 src/strategies/subgraph-split-delegation/README.md create mode 100644 src/strategies/subgraph-split-delegation/examples.json create mode 100644 src/strategies/subgraph-split-delegation/index.ts create mode 100644 src/strategies/subgraph-split-delegation/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index c28fc3116..b94781317 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -1,6 +1,7 @@ import { readFileSync } from 'fs'; import path from 'path'; +import * as subgraphSplitDelegation from './subgraph-split-delegation'; import * as polygonSelfStaked from './polygon-self-staked-pol'; import * as delegatexyzErc721BalanceOf from './delegatexyz-erc721-balance-of'; import * as urbitGalaxies from './urbit-galaxies/index'; @@ -831,6 +832,7 @@ const strategies = { spaceid, 'delegate-registry-v2': delegateRegistryV2, 'split-delegation': splitDelegation, + 'subgraph-split-delegation': subgraphSplitDelegation, 'polygon-self-staked-pol': polygonSelfStaked, 'hats-protocol-single-vote-per-org': hatsProtocolSingleVotePerOrg, 'karma-discord-roles': karmaDiscordRoles, diff --git a/src/strategies/subgraph-split-delegation/README.md b/src/strategies/subgraph-split-delegation/README.md new file mode 100644 index 000000000..da884137a --- /dev/null +++ b/src/strategies/subgraph-split-delegation/README.md @@ -0,0 +1,33 @@ +# subgraph-split-delegation + +If you want to delegate your voting power to different addresses, you can use this strategy to calculate the voting power that will be delegated based on the Subgraph data. + +```TEXT +Total VP = incoming delegated VP + own VP - outgoing delegated VP +``` + +The sub strategies defined in params are used to get the votint power that will be delegated based on the Subgraph data. + +| Param Name | Description | +| ----------- | ----------- | +| strategies | list of sub strategies to calculate voting power based on delegation | +| subgraphUrl | The URL of the subgraph to query for the delegation data | + +Here is an example of parameters: + +```json +{ + "subgraphUrl": "https://api.studio.thegraph.com/query/87073/split-delegation/v0.0.5", + "strategies": [ + { + "name": "erc20-balance-of", + "params": { + "address": "0xD01Db8Fb3CE7AeeBfB24317E12a0A854c256E99b", + "symbol": "EPT", + "decimals": 18 + } + } + ] +} + +``` diff --git a/src/strategies/subgraph-split-delegation/examples.json b/src/strategies/subgraph-split-delegation/examples.json new file mode 100644 index 000000000..3592ccd33 --- /dev/null +++ b/src/strategies/subgraph-split-delegation/examples.json @@ -0,0 +1,35 @@ +[ + { + "name": "Subgraph split delegation", + "strategy": { + "name": "subgraph-split-delegation", + "params": { + "subgraphUrl": "https://api.studio.thegraph.com/query/87073/split-delegation/v0.0.5", + "strategies": [ + { + "name": "erc20-balance-of", + "params": { + "address": "0xD01Db8Fb3CE7AeeBfB24317E12a0A854c256E99b", + "symbol": "EPT", + "decimals": 18 + } + } + ] + } + }, + "network": "11155111", + "addresses": [ + "0xb347106e4a026dd86c4bbe8df7274ba9ee7442cc", + "0x048fee7c3279a24af0790b6b002ded42be021d2b", + "0x139a9032a46c3afe3456eb5f0a35183b5f189cae", + "0xc1d60f584879f024299da0f19cdb47b931e35b53", + "0x376c649111543c46ce15fd3a9386b4f202a6e06c", + "0x0dcbc5d2bda11c4247d088f1ac5209e30f47b595", + "0x35911cc89aabe7af6726046823d5b678b6a1498d", + "0x6cdebe940bc0f26850285caca097c11c33103e47", + "0xa76c5788be9a2e1416de639c50c60b184d0ceccd", + "0xffb026f67da0869eb3abb090cb7f015ce0925cdf" + ], + "snapshot": 6716841 + } +] \ No newline at end of file diff --git a/src/strategies/subgraph-split-delegation/index.ts b/src/strategies/subgraph-split-delegation/index.ts new file mode 100644 index 000000000..2895e16cf --- /dev/null +++ b/src/strategies/subgraph-split-delegation/index.ts @@ -0,0 +1,210 @@ +import { getAddress } from '@ethersproject/address'; +import { subgraphRequest, getScoresDirect } from '../../utils'; +import { Strategy } from '@snapshot-labs/snapshot.js/dist/src/voting/types'; + +export const author = 'aragon'; +export const version = '0.1.0'; + +const DEFAULT_BACKEND_URL = + 'https://api.studio.thegraph.com/query/87073/split-delegation/version/latest'; + +type Params = { + subgraphUrl: string; + strategies: Strategy[]; +}; + +type Delegation = { + delegator?: Member; + delegatee?: Member; + ratio: number; +}; + +type Member = { + id?: string; + address: string; + delegators?: Delegation[]; + delegatees?: Delegation[]; +}; + +export async function strategy( + space: string, + network: string, + provider: any, + addresses: string[], + options: Params = { + subgraphUrl: DEFAULT_BACKEND_URL, + strategies: [] + }, + snapshot: string | number +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const block = await provider.getBlock(blockTag); + + const members = await getDelegations( + options.subgraphUrl, + addresses, + space, + block + ); + + addresses = addresses.map(getAddress); + + const allAddresses = new Set(addresses); + + members.forEach((member) => { + allAddresses.add(member.address); + member.delegators?.forEach((delegation) => + delegation.delegator + ? allAddresses.add(delegation.delegator.address) + : null + ); + member.delegatees?.forEach((delegation) => + delegation.delegatee + ? allAddresses.add(delegation.delegatee.address) + : null + ); + }); + + const scores: { [k: string]: unknown }[] = ( + await getScoresDirect( + space, + options.strategies, + network, + provider, + [...allAddresses], + snapshot + ) + ).filter((score) => Object.keys(score).length !== 0); + + return Object.fromEntries( + addresses.map((address) => { + const member = members.find( + (member) => member.address.toLowerCase() === address.toLowerCase() + ); + return [ + getAddress(address), + member ? getVp(member, scores) : getAddressScore(scores, address) + ]; + }) + ); +} + +const getAddressScore = ( + scores: { [k: string]: any }[], + address?: string +): any => { + if (!address) return 0; + return scores.reduce((total, score) => total + (score[address] ?? 0), 0); +}; + +const getVp = (member: Member, scores: { [k: string]: any }[]): any => { + const addressScore = getAddressScore(scores, member.address); + const delegatedVp = + member.delegatees?.reduce((total, delegation) => { + const vp = addressScore; + return total + delegation.ratio * vp; + }, 0) ?? 0; + const receivedVp = + member.delegators?.reduce((total, delegation) => { + const vp = getAddressScore(scores, delegation.delegator?.address); + return total + delegation.ratio * vp; + }, 0) ?? 0; + + return addressScore + receivedVp - delegatedVp; +}; + +async function getDelegations( + subgraphURL: string, + addresses: string[], + space: string, + block: any +): Promise { + const chunkSize = 25; + const pageSize = 20; // chunkSize * pageSize * 2 <= 1000 (max elements per query) + + const chunks: string[][] = []; + for (let i = 0; i < addresses.length; i += chunkSize) { + chunks.push(addresses.slice(i, i + chunkSize)); + } + + const results: Member[] = []; + for (const chunk of chunks) { + let page = 0; + let reqAddresses = chunk.map((address) => address.toLowerCase()); + while (reqAddresses.length) { + const params = { + members: { + __args: { + block: { number: block.number }, + where: { + address_in: reqAddresses + } + }, + id: true, + address: true, + delegators: { + __args: { + where: { + context: space, + expirationTimestamp_gte: block.timestamp + }, + first: pageSize, + skip: page * pageSize + }, + delegator: { + address: true + }, + ratio: true + }, + delegatees: { + __args: { + where: { + context: space, + expirationTimestamp_gte: block.timestamp + }, + first: pageSize, + skip: page * pageSize + }, + delegatee: { + address: true + }, + ratio: true + } + } + }; + const result: { members: Member[] } = await subgraphRequest( + subgraphURL, + params + ); + result.members.forEach((newMember) => { + const existingMemberIndex = results.findIndex( + (member) => + member.address.toLowerCase() === newMember.address.toLowerCase() + ); + if (existingMemberIndex !== -1) { + const existingMember = results[existingMemberIndex]; + existingMember.delegatees = [ + ...(existingMember.delegatees || []), + ...(newMember.delegatees || []) + ]; + existingMember.delegators = [ + ...(existingMember.delegators || []), + ...(newMember.delegators || []) + ]; + } else { + results.push(newMember); + } + }); + reqAddresses = result.members + .filter( + (member) => + member.delegatees?.length === pageSize || + member.delegators?.length === pageSize + ) + .map((member) => member.address); + page++; + } + } + + return results; +} diff --git a/src/strategies/subgraph-split-delegation/schema.json b/src/strategies/subgraph-split-delegation/schema.json new file mode 100644 index 000000000..454e1000a --- /dev/null +++ b/src/strategies/subgraph-split-delegation/schema.json @@ -0,0 +1,44 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "subgraphUrl": { + "type": "string", + "title": "Subgraph endpoint" + }, + "strategies": { + "title": "Strategies", + "type": "array", + "items": { + "title": "Strategy", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "network": { + "type": "string" + }, + "params": { + "type": "object" + } + }, + "required": [ + "name", + "params" + ] + } + } + }, + "required": [ + "subgraphUrl", + "strategies" + ], + "additionalProperties": false + } + } +} \ No newline at end of file From 101c2bacc6a59de15bb33804dc0e06087ae6930c Mon Sep 17 00:00:00 2001 From: meb <4982406+barrasso@users.noreply.github.com> Date: Thu, 26 Sep 2024 21:48:57 -0400 Subject: [PATCH 754/815] [snx-multichain] feat: Add synthetix collateral voting strategy (#1592) * add snx-multichain voting strategy * add v3 voting power logic * update README.md * Update src/strategies/snx-multichain/index.ts * Update src/strategies/snx-multichain/index.ts * Update src/strategies/snx-multichain/index.ts Co-authored-by: Chaitanya * add fixes * fix: check account balance * Update src/strategies/snx-multichain/index.ts * Update src/strategies/snx-multichain/index.ts Co-authored-by: Chaitanya --------- Co-authored-by: Chaitanya --- src/strategies/index.ts | 4 +- src/strategies/snx-multichain/README.md | 66 +++++++++ src/strategies/snx-multichain/examples.json | 80 ++++++++++ src/strategies/snx-multichain/index.ts | 153 ++++++++++++++++++++ 4 files changed, 302 insertions(+), 1 deletion(-) create mode 100644 src/strategies/snx-multichain/README.md create mode 100644 src/strategies/snx-multichain/examples.json create mode 100644 src/strategies/snx-multichain/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index b94781317..50dc61925 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -455,6 +455,7 @@ import * as candyNftStaking from './candy-nft-staking'; import * as pom from './pom'; import * as superboring from './superboring'; import * as erableGovernanceV1 from './erable-governance-v1'; +import * as snxMultichain from './snx-multichain'; const strategies = { 'delegatexyz-erc721-balance-of': delegatexyzErc721BalanceOf, @@ -920,7 +921,8 @@ const strategies = { 'candy-nft-staking': candyNftStaking, pom, superboring, - 'erable-governance-v1': erableGovernanceV1 + 'erable-governance-v1': erableGovernanceV1, + 'snx-multichain': snxMultichain }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/snx-multichain/README.md b/src/strategies/snx-multichain/README.md new file mode 100644 index 000000000..b1af1e30a --- /dev/null +++ b/src/strategies/snx-multichain/README.md @@ -0,0 +1,66 @@ +# snx-multichain + +This strategy calculates the voting power of addresses based on their collateral values across all Synthetix deployments. It queries the collateral values from the Synthetix v2x system as well as the v3 system on each network, and sums the results to determine the total voting power for each address. + +Here is an example of the parameters used: + +```json +{ + "symbol": "SNX", + "strategies": [ + { + "name": "contract-call", + "network": "1", + "params": { + "address": "0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F", + "decimals": 18, + "methodABI": { + "name": "collateral", + "type": "function", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint", + "internalType": "uint256" + } + ], + "stateMutability": "view" + } + } + }, + { + "name": "contract-call", + "network": "10", + "params": { + "address": "0x8700dAec35aF8Ff88c16BdF0418774CB3D7599B4", + "decimals": 18, + "methodABI": { + "name": "collateral", + "type": "function", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint", + "internalType": "uint256" + } + ], + "stateMutability": "view" + } + } + } + ] +} diff --git a/src/strategies/snx-multichain/examples.json b/src/strategies/snx-multichain/examples.json new file mode 100644 index 000000000..bd4afe879 --- /dev/null +++ b/src/strategies/snx-multichain/examples.json @@ -0,0 +1,80 @@ +[ + { + "name": "Synthetix Collateral Voting Strategy", + "strategy": { + "name": "snx-multichain", + "params": { + "symbol": "SNX", + "strategies": [ + { + "name": "contract-call", + "network": "1", + "params": { + "address": "0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F", + "decimals": 18, + "methodABI": { + "name": "collateral", + "type": "function", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint", + "internalType": "uint256" + } + ], + "stateMutability": "view" + } + } + }, + { + "name": "contract-call", + "network": "10", + "params": { + "address": "0x8700dAec35aF8Ff88c16BdF0418774CB3D7599B4", + "decimals": 18, + "methodABI": { + "name": "collateral", + "type": "function", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint", + "internalType": "uint256" + } + ], + "stateMutability": "view" + } + } + } + ], + "collateralType": { + "1": "0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F", + "10": "0x8700dAec35aF8Ff88c16BdF0418774CB3D7599B4", + "8453": "0x22e6966b799c4d5b13be962e1d117b56327fda66" + } + } + }, + "network": "1", + "addresses": [ + "0x27Cc4d6bc95b55a3a981BF1F1c7261CDa7bB0931", + "0xcb68110C43C97b6051FEd5e2Bacc2814aDaD1688", + "0xB08dd71c47Cb8c00E2155C1f12877F0e7d17B449", + "0x99F4176EE457afedFfCB1839c7aB7A030a5e4A92" + ], + "snapshot": 16000000 + } +] diff --git a/src/strategies/snx-multichain/index.ts b/src/strategies/snx-multichain/index.ts new file mode 100644 index 000000000..cc434a88d --- /dev/null +++ b/src/strategies/snx-multichain/index.ts @@ -0,0 +1,153 @@ +import { getProvider, getSnapshots } from '../../utils'; +import strategies from '..'; +import { Contract } from '@ethersproject/contracts'; + +export const author = 'barrasso'; +export const version = '1.0.0'; + +const CONTRACT_ADDRESSES = { + '1': { + accountProxy: '0x0E429603D3Cb1DFae4E6F52Add5fE82d96d77Dac', + coreProxy: '0xffffffaEff0B96Ea8e4f94b2253f31abdD875847' + }, + '10': { + accountProxy: '0x0E429603D3Cb1DFae4E6F52Add5fE82d96d77Dac', + coreProxy: '0xffffffaEff0B96Ea8e4f94b2253f31abdD875847' + }, + '8453': { + accountProxy: '0x63f4Dd0434BEB5baeCD27F3778a909278d8cf5b8', + coreProxy: '0x32C222A9A159782aFD7529c87FA34b96CA72C696' + } +}; + +const COLLATERAL_TYPES = { + '1': '0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F', + '10': '0x8700dAec35aF8Ff88c16BdF0418774CB3D7599B4', + '8453': '0x22e6966b799c4d5b13be962e1d117b56327fda66' +}; + +const accountProxyABI = [ + 'function tokenOfOwnerByIndex(address owner, uint256 index) view returns (uint256)' +]; + +const coreProxyABI = [ + 'function getAccountCollateral(uint128 accountId, address collateralType) view returns (uint256 totalDeposited, uint256 totalAssigned, uint256 totalLocked)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const promises: any = []; + const validStrategies = options.strategies.filter( + (s) => s.network === '1' || s.network === '10' || s.network === '8453' + ); + + if (validStrategies.length > 4) { + throw new Error('Exceeded the maximum limit of 4 valid strategies.'); + } + + const blocks = await getSnapshots( + network, + snapshot, + provider, + validStrategies.map((s) => s.network || network) + ); + + for (const strategy of validStrategies) { + if ( + options.startBlocks && + blocks[strategy.network] < options.startBlocks[strategy.network] + ) { + continue; + } + + promises.push( + strategies[strategy.name].strategy( + space, + strategy.network, + getProvider(strategy.network), + addresses, + strategy.params, + blocks[strategy.network] + ) + ); + } + + // Fetch v3 collateral values + const v3CollateralPromises = addresses.map(async (address) => { + const networkAddresses = CONTRACT_ADDRESSES[network]; + if (!networkAddresses) return { [address]: 0 }; + + const accountProxy = new Contract( + networkAddresses.accountProxy, + accountProxyABI, + provider + ); + + const coreProxy = new Contract( + networkAddresses.coreProxy, + coreProxyABI, + provider + ); + + let totalCollateral = 0; + + try { + // Check the number of tokens owned by the address + const balance = await accountProxy.balanceOf(address); + if (balance.eq(0)) { + return { [address]: 0 }; + } + + // Use only the first account (index 0) + const accountId = await accountProxy.tokenOfOwnerByIndex(address, 0); + + // Select the appropriate collateralType based on the network + const collateralType = COLLATERAL_TYPES[network]; + + // Fetch only the totalDeposited value for the account ID + const { totalDeposited } = await coreProxy.getAccountCollateral( + accountId, + collateralType + ); + + totalCollateral = totalDeposited; + } catch (err) { + // Assume the account doesn't exist and continue. + // console.log(`Error fetching v3 collateral for address ${address}:`, err); + } + + return { [address]: totalCollateral }; + }); + + const v3Results = await Promise.all(v3CollateralPromises); + const results = await Promise.all(promises); + + // Sum collateral values from v2 and v3 systems for each address + const finalResults = results.reduce((acc, strategyResult) => { + for (const [address, value] of Object.entries(strategyResult)) { + if (!acc[address]) { + acc[address] = 0; + } + acc[address] += value as number; + } + return acc; + }, {}); + + // Add v3 collateral values to the final results + v3Results.forEach((v3Result) => { + for (const [address, value] of Object.entries(v3Result)) { + if (!finalResults[address]) { + finalResults[address] = 0; + } + finalResults[address] += value as number; + } + }); + + return finalResults; +} From d08d943bad029a4f4ddbfe8df520e7ea08bf7006 Mon Sep 17 00:00:00 2001 From: meb <4982406+barrasso@users.noreply.github.com> Date: Fri, 27 Sep 2024 12:37:29 -0400 Subject: [PATCH 755/815] [snx-multichain] fix v3 collateral voting power (#1594) * fix: snx-multichain v3 collateral voting power * iterate over all snx v3 account tokens * throw if failing on v3 collateral query * fix lint --- src/strategies/snx-multichain/examples.json | 4 +-- src/strategies/snx-multichain/index.ts | 31 ++++++++++--------- .../subgraph-split-delegation/examples.json | 2 +- .../subgraph-split-delegation/schema.json | 12 ++----- 4 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/strategies/snx-multichain/examples.json b/src/strategies/snx-multichain/examples.json index bd4afe879..529519b46 100644 --- a/src/strategies/snx-multichain/examples.json +++ b/src/strategies/snx-multichain/examples.json @@ -72,9 +72,9 @@ "addresses": [ "0x27Cc4d6bc95b55a3a981BF1F1c7261CDa7bB0931", "0xcb68110C43C97b6051FEd5e2Bacc2814aDaD1688", - "0xB08dd71c47Cb8c00E2155C1f12877F0e7d17B449", + "0xf07A2439296e07Bc4320AF924E655a01fb69D89C", "0x99F4176EE457afedFfCB1839c7aB7A030a5e4A92" ], - "snapshot": 16000000 + "snapshot": 20000000 } ] diff --git a/src/strategies/snx-multichain/index.ts b/src/strategies/snx-multichain/index.ts index cc434a88d..5fe2362ca 100644 --- a/src/strategies/snx-multichain/index.ts +++ b/src/strategies/snx-multichain/index.ts @@ -27,6 +27,7 @@ const COLLATERAL_TYPES = { }; const accountProxyABI = [ + 'function balanceOf(address account) view returns (uint256)', 'function tokenOfOwnerByIndex(address owner, uint256 index) view returns (uint256)' ]; @@ -95,31 +96,33 @@ export async function strategy( provider ); + // Select the appropriate collateralType based on the network + const collateralType = COLLATERAL_TYPES[network]; + let totalCollateral = 0; try { - // Check the number of tokens owned by the address + // Check if the user has a v3 account const balance = await accountProxy.balanceOf(address); if (balance.eq(0)) { return { [address]: 0 }; } - // Use only the first account (index 0) - const accountId = await accountProxy.tokenOfOwnerByIndex(address, 0); - - // Select the appropriate collateralType based on the network - const collateralType = COLLATERAL_TYPES[network]; + // Iterate over all accounts based on their token balance + for (let i = 0; i < balance.toNumber(); i++) { + // Fetch the accountId at each index + const accountId = await accountProxy.tokenOfOwnerByIndex(address, i); - // Fetch only the totalDeposited value for the account ID - const { totalDeposited } = await coreProxy.getAccountCollateral( - accountId, - collateralType - ); + // Fetch only the totalDeposited value for the account ID + const { totalDeposited } = await coreProxy.getAccountCollateral( + accountId, + collateralType + ); - totalCollateral = totalDeposited; + totalCollateral += Number(totalDeposited) / 1e18; + } } catch (err) { - // Assume the account doesn't exist and continue. - // console.log(`Error fetching v3 collateral for address ${address}:`, err); + throw new Error(`Error fetching v3 collateral for ${address}: ${err}`); } return { [address]: totalCollateral }; diff --git a/src/strategies/subgraph-split-delegation/examples.json b/src/strategies/subgraph-split-delegation/examples.json index 3592ccd33..6bf021361 100644 --- a/src/strategies/subgraph-split-delegation/examples.json +++ b/src/strategies/subgraph-split-delegation/examples.json @@ -32,4 +32,4 @@ ], "snapshot": 6716841 } -] \ No newline at end of file +] diff --git a/src/strategies/subgraph-split-delegation/schema.json b/src/strategies/subgraph-split-delegation/schema.json index 454e1000a..be2118cfb 100644 --- a/src/strategies/subgraph-split-delegation/schema.json +++ b/src/strategies/subgraph-split-delegation/schema.json @@ -27,18 +27,12 @@ "type": "object" } }, - "required": [ - "name", - "params" - ] + "required": ["name", "params"] } } }, - "required": [ - "subgraphUrl", - "strategies" - ], + "required": ["subgraphUrl", "strategies"], "additionalProperties": false } } -} \ No newline at end of file +} From 48a12317f71d7e1ffb8ee6c3e104088abf23dc09 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 28 Sep 2024 07:55:53 +0530 Subject: [PATCH 756/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.18 (#1593) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index ba9056649..5389e3c4f 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.16", + "@snapshot-labs/snapshot.js": "^0.12.18", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 0eeded8ba..3a4ae8c15 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.16": - version "0.12.16" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.16.tgz#643def33ee564f1c9c0379b35165f73eddb148c8" - integrity sha512-TI5cCsQk0eyj/jxzyjrPc6yOT7mnb+Q1GYUYL3g/P1kECyhrVttV7zlilXBwjIB0IscgdfIQUMgA67J1Pcb2zg== +"@snapshot-labs/snapshot.js@^0.12.18": + version "0.12.18" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.18.tgz#58421fc0fd8c424b76923a2d9b41e1f73c4767b0" + integrity sha512-zGRFgWws3cjQUZRw12uOpHlrdUgctMNRWlMu2N6QYD1VKQKZ21nW4ONanmSE/eWsQtiQL11wAAApaFxa4DdosA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 461a69277118a8d982da46b7027e09da24902acb Mon Sep 17 00:00:00 2001 From: Coderdan Date: Tue, 1 Oct 2024 13:37:35 +0800 Subject: [PATCH 757/815] [aavegotchi-agip] Update Aavegotchi Strategy (#1596) * add strategies * chore: add wearables and update example * chore: cleanup * chore: cleanup * chore: add new wearables --- src/strategies/aavegotchi-agip/index.ts | 718 ++++++++++++------------ 1 file changed, 372 insertions(+), 346 deletions(-) diff --git a/src/strategies/aavegotchi-agip/index.ts b/src/strategies/aavegotchi-agip/index.ts index 83dc40d53..d7ad25435 100644 --- a/src/strategies/aavegotchi-agip/index.ts +++ b/src/strategies/aavegotchi-agip/index.ts @@ -11,363 +11,389 @@ const AAVEGOTCHI_SUBGRAPH_URL = { 137: 'https://subgraph.satsuma-prod.com/tWYl5n5y04oz/aavegotchi/aavegotchi-core-matic/api' }; +enum GotchiRarityPrices { + None = 0, + Common = 5, + Uncommon = 10, + Rare = 10, + Legendary = 300, + Mythical = 2000, + Godlike = 10000 +} + const prices: Prices = { - '0': 0, - '1': 5, - '2': 5, - '3': 5, - '4': 10, - '5': 10, - '6': 10, - '7': 100, - '8': 100, - '9': 100, - '10': 300, - '11': 300, - '12': 300, - '13': 2000, - '14': 2000, - '15': 2000, - '16': 10000, - '17': 10000, - '18': 5, - '19': 5, - '20': 5, - '21': 10, - '22': 10, - '23': 10, - '24': 100, - '25': 100, - '26': 100, - '27': 300, - '28': 300, - '29': 300, - '30': 2000, - '31': 2000, - '32': 2000, - '33': 10000, - '34': 10000, - '35': 10000, - '36': 5, - '37': 5, - '38': 5, - '39': 10, - '40': 10, - '41': 10, - '42': 100, - '43': 100, - '44': 100, - '45': 300, - '46': 300, - '47': 300, - '48': 2000, - '49': 2000, - '50': 2000, - '51': 2000, - '52': 10000, - '53': 10000, - '54': 10000, - '55': 100, - '56': 100, - '57': 100, - '58': 100, - '59': 100, - '60': 5, - '61': 300, - '62': 2000, - '63': 10000, - '64': 5, - '65': 300, - '66': 5, - '67': 5, - '68': 5, - '69': 5, - '70': 2000, - '71': 100, - '72': 2000, - '73': 2000, - '74': 2000, - '75': 2000, - '76': 5, - '77': 10, - '78': 10, - '79': 100, - '80': 100, - '81': 100, - '82': 300, - '83': 100, - '84': 300, - '85': 300, - '86': 2000, - '87': 10, - '88': 10, - '89': 100, - '90': 5, - '91': 10, - '92': 100, - '93': 300, - '94': 10, - '95': 10, - '96': 10, - '97': 300, - '98': 300, - '99': 2000, - '100': 300, - '101': 300, - '102': 300, - '103': 2000, - '104': 300, - '105': 300, - '106': 300, - '107': 10000, - '108': 10, - '109': 10, - '110': 100, - '111': 300, - '112': 300, - '113': 10000, - '114': 2000, - '115': 300, - '116': 100, - '117': 5, - '118': 300, - '119': 300, - '120': 300, - '121': 100, - '122': 2000, - '123': 10, - '124': 2000, - '125': 300, - '126': 5, + '0': GotchiRarityPrices.None, + '1': GotchiRarityPrices.Common, + '2': GotchiRarityPrices.Common, + '3': GotchiRarityPrices.Common, + '4': GotchiRarityPrices.Uncommon, + '5': GotchiRarityPrices.Uncommon, + '6': GotchiRarityPrices.Uncommon, + '7': GotchiRarityPrices.Rare, + '8': GotchiRarityPrices.Rare, + '9': GotchiRarityPrices.Rare, + '10': GotchiRarityPrices.Legendary, + '11': GotchiRarityPrices.Legendary, + '12': GotchiRarityPrices.Legendary, + '13': GotchiRarityPrices.Mythical, + '14': GotchiRarityPrices.Mythical, + '15': GotchiRarityPrices.Mythical, + '16': GotchiRarityPrices.Godlike, + '17': GotchiRarityPrices.Godlike, + '18': GotchiRarityPrices.Common, + '19': GotchiRarityPrices.Common, + '20': GotchiRarityPrices.Common, + '21': GotchiRarityPrices.Uncommon, + '22': GotchiRarityPrices.Uncommon, + '23': GotchiRarityPrices.Uncommon, + '24': GotchiRarityPrices.Rare, + '25': GotchiRarityPrices.Rare, + '26': GotchiRarityPrices.Rare, + '27': GotchiRarityPrices.Legendary, + '28': GotchiRarityPrices.Legendary, + '29': GotchiRarityPrices.Legendary, + '30': GotchiRarityPrices.Mythical, + '31': GotchiRarityPrices.Mythical, + '32': GotchiRarityPrices.Mythical, + '33': GotchiRarityPrices.Godlike, + '34': GotchiRarityPrices.Godlike, + '35': GotchiRarityPrices.Godlike, + '36': GotchiRarityPrices.Common, + '37': GotchiRarityPrices.Common, + '38': GotchiRarityPrices.Common, + '39': GotchiRarityPrices.Uncommon, + '40': GotchiRarityPrices.Uncommon, + '41': GotchiRarityPrices.Uncommon, + '42': GotchiRarityPrices.Rare, + '43': GotchiRarityPrices.Rare, + '44': GotchiRarityPrices.Rare, + '45': GotchiRarityPrices.Legendary, + '46': GotchiRarityPrices.Legendary, + '47': GotchiRarityPrices.Legendary, + '48': GotchiRarityPrices.Mythical, + '49': GotchiRarityPrices.Mythical, + '50': GotchiRarityPrices.Mythical, + '51': GotchiRarityPrices.Mythical, + '52': GotchiRarityPrices.Godlike, + '53': GotchiRarityPrices.Godlike, + '54': GotchiRarityPrices.Godlike, + '55': GotchiRarityPrices.Rare, + '56': GotchiRarityPrices.Rare, + '57': GotchiRarityPrices.Rare, + '58': GotchiRarityPrices.Rare, + '59': GotchiRarityPrices.Rare, + '60': GotchiRarityPrices.Common, + '61': GotchiRarityPrices.Legendary, + '62': GotchiRarityPrices.Mythical, + '63': GotchiRarityPrices.Godlike, + '64': GotchiRarityPrices.Common, + '65': GotchiRarityPrices.Legendary, + '66': GotchiRarityPrices.Common, + '67': GotchiRarityPrices.Common, + '68': GotchiRarityPrices.Common, + '69': GotchiRarityPrices.Common, + '70': GotchiRarityPrices.Mythical, + '71': GotchiRarityPrices.Rare, + '72': GotchiRarityPrices.Mythical, + '73': GotchiRarityPrices.Mythical, + '74': GotchiRarityPrices.Mythical, + '75': GotchiRarityPrices.Mythical, + '76': GotchiRarityPrices.Common, + '77': GotchiRarityPrices.Uncommon, + '78': GotchiRarityPrices.Uncommon, + '79': GotchiRarityPrices.Rare, + '80': GotchiRarityPrices.Rare, + '81': GotchiRarityPrices.Rare, + '82': GotchiRarityPrices.Legendary, + '83': GotchiRarityPrices.Rare, + '84': GotchiRarityPrices.Legendary, + '85': GotchiRarityPrices.Legendary, + '86': GotchiRarityPrices.Mythical, + '87': GotchiRarityPrices.Uncommon, + '88': GotchiRarityPrices.Uncommon, + '89': GotchiRarityPrices.Rare, + '90': GotchiRarityPrices.Common, + '91': GotchiRarityPrices.Uncommon, + '92': GotchiRarityPrices.Rare, + '93': GotchiRarityPrices.Legendary, + '94': GotchiRarityPrices.Uncommon, + '95': GotchiRarityPrices.Uncommon, + '96': GotchiRarityPrices.Uncommon, + '97': GotchiRarityPrices.Legendary, + '98': GotchiRarityPrices.Legendary, + '99': GotchiRarityPrices.Mythical, + '100': GotchiRarityPrices.Legendary, + '101': GotchiRarityPrices.Legendary, + '102': GotchiRarityPrices.Legendary, + '103': GotchiRarityPrices.Mythical, + '104': GotchiRarityPrices.Legendary, + '105': GotchiRarityPrices.Legendary, + '106': GotchiRarityPrices.Legendary, + '107': GotchiRarityPrices.Godlike, + '108': GotchiRarityPrices.Uncommon, + '109': GotchiRarityPrices.Uncommon, + '110': GotchiRarityPrices.Rare, + '111': GotchiRarityPrices.Legendary, + '112': GotchiRarityPrices.Legendary, + '113': GotchiRarityPrices.Godlike, + '114': GotchiRarityPrices.Mythical, + '115': GotchiRarityPrices.Legendary, + '116': GotchiRarityPrices.Rare, + '117': GotchiRarityPrices.Common, + '118': GotchiRarityPrices.Legendary, + '119': GotchiRarityPrices.Legendary, + '120': GotchiRarityPrices.Legendary, + '121': GotchiRarityPrices.Rare, + '122': GotchiRarityPrices.Mythical, + '123': GotchiRarityPrices.Uncommon, + '124': GotchiRarityPrices.Mythical, + '125': GotchiRarityPrices.Legendary, + '126': GotchiRarityPrices.Common, '127': 20, '128': 20, '129': 50, - '130': 5, - '131': 10, - '132': 100, - '133': 300, - '134': 5, - '135': 10, - '136': 100, - '137': 5, - '138': 10, - '139': 100, - '140': 5, - '141': 10, - '142': 100, - '143': 300, - '144': 2000, - '145': 10000, - '146': 5, - '147': 10, - '148': 100, - '149': 300, - '150': 2000, - '151': 5, - '152': 10, - '153': 100, - '154': 300, - '155': 2000, - '156': 10000, - '157': 10, - '158': 100, - '159': 300, - '160': 2000, - '161': 10000, - '162': 5, - '163': 0, - '164': 0, - '165': 0, - '166': 0, - '167': 0, - '168': 0, - '169': 0, - '170': 0, - '171': 0, - '172': 0, - '173': 0, - '174': 0, - '175': 0, - '176': 0, - '177': 0, - '178': 0, - '179': 0, - '180': 0, - '181': 0, - '182': 0, - '183': 0, - '184': 0, - '185': 0, - '186': 0, - '187': 0, - '188': 0, - '189': 0, - '190': 0, - '191': 0, - '192': 0, - '193': 0, - '194': 0, - '195': 0, - '196': 0, - '197': 0, - '198': 0, - '199': 100, - '200': 10, - '201': 300, - '202': 2000, - '203': 100, - '204': 10, - '205': 5, - '206': 100, - '207': 10, - '208': 10, - '209': 300, - '210': 5, - '211': 5, + '130': GotchiRarityPrices.Common, + '131': GotchiRarityPrices.Uncommon, + '132': GotchiRarityPrices.Rare, + '133': GotchiRarityPrices.Legendary, + '134': GotchiRarityPrices.Common, + '135': GotchiRarityPrices.Uncommon, + '136': GotchiRarityPrices.Rare, + '137': GotchiRarityPrices.Common, + '138': GotchiRarityPrices.Uncommon, + '139': GotchiRarityPrices.Rare, + '140': GotchiRarityPrices.Common, + '141': GotchiRarityPrices.Uncommon, + '142': GotchiRarityPrices.Rare, + '143': GotchiRarityPrices.Legendary, + '144': GotchiRarityPrices.Mythical, + '145': GotchiRarityPrices.Godlike, + '146': GotchiRarityPrices.Common, + '147': GotchiRarityPrices.Uncommon, + '148': GotchiRarityPrices.Rare, + '149': GotchiRarityPrices.Legendary, + '150': GotchiRarityPrices.Mythical, + '151': GotchiRarityPrices.Common, + '152': GotchiRarityPrices.Uncommon, + '153': GotchiRarityPrices.Rare, + '154': GotchiRarityPrices.Legendary, + '155': GotchiRarityPrices.Mythical, + '156': GotchiRarityPrices.Godlike, + '157': GotchiRarityPrices.Uncommon, + '158': GotchiRarityPrices.Rare, + '159': GotchiRarityPrices.Legendary, + '160': GotchiRarityPrices.Mythical, + '161': GotchiRarityPrices.Godlike, + '162': GotchiRarityPrices.Common, + '163': GotchiRarityPrices.None, + '164': GotchiRarityPrices.None, + '165': GotchiRarityPrices.None, + '166': GotchiRarityPrices.None, + '167': GotchiRarityPrices.None, + '168': GotchiRarityPrices.None, + '169': GotchiRarityPrices.None, + '170': GotchiRarityPrices.None, + '171': GotchiRarityPrices.None, + '172': GotchiRarityPrices.None, + '173': GotchiRarityPrices.None, + '174': GotchiRarityPrices.None, + '175': GotchiRarityPrices.None, + '176': GotchiRarityPrices.None, + '177': GotchiRarityPrices.None, + '178': GotchiRarityPrices.None, + '179': GotchiRarityPrices.None, + '180': GotchiRarityPrices.None, + '181': GotchiRarityPrices.None, + '182': GotchiRarityPrices.None, + '183': GotchiRarityPrices.None, + '184': GotchiRarityPrices.None, + '185': GotchiRarityPrices.None, + '186': GotchiRarityPrices.None, + '187': GotchiRarityPrices.None, + '188': GotchiRarityPrices.None, + '189': GotchiRarityPrices.None, + '190': GotchiRarityPrices.None, + '191': GotchiRarityPrices.None, + '192': GotchiRarityPrices.None, + '193': GotchiRarityPrices.None, + '194': GotchiRarityPrices.None, + '195': GotchiRarityPrices.None, + '196': GotchiRarityPrices.None, + '197': GotchiRarityPrices.None, + '198': GotchiRarityPrices.None, + '199': GotchiRarityPrices.Rare, + '200': GotchiRarityPrices.Uncommon, + '201': GotchiRarityPrices.Legendary, + '202': GotchiRarityPrices.Mythical, + '203': GotchiRarityPrices.Rare, + '204': GotchiRarityPrices.Uncommon, + '205': GotchiRarityPrices.Common, + '206': GotchiRarityPrices.Rare, + '207': GotchiRarityPrices.Uncommon, + '208': GotchiRarityPrices.Uncommon, + '209': GotchiRarityPrices.Legendary, + '210': GotchiRarityPrices.Common, + '211': GotchiRarityPrices.Common, '212': 3000, - '213': 300, - '214': 10000, - '215': 300, + '213': GotchiRarityPrices.Legendary, + '214': GotchiRarityPrices.Godlike, + '215': GotchiRarityPrices.Legendary, '216': 3000, '217': 3000, - '218': 10, - '219': 100, - '220': 300, - '221': 5, - '222': 10, - '223': 10, - '224': 100, - '225': 5, - '226': 100, - '227': 100, - '228': 5, - '229': 10, - '230': 5, - '231': 10, - '232': 5, - '233': 10, + '218': GotchiRarityPrices.Uncommon, + '219': GotchiRarityPrices.Rare, + '220': GotchiRarityPrices.Legendary, + '221': GotchiRarityPrices.Common, + '222': GotchiRarityPrices.Uncommon, + '223': GotchiRarityPrices.Uncommon, + '224': GotchiRarityPrices.Rare, + '225': GotchiRarityPrices.Common, + '226': GotchiRarityPrices.Rare, + '227': GotchiRarityPrices.Rare, + '228': GotchiRarityPrices.Common, + '229': GotchiRarityPrices.Uncommon, + '230': GotchiRarityPrices.Common, + '231': GotchiRarityPrices.Uncommon, + '232': GotchiRarityPrices.Common, + '233': GotchiRarityPrices.Uncommon, '234': 3000, - '235': 300, - '236': 100, + '235': GotchiRarityPrices.Legendary, + '236': GotchiRarityPrices.Rare, '237': 3000, - '238': 10000, - '239': 10, - '240': 10, - '241': 100, - '242': 300, - '243': 100, - '244': 100, - '245': 100, - '246': 10, - '247': 10, - '248': 10, - '249': 100, - '250': 100, - '251': 100, - '252': 5, - '253': 5, - '254': 5, - '255': 300, - '256': 300, - '257': 300, - '258': 10000, - '259': 10000, - '260': 10000, - '261': 2000, - '262': 2000, - '263': 2000, - '264': 0, - '265': 0, - '266': 0, - '267': 0, - '268': 0, - '269': 0, - '270': 0, - '271': 0, - '272': 0, - '273': 0, - '274': 0, - '275': 0, - '276': 0, - '277': 0, - '278': 0, - '279': 0, - '280': 0, - '281': 0, - '282': 0, - '283': 0, - '284': 0, - '285': 0, - '286': 0, - '287': 0, - '288': 0, - '289': 0, - '290': 0, - '291': 0, - '292': 5, - '293': 5, - '294': 5, - '295': 5, - '296': 10, - '297': 10, - '298': 5, - '299': 10, - '300': 10, - '301': 100, - '302': 100, - '303': 100, - '304': 100, - '305': 300, - '306': 300, - '307': 300, - '308': 300, - '309': 2000, - '310': 2000, - '311': 2000, - '312': 2000, - '313': 10000, - '314': 10000, - '315': 10000, + '238': GotchiRarityPrices.Godlike, + '239': GotchiRarityPrices.Uncommon, + '240': GotchiRarityPrices.Uncommon, + '241': GotchiRarityPrices.Rare, + '242': GotchiRarityPrices.Legendary, + '243': GotchiRarityPrices.Rare, + '244': GotchiRarityPrices.Rare, + '245': GotchiRarityPrices.Rare, + '246': GotchiRarityPrices.Uncommon, + '247': GotchiRarityPrices.Uncommon, + '248': GotchiRarityPrices.Uncommon, + '249': GotchiRarityPrices.Rare, + '250': GotchiRarityPrices.Rare, + '251': GotchiRarityPrices.Rare, + '252': GotchiRarityPrices.Common, + '253': GotchiRarityPrices.Common, + '254': GotchiRarityPrices.Common, + '255': GotchiRarityPrices.Legendary, + '256': GotchiRarityPrices.Legendary, + '257': GotchiRarityPrices.Legendary, + '258': GotchiRarityPrices.Godlike, + '259': GotchiRarityPrices.Godlike, + '260': GotchiRarityPrices.Godlike, + '261': GotchiRarityPrices.Mythical, + '262': GotchiRarityPrices.Mythical, + '263': GotchiRarityPrices.Mythical, + '264': GotchiRarityPrices.None, + '265': GotchiRarityPrices.None, + '266': GotchiRarityPrices.None, + '267': GotchiRarityPrices.None, + '268': GotchiRarityPrices.None, + '269': GotchiRarityPrices.None, + '270': GotchiRarityPrices.None, + '271': GotchiRarityPrices.None, + '272': GotchiRarityPrices.None, + '273': GotchiRarityPrices.None, + '274': GotchiRarityPrices.None, + '275': GotchiRarityPrices.None, + '276': GotchiRarityPrices.None, + '277': GotchiRarityPrices.None, + '278': GotchiRarityPrices.None, + '279': GotchiRarityPrices.None, + '280': GotchiRarityPrices.None, + '281': GotchiRarityPrices.None, + '282': GotchiRarityPrices.None, + '283': GotchiRarityPrices.None, + '284': GotchiRarityPrices.None, + '285': GotchiRarityPrices.None, + '286': GotchiRarityPrices.None, + '287': GotchiRarityPrices.None, + '288': GotchiRarityPrices.None, + '289': GotchiRarityPrices.None, + '290': GotchiRarityPrices.None, + '291': GotchiRarityPrices.None, + '292': GotchiRarityPrices.Common, + '293': GotchiRarityPrices.Common, + '294': GotchiRarityPrices.Common, + '295': GotchiRarityPrices.Common, + '296': GotchiRarityPrices.Uncommon, + '297': GotchiRarityPrices.Uncommon, + '298': GotchiRarityPrices.Common, + '299': GotchiRarityPrices.Uncommon, + '300': GotchiRarityPrices.Uncommon, + '301': GotchiRarityPrices.Rare, + '302': GotchiRarityPrices.Rare, + '303': GotchiRarityPrices.Rare, + '304': GotchiRarityPrices.Rare, + '305': GotchiRarityPrices.Legendary, + '306': GotchiRarityPrices.Legendary, + '307': GotchiRarityPrices.Legendary, + '308': GotchiRarityPrices.Legendary, + '309': GotchiRarityPrices.Mythical, + '310': GotchiRarityPrices.Mythical, + '311': GotchiRarityPrices.Mythical, + '312': GotchiRarityPrices.Mythical, + '313': GotchiRarityPrices.Godlike, + '314': GotchiRarityPrices.Godlike, + '315': GotchiRarityPrices.Godlike, //new - '350': 5, - '351': 5, - '352': 5, - '353': 5, - '354': 10, - '355': 100, - '356': 10, - '357': 100, - '358': 300, - '359': 300, - '360': 300, - '361': 300, - '362': 2000, - '363': 2000, - '364': 2000, - '365': 2000, - '366': 10000, - '367': 10000, - '368': 10000, - '369': 10000, - '370': 5, - '371': 5, - '372': 5, - '373': 10, - '374': 100, - '375': 5, - '376': 100, - '377': 10, - '378': 100, - '379': 100, - '380': 300, - '381': 300, - '382': 300, - '383': 300, - '384': 2000, - '385': 10000, - '386': 10000, - '387': 10000 + '350': GotchiRarityPrices.Common, + '351': GotchiRarityPrices.Common, + '352': GotchiRarityPrices.Common, + '353': GotchiRarityPrices.Common, + '354': GotchiRarityPrices.Uncommon, + '355': GotchiRarityPrices.Rare, + '356': GotchiRarityPrices.Uncommon, + '357': GotchiRarityPrices.Rare, + '358': GotchiRarityPrices.Legendary, + '359': GotchiRarityPrices.Legendary, + '360': GotchiRarityPrices.Legendary, + '361': GotchiRarityPrices.Legendary, + '362': GotchiRarityPrices.Mythical, + '363': GotchiRarityPrices.Mythical, + '364': GotchiRarityPrices.Mythical, + '365': GotchiRarityPrices.Mythical, + '366': GotchiRarityPrices.Godlike, + '367': GotchiRarityPrices.Godlike, + '368': GotchiRarityPrices.Godlike, + '369': GotchiRarityPrices.Godlike, + '370': GotchiRarityPrices.Common, + '371': GotchiRarityPrices.Common, + '372': GotchiRarityPrices.Common, + '373': GotchiRarityPrices.Uncommon, + '374': GotchiRarityPrices.Rare, + '375': GotchiRarityPrices.Common, + '376': GotchiRarityPrices.Rare, + '377': GotchiRarityPrices.Uncommon, + '378': GotchiRarityPrices.Rare, + '379': GotchiRarityPrices.Rare, + '380': GotchiRarityPrices.Legendary, + '381': GotchiRarityPrices.Legendary, + '382': GotchiRarityPrices.Legendary, + '383': GotchiRarityPrices.Legendary, + '384': GotchiRarityPrices.Mythical, + '385': GotchiRarityPrices.Godlike, + '386': GotchiRarityPrices.Godlike, + '387': GotchiRarityPrices.Godlike, + + //404 - 417 + '404': GotchiRarityPrices.Common, + '405': GotchiRarityPrices.Common, + '406': GotchiRarityPrices.Common, + '407': GotchiRarityPrices.Uncommon, + '408': GotchiRarityPrices.Uncommon, + '409': GotchiRarityPrices.Uncommon, + '410': GotchiRarityPrices.Uncommon, + '411': GotchiRarityPrices.Rare, + '412': GotchiRarityPrices.Rare, + '413': GotchiRarityPrices.Rare, + '414': GotchiRarityPrices.Legendary, + '415': GotchiRarityPrices.Legendary, + '416': GotchiRarityPrices.Mythical, + '417': GotchiRarityPrices.Mythical }; const tokenAbi = [ From 1f8f92b284f807bec1353567034349246e379799 Mon Sep 17 00:00:00 2001 From: Coderdan Date: Tue, 1 Oct 2024 20:01:29 +0800 Subject: [PATCH 758/815] Update Aavegotchi Strategy (#1597) * add strategies * chore: add wearables and update example * chore: cleanup * chore: cleanup * chore: add new wearables * chore: fix rarity score --- src/strategies/aavegotchi-agip/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategies/aavegotchi-agip/index.ts b/src/strategies/aavegotchi-agip/index.ts index d7ad25435..5c9a84688 100644 --- a/src/strategies/aavegotchi-agip/index.ts +++ b/src/strategies/aavegotchi-agip/index.ts @@ -15,7 +15,7 @@ enum GotchiRarityPrices { None = 0, Common = 5, Uncommon = 10, - Rare = 10, + Rare = 100, Legendary = 300, Mythical = 2000, Godlike = 10000 From e1a353823f3b7aed2c5d31c1b8e1f4d727a3e9ef Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Fri, 4 Oct 2024 16:17:07 +0530 Subject: [PATCH 759/815] [rocketpool-node-operator-delegate-v8] send secret in header (#1598) * [rocketpool-node-operator-delegate-v8] send secret in header * [rocketpool-node-operator-delegate-v8] send secret in header * [rocketpool-node-operator-delegate-v8] send secret in header --- .../rocketpool-node-operator-delegate-v8/index.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/strategies/rocketpool-node-operator-delegate-v8/index.ts b/src/strategies/rocketpool-node-operator-delegate-v8/index.ts index 506d97c82..491d52ef9 100644 --- a/src/strategies/rocketpool-node-operator-delegate-v8/index.ts +++ b/src/strategies/rocketpool-node-operator-delegate-v8/index.ts @@ -1,5 +1,5 @@ import fetch from 'cross-fetch'; -import { getScoresDirect, Multicaller } from '../../utils'; +import { getScoresDirect, Multicaller, sha256 } from '../../utils'; import { getAddress } from '@ethersproject/address'; export const author = 'rocket-pool'; @@ -12,6 +12,10 @@ const signerRegistryAbi = [ 'function signerToNode(address) external view returns (address)' ]; +const snapshotSecretHeader = sha256( + `https://api.rocketpool.net/mainnet/delegates/block/${process.env.SNAPSHOT_API_STRATEGY_SALT}` +); + export async function strategy( space, network, @@ -33,7 +37,12 @@ export async function strategy( } const req = await fetch( - 'https://api.rocketpool.net/mainnet/delegates/block/' + blockTag + 'https://api.rocketpool.net/mainnet/delegates/block/' + blockTag, + { + headers: { + 'X-Snapshot-API-Secret': snapshotSecretHeader + } + } ); const resp = await req.json(); From e91d1af424c283b28fbd10d967b30f870ae91714 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Fri, 4 Oct 2024 16:59:08 +0530 Subject: [PATCH 760/815] [rocketpool-node-operator-delegate-v8] Add limit to strategies passed (#1599) * [rocketpool-node-operator-delegate-v8] send secret in header * [rocketpool-node-operator-delegate-v8] send secret in header * [rocketpool-node-operator-delegate-v8] send secret in header * Add limit to strategies passed --- src/strategies/rocketpool-node-operator-delegate-v8/index.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/strategies/rocketpool-node-operator-delegate-v8/index.ts b/src/strategies/rocketpool-node-operator-delegate-v8/index.ts index 491d52ef9..65350c473 100644 --- a/src/strategies/rocketpool-node-operator-delegate-v8/index.ts +++ b/src/strategies/rocketpool-node-operator-delegate-v8/index.ts @@ -28,12 +28,14 @@ export async function strategy( const validPrefix = 'rocketpool-node-operator-v'; if ( + !options.strategies.length || + options.strategies.length > 1 || !options.strategies.some((s) => { const parsedStrategy = JSON.parse(JSON.stringify(s)); return parsedStrategy.name.startsWith(validPrefix); }) ) { - return {}; + throw new Error('Invalid strategies passed'); } const req = await fetch( From 491c062a388a1bfcc865a7cf2d6a70c2de3a57e6 Mon Sep 17 00:00:00 2001 From: Wan <495709+wa0x6e@users.noreply.github.com> Date: Sat, 5 Oct 2024 15:08:10 +0900 Subject: [PATCH 761/815] fix: use customFetch instead of fetch (#1600) * fix: use customFetch instead of fetch * style: fix lint * style: reorder import * fix fetch in safe-vested --------- Co-authored-by: ChaituVR --- src/strategies/aelin-council/index.ts | 5 ++-- src/strategies/aks/index.ts | 5 ++-- src/strategies/api-post/index.ts | 4 +-- src/strategies/api-v2/index.ts | 5 ++-- src/strategies/api/index.ts | 4 +-- src/strategies/bsc-mvb/index.ts | 5 ++-- src/strategies/colony-reputation/index.ts | 5 ++-- src/strategies/delegate-registry-v2/index.ts | 5 ++-- .../digitalax-genesis-contribution/index.ts | 5 ++-- src/strategies/erc20-price/index.ts | 4 +-- src/strategies/erc20-received/index.ts | 6 ++-- src/strategies/eth-wallet-age/index.ts | 6 ++-- src/strategies/ethermon-erc721/index.ts | 5 ++-- .../etherorcs-combo-balanceof/index.ts | 4 +-- .../flexa-capacity-staking/index.ts | 4 +-- src/strategies/forta-shares/index.ts | 5 ++-- src/strategies/galaxy-nft-with-score/index.ts | 5 ++-- src/strategies/galxe-loyalty-points/index.ts | 4 +-- src/strategies/iotex-staked-balance/index.ts | 28 +++++++++++-------- src/strategies/karma-discord-roles/index.ts | 7 +++-- src/strategies/l2-deversifi/index.ts | 4 +-- src/strategies/landdao-token-tiers/index.ts | 5 ++-- .../masterchef-pool-balance-price/index.ts | 5 ++-- src/strategies/meebitsdao/index.ts | 5 ++-- src/strategies/offchain-delegation/index.ts | 5 ++-- .../orange-reputation-based-voting/index.ts | 4 +-- .../proxyprotocol-erc721-balance-of/index.ts | 4 +-- src/strategies/reverse-voting-escrow/index.ts | 6 ++-- src/strategies/sablier-v2/queries.ts | 5 ++-- src/strategies/safe-vested/index.ts | 5 ++-- src/strategies/spreadsheet/index.ts | 4 +-- src/strategies/starsharks/index.ts | 4 +-- .../synthetic-nouns-with-claimer/index.ts | 6 ++-- .../xdai-stakers-and-holders/index.ts | 5 ++-- src/strategies/xrc20-balance-of/index.ts | 4 +-- src/strategies/zrx-voting-power/index.ts | 5 ++-- src/utils.ts | 6 +++- .../karma-eas-attestation/index.ts | 4 +-- src/validations/passport-gated/index.ts | 22 +++++++++------ 39 files changed, 114 insertions(+), 115 deletions(-) diff --git a/src/strategies/aelin-council/index.ts b/src/strategies/aelin-council/index.ts index 9da2de011..3e0ee9f10 100644 --- a/src/strategies/aelin-council/index.ts +++ b/src/strategies/aelin-council/index.ts @@ -1,8 +1,7 @@ import { getAddress } from '@ethersproject/address'; import { Contract } from '@ethersproject/contracts'; import { JsonRpcProvider } from '@ethersproject/providers'; -import { subgraphRequest } from '../../utils'; -import fetch from 'cross-fetch'; +import { subgraphRequest, customFetch } from '../../utils'; export const author = '0xcdb'; export const version = '1.0.0'; @@ -46,7 +45,7 @@ function returnGraphParams(snapshot: number | string, addresses: string[]) { } const getTokenRates = async () => { - const results = await fetch( + const results = await customFetch( 'https://api.coingecko.com/api/v3/simple/price?ids=aelin%2Cethereum&vs_currencies=usd' ); const rates = await results.json(); diff --git a/src/strategies/aks/index.ts b/src/strategies/aks/index.ts index dc37f3482..097d9def4 100644 --- a/src/strategies/aks/index.ts +++ b/src/strategies/aks/index.ts @@ -1,5 +1,4 @@ -import fetch from 'cross-fetch'; -import { subgraphRequest } from '../../utils'; +import { subgraphRequest, customFetch } from '../../utils'; export const author = 'akshaysoam8'; export const version = '0.0.1'; @@ -28,7 +27,7 @@ const fetchVotingPower = async ( block: number, poolAddresses: string[] ): Promise => { - const response = await fetch(VOTING_API_URL, { + const response = await customFetch(VOTING_API_URL, { method: 'POST', body: JSON.stringify({ block, diff --git a/src/strategies/api-post/index.ts b/src/strategies/api-post/index.ts index 115a4a0c7..9cf170dec 100644 --- a/src/strategies/api-post/index.ts +++ b/src/strategies/api-post/index.ts @@ -1,6 +1,6 @@ import { getAddress } from '@ethersproject/address'; -import fetch from 'cross-fetch'; import { formatUnits } from '@ethersproject/units'; +import { customFetch } from '../../utils'; export const author = 'miertschink'; export const version = '0.1.1'; @@ -20,7 +20,7 @@ export async function strategy( addresses }; - const response = await fetch(options.api, { + const response = await customFetch(options.api, { method: 'POST', headers: { Accept: 'application/json', diff --git a/src/strategies/api-v2/index.ts b/src/strategies/api-v2/index.ts index b9bbfe34b..969b27b38 100644 --- a/src/strategies/api-v2/index.ts +++ b/src/strategies/api-v2/index.ts @@ -1,7 +1,6 @@ import { getAddress } from '@ethersproject/address'; -import fetch from 'cross-fetch'; import { formatUnits } from '@ethersproject/units'; -import { sha256 } from '../../utils'; +import { sha256, customFetch } from '../../utils'; export const author = 'snapshot-labs'; export const version = '0.1.0'; @@ -42,7 +41,7 @@ export async function strategy( `${url}${process.env.SNAPSHOT_API_STRATEGY_SALT}` ); - const response = await fetch(url, { + const response = await customFetch(url, { method, headers: { Accept: 'application/json', diff --git a/src/strategies/api/index.ts b/src/strategies/api/index.ts index d48e05d44..71bce0fd4 100644 --- a/src/strategies/api/index.ts +++ b/src/strategies/api/index.ts @@ -1,6 +1,6 @@ import { getAddress } from '@ethersproject/address'; -import fetch from 'cross-fetch'; import { formatUnits } from '@ethersproject/units'; +import { customFetch } from '../../utils'; export const author = 'ganzai-san'; export const version = '0.1.2'; @@ -38,7 +38,7 @@ export async function strategy( } if (additionalParameters) api_url += '&' + additionalParameters; - const response = await fetch(api_url, { + const response = await customFetch(api_url, { method: 'GET', headers: { Accept: 'application/json', diff --git a/src/strategies/bsc-mvb/index.ts b/src/strategies/bsc-mvb/index.ts index 552cdedcb..bfd4e6293 100644 --- a/src/strategies/bsc-mvb/index.ts +++ b/src/strategies/bsc-mvb/index.ts @@ -1,5 +1,4 @@ -import fetch from 'cross-fetch'; -import { subgraphRequest } from '../../utils'; +import { subgraphRequest, customFetch } from '../../utils'; export const author = 'alberthaotan'; export const version = '0.1.0'; @@ -105,7 +104,7 @@ export async function strategy( }) }; - const graphqlPromise = fetch(Endpoint.graphql, graphqlParams); + const graphqlPromise = customFetch(Endpoint.graphql, graphqlParams); const subgraphPromise = subgraphRequest(Endpoint.subgraph, subgraphParams); const promisesRes = await Promise.all([graphqlPromise, subgraphPromise]); const graphqlData = await promisesRes[0].json(); diff --git a/src/strategies/colony-reputation/index.ts b/src/strategies/colony-reputation/index.ts index 9ea867382..2e70ab201 100644 --- a/src/strategies/colony-reputation/index.ts +++ b/src/strategies/colony-reputation/index.ts @@ -1,6 +1,5 @@ -import { call } from '../../utils'; import { formatUnits } from '@ethersproject/units'; -import fetch from 'cross-fetch'; +import { call, customFetch } from '../../utils'; export const author = 'colony'; export const version = '0.1'; @@ -56,7 +55,7 @@ export async function strategy( const url = `https://xdai.colony.io/reputation/xdai/${rootHashAtBlock}/${options.colonyAddress}/${domain[0]}`; - const res = await fetch(url, { + const res = await customFetch(url, { method: 'GET', headers: { Accept: 'application/json', diff --git a/src/strategies/delegate-registry-v2/index.ts b/src/strategies/delegate-registry-v2/index.ts index 7e4b8bfe7..4837bacc9 100644 --- a/src/strategies/delegate-registry-v2/index.ts +++ b/src/strategies/delegate-registry-v2/index.ts @@ -1,8 +1,7 @@ -import fetch from 'cross-fetch'; import { StaticJsonRpcProvider } from '@ethersproject/providers'; import { Strategy } from '@snapshot-labs/snapshot.js/dist/src/voting/types'; -import { getScoresDirect } from '../../utils'; import { getAddress } from '@ethersproject/address'; +import { getScoresDirect, customFetch } from '../../utils'; export const author = 'gnosis'; export const version = '0.0.2'; @@ -34,7 +33,7 @@ export async function strategy( if (options.strategies.length > 8) throw new Error('Maximum 8 strategies allowed'); - const response = await fetch( + const response = await customFetch( `${options.backendUrl}/api/${space}/snapshot/${blockTag}/strategy-formatted-vote-weights`, { method: 'POST', diff --git a/src/strategies/digitalax-genesis-contribution/index.ts b/src/strategies/digitalax-genesis-contribution/index.ts index 1945b9905..20de06f3e 100644 --- a/src/strategies/digitalax-genesis-contribution/index.ts +++ b/src/strategies/digitalax-genesis-contribution/index.ts @@ -1,7 +1,6 @@ -import { subgraphRequest, multicall } from '../../utils'; import { BigNumberish } from '@ethersproject/bignumber'; import { formatUnits } from '@ethersproject/units'; -import fetch from 'cross-fetch'; +import { subgraphRequest, multicall, customFetch } from '../../utils'; export const author = 'onigiri-x'; export const version = '0.1.0'; @@ -137,7 +136,7 @@ async function getConversionMonaPerETH(block) { const coingeckoApiURL = `https://api.coingecko.com/api/v3/coins/monavale/market_chart/range?vs_currency=eth&from=${ block.timestamp - 100000 }&to=${block.timestamp}`; - const coingeckoData = await fetch(coingeckoApiURL) + const coingeckoData = await customFetch(coingeckoApiURL) .then(async (r) => { const json = await r.json(); return json; diff --git a/src/strategies/erc20-price/index.ts b/src/strategies/erc20-price/index.ts index 9c64ccdc3..893aee569 100644 --- a/src/strategies/erc20-price/index.ts +++ b/src/strategies/erc20-price/index.ts @@ -1,4 +1,4 @@ -import fetch from 'cross-fetch'; +import { customFetch } from '../../utils'; import { strategy as erc20BalanceOfStrategy } from '../erc20-balance-of'; export const author = 'snapshot-labs'; @@ -35,7 +35,7 @@ export async function strategy( const coingeckoApiURL = `https://api.coingecko.com/api/v3/coins/${platform}/contract/${address}/market_chart/range?vs_currency=${currency}&from=${ block.timestamp - 100000 }&to=${block.timestamp}`; - const coingeckoData = await fetch(coingeckoApiURL) + const coingeckoData = await customFetch(coingeckoApiURL) .then(async (r) => { const json = await r.json(); return json; diff --git a/src/strategies/erc20-received/index.ts b/src/strategies/erc20-received/index.ts index 99c8bba03..7c10ef79b 100644 --- a/src/strategies/erc20-received/index.ts +++ b/src/strategies/erc20-received/index.ts @@ -1,7 +1,7 @@ -import fetch from 'cross-fetch'; import { Web3Provider } from '@ethersproject/providers'; import { formatUnits } from '@ethersproject/units'; import { BigNumber } from '@ethersproject/bignumber'; +import { customFetch } from '../../utils'; export const author = 'mccallofthewild'; export const version = '0.1.0'; @@ -32,7 +32,7 @@ export async function strategy( } = options; const loadJWT = async (dfuseApiKey: string): Promise => - fetch('https://auth.dfuse.io/v1/auth/issue', { + customFetch('https://auth.dfuse.io/v1/auth/issue', { method: 'POST', headers: { Accept: 'application/json', @@ -47,7 +47,7 @@ export async function strategy( data: { searchTransactions: { edges } } - } = await fetch('https://mainnet.eth.dfuse.io/graphql', { + } = await customFetch('https://mainnet.eth.dfuse.io/graphql', { method: 'POST', headers: { Accept: 'application/json', diff --git a/src/strategies/eth-wallet-age/index.ts b/src/strategies/eth-wallet-age/index.ts index d71f89584..a41a53598 100644 --- a/src/strategies/eth-wallet-age/index.ts +++ b/src/strategies/eth-wallet-age/index.ts @@ -1,12 +1,12 @@ import { EnumType } from 'json-to-graphql-query'; -import fetch from 'cross-fetch'; -import { subgraphRequest } from '../../utils'; + +import { subgraphRequest, customFetch } from '../../utils'; export const author = 'ChaituVR'; export const version = '0.1.0'; const getJWT = async (dfuseApiKey) => { - const rawResponse = await fetch('https://auth.dfuse.io/v1/auth/issue', { + const rawResponse = await customFetch('https://auth.dfuse.io/v1/auth/issue', { method: 'POST', headers: { Accept: 'application/json', diff --git a/src/strategies/ethermon-erc721/index.ts b/src/strategies/ethermon-erc721/index.ts index 1fa0bfc18..b7a4bb95d 100644 --- a/src/strategies/ethermon-erc721/index.ts +++ b/src/strategies/ethermon-erc721/index.ts @@ -1,6 +1,5 @@ -import fetch from 'cross-fetch'; import { BigNumber } from '@ethersproject/bignumber'; -import { Multicaller } from '../../utils'; +import { Multicaller, customFetch } from '../../utils'; export const author = 'syedMohib44'; export const version = '0.0.2'; @@ -59,7 +58,7 @@ export async function strategy( const monObject: Record = await multi2.execute(); - const response = await fetch( + const response = await customFetch( 'https://storageapi.fleek.co/' + options.tokenWeightIPFS, { method: 'GET', diff --git a/src/strategies/etherorcs-combo-balanceof/index.ts b/src/strategies/etherorcs-combo-balanceof/index.ts index b750b10fd..6476d91b2 100644 --- a/src/strategies/etherorcs-combo-balanceof/index.ts +++ b/src/strategies/etherorcs-combo-balanceof/index.ts @@ -1,4 +1,4 @@ -import fetch from 'cross-fetch'; +import { customFetch } from '../../utils'; export const author = 'tempest-sol'; export const version = '0.1.1'; @@ -15,7 +15,7 @@ export async function strategy( addresses ): Promise> { const count: Record = {}; - const res = await fetch('https://open-api.etherorcs.com/api/graphql', { + const res = await customFetch('https://open-api.etherorcs.com/api/graphql', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ diff --git a/src/strategies/flexa-capacity-staking/index.ts b/src/strategies/flexa-capacity-staking/index.ts index 1c26520dd..50600d094 100644 --- a/src/strategies/flexa-capacity-staking/index.ts +++ b/src/strategies/flexa-capacity-staking/index.ts @@ -1,7 +1,7 @@ -import fetch from 'cross-fetch'; import { getAddress } from '@ethersproject/address'; import { BigNumber } from '@ethersproject/bignumber'; import { formatUnits } from '@ethersproject/units'; +import { customFetch } from '../../utils'; export const author = 'amptoken'; export const version = '0.1.0'; @@ -18,7 +18,7 @@ export async function strategy( ',' )}&snapshot=${snapshot}`; - const response = await fetch(apiUrl, { + const response = await customFetch(apiUrl, { method: 'GET', headers: { Accept: 'application/vnd.flexa.capacity.v1+json' diff --git a/src/strategies/forta-shares/index.ts b/src/strategies/forta-shares/index.ts index 9bc71f1c4..7e52793eb 100644 --- a/src/strategies/forta-shares/index.ts +++ b/src/strategies/forta-shares/index.ts @@ -1,7 +1,6 @@ -import fetch from 'cross-fetch'; -import { multicall } from '../../utils'; import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; import { formatUnits } from '@ethersproject/units'; +import { multicall, customFetch } from '../../utils'; export const author = 'emanuel-sol'; export const version = '0.0.1'; @@ -37,7 +36,7 @@ export async function strategy( addresses: addresses }; - const response = await fetch('https://api.forta.network/stats/shares', { + const response = await customFetch('https://api.forta.network/stats/shares', { method: 'POST', headers: { Accept: 'application/json', diff --git a/src/strategies/galaxy-nft-with-score/index.ts b/src/strategies/galaxy-nft-with-score/index.ts index 2797aba1f..67c4995f3 100644 --- a/src/strategies/galaxy-nft-with-score/index.ts +++ b/src/strategies/galaxy-nft-with-score/index.ts @@ -1,5 +1,4 @@ -import fetch from 'cross-fetch'; -import { subgraphRequest } from '../../utils'; +import { subgraphRequest, customFetch } from '../../utils'; export const author = 'alberthaotan'; export const version = '0.3.2'; @@ -118,7 +117,7 @@ export async function strategy( }) }; - const graphqlPromise = fetch(Networks[network].graphql, graphqlParams); + const graphqlPromise = customFetch(Networks[network].graphql, graphqlParams); const subgraphPromise = subgraphRequest( options.params.subgraph ? options.params.subgraph diff --git a/src/strategies/galxe-loyalty-points/index.ts b/src/strategies/galxe-loyalty-points/index.ts index 5df3e24d2..a55b14244 100644 --- a/src/strategies/galxe-loyalty-points/index.ts +++ b/src/strategies/galxe-loyalty-points/index.ts @@ -1,5 +1,5 @@ -import fetch from 'cross-fetch'; import { error } from 'console'; +import { customFetch } from '../../utils'; export const author = 'HaynarCool'; export const version = '0.1.0'; @@ -46,7 +46,7 @@ export async function strategy( } }) }; - const graphqlData = await fetch(graphqlUrl, graphqlParams) + const graphqlData = await customFetch(graphqlUrl, graphqlParams) .then((r) => r.json()) .catch((e) => { console.error('query galxe user loyalty points failed'); diff --git a/src/strategies/iotex-staked-balance/index.ts b/src/strategies/iotex-staked-balance/index.ts index b0c364af8..ce51ec238 100644 --- a/src/strategies/iotex-staked-balance/index.ts +++ b/src/strategies/iotex-staked-balance/index.ts @@ -1,4 +1,5 @@ -import fetch from 'cross-fetch'; +import { customFetch } from '../../utils'; + interface ApiReturn { voteWeight: string[]; } @@ -23,17 +24,20 @@ export async function strategy( ) { const height = typeof snapshot === 'number' ? snapshot : 10000000000; const apiUrl = getUrl(network); - const response = await fetch(`${apiUrl}/api.StakingService.VoteByHeight`, { - method: 'POST', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - address: addresses, - height - }) - }); + const response = await customFetch( + `${apiUrl}/api.StakingService.VoteByHeight`, + { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + address: addresses, + height + }) + } + ); const ret: ApiReturn = await response.json(); return Object.fromEntries( diff --git a/src/strategies/karma-discord-roles/index.ts b/src/strategies/karma-discord-roles/index.ts index 5a645a47c..9e805d8f8 100644 --- a/src/strategies/karma-discord-roles/index.ts +++ b/src/strategies/karma-discord-roles/index.ts @@ -1,5 +1,5 @@ -import fetch from 'cross-fetch'; import { getAddress } from '@ethersproject/address'; +import { customFetch } from '../../utils'; export const author = 'show-karma'; export const version = '1.0.1'; @@ -48,7 +48,10 @@ export async function strategy( } }; - const response = await fetch(`${KARMA_API}?${queryParams}`, requestOptions); + const response = await customFetch( + `${KARMA_API}?${queryParams}`, + requestOptions + ); const parsedResponse = !response.ok ? [] : await response.json(); const delegates = parsedResponse.data?.delegates || []; diff --git a/src/strategies/l2-deversifi/index.ts b/src/strategies/l2-deversifi/index.ts index 4a1e57112..75e1d1139 100644 --- a/src/strategies/l2-deversifi/index.ts +++ b/src/strategies/l2-deversifi/index.ts @@ -1,5 +1,5 @@ -import fetch from 'cross-fetch'; import examplesFile from './examples.json'; +import { customFetch } from '../../utils'; export const author = 'deversifi'; export const version = '0.1.0'; @@ -25,7 +25,7 @@ export async function strategy( Array.from(Array(pages)).forEach((x, i) => { const pageAddresses = addresses.slice(limit * i, limit * (i + 1)); promises.push( - fetch(`${api_url}&addresses=${pageAddresses.join('&addresses=')}`, { + customFetch(`${api_url}&addresses=${pageAddresses.join('&addresses=')}`, { method: 'GET', headers: { Accept: 'application/json', diff --git a/src/strategies/landdao-token-tiers/index.ts b/src/strategies/landdao-token-tiers/index.ts index 1cb860f33..e2b35eb92 100644 --- a/src/strategies/landdao-token-tiers/index.ts +++ b/src/strategies/landdao-token-tiers/index.ts @@ -1,6 +1,5 @@ -import fetch from 'cross-fetch'; -import { Multicaller } from '../../utils'; import { BigNumber } from '@ethersproject/bignumber'; +import { Multicaller, customFetch } from '../../utils'; export const author = 'ethantddavis'; export const version = '0.1.0'; @@ -50,7 +49,7 @@ export async function strategy( await callWalletToAddresses.execute(); // fetch ipfs tier weights - const response = await fetch( + const response = await customFetch( 'https://ipfs.io/ipfs/' + options.tokenWeightIPFS, { method: 'GET', diff --git a/src/strategies/masterchef-pool-balance-price/index.ts b/src/strategies/masterchef-pool-balance-price/index.ts index 17667d216..1ceb8d90e 100644 --- a/src/strategies/masterchef-pool-balance-price/index.ts +++ b/src/strategies/masterchef-pool-balance-price/index.ts @@ -1,7 +1,6 @@ import { formatUnits } from '@ethersproject/units'; -import { multicall } from '../../utils'; import { BigNumber } from '@ethersproject/bignumber'; -import fetch from 'cross-fetch'; +import { multicall, customFetch } from '../../utils'; export const author = 'joaomajesus'; export const version = '0.2.0'; @@ -453,7 +452,7 @@ async function getPrice(network, provider, address, blockTag) { log.push(`to = ${from}`); log.push(`coingeckoApiURL = ${coingeckoApiURL}`); - const coingeckoData = await fetch(coingeckoApiURL) + const coingeckoData = await customFetch(coingeckoApiURL) .then(async (r) => { log.push(`coingeco response = ${JSON.stringify(r, undefined, 2)}`); diff --git a/src/strategies/meebitsdao/index.ts b/src/strategies/meebitsdao/index.ts index af6940bd5..a33883e9c 100644 --- a/src/strategies/meebitsdao/index.ts +++ b/src/strategies/meebitsdao/index.ts @@ -1,5 +1,4 @@ -import { multicall } from '../../utils'; -import fetch from 'cross-fetch'; +import { multicall, customFetch } from '../../utils'; export const author = 'peters-josh'; export const version = '0.1.0'; @@ -33,7 +32,7 @@ export async function strategy( blockTag }); - const resp = await fetch(options.apiUrl); + const resp = await customFetch(options.apiUrl); const tokenStatus = await resp.json(); function checkActivated(address: any) { diff --git a/src/strategies/offchain-delegation/index.ts b/src/strategies/offchain-delegation/index.ts index c03fc1991..482cc932b 100644 --- a/src/strategies/offchain-delegation/index.ts +++ b/src/strategies/offchain-delegation/index.ts @@ -1,6 +1,5 @@ -import fetch from 'cross-fetch'; import { getAddress } from '@ethersproject/address'; -import { getScoresDirect } from '../../utils'; +import { getScoresDirect, customFetch } from '../../utils'; export const author = 'bonustrack'; export const version = '0.1.0'; @@ -35,7 +34,7 @@ export async function strategy( const SPREADSHEET_ID = options.sheetId ?? DEFAULT_SPREADSHEET_ID; const GID = options.gid ?? DEFAULT_GID; const url = `https://docs.google.com/spreadsheets/d/e/${SPREADSHEET_ID}/pub?gid=${GID}&single=true&output=csv`; - const res = await fetch(url); + const res = await customFetch(url); const text = await res.text(); const csv = csvToJson(text) || []; const delegations = Object.fromEntries( diff --git a/src/strategies/orange-reputation-based-voting/index.ts b/src/strategies/orange-reputation-based-voting/index.ts index 6265b6081..137ae130e 100644 --- a/src/strategies/orange-reputation-based-voting/index.ts +++ b/src/strategies/orange-reputation-based-voting/index.ts @@ -1,4 +1,4 @@ -import fetch from 'cross-fetch'; +import { customFetch } from '../../utils'; export const author = 'orange-protocol'; export const version = '0.1.0'; @@ -26,7 +26,7 @@ export async function strategy( query, variables: {} }; - const rawResponse = await fetch( + const rawResponse = await customFetch( 'https://api.orangeprotocol.io/orange2c/query', { method: 'POST', diff --git a/src/strategies/proxyprotocol-erc721-balance-of/index.ts b/src/strategies/proxyprotocol-erc721-balance-of/index.ts index 4a87c7037..8472f1f45 100644 --- a/src/strategies/proxyprotocol-erc721-balance-of/index.ts +++ b/src/strategies/proxyprotocol-erc721-balance-of/index.ts @@ -1,4 +1,4 @@ -import fetch from 'cross-fetch'; +import { customFetch } from '../../utils'; import { strategy as erc721BalanceOfStrategy } from '../erc721'; export const author = 'rawrjustin'; @@ -29,7 +29,7 @@ export async function strategy( const params = { proxyAddresses: addresses }; - const apiResponse = await fetch(url, { + const apiResponse = await customFetch(url, { method: 'POST', headers: { Accept: 'application/json', diff --git a/src/strategies/reverse-voting-escrow/index.ts b/src/strategies/reverse-voting-escrow/index.ts index b12ce4ee0..bef5db183 100644 --- a/src/strategies/reverse-voting-escrow/index.ts +++ b/src/strategies/reverse-voting-escrow/index.ts @@ -1,6 +1,6 @@ import { BigNumber } from '@ethersproject/bignumber'; -import { Multicaller } from '../../utils'; -import fetch from 'cross-fetch'; + +import { Multicaller, customFetch } from '../../utils'; import { formatUnits } from '@ethersproject/units'; export const author = 'nascentxyz'; @@ -62,7 +62,7 @@ export async function strategy( // [GET] all-claim-data/:account: returns the claim data for a specific account from all the cohorts it is in // [GET] all-data: returns all claim data - const allData = await fetch(`https://club.agora.space/api/all-data`); + const allData = await customFetch(`https://club.agora.space/api/all-data`); const allDataJSON = await allData.json(); // ** Claimed $CLUB tokens ** // diff --git a/src/strategies/sablier-v2/queries.ts b/src/strategies/sablier-v2/queries.ts index 6d82bec16..1dbe7c7a5 100644 --- a/src/strategies/sablier-v2/queries.ts +++ b/src/strategies/sablier-v2/queries.ts @@ -8,8 +8,7 @@ import type { } from './configuration'; import { abi, deployments, queries, page } from './configuration'; -import { multicall, subgraphRequest } from '../../utils'; -import fetch from 'cross-fetch'; +import { multicall, subgraphRequest, customFetch } from '../../utils'; /** * Query the subgraph for all the streams owned by all recipients. @@ -457,7 +456,7 @@ async function getLatestBlock( const query = `{indexingStatusForCurrentVersion(subgraphName: \"${name}\"){ chains { latestBlock { number }}}}`; - const response = await fetch(url, { + const response = await customFetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ query }), diff --git a/src/strategies/safe-vested/index.ts b/src/strategies/safe-vested/index.ts index 129f4ce2a..f74228239 100644 --- a/src/strategies/safe-vested/index.ts +++ b/src/strategies/safe-vested/index.ts @@ -1,9 +1,8 @@ -import fetch from 'cross-fetch'; import { formatUnits, parseUnits } from '@ethersproject/units'; import { isAddress } from '@ethersproject/address'; import { isHexString } from '@ethersproject/bytes'; -import { Multicaller } from '../../utils'; +import { customFetch, Multicaller } from '../../utils'; export const author = 'dasanra'; export const version = '0.2.0'; @@ -43,7 +42,7 @@ async function loadAllocationMap( options: Options ): Promise> { if (!_allocationMap) { - const response = await fetch(options.allocationsSource, { + const response = await customFetch(options.allocationsSource, { method: 'GET', headers: { Accept: 'application/json', diff --git a/src/strategies/spreadsheet/index.ts b/src/strategies/spreadsheet/index.ts index eb3ca106a..f3fd0eb73 100644 --- a/src/strategies/spreadsheet/index.ts +++ b/src/strategies/spreadsheet/index.ts @@ -1,4 +1,4 @@ -import fetch from 'cross-fetch'; +import { customFetch } from '../../utils'; export const author = 'bonustrack'; export const version = '0.1.0'; @@ -27,7 +27,7 @@ export async function strategy( const block = await provider.getBlock(snapshot); const ts = block.timestamp; - const res = await fetch( + const res = await customFetch( `https://docs.google.com/spreadsheets/d/e/${options.sheetId}/pub?gid=${ options.gid || '0' }&single=true&output=csv` diff --git a/src/strategies/starsharks/index.ts b/src/strategies/starsharks/index.ts index 15bc0e8b6..e388df0c1 100644 --- a/src/strategies/starsharks/index.ts +++ b/src/strategies/starsharks/index.ts @@ -1,6 +1,6 @@ -import fetch from 'cross-fetch'; import { formatUnits } from '@ethersproject/units'; const { getAddress } = require('@ethersproject/address'); +import { customFetch } from '../../utils'; export const author = 'starsharks'; export const version = '0.1.0'; @@ -29,7 +29,7 @@ async function getAddressesDespoits({ block_id, network }: DepositListRequest): Promise { - const res = await fetch(API_URLS[network], { + const res = await customFetch(API_URLS[network], { method: 'POST', headers: { Accept: 'application/json', 'Content-Type': 'application/json' }, body: JSON.stringify({ diff --git a/src/strategies/synthetic-nouns-with-claimer/index.ts b/src/strategies/synthetic-nouns-with-claimer/index.ts index 914cf3023..e83230507 100644 --- a/src/strategies/synthetic-nouns-with-claimer/index.ts +++ b/src/strategies/synthetic-nouns-with-claimer/index.ts @@ -1,6 +1,6 @@ -import { Multicaller } from '../../utils'; -import fetch from 'cross-fetch'; import { getAddress } from '@ethersproject/address'; +import { Multicaller, customFetch } from '../../utils'; + export const author = 'stephancill'; export const version = '0.1.0'; @@ -19,7 +19,7 @@ export async function strategy( const checksummedAddresses = addresses.map((address) => getAddress(address)); // Get the minter from zora api - const mints = await fetch('https://api.zora.co/graphql', { + const mints = await customFetch('https://api.zora.co/graphql', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ diff --git a/src/strategies/xdai-stakers-and-holders/index.ts b/src/strategies/xdai-stakers-and-holders/index.ts index 03a60a825..3cd55db04 100644 --- a/src/strategies/xdai-stakers-and-holders/index.ts +++ b/src/strategies/xdai-stakers-and-holders/index.ts @@ -1,6 +1,5 @@ -import fetch from 'cross-fetch'; import { formatUnits } from '@ethersproject/units'; -import { subgraphRequest } from '../../utils'; +import { subgraphRequest, customFetch } from '../../utils'; export const author = 'maxaleks'; export const version = '0.1.0'; @@ -40,7 +39,7 @@ async function getUsers(addresses, snapshot, userType) { } const getXdaiBlockNumber = async (timestamp: number): Promise => - fetch( + customFetch( `https://blockscout.com/xdai/mainnet/api?module=block&action=getblocknobytime×tamp=${timestamp}&closest=before` ) .then((r) => r.json()) diff --git a/src/strategies/xrc20-balance-of/index.ts b/src/strategies/xrc20-balance-of/index.ts index f78d9880c..301157757 100644 --- a/src/strategies/xrc20-balance-of/index.ts +++ b/src/strategies/xrc20-balance-of/index.ts @@ -1,5 +1,5 @@ -import fetch from 'cross-fetch'; import { strategy as erc20BalanceStrategy } from '../erc20-balance-of'; +import { customFetch } from '../../utils'; interface ApiReturn { balance: string[]; @@ -35,7 +35,7 @@ export async function strategy( ); const apiUrl = getUrl(network); - const response = await fetch( + const response = await customFetch( `${apiUrl}/api.AccountService.Erc20TokenBalanceByHeight`, { method: 'POST', diff --git a/src/strategies/zrx-voting-power/index.ts b/src/strategies/zrx-voting-power/index.ts index 24d0bafb1..47954e044 100644 --- a/src/strategies/zrx-voting-power/index.ts +++ b/src/strategies/zrx-voting-power/index.ts @@ -1,7 +1,6 @@ -import fetch from 'cross-fetch'; import { BigNumber } from '@ethersproject/bignumber'; import { formatUnits } from '@ethersproject/units'; -import { multicall } from '../../utils'; +import { multicall, customFetch } from '../../utils'; import { strategy as erc20BalanceOfStrategy } from '../erc20-balance-of'; export const author = 'benlyaunzon'; @@ -43,7 +42,7 @@ export async function strategy( snapshot ); - const zrxStakingPoolsRes = await fetch(ZRX_STAKING_POOLS[network]); + const zrxStakingPoolsRes = await customFetch(ZRX_STAKING_POOLS[network]); const { stakingPools } = await zrxStakingPoolsRes.json(); const response: BigNumber[] = await multicall( network, diff --git a/src/utils.ts b/src/utils.ts index f83ed6012..449acaae8 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -67,7 +67,11 @@ export async function getScoresDirect( } } -export function customFetch(url, options, timeout = 20000): Promise { +export function customFetch( + url: RequestInfo | URL, + options: RequestInit = {}, + timeout = 20000 +): Promise { return Promise.race([ fetch(url, options), new Promise((_, reject) => diff --git a/src/validations/karma-eas-attestation/index.ts b/src/validations/karma-eas-attestation/index.ts index adb7ba365..f4d4d24dc 100644 --- a/src/validations/karma-eas-attestation/index.ts +++ b/src/validations/karma-eas-attestation/index.ts @@ -1,5 +1,5 @@ import Validation from '../validation'; -import fetch from 'cross-fetch'; +import { customFetch } from '../../utils'; interface Attestation { attester: string; @@ -47,7 +47,7 @@ async function isAttested(schemaId: string, address: string, network = 1) { const easUrl = EASNetworks[network]; if (!easUrl) throw new Error(`EAS network ${network} not supported`); - const response: SubgraphResponse = await fetch(easUrl, { + const response: SubgraphResponse = await customFetch(easUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ diff --git a/src/validations/passport-gated/index.ts b/src/validations/passport-gated/index.ts index 6bad1f765..d8e8f3118 100644 --- a/src/validations/passport-gated/index.ts +++ b/src/validations/passport-gated/index.ts @@ -1,5 +1,5 @@ -import fetch from 'cross-fetch'; import snapshot from '@snapshot-labs/snapshot.js'; +import { customFetch } from '../../utils'; import STAMPS from './stampsMetadata.json'; import Validation from '../validation'; @@ -68,9 +68,12 @@ async function validateStamps( ): Promise { if (requiredStamps.length === 0) return true; - const stampsResponse = await fetch(GET_PASSPORT_STAMPS_URI + currentAddress, { - headers - }); + const stampsResponse = await customFetch( + GET_PASSPORT_STAMPS_URI + currentAddress, + { + headers + } + ); const stampsData = await stampsResponse.json(); if (!stampsData?.items) { @@ -114,7 +117,7 @@ async function validatePassportScore( scoreThreshold: number ): Promise { // always hit the /submit-passport endpoint to get the latest passport score - const submittedPassport = await fetch(POST_SUBMIT_PASSPORT_URI, { + const submittedPassport = await customFetch(POST_SUBMIT_PASSPORT_URI, { headers, method: 'POST', body: JSON.stringify({ address: currentAddress, scorer_id: SCORER_ID }) @@ -137,9 +140,12 @@ async function validatePassportScore( // Try to fetch Passport Score if still processing (submittedPassport.status === 'PROCESSING') for (let i = 0; i < PASSPORT_SCORER_MAX_ATTEMPTS; i++) { - const scoreResponse = await fetch(GET_PASSPORT_SCORE_URI + currentAddress, { - headers - }); + const scoreResponse = await customFetch( + GET_PASSPORT_SCORE_URI + currentAddress, + { + headers + } + ); const scoreData = await scoreResponse.json(); if (scoreResponse.ok && scoreData.status === 'DONE') { From b89f3d9a55eb3d25c0f0cb6c58a34c4c4c1f808e Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Mon, 7 Oct 2024 00:52:34 +0530 Subject: [PATCH 762/815] fix: Abort fetch in customFetch on timeout (#1601) --- src/utils.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/utils.ts b/src/utils.ts index 449acaae8..4061818f6 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -72,10 +72,21 @@ export function customFetch( options: RequestInit = {}, timeout = 20000 ): Promise { + const controller = new AbortController(); + const { signal } = controller; + const fetchOptions = { ...options, signal }; + return Promise.race([ - fetch(url, options), - new Promise((_, reject) => - setTimeout(() => reject(new Error('API request timeout')), timeout) + fetch(url, fetchOptions).catch((error) => { + if (error.name === 'AbortError') { + throw new Error('API request timeout'); + } + throw error; + }), + new Promise(() => + setTimeout(() => { + controller.abort(); + }, timeout) ) ]); } From 902c431857931cb1189a401840a3963ef7d0513a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 11:08:40 +0530 Subject: [PATCH 763/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.20 (#1595) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 5389e3c4f..3253e7846 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.18", + "@snapshot-labs/snapshot.js": "^0.12.20", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 3a4ae8c15..085df2d47 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.18": - version "0.12.18" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.18.tgz#58421fc0fd8c424b76923a2d9b41e1f73c4767b0" - integrity sha512-zGRFgWws3cjQUZRw12uOpHlrdUgctMNRWlMu2N6QYD1VKQKZ21nW4ONanmSE/eWsQtiQL11wAAApaFxa4DdosA== +"@snapshot-labs/snapshot.js@^0.12.20": + version "0.12.21" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.21.tgz#c8ed9b5e4658648d9013721dea8489ed73768eb0" + integrity sha512-n/A+5YfyFU33FED2Qxz2a/APDD/Mo33EKWNQurSPC8u47Z4TNCa9yQxd+7EnLHgYsyg2zeXBjy2d3oV3oVKphw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 69da3b09fe2f8c997331d1339e4ff3c836be5813 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 8 Oct 2024 18:04:00 +0530 Subject: [PATCH 764/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.22 (#1602) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 3253e7846..140d8cab9 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.20", + "@snapshot-labs/snapshot.js": "^0.12.22", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 085df2d47..3cdf275d2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.20": - version "0.12.21" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.21.tgz#c8ed9b5e4658648d9013721dea8489ed73768eb0" - integrity sha512-n/A+5YfyFU33FED2Qxz2a/APDD/Mo33EKWNQurSPC8u47Z4TNCa9yQxd+7EnLHgYsyg2zeXBjy2d3oV3oVKphw== +"@snapshot-labs/snapshot.js@^0.12.22": + version "0.12.22" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.22.tgz#72e29301c48bfa1d884cfa2c1a3d58815b778c6e" + integrity sha512-t8AwPc7LIfhoa69f62GopdnwXlWamvmi6jhIhNs9mSkJNTmixCXkQJtYTzWh7wko1GR1hMqX5M0jutiASCsOYw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 442c51d206634b262209e676abe6d111224cf753 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 9 Oct 2024 11:52:40 +0530 Subject: [PATCH 765/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.23 (#1603) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 140d8cab9..8244ed5dc 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.22", + "@snapshot-labs/snapshot.js": "^0.12.23", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 3cdf275d2..46c1fb223 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.22": - version "0.12.22" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.22.tgz#72e29301c48bfa1d884cfa2c1a3d58815b778c6e" - integrity sha512-t8AwPc7LIfhoa69f62GopdnwXlWamvmi6jhIhNs9mSkJNTmixCXkQJtYTzWh7wko1GR1hMqX5M0jutiASCsOYw== +"@snapshot-labs/snapshot.js@^0.12.23": + version "0.12.23" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.23.tgz#31fea49f8cb1d3fccf9d5898f05edd9c68500d69" + integrity sha512-n3qJUblvZFhaGzqW+TUL32YkNnPl7uAKwrofx1rG6em3E/LjE9Wr2HdbFtdBzIK0QiZQPYdHzQNokjE6jJJ+tw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From fc5b1d1260797f080c19c8979779de85e1778263 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 10 Oct 2024 14:31:00 +0530 Subject: [PATCH 766/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.24 (#1605) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 8244ed5dc..c8bb93a10 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.23", + "@snapshot-labs/snapshot.js": "^0.12.24", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 46c1fb223..21aad61ea 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.23": - version "0.12.23" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.23.tgz#31fea49f8cb1d3fccf9d5898f05edd9c68500d69" - integrity sha512-n3qJUblvZFhaGzqW+TUL32YkNnPl7uAKwrofx1rG6em3E/LjE9Wr2HdbFtdBzIK0QiZQPYdHzQNokjE6jJJ+tw== +"@snapshot-labs/snapshot.js@^0.12.24": + version "0.12.24" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.24.tgz#9a10e76297571b3c5eb31b2881a6b7514dbfc1e8" + integrity sha512-ggkMhVUzokOXwrHpdLjmnwhm33g7lqkjcx8aBbu4Jvhit2ZYq2SRnZUUCa+Tn5bP6cf7TdnUvvPIS78LCdZstw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 2eb039bb3245e42123c4eda1447cc35daf47ff26 Mon Sep 17 00:00:00 2001 From: Juanma Hidalgo Date: Fri, 11 Oct 2024 15:14:13 +0200 Subject: [PATCH 767/815] feat: use enums instead of strings in graphql queries (#1607) --- .../decentraland-wearable-rarity/index.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/strategies/decentraland-wearable-rarity/index.ts b/src/strategies/decentraland-wearable-rarity/index.ts index ce800ea82..846f7bceb 100644 --- a/src/strategies/decentraland-wearable-rarity/index.ts +++ b/src/strategies/decentraland-wearable-rarity/index.ts @@ -1,3 +1,4 @@ +import { EnumType } from 'json-to-graphql-query'; import { getAddress } from '@ethersproject/address'; import { subgraphRequest } from '../../utils'; @@ -53,16 +54,16 @@ export async function strategy( __args: { where: { itemType_in: [ - 'wearable_v1', - 'wearable_v2', - 'smart_wearable_v1', - 'emote_v1' + new EnumType('wearable_v1'), + new EnumType('wearable_v2'), + new EnumType('smart_wearable_v1'), + new EnumType('emote_v1') ], owner_in: chunk.map((address) => address.toLowerCase()), id_gt: '' }, - orderBy: 'id', - orderDirection: 'asc', + orderBy: new EnumType('id'), + orderDirection: new EnumType('asc'), first: 1000 }, id: true, From 50d11295a931bea6a8068e35ae8ec5747dd0bdb7 Mon Sep 17 00:00:00 2001 From: Corey Caplan Date: Sun, 13 Oct 2024 10:02:17 -0400 Subject: [PATCH 768/815] added WLFI voting strategy for untransferable tokens (#1609) --- src/strategies/index.ts | 2 ++ .../README.md | 13 +++++++ .../examples.json | 20 +++++++++++ .../index.ts | 34 +++++++++++++++++++ .../schema.json | 34 +++++++++++++++++++ 5 files changed, 103 insertions(+) create mode 100644 src/strategies/world-liberty-financial-erc20-balance-of-votes/README.md create mode 100644 src/strategies/world-liberty-financial-erc20-balance-of-votes/examples.json create mode 100644 src/strategies/world-liberty-financial-erc20-balance-of-votes/index.ts create mode 100644 src/strategies/world-liberty-financial-erc20-balance-of-votes/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 50dc61925..863f5e3cf 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -455,6 +455,7 @@ import * as candyNftStaking from './candy-nft-staking'; import * as pom from './pom'; import * as superboring from './superboring'; import * as erableGovernanceV1 from './erable-governance-v1'; +import * as worldLibertyFinancial from './world-liberty-financial-erc20-balance-of-votes'; import * as snxMultichain from './snx-multichain'; const strategies = { @@ -922,6 +923,7 @@ const strategies = { pom, superboring, 'erable-governance-v1': erableGovernanceV1, + 'world-liberty-financial-erc20-balance-of-votes': worldLibertyFinancial, 'snx-multichain': snxMultichain }; diff --git a/src/strategies/world-liberty-financial-erc20-balance-of-votes/README.md b/src/strategies/world-liberty-financial-erc20-balance-of-votes/README.md new file mode 100644 index 000000000..2e7ce1090 --- /dev/null +++ b/src/strategies/world-liberty-financial-erc20-balance-of-votes/README.md @@ -0,0 +1,13 @@ +# world-liberty-financial-erc20-balance-of-votes + +This query returns the balances of the voters for the WLFI ERC20 token while transfers are disabled. + +Here is an example of parameters: + +```json +{ + "address": "0xdA5e1988097297dCdc1f90D4dFE7909e847CBeF6", + "symbol": "WLFI", + "decimals": 18 +} +``` diff --git a/src/strategies/world-liberty-financial-erc20-balance-of-votes/examples.json b/src/strategies/world-liberty-financial-erc20-balance-of-votes/examples.json new file mode 100644 index 000000000..7e2e4dfec --- /dev/null +++ b/src/strategies/world-liberty-financial-erc20-balance-of-votes/examples.json @@ -0,0 +1,20 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "world-liberty-financial-erc20-balance-of-votes", + "params": { + "address": "0xdA5e1988097297dCdc1f90D4dFE7909e847CBeF6", + "symbol": "WLFI", + "decimals": 18 + } + }, + "network": "1", + "addresses": [ + "0x1246E490308db61DCa45ead613f47430De3830ad", + "0xEe7f7f53F0D0c8c56A38e97c5a58E4d321A174dC", + "0xF32e3596f555546ACc4aD6Ef67e1ABF36b134748" + ], + "snapshot": 20942069 + } +] diff --git a/src/strategies/world-liberty-financial-erc20-balance-of-votes/index.ts b/src/strategies/world-liberty-financial-erc20-balance-of-votes/index.ts new file mode 100644 index 000000000..e1b9d114e --- /dev/null +++ b/src/strategies/world-liberty-financial-erc20-balance-of-votes/index.ts @@ -0,0 +1,34 @@ +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'coreycaplan3'; +export const version = '0.1.0'; + +const abi = [ + 'function balanceOfVotes(address account) external view returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multi = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => + multi.call(address, options.address, 'balanceOfVotes', [address]) + ); + const result: Record = await multi.execute(); + + return Object.fromEntries( + Object.entries(result).map(([address, balance]) => [ + address, + parseFloat(formatUnits(balance, options.decimals)) + ]) + ); +} diff --git a/src/strategies/world-liberty-financial-erc20-balance-of-votes/schema.json b/src/strategies/world-liberty-financial-erc20-balance-of-votes/schema.json new file mode 100644 index 000000000..0d5455492 --- /dev/null +++ b/src/strategies/world-liberty-financial-erc20-balance-of-votes/schema.json @@ -0,0 +1,34 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. UNI"], + "maxLength": 16 + }, + "address": { + "type": "string", + "title": "Contract address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 18"], + "minimum": 0 + } + }, + "required": ["address", "decimals"], + "additionalProperties": false + } + } +} From 57c9f1f734a05e41db9a2f44dbf3eee6a26da62a Mon Sep 17 00:00:00 2001 From: JanBajecDev <139755528+JanBajecDev@users.noreply.github.com> Date: Mon, 14 Oct 2024 14:25:53 +0200 Subject: [PATCH 769/815] [staking-amount-duration-exponential] 2 new strategies needed for our project (#1608) * Added 2 new strategies for staking that we need for our project * Update src/strategies/staking-amount-duration-exponential/index.ts Co-authored-by: Chaitanya * Update src/strategies/staking-amount-duration-exponential/index.ts Co-authored-by: Chaitanya * Update src/strategies/staking-amount-duration-exponential/index.ts Co-authored-by: Chaitanya * Update src/strategies/staking-amount-duration-linear/index.ts Co-authored-by: Chaitanya * Update src/strategies/staking-amount-duration-linear/index.ts Co-authored-by: Chaitanya * Update src/strategies/staking-amount-duration-linear/index.ts Co-authored-by: Chaitanya * Update src/strategies/index.ts --------- Co-authored-by: Chaitanya --- src/strategies/index.ts | 6 +- .../README.md | 16 +++++ .../examples.json | 21 +++++++ .../index.ts | 58 +++++++++++++++++++ .../schema.json | 40 +++++++++++++ .../staking-amount-duration-linear/README.md | 15 +++++ .../examples.json | 20 +++++++ .../staking-amount-duration-linear/index.ts | 57 ++++++++++++++++++ .../schema.json | 34 +++++++++++ 9 files changed, 266 insertions(+), 1 deletion(-) create mode 100644 src/strategies/staking-amount-duration-exponential/README.md create mode 100644 src/strategies/staking-amount-duration-exponential/examples.json create mode 100644 src/strategies/staking-amount-duration-exponential/index.ts create mode 100644 src/strategies/staking-amount-duration-exponential/schema.json create mode 100644 src/strategies/staking-amount-duration-linear/README.md create mode 100644 src/strategies/staking-amount-duration-linear/examples.json create mode 100644 src/strategies/staking-amount-duration-linear/index.ts create mode 100644 src/strategies/staking-amount-duration-linear/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 863f5e3cf..0de78ef13 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -457,6 +457,8 @@ import * as superboring from './superboring'; import * as erableGovernanceV1 from './erable-governance-v1'; import * as worldLibertyFinancial from './world-liberty-financial-erc20-balance-of-votes'; import * as snxMultichain from './snx-multichain'; +import * as stakingAmountDurationLinear from './staking-amount-duration-linear'; +import * as stakingAmountDurationExponential from './staking-amount-duration-exponential'; const strategies = { 'delegatexyz-erc721-balance-of': delegatexyzErc721BalanceOf, @@ -924,7 +926,9 @@ const strategies = { superboring, 'erable-governance-v1': erableGovernanceV1, 'world-liberty-financial-erc20-balance-of-votes': worldLibertyFinancial, - 'snx-multichain': snxMultichain + 'snx-multichain': snxMultichain, + 'staking-amount-duration-linear': stakingAmountDurationLinear, + 'staking-amount-duration-exponential': stakingAmountDurationExponential }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/staking-amount-duration-exponential/README.md b/src/strategies/staking-amount-duration-exponential/README.md new file mode 100644 index 000000000..e029c1d7e --- /dev/null +++ b/src/strategies/staking-amount-duration-exponential/README.md @@ -0,0 +1,16 @@ +# staking-amount-duration-exponential + +This is a strategy for calculating voting power with this formula + +Voting Power = Stake Amount × (1 + r) ^ Stake Duration + +Here is an example of parameters: + +```json +{ + "address": "0x6b175474e89094c44da98b954eedeac495271d0f", + "symbol": "DAI", + "decimals": 18, + "rate": 0.1 +} +``` diff --git a/src/strategies/staking-amount-duration-exponential/examples.json b/src/strategies/staking-amount-duration-exponential/examples.json new file mode 100644 index 000000000..b683fdab2 --- /dev/null +++ b/src/strategies/staking-amount-duration-exponential/examples.json @@ -0,0 +1,21 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "staking-amount-duration-exponential", + "params": { + "address": "0x520BDBFCe65CECa0813e51D724804BC7Fd6107dd", + "symbol": "STAKE", + "decimals": 18, + "rate": 0.1 + } + }, + "network": "11155111", + "addresses": [ + "0x57bABaf9E18587C2C1E97244729847604789fC81", + "0xc62BD6B53f46883038b5f018aE74155f07b0e6Db", + "0x6CcE789f04A3f0c291E97042765E07bccC6D73B3" + ], + "snapshot": 6856587 + } +] diff --git a/src/strategies/staking-amount-duration-exponential/index.ts b/src/strategies/staking-amount-duration-exponential/index.ts new file mode 100644 index 000000000..9f0c7d4d8 --- /dev/null +++ b/src/strategies/staking-amount-duration-exponential/index.ts @@ -0,0 +1,58 @@ +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'JanBajecDev'; +export const version = '0.1.0'; + +const abi = [ + 'function getUserStakes(address user) view returns (tuple(uint256 amount, uint256 claimed, uint48 stakeTime, uint8 planId, bool unstaked)[])' +]; +const secondsInAMonth = 30.44 * 24 * 60 * 60; + +interface Stake { + amount: bigint; + claimed: bigint; + stakeTime: bigint; + planId: bigint; + unstaked: boolean; +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const snapshotBlock = await provider.getBlock(blockTag); + + const multi = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => + multi.call(address, options.address, 'getUserStakes', [address]) + ); + const result: Record = await multi.execute(); + + return Object.fromEntries( + Object.entries(result).map(([address, stakes]) => { + let power = 0; + stakes.forEach((stake) => { + if (!stake.unstaked) { + if (snapshotBlock.timestamp > stake.stakeTime) { + const duration = + Number(snapshotBlock.timestamp - stake.stakeTime) / + secondsInAMonth; + const durationRateCalculated = Math.pow(1 + options.rate, duration); + power += + parseFloat(formatUnits(stake.amount, options.decimals)) * + durationRateCalculated; + } + } + }); + + return [address, power]; + }) + ); +} diff --git a/src/strategies/staking-amount-duration-exponential/schema.json b/src/strategies/staking-amount-duration-exponential/schema.json new file mode 100644 index 000000000..2535aefd5 --- /dev/null +++ b/src/strategies/staking-amount-duration-exponential/schema.json @@ -0,0 +1,40 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. UNI"], + "maxLength": 16 + }, + "address": { + "type": "string", + "title": "Contract address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 18"], + "minimum": 0 + }, + "rate": { + "type": "number", + "title": "Rate (Voting Power = Stake Amount × (1 + rate) ^ Stake Duration)", + "examples": ["e.g. 0.1"], + "minimum": 0 + } + }, + "required": ["address", "decimals"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/staking-amount-duration-linear/README.md b/src/strategies/staking-amount-duration-linear/README.md new file mode 100644 index 000000000..5fecd3185 --- /dev/null +++ b/src/strategies/staking-amount-duration-linear/README.md @@ -0,0 +1,15 @@ +# staking-amount-duration-linear + +This is a strategy for calculating voting power with this formula + +Voting Power = Stake Amount × Stake Duration (in time units) + +Here is an example of parameters: + +```json +{ + "address": "0x6b175474e89094c44da98b954eedeac495271d0f", + "symbol": "DAI", + "decimals": 18 +} +``` diff --git a/src/strategies/staking-amount-duration-linear/examples.json b/src/strategies/staking-amount-duration-linear/examples.json new file mode 100644 index 000000000..e008d340b --- /dev/null +++ b/src/strategies/staking-amount-duration-linear/examples.json @@ -0,0 +1,20 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "staking-amount-duration-linear", + "params": { + "address": "0x520BDBFCe65CECa0813e51D724804BC7Fd6107dd", + "symbol": "STAKE", + "decimals": 18 + } + }, + "network": "11155111", + "addresses": [ + "0x57bABaf9E18587C2C1E97244729847604789fC81", + "0xc62BD6B53f46883038b5f018aE74155f07b0e6Db", + "0x6CcE789f04A3f0c291E97042765E07bccC6D73B3" + ], + "snapshot": 6856587 + } +] diff --git a/src/strategies/staking-amount-duration-linear/index.ts b/src/strategies/staking-amount-duration-linear/index.ts new file mode 100644 index 000000000..7e97ba72c --- /dev/null +++ b/src/strategies/staking-amount-duration-linear/index.ts @@ -0,0 +1,57 @@ +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'JanBajecDev'; +export const version = '0.1.0'; + +const abi = [ + 'function getUserStakes(address user) view returns (tuple(uint256 amount, uint256 claimed, uint48 stakeTime, uint8 planId, bool unstaked)[])' +]; +const secondsInAMonth = 30.44 * 24 * 60 * 60; + +interface Stake { + amount: bigint; + claimed: bigint; + stakeTime: bigint; + planId: bigint; + unstaked: boolean; +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const snapshotBlock = await provider.getBlock(blockTag); + + const multi = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => + multi.call(address, options.address, 'getUserStakes', [address]) + ); + const result: Record = await multi.execute(); + + return Object.fromEntries( + Object.entries(result).map(([address, stakes]) => { + let power = 0; + stakes.forEach((stake) => { + if (!stake.unstaked) { + if (snapshotBlock.timestamp > stake.stakeTime) { + const duration = + Number(snapshotBlock.timestamp - stake.stakeTime) / + secondsInAMonth; + power += + parseFloat(formatUnits(stake.amount, options.decimals)) * + duration; + } + } + }); + + return [address, power]; + }) + ); +} diff --git a/src/strategies/staking-amount-duration-linear/schema.json b/src/strategies/staking-amount-duration-linear/schema.json new file mode 100644 index 000000000..0d5455492 --- /dev/null +++ b/src/strategies/staking-amount-duration-linear/schema.json @@ -0,0 +1,34 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. UNI"], + "maxLength": 16 + }, + "address": { + "type": "string", + "title": "Contract address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 18"], + "minimum": 0 + } + }, + "required": ["address", "decimals"], + "additionalProperties": false + } + } +} From e0c64b70f0cf9a689c9a905236897af110b5bfda Mon Sep 17 00:00:00 2001 From: Hrishikesh K Thakkar Date: Tue, 15 Oct 2024 15:33:44 +0530 Subject: [PATCH 770/815] [moxie] Adding Strategy For Moxie Voting Power Calculation (#1604) * Adding Snapshot Strategy for Moxie * adding page limit in subgraph calls * Adding URLs through options * Update src/strategies/index.ts Co-authored-by: Chaitanya * fixing indentation * updating example * Updating PR Feedback to add env * Adding error check for addresses not equal to 1 * updating the example --------- Co-authored-by: Chaitanya --- .env.example | 4 + src/strategies/index.ts | 2 + src/strategies/moxie/README.md | 13 ++ src/strategies/moxie/examples.json | 14 ++ src/strategies/moxie/index.ts | 213 +++++++++++++++++++++++++++++ 5 files changed, 246 insertions(+) create mode 100644 src/strategies/moxie/README.md create mode 100644 src/strategies/moxie/examples.json create mode 100644 src/strategies/moxie/index.ts diff --git a/.env.example b/.env.example index e8f1655fe..8af16a922 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,7 @@ SNAPSHOT_API_STRATEGY_SALT=12345 # Salt for the snapshot API strategy to send a key in header (optional) PASSPORT_API_KEY= # API key for the passport API (optional for other strategies) PASSPORT_SCORER_ID= # Scorer ID for the passport API (optional for other strategies) +MOXIE_API_KEY= # API key for the moxie APIs (optional for other strategies) +MOXIE_PROTOCOL_ID= #Protocol ID for the moxie API (optional for other strategies) +MOXIE_VESTING_ID= # Vesting ID for the moxie API (optional for other strategies) +MOXIE_LIQUDITY_ID= # Liquidity ID for the moxie API (optional for other strategies) \ No newline at end of file diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 0de78ef13..4bb1ea820 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -457,6 +457,7 @@ import * as superboring from './superboring'; import * as erableGovernanceV1 from './erable-governance-v1'; import * as worldLibertyFinancial from './world-liberty-financial-erc20-balance-of-votes'; import * as snxMultichain from './snx-multichain'; +import * as moxie from './moxie' import * as stakingAmountDurationLinear from './staking-amount-duration-linear'; import * as stakingAmountDurationExponential from './staking-amount-duration-exponential'; @@ -927,6 +928,7 @@ const strategies = { 'erable-governance-v1': erableGovernanceV1, 'world-liberty-financial-erc20-balance-of-votes': worldLibertyFinancial, 'snx-multichain': snxMultichain, + 'moxie': moxie, 'staking-amount-duration-linear': stakingAmountDurationLinear, 'staking-amount-duration-exponential': stakingAmountDurationExponential }; diff --git a/src/strategies/moxie/README.md b/src/strategies/moxie/README.md new file mode 100644 index 000000000..47ca4394d --- /dev/null +++ b/src/strategies/moxie/README.md @@ -0,0 +1,13 @@ +# moxie + +This strategy returns the voting power of users. This takes into consideration +1. Vesting Contract Moxie Balance +2. Wallet Moxie Balance +3. Vesting Contract Fan Token Balance +4. Wallet Fan Token Balance +5. Liquidity Pool Contributions +6. Staked fan tokens for Wallet & Vesting Contracts + +There are special multipliers provided for Fan Token Balances and Liquidity Pool Contributions + + diff --git a/src/strategies/moxie/examples.json b/src/strategies/moxie/examples.json new file mode 100644 index 000000000..517ec6feb --- /dev/null +++ b/src/strategies/moxie/examples.json @@ -0,0 +1,14 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "moxie" + }, + "network": "8453", + "addresses": [ + "0xb59aa5bb9270d44be3fa9b6d67520a2d28cf80ab" + ], + "snapshot": 20631331 + } + ] + \ No newline at end of file diff --git a/src/strategies/moxie/index.ts b/src/strategies/moxie/index.ts new file mode 100644 index 000000000..32ee0e511 --- /dev/null +++ b/src/strategies/moxie/index.ts @@ -0,0 +1,213 @@ +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller, subgraphRequest } from '../../utils'; +import { getAddress } from '@ethersproject/address'; + +export const author = 'Hrishikesh-Thakkar'; +export const version = '0.0.1'; + +const abi = [ + 'function balanceOf(address account) external view returns (uint256)' +]; + +const QUERY_LIMIT = 1000; +const UNSTAKED_FAN_TOKEN_MULTIPLIER = 2; +const STAKED_FAN_TOKEN_MULTIPLIER = 3; +const MOXIE_LIQUIDITY_MULTIPLIER = 2; +const MOXIE_CONTRACT_ADDRESS = "0x8C9037D1Ef5c6D1f6816278C7AAF5491d24CD527"; +const MOXIE_DECIMALS = 18; +const PORTFOLIO_SUBGRAPH_PAGE_LIMIT = 2; +const LIQUIDITY_POOL_SUBGRAPH_PAGE_LIMIT = 1; + +//Strategy to Compute Voting Power for MoxieDAO +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + //Check if the addresses array has length not equal to 1 + if(addresses.length != 1) { + throw new Error("This strategy expects a single address"); + }; + const MOXIE_API_KEY = process.env.MOXIE_API_KEY || ""; + const MOXIE_PROTOCOL_ID = process.env.MOXIE_PROTOCOL_ID || ""; + const MOXIE_VESTING_ID = process.env.MOXIE_VESTING_ID || ""; + const MOXIE_LIQUIDITY_ID = process.env.MOXIE_LIQUIDITY_ID || ""; + + //SETTING DEFAULT SUBGRAPH URLS + let MOXIE_PROTOCOL_SUBGRAPH_URL = "https://api.studio.thegraph.com/query/88457/moxie-protocol/version/latest"; + let MOXIE_VESTING_SUBGRAPH_URL = "https://api.studio.thegraph.com/query/88457/moxie-vesting/version/latest"; + let MOXIE_LIQUIDITY_POOL_SUBGRAPH_URL = "https://api.studio.thegraph.com/query/88457/moxie-liquidity/version/latest"; + + if (MOXIE_API_KEY !== "" && MOXIE_PROTOCOL_ID !== "") { + MOXIE_PROTOCOL_SUBGRAPH_URL = `https://gateway.thegraph.com/api/${MOXIE_API_KEY}/subgraphs/id/${MOXIE_PROTOCOL_ID}`; + } + if (MOXIE_API_KEY !== "" && MOXIE_LIQUIDITY_ID !== "") { + MOXIE_LIQUIDITY_POOL_SUBGRAPH_URL = `https://gateway.thegraph.com/api/${MOXIE_API_KEY}/subgraphs/id/${MOXIE_LIQUIDITY_ID}`; + } + if (MOXIE_API_KEY !== "" && MOXIE_VESTING_ID !== "") { + MOXIE_VESTING_SUBGRAPH_URL = `https://gateway.thegraph.com/api/${MOXIE_API_KEY}/subgraphs/id/${MOXIE_VESTING_ID}`; + } + + //Check if the snapshot is for a specific block number or it's latest + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const addressesMap = addresses.reduce((map, address) => { + map[getAddress(address)] = 0; + return map; + }, {}); + + const lowercaseAddresses = Object.keys(addressesMap).map((address) => + address.toLowerCase() + ); + + // Once we have the addresses we need to query the subgraphs to get the vesting contract addresses + const vestingSubgraphQuery = { + tokenLockWallets: { + __args: { + where: { + beneficiary_in: lowercaseAddresses + } + }, + id: true, + beneficiary: true, + } + }; + //Adding block to the query if the snapshot is not latest + if (snapshot !== 'latest') { + vestingSubgraphQuery.tokenLockWallets.__args['block'] = { number: snapshot }; + } + + //Query the vesting subgraph to get the vesting contract addresses + const vestingContractResponse = await subgraphRequest(MOXIE_VESTING_SUBGRAPH_URL, vestingSubgraphQuery); + + // Generate a map of vesting contract addresses to beneficiaries + const addressToBeneficiaryMap = vestingContractResponse.tokenLockWallets.reduce((map, wallet) => { + map[wallet.id.toLowerCase()] = wallet.beneficiary.toLowerCase(); + return map; + }, {}); + + // Add vesting contract addresses to the list of addresses to query + const allAddresses = [ + ...Object.keys(addressToBeneficiaryMap), + ...lowercaseAddresses + ]; + + // Initialise all the addresses with a score of 0 + const allAddressesScoreMap = allAddresses.reduce((map, address) => { + map[getAddress(address)] = 0; + return map; + }, {}); + + const protocolSubgraphQuery = { + portfolios: { + __args: { + where: { + user_in: allAddresses, + balance_gt: 0 + }, + first: QUERY_LIMIT, + skip: 0 + }, + unstakedBalance: true, + stakedBalance: true, + subjectToken: { + currentPriceInMoxie: true + }, + user: { + id: true + } + } + }; + + const liquidityPoolSubgraphQuery = { + userPools: { + __args: { + where: { + user_in: allAddresses, + }, + first: QUERY_LIMIT, + skip: 0 + }, + totalLPAmount: true, + pool: { + totalSupply: true, + moxieReserve: true, + }, + user: { + id: true + } + } + }; + + //Adding block to the queries if the snapshot is not latest + if (snapshot !== 'latest') { + protocolSubgraphQuery.portfolios.__args['block'] = { number: snapshot }; + liquidityPoolSubgraphQuery.userPools.__args['block'] = { number: snapshot }; + } + + const fetchSubgraphData = async (subgraphUrl, query, processFunction, key, pageLimit) => { + let next_page = 0; + while (next_page < pageLimit) { + query[key].__args.skip = next_page * QUERY_LIMIT; + const response = await subgraphRequest(subgraphUrl, query); + const data = response[Object.keys(response)[0]]; + + processFunction(data); + + if (data.length < QUERY_LIMIT) break; + next_page++; + } + }; + + const processProtocolData = (portfolios) => { + portfolios.forEach((portfolio) => { + const userAddress = getAddress(portfolio.user.id); + allAddressesScoreMap[userAddress] += parseFloat(formatUnits(portfolio.unstakedBalance, MOXIE_DECIMALS)) * UNSTAKED_FAN_TOKEN_MULTIPLIER * portfolio.subjectToken.currentPriceInMoxie + + parseFloat(formatUnits(portfolio.stakedBalance, MOXIE_DECIMALS)) * STAKED_FAN_TOKEN_MULTIPLIER * portfolio.subjectToken.currentPriceInMoxie; + }); + }; + + const processLiquidityPoolData = (userPools) => { + userPools.forEach((userPool) => { + const userAddress = getAddress(userPool.user.id); + allAddressesScoreMap[userAddress] += MOXIE_LIQUIDITY_MULTIPLIER * parseFloat(formatUnits(userPool.totalLPAmount, MOXIE_DECIMALS)) * + parseFloat(formatUnits(userPool.pool.moxieReserve, MOXIE_DECIMALS)) / + parseFloat(formatUnits(userPool.pool.totalSupply, MOXIE_DECIMALS)); + }); + }; + + // RPC Call to get balance of Moxie at a block for users + const fetchBalances = async () => { + const multi = new Multicaller(network, provider, abi, { blockTag }); + allAddresses.forEach((address) => + multi.call(address, MOXIE_CONTRACT_ADDRESS, 'balanceOf', [address]) + ); + const result: Record = await multi.execute(); + Object.entries(result).forEach(([address, balance]) => { + let formattedBalance = parseFloat(formatUnits(balance, MOXIE_DECIMALS)); + allAddressesScoreMap[getAddress(address)] += formattedBalance; + }); + }; + + // Fetch data from both subgraphs in parallel + await Promise.all([ + fetchSubgraphData(MOXIE_PROTOCOL_SUBGRAPH_URL, protocolSubgraphQuery, processProtocolData, "portfolios", PORTFOLIO_SUBGRAPH_PAGE_LIMIT), + fetchSubgraphData(MOXIE_LIQUIDITY_POOL_SUBGRAPH_URL, liquidityPoolSubgraphQuery, processLiquidityPoolData, "userPools", LIQUIDITY_POOL_SUBGRAPH_PAGE_LIMIT), + fetchBalances(), + ]); + + // Now we have the score for each address we need to ensure it is added to the beneficiary address if it exists + Object.keys(allAddressesScoreMap).forEach((address) => { + const beneficiary = addressToBeneficiaryMap[address.toLowerCase()]; + if (beneficiary) { + addressesMap[getAddress(beneficiary)] += allAddressesScoreMap[address]; + } else { + addressesMap[address] += allAddressesScoreMap[address]; + } + }); + + return addressesMap; +} \ No newline at end of file From ea7dcd60fa14c17b202fa27514edc7e19832d4ec Mon Sep 17 00:00:00 2001 From: Hrishikesh K Thakkar Date: Tue, 15 Oct 2024 15:57:08 +0530 Subject: [PATCH 771/815] hardcoding the subgraph ids and refactoring (#1610) --- .env.example | 5 +---- src/strategies/moxie/index.ts | 12 ++++-------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/.env.example b/.env.example index 8af16a922..09a8f8d33 100644 --- a/.env.example +++ b/.env.example @@ -1,7 +1,4 @@ SNAPSHOT_API_STRATEGY_SALT=12345 # Salt for the snapshot API strategy to send a key in header (optional) PASSPORT_API_KEY= # API key for the passport API (optional for other strategies) PASSPORT_SCORER_ID= # Scorer ID for the passport API (optional for other strategies) -MOXIE_API_KEY= # API key for the moxie APIs (optional for other strategies) -MOXIE_PROTOCOL_ID= #Protocol ID for the moxie API (optional for other strategies) -MOXIE_VESTING_ID= # Vesting ID for the moxie API (optional for other strategies) -MOXIE_LIQUDITY_ID= # Liquidity ID for the moxie API (optional for other strategies) \ No newline at end of file +MOXIE_API_KEY= # API key for the moxie APIs (optional for other strategies) \ No newline at end of file diff --git a/src/strategies/moxie/index.ts b/src/strategies/moxie/index.ts index 32ee0e511..5de34bc9e 100644 --- a/src/strategies/moxie/index.ts +++ b/src/strategies/moxie/index.ts @@ -33,22 +33,18 @@ export async function strategy( throw new Error("This strategy expects a single address"); }; const MOXIE_API_KEY = process.env.MOXIE_API_KEY || ""; - const MOXIE_PROTOCOL_ID = process.env.MOXIE_PROTOCOL_ID || ""; - const MOXIE_VESTING_ID = process.env.MOXIE_VESTING_ID || ""; - const MOXIE_LIQUIDITY_ID = process.env.MOXIE_LIQUIDITY_ID || ""; + const MOXIE_PROTOCOL_ID = "7zS29h4BDSujQq8R3TFF37JfpjtPQsRUpoC9p4vo4scx"; + const MOXIE_VESTING_ID = "BuR6zAj2GSVZz6smGbJZkgQx8S6GUS881R493ZYZKSk3"; + const MOXIE_LIQUIDITY_ID = "2rv5XN3LDQiuc9BXFzUri7ZLnS6K1ZqNJzp8Zj8TqMhy"; //SETTING DEFAULT SUBGRAPH URLS let MOXIE_PROTOCOL_SUBGRAPH_URL = "https://api.studio.thegraph.com/query/88457/moxie-protocol/version/latest"; let MOXIE_VESTING_SUBGRAPH_URL = "https://api.studio.thegraph.com/query/88457/moxie-vesting/version/latest"; let MOXIE_LIQUIDITY_POOL_SUBGRAPH_URL = "https://api.studio.thegraph.com/query/88457/moxie-liquidity/version/latest"; - if (MOXIE_API_KEY !== "" && MOXIE_PROTOCOL_ID !== "") { + if (MOXIE_API_KEY !== "" ) { MOXIE_PROTOCOL_SUBGRAPH_URL = `https://gateway.thegraph.com/api/${MOXIE_API_KEY}/subgraphs/id/${MOXIE_PROTOCOL_ID}`; - } - if (MOXIE_API_KEY !== "" && MOXIE_LIQUIDITY_ID !== "") { MOXIE_LIQUIDITY_POOL_SUBGRAPH_URL = `https://gateway.thegraph.com/api/${MOXIE_API_KEY}/subgraphs/id/${MOXIE_LIQUIDITY_ID}`; - } - if (MOXIE_API_KEY !== "" && MOXIE_VESTING_ID !== "") { MOXIE_VESTING_SUBGRAPH_URL = `https://gateway.thegraph.com/api/${MOXIE_API_KEY}/subgraphs/id/${MOXIE_VESTING_ID}`; } From a34aa66faae4bd55c1e385a6670ce8b37f985f79 Mon Sep 17 00:00:00 2001 From: spaceh3ad <52543683+spaceh3ad@users.noreply.github.com> Date: Tue, 15 Oct 2024 19:37:09 +0200 Subject: [PATCH 772/815] [cookie-staking] cookie staking strategy (#1611) * updates * some test are passing * test passing * reverted unnecesary changes --- src/strategies/cookie-staking/examples.json | 19 +++++ src/strategies/cookie-staking/index.ts | 78 +++++++++++++++++++++ src/strategies/cookie-staking/schema.json | 23 ++++++ src/strategies/index.ts | 2 + yarn.lock | 2 +- 5 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 src/strategies/cookie-staking/examples.json create mode 100644 src/strategies/cookie-staking/index.ts create mode 100644 src/strategies/cookie-staking/schema.json diff --git a/src/strategies/cookie-staking/examples.json b/src/strategies/cookie-staking/examples.json new file mode 100644 index 000000000..068f24583 --- /dev/null +++ b/src/strategies/cookie-staking/examples.json @@ -0,0 +1,19 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "cookie-staking", + "params": { + "address": "0x036b6BA384656151471f348fccf5c2818b9223aE", + "decimals": 18 + } + }, + "network": "56", + "addresses": [ + "0xaE7EF51F517380Ca0211A60BeA83596080ddF478", + "0xd0825555aA656c56e687A6412d40534ba7f0E096", + "0x7018b9aB744cd438De14e9186De43698A29A7aAA" + ], + "snapshot": 43137800 + } +] diff --git a/src/strategies/cookie-staking/index.ts b/src/strategies/cookie-staking/index.ts new file mode 100644 index 000000000..114bbe245 --- /dev/null +++ b/src/strategies/cookie-staking/index.ts @@ -0,0 +1,78 @@ +import { Multicaller } from '../../utils'; +import { formatUnits } from '@ethersproject/units'; +import { BigNumber } from '@ethersproject/bignumber'; + +export const author = 'spaceh3ad'; +export const version = '0.1.0'; + +const abi = [ + 'function users(uint256,address) view returns (uint256 shares, uint256 lastDepositedTime, uint256 totalInvested, uint256 totalClaimed)' +]; + +interface UserData { + shares: BigNumber; + lastDepositedTime: BigNumber; + totalInvested: BigNumber; + totalClaimed: BigNumber; +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multi = new Multicaller(network, provider, abi, { blockTag }); + + const poolIds = 11; + + // Prepare multicall + addresses.forEach((address) => { + for (let poolId = 0; poolId < poolIds; poolId++) { + multi.call(`${address}-${poolId}`, options.address, 'users', [ + poolId, + address + ]); + } + }); + + // Typecast result to Record + const result = (await multi.execute()) as Record; + + // Initialize a mapping for user totals + const userTotals: { [address: string]: BigNumber } = {}; + + // Process the result + for (const [key, userData] of Object.entries(result)) { + const address = key.split('-')[0]; + + const totalInvested = BigNumber.from(userData.totalInvested); + const totalClaimed = BigNumber.from(userData.totalClaimed); + + if (!userTotals[address]) { + userTotals[address] = BigNumber.from(0); + } + + const amount = totalInvested.sub(totalClaimed); + + userTotals[address] = userTotals[address].add(amount); + } + + const formattedResult = Object.fromEntries( + addresses.map((address) => [ + address, + parseFloat( + formatUnits( + userTotals[address] || BigNumber.from(0), + options.decimals || 18 + ) + ) + ]) + ); + + return formattedResult; +} diff --git a/src/strategies/cookie-staking/schema.json b/src/strategies/cookie-staking/schema.json new file mode 100644 index 000000000..cd965532d --- /dev/null +++ b/src/strategies/cookie-staking/schema.json @@ -0,0 +1,23 @@ +{ + "type": "object", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "address": { + "type": "string", + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["address"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 4bb1ea820..770673547 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -344,6 +344,7 @@ import * as rep3Badges from './rep3-badges'; import * as marsecosystem from './marsecosystem'; import * as ari10StakingLocked from './ari10-staking-locked'; import * as skaleDelegationWeighted from './skale-delegation-weighted'; +import * as cookieStaking from './cookie-staking'; import * as reliquary from './reliquary'; import * as acrossStakedAcx from './across-staked-acx'; import * as lodestarVesting from './lodestar-vesting'; @@ -817,6 +818,7 @@ const strategies = { 'ari10-staking-locked': ari10StakingLocked, 'skale-delegation-weighted': skaleDelegationWeighted, reliquary, + 'cookie-staking': cookieStaking, 'jpegd-locked-jpeg-of': jpegdLockedJpegOf, 'lodestar-vesting': lodestarVesting, 'lodestar-staked-lp': lodestarStakedLp, diff --git a/yarn.lock b/yarn.lock index 21aad61ea..fe1501d93 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4568,4 +4568,4 @@ yargs@^17.7.2: yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== \ No newline at end of file From 1e969023912b9bcf981c26460d5f0f295f8b968f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 16 Oct 2024 11:05:46 +0530 Subject: [PATCH 773/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.25 (#1612) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index c8bb93a10..492e7eb61 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.24", + "@snapshot-labs/snapshot.js": "^0.12.25", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index fe1501d93..ac6508a62 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.24": - version "0.12.24" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.24.tgz#9a10e76297571b3c5eb31b2881a6b7514dbfc1e8" - integrity sha512-ggkMhVUzokOXwrHpdLjmnwhm33g7lqkjcx8aBbu4Jvhit2ZYq2SRnZUUCa+Tn5bP6cf7TdnUvvPIS78LCdZstw== +"@snapshot-labs/snapshot.js@^0.12.25": + version "0.12.25" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.25.tgz#0011290e3761624efba1abeb01f72259f09b5fa2" + integrity sha512-8+VsFt33xxMbMTrS5En3K107Z9Sk8SQpQQpgaiq1Ty/IMX0EGnUcBLCbbJm8fnyK3rB4rQwvwg81N+xTDhcyLw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" @@ -4568,4 +4568,4 @@ yargs@^17.7.2: yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== \ No newline at end of file + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== From e0a2d52458df1a8fd6223f571c93409691e694bc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 17 Oct 2024 22:24:49 +0530 Subject: [PATCH 774/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.27 (#1613) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 492e7eb61..baae205c3 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.25", + "@snapshot-labs/snapshot.js": "^0.12.27", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index ac6508a62..5987be879 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.25": - version "0.12.25" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.25.tgz#0011290e3761624efba1abeb01f72259f09b5fa2" - integrity sha512-8+VsFt33xxMbMTrS5En3K107Z9Sk8SQpQQpgaiq1Ty/IMX0EGnUcBLCbbJm8fnyK3rB4rQwvwg81N+xTDhcyLw== +"@snapshot-labs/snapshot.js@^0.12.27": + version "0.12.27" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.27.tgz#ed4c3c50f8cf8788831c0250eb8b76350baaf5e3" + integrity sha512-1pP8Ex8vZgvl6KEwqBsVXCJSlKBSxPlr4yknNz9erBAtw1VAppOJ2ZkRHVs0x7+4nrcxnuzU/I3y0GkfLPLTPg== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 6be68d233ebc386cd85e98bc67a2970ac23e8dbd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 20 Oct 2024 20:44:17 +0530 Subject: [PATCH 775/815] Automated lint (#1615) Co-authored-by: ChaituVR --- src/strategies/index.ts | 4 +- src/strategies/moxie/examples.json | 23 +++---- src/strategies/moxie/index.ts | 106 +++++++++++++++++++---------- 3 files changed, 82 insertions(+), 51 deletions(-) diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 770673547..5edc588cf 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -458,7 +458,7 @@ import * as superboring from './superboring'; import * as erableGovernanceV1 from './erable-governance-v1'; import * as worldLibertyFinancial from './world-liberty-financial-erc20-balance-of-votes'; import * as snxMultichain from './snx-multichain'; -import * as moxie from './moxie' +import * as moxie from './moxie'; import * as stakingAmountDurationLinear from './staking-amount-duration-linear'; import * as stakingAmountDurationExponential from './staking-amount-duration-exponential'; @@ -930,7 +930,7 @@ const strategies = { 'erable-governance-v1': erableGovernanceV1, 'world-liberty-financial-erc20-balance-of-votes': worldLibertyFinancial, 'snx-multichain': snxMultichain, - 'moxie': moxie, + moxie: moxie, 'staking-amount-duration-linear': stakingAmountDurationLinear, 'staking-amount-duration-exponential': stakingAmountDurationExponential }; diff --git a/src/strategies/moxie/examples.json b/src/strategies/moxie/examples.json index 517ec6feb..e6377288b 100644 --- a/src/strategies/moxie/examples.json +++ b/src/strategies/moxie/examples.json @@ -1,14 +1,11 @@ [ - { - "name": "Example query", - "strategy": { - "name": "moxie" - }, - "network": "8453", - "addresses": [ - "0xb59aa5bb9270d44be3fa9b6d67520a2d28cf80ab" - ], - "snapshot": 20631331 - } - ] - \ No newline at end of file + { + "name": "Example query", + "strategy": { + "name": "moxie" + }, + "network": "8453", + "addresses": ["0xb59aa5bb9270d44be3fa9b6d67520a2d28cf80ab"], + "snapshot": 20631331 + } +] diff --git a/src/strategies/moxie/index.ts b/src/strategies/moxie/index.ts index 5de34bc9e..df81beac6 100644 --- a/src/strategies/moxie/index.ts +++ b/src/strategies/moxie/index.ts @@ -14,7 +14,7 @@ const QUERY_LIMIT = 1000; const UNSTAKED_FAN_TOKEN_MULTIPLIER = 2; const STAKED_FAN_TOKEN_MULTIPLIER = 3; const MOXIE_LIQUIDITY_MULTIPLIER = 2; -const MOXIE_CONTRACT_ADDRESS = "0x8C9037D1Ef5c6D1f6816278C7AAF5491d24CD527"; +const MOXIE_CONTRACT_ADDRESS = '0x8C9037D1Ef5c6D1f6816278C7AAF5491d24CD527'; const MOXIE_DECIMALS = 18; const PORTFOLIO_SUBGRAPH_PAGE_LIMIT = 2; const LIQUIDITY_POOL_SUBGRAPH_PAGE_LIMIT = 1; @@ -29,25 +29,28 @@ export async function strategy( snapshot ) { //Check if the addresses array has length not equal to 1 - if(addresses.length != 1) { - throw new Error("This strategy expects a single address"); - }; - const MOXIE_API_KEY = process.env.MOXIE_API_KEY || ""; - const MOXIE_PROTOCOL_ID = "7zS29h4BDSujQq8R3TFF37JfpjtPQsRUpoC9p4vo4scx"; - const MOXIE_VESTING_ID = "BuR6zAj2GSVZz6smGbJZkgQx8S6GUS881R493ZYZKSk3"; - const MOXIE_LIQUIDITY_ID = "2rv5XN3LDQiuc9BXFzUri7ZLnS6K1ZqNJzp8Zj8TqMhy"; + if (addresses.length != 1) { + throw new Error('This strategy expects a single address'); + } + const MOXIE_API_KEY = process.env.MOXIE_API_KEY || ''; + const MOXIE_PROTOCOL_ID = '7zS29h4BDSujQq8R3TFF37JfpjtPQsRUpoC9p4vo4scx'; + const MOXIE_VESTING_ID = 'BuR6zAj2GSVZz6smGbJZkgQx8S6GUS881R493ZYZKSk3'; + const MOXIE_LIQUIDITY_ID = '2rv5XN3LDQiuc9BXFzUri7ZLnS6K1ZqNJzp8Zj8TqMhy'; //SETTING DEFAULT SUBGRAPH URLS - let MOXIE_PROTOCOL_SUBGRAPH_URL = "https://api.studio.thegraph.com/query/88457/moxie-protocol/version/latest"; - let MOXIE_VESTING_SUBGRAPH_URL = "https://api.studio.thegraph.com/query/88457/moxie-vesting/version/latest"; - let MOXIE_LIQUIDITY_POOL_SUBGRAPH_URL = "https://api.studio.thegraph.com/query/88457/moxie-liquidity/version/latest"; - - if (MOXIE_API_KEY !== "" ) { + let MOXIE_PROTOCOL_SUBGRAPH_URL = + 'https://api.studio.thegraph.com/query/88457/moxie-protocol/version/latest'; + let MOXIE_VESTING_SUBGRAPH_URL = + 'https://api.studio.thegraph.com/query/88457/moxie-vesting/version/latest'; + let MOXIE_LIQUIDITY_POOL_SUBGRAPH_URL = + 'https://api.studio.thegraph.com/query/88457/moxie-liquidity/version/latest'; + + if (MOXIE_API_KEY !== '') { MOXIE_PROTOCOL_SUBGRAPH_URL = `https://gateway.thegraph.com/api/${MOXIE_API_KEY}/subgraphs/id/${MOXIE_PROTOCOL_ID}`; MOXIE_LIQUIDITY_POOL_SUBGRAPH_URL = `https://gateway.thegraph.com/api/${MOXIE_API_KEY}/subgraphs/id/${MOXIE_LIQUIDITY_ID}`; MOXIE_VESTING_SUBGRAPH_URL = `https://gateway.thegraph.com/api/${MOXIE_API_KEY}/subgraphs/id/${MOXIE_VESTING_ID}`; } - + //Check if the snapshot is for a specific block number or it's latest const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; const addressesMap = addresses.reduce((map, address) => { @@ -68,22 +71,28 @@ export async function strategy( } }, id: true, - beneficiary: true, + beneficiary: true } }; //Adding block to the query if the snapshot is not latest if (snapshot !== 'latest') { - vestingSubgraphQuery.tokenLockWallets.__args['block'] = { number: snapshot }; + vestingSubgraphQuery.tokenLockWallets.__args['block'] = { + number: snapshot + }; } //Query the vesting subgraph to get the vesting contract addresses - const vestingContractResponse = await subgraphRequest(MOXIE_VESTING_SUBGRAPH_URL, vestingSubgraphQuery); - + const vestingContractResponse = await subgraphRequest( + MOXIE_VESTING_SUBGRAPH_URL, + vestingSubgraphQuery + ); + // Generate a map of vesting contract addresses to beneficiaries - const addressToBeneficiaryMap = vestingContractResponse.tokenLockWallets.reduce((map, wallet) => { - map[wallet.id.toLowerCase()] = wallet.beneficiary.toLowerCase(); - return map; - }, {}); + const addressToBeneficiaryMap = + vestingContractResponse.tokenLockWallets.reduce((map, wallet) => { + map[wallet.id.toLowerCase()] = wallet.beneficiary.toLowerCase(); + return map; + }, {}); // Add vesting contract addresses to the list of addresses to query const allAddresses = [ @@ -122,7 +131,7 @@ export async function strategy( userPools: { __args: { where: { - user_in: allAddresses, + user_in: allAddresses }, first: QUERY_LIMIT, skip: 0 @@ -130,7 +139,7 @@ export async function strategy( totalLPAmount: true, pool: { totalSupply: true, - moxieReserve: true, + moxieReserve: true }, user: { id: true @@ -144,13 +153,19 @@ export async function strategy( liquidityPoolSubgraphQuery.userPools.__args['block'] = { number: snapshot }; } - const fetchSubgraphData = async (subgraphUrl, query, processFunction, key, pageLimit) => { + const fetchSubgraphData = async ( + subgraphUrl, + query, + processFunction, + key, + pageLimit + ) => { let next_page = 0; while (next_page < pageLimit) { query[key].__args.skip = next_page * QUERY_LIMIT; const response = await subgraphRequest(subgraphUrl, query); const data = response[Object.keys(response)[0]]; - + processFunction(data); if (data.length < QUERY_LIMIT) break; @@ -161,20 +176,27 @@ export async function strategy( const processProtocolData = (portfolios) => { portfolios.forEach((portfolio) => { const userAddress = getAddress(portfolio.user.id); - allAddressesScoreMap[userAddress] += parseFloat(formatUnits(portfolio.unstakedBalance, MOXIE_DECIMALS)) * UNSTAKED_FAN_TOKEN_MULTIPLIER * portfolio.subjectToken.currentPriceInMoxie + - parseFloat(formatUnits(portfolio.stakedBalance, MOXIE_DECIMALS)) * STAKED_FAN_TOKEN_MULTIPLIER * portfolio.subjectToken.currentPriceInMoxie; + allAddressesScoreMap[userAddress] += + parseFloat(formatUnits(portfolio.unstakedBalance, MOXIE_DECIMALS)) * + UNSTAKED_FAN_TOKEN_MULTIPLIER * + portfolio.subjectToken.currentPriceInMoxie + + parseFloat(formatUnits(portfolio.stakedBalance, MOXIE_DECIMALS)) * + STAKED_FAN_TOKEN_MULTIPLIER * + portfolio.subjectToken.currentPriceInMoxie; }); }; const processLiquidityPoolData = (userPools) => { userPools.forEach((userPool) => { const userAddress = getAddress(userPool.user.id); - allAddressesScoreMap[userAddress] += MOXIE_LIQUIDITY_MULTIPLIER * parseFloat(formatUnits(userPool.totalLPAmount, MOXIE_DECIMALS)) * - parseFloat(formatUnits(userPool.pool.moxieReserve, MOXIE_DECIMALS)) / + allAddressesScoreMap[userAddress] += + (MOXIE_LIQUIDITY_MULTIPLIER * + parseFloat(formatUnits(userPool.totalLPAmount, MOXIE_DECIMALS)) * + parseFloat(formatUnits(userPool.pool.moxieReserve, MOXIE_DECIMALS))) / parseFloat(formatUnits(userPool.pool.totalSupply, MOXIE_DECIMALS)); }); }; - + // RPC Call to get balance of Moxie at a block for users const fetchBalances = async () => { const multi = new Multicaller(network, provider, abi, { blockTag }); @@ -183,16 +205,28 @@ export async function strategy( ); const result: Record = await multi.execute(); Object.entries(result).forEach(([address, balance]) => { - let formattedBalance = parseFloat(formatUnits(balance, MOXIE_DECIMALS)); + const formattedBalance = parseFloat(formatUnits(balance, MOXIE_DECIMALS)); allAddressesScoreMap[getAddress(address)] += formattedBalance; }); }; // Fetch data from both subgraphs in parallel await Promise.all([ - fetchSubgraphData(MOXIE_PROTOCOL_SUBGRAPH_URL, protocolSubgraphQuery, processProtocolData, "portfolios", PORTFOLIO_SUBGRAPH_PAGE_LIMIT), - fetchSubgraphData(MOXIE_LIQUIDITY_POOL_SUBGRAPH_URL, liquidityPoolSubgraphQuery, processLiquidityPoolData, "userPools", LIQUIDITY_POOL_SUBGRAPH_PAGE_LIMIT), - fetchBalances(), + fetchSubgraphData( + MOXIE_PROTOCOL_SUBGRAPH_URL, + protocolSubgraphQuery, + processProtocolData, + 'portfolios', + PORTFOLIO_SUBGRAPH_PAGE_LIMIT + ), + fetchSubgraphData( + MOXIE_LIQUIDITY_POOL_SUBGRAPH_URL, + liquidityPoolSubgraphQuery, + processLiquidityPoolData, + 'userPools', + LIQUIDITY_POOL_SUBGRAPH_PAGE_LIMIT + ), + fetchBalances() ]); // Now we have the score for each address we need to ensure it is added to the beneficiary address if it exists @@ -206,4 +240,4 @@ export async function strategy( }); return addressesMap; -} \ No newline at end of file +} From e7939f10bf72e82aba146bcd5270484e9d7de3e8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 18:24:24 +0530 Subject: [PATCH 776/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.28 (#1616) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index baae205c3..500e28d69 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.27", + "@snapshot-labs/snapshot.js": "^0.12.28", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 5987be879..ef24071a2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.27": - version "0.12.27" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.27.tgz#ed4c3c50f8cf8788831c0250eb8b76350baaf5e3" - integrity sha512-1pP8Ex8vZgvl6KEwqBsVXCJSlKBSxPlr4yknNz9erBAtw1VAppOJ2ZkRHVs0x7+4nrcxnuzU/I3y0GkfLPLTPg== +"@snapshot-labs/snapshot.js@^0.12.28": + version "0.12.28" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.28.tgz#6f6644038c9df06daaea508b57d0b3d5d7a55cd9" + integrity sha512-F2rwwgkV1NtYeeOy1Tl1qemJvm7Ux/D8mM5k/+uD53ptWsX6//zlv9daajZjT+7h7pYqycKvNJJE1f7Rr0m4cQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From bcaa0bd1c2f2607cf2cb47756c80b596278a5ab4 Mon Sep 17 00:00:00 2001 From: !ruby <43858546+alexandersazonof@users.noreply.github.com> Date: Wed, 23 Oct 2024 05:21:48 +0300 Subject: [PATCH 777/815] Add sacra subgraph strategy (#1617) Co-authored-by: Chaitanya --- src/strategies/index.ts | 4 +- src/strategies/sacra-subgraph/README.md | 17 +++++ src/strategies/sacra-subgraph/examples.json | 16 +++++ src/strategies/sacra-subgraph/index.ts | 72 +++++++++++++++++++++ 4 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 src/strategies/sacra-subgraph/README.md create mode 100644 src/strategies/sacra-subgraph/examples.json create mode 100644 src/strategies/sacra-subgraph/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 5edc588cf..5a3ac613a 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -461,6 +461,7 @@ import * as snxMultichain from './snx-multichain'; import * as moxie from './moxie'; import * as stakingAmountDurationLinear from './staking-amount-duration-linear'; import * as stakingAmountDurationExponential from './staking-amount-duration-exponential'; +import * as sacraSubgraph from './sacra-subgraph'; const strategies = { 'delegatexyz-erc721-balance-of': delegatexyzErc721BalanceOf, @@ -932,7 +933,8 @@ const strategies = { 'snx-multichain': snxMultichain, moxie: moxie, 'staking-amount-duration-linear': stakingAmountDurationLinear, - 'staking-amount-duration-exponential': stakingAmountDurationExponential + 'staking-amount-duration-exponential': stakingAmountDurationExponential, + 'sacra-subgraph': sacraSubgraph }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/sacra-subgraph/README.md b/src/strategies/sacra-subgraph/README.md new file mode 100644 index 000000000..dd63aaf38 --- /dev/null +++ b/src/strategies/sacra-subgraph/README.md @@ -0,0 +1,17 @@ +# Sacra score power from Subgraph + +Calculates users power by hero score from Sacra subgraph. + +``` + heroEntities( + where:{ + owner: $address + dead: false + } + orderBy: score + orderDirection: desc + first: 1000 + ) { + score + } +``` \ No newline at end of file diff --git a/src/strategies/sacra-subgraph/examples.json b/src/strategies/sacra-subgraph/examples.json new file mode 100644 index 000000000..7d708c78c --- /dev/null +++ b/src/strategies/sacra-subgraph/examples.json @@ -0,0 +1,16 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "sacra-subgraph", + "params": {} + }, + "network": "250", + "addresses": [ + "0x0009d6f1ee24dce26b3d59f7687acf9ef186908d", + "0x006028a11d9fff45112b4983f3dad6313784eee3", + "0x00662c5a6d56616b22f6180b325501b796825571" + ], + "snapshot": 95377862 + } +] diff --git a/src/strategies/sacra-subgraph/index.ts b/src/strategies/sacra-subgraph/index.ts new file mode 100644 index 000000000..b9d4d4d84 --- /dev/null +++ b/src/strategies/sacra-subgraph/index.ts @@ -0,0 +1,72 @@ +import { getAddress } from '@ethersproject/address'; +import { subgraphRequest } from '../../utils'; + +const SUBGRAPH_URL = { + '250': 'https://graph.tetu.io/subgraphs/name/sacra-fantom', + '111188': 'https://graph.tetu.io/subgraphs/name/sacra-real' +}; + +export const author = 'alexandersazonof'; +export const version = '0.0.1'; + +export async function strategy( + _space, + network, + _provider, + addresses, + options, + snapshot +) { + // initialize scores + const scores = {}; + + // If graph doesn't exist return + if (!SUBGRAPH_URL[network]) { + return scores; + } + + const params = { + heroEntities: { + __args: { + where: { + owner_in: addresses.map((address) => address.toLowerCase()), + id_gt: '', + dead: false + }, + orderBy: 'id', + orderDirection: 'asc', + first: 1000 + }, + id: true, + score: true, + owner: { + id: true + } + } + }; + + if (snapshot !== 'latest') { + // @ts-ignore + params.heroEntities.__args.block = { number: snapshot }; + } + + let hasNext = true; + while (hasNext) { + const result = await subgraphRequest(SUBGRAPH_URL[network], params); + + const heroEntities = + result && result.heroEntities ? result.heroEntities : []; + const latest = heroEntities[heroEntities.length - 1]; + + for (const heroEntity of heroEntities) { + const userAddress = getAddress(heroEntity.owner.id); + const score = heroEntity.score; + scores[userAddress] = (scores[userAddress] ?? 0) + score; + } + + hasNext = heroEntities.length === params.heroEntities.__args.first; + params.heroEntities.__args.where.id_gt = latest ? latest.id : ''; + } + + return scores || {}; +} From c414a07645ecbb1eecef60f4467ccf55060afa64 Mon Sep 17 00:00:00 2001 From: "Sarvesh Jain | tokenstaker.eth" Date: Sun, 27 Oct 2024 16:30:20 +0530 Subject: [PATCH 778/815] [moxie] Moxie DAO voting strategy (#1618) * hardcoding the subgraph ids and refactoring * updated strategy to use moxie endpoints * Updated to post request to handle upto 500 addresses * Changing timeout from 20 to 60 sec --------- Co-authored-by: Hrishikesh-Thakkar --- src/strategies/moxie/examples.json | 7 +- src/strategies/moxie/index.ts | 249 +++-------------------------- 2 files changed, 28 insertions(+), 228 deletions(-) diff --git a/src/strategies/moxie/examples.json b/src/strategies/moxie/examples.json index e6377288b..e5723a02c 100644 --- a/src/strategies/moxie/examples.json +++ b/src/strategies/moxie/examples.json @@ -5,7 +5,12 @@ "name": "moxie" }, "network": "8453", - "addresses": ["0xb59aa5bb9270d44be3fa9b6d67520a2d28cf80ab"], + "addresses": [ + "0x764e427020ad72624075c61260192c6e486d15a5", + "0xb59aa5bb9270d44be3fa9b6d67520a2d28cf80ab", + "0xcf03287A85298166522002c97aE4B1556fF026B3", + "0xcBFBcbFcA74955B8AB75Dec41F7b9eF36F329879" + ], "snapshot": 20631331 } ] diff --git a/src/strategies/moxie/index.ts b/src/strategies/moxie/index.ts index df81beac6..35ee37c48 100644 --- a/src/strategies/moxie/index.ts +++ b/src/strategies/moxie/index.ts @@ -1,23 +1,10 @@ -import { BigNumberish } from '@ethersproject/bignumber'; -import { formatUnits } from '@ethersproject/units'; -import { Multicaller, subgraphRequest } from '../../utils'; -import { getAddress } from '@ethersproject/address'; +import { customFetch } from '../../utils'; -export const author = 'Hrishikesh-Thakkar'; -export const version = '0.0.1'; +export const author = '0xsarvesh'; +export const version = '0.0.2'; -const abi = [ - 'function balanceOf(address account) external view returns (uint256)' -]; - -const QUERY_LIMIT = 1000; -const UNSTAKED_FAN_TOKEN_MULTIPLIER = 2; -const STAKED_FAN_TOKEN_MULTIPLIER = 3; -const MOXIE_LIQUIDITY_MULTIPLIER = 2; -const MOXIE_CONTRACT_ADDRESS = '0x8C9037D1Ef5c6D1f6816278C7AAF5491d24CD527'; -const MOXIE_DECIMALS = 18; -const PORTFOLIO_SUBGRAPH_PAGE_LIMIT = 2; -const LIQUIDITY_POOL_SUBGRAPH_PAGE_LIMIT = 1; +const MOXIE_ENDPOINT = 'https://api.moxie.xyz/protocol/address-votes'; +const MOXIE_API_KEY = process.env.MOXIE_API_KEY || ''; //Strategy to Compute Voting Power for MoxieDAO export async function strategy( @@ -28,216 +15,24 @@ export async function strategy( options, snapshot ) { - //Check if the addresses array has length not equal to 1 - if (addresses.length != 1) { - throw new Error('This strategy expects a single address'); - } - const MOXIE_API_KEY = process.env.MOXIE_API_KEY || ''; - const MOXIE_PROTOCOL_ID = '7zS29h4BDSujQq8R3TFF37JfpjtPQsRUpoC9p4vo4scx'; - const MOXIE_VESTING_ID = 'BuR6zAj2GSVZz6smGbJZkgQx8S6GUS881R493ZYZKSk3'; - const MOXIE_LIQUIDITY_ID = '2rv5XN3LDQiuc9BXFzUri7ZLnS6K1ZqNJzp8Zj8TqMhy'; - - //SETTING DEFAULT SUBGRAPH URLS - let MOXIE_PROTOCOL_SUBGRAPH_URL = - 'https://api.studio.thegraph.com/query/88457/moxie-protocol/version/latest'; - let MOXIE_VESTING_SUBGRAPH_URL = - 'https://api.studio.thegraph.com/query/88457/moxie-vesting/version/latest'; - let MOXIE_LIQUIDITY_POOL_SUBGRAPH_URL = - 'https://api.studio.thegraph.com/query/88457/moxie-liquidity/version/latest'; - - if (MOXIE_API_KEY !== '') { - MOXIE_PROTOCOL_SUBGRAPH_URL = `https://gateway.thegraph.com/api/${MOXIE_API_KEY}/subgraphs/id/${MOXIE_PROTOCOL_ID}`; - MOXIE_LIQUIDITY_POOL_SUBGRAPH_URL = `https://gateway.thegraph.com/api/${MOXIE_API_KEY}/subgraphs/id/${MOXIE_LIQUIDITY_ID}`; - MOXIE_VESTING_SUBGRAPH_URL = `https://gateway.thegraph.com/api/${MOXIE_API_KEY}/subgraphs/id/${MOXIE_VESTING_ID}`; - } - - //Check if the snapshot is for a specific block number or it's latest - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - const addressesMap = addresses.reduce((map, address) => { - map[getAddress(address)] = 0; - return map; - }, {}); - - const lowercaseAddresses = Object.keys(addressesMap).map((address) => - address.toLowerCase() - ); - - // Once we have the addresses we need to query the subgraphs to get the vesting contract addresses - const vestingSubgraphQuery = { - tokenLockWallets: { - __args: { - where: { - beneficiary_in: lowercaseAddresses - } - }, - id: true, - beneficiary: true - } - }; - //Adding block to the query if the snapshot is not latest - if (snapshot !== 'latest') { - vestingSubgraphQuery.tokenLockWallets.__args['block'] = { - number: snapshot - }; - } - - //Query the vesting subgraph to get the vesting contract addresses - const vestingContractResponse = await subgraphRequest( - MOXIE_VESTING_SUBGRAPH_URL, - vestingSubgraphQuery - ); - - // Generate a map of vesting contract addresses to beneficiaries - const addressToBeneficiaryMap = - vestingContractResponse.tokenLockWallets.reduce((map, wallet) => { - map[wallet.id.toLowerCase()] = wallet.beneficiary.toLowerCase(); - return map; - }, {}); - - // Add vesting contract addresses to the list of addresses to query - const allAddresses = [ - ...Object.keys(addressToBeneficiaryMap), - ...lowercaseAddresses - ]; - - // Initialise all the addresses with a score of 0 - const allAddressesScoreMap = allAddresses.reduce((map, address) => { - map[getAddress(address)] = 0; - return map; - }, {}); - - const protocolSubgraphQuery = { - portfolios: { - __args: { - where: { - user_in: allAddresses, - balance_gt: 0 - }, - first: QUERY_LIMIT, - skip: 0 - }, - unstakedBalance: true, - stakedBalance: true, - subjectToken: { - currentPriceInMoxie: true - }, - user: { - id: true - } - } - }; - - const liquidityPoolSubgraphQuery = { - userPools: { - __args: { - where: { - user_in: allAddresses - }, - first: QUERY_LIMIT, - skip: 0 - }, - totalLPAmount: true, - pool: { - totalSupply: true, - moxieReserve: true - }, - user: { - id: true + const response = await customFetch( + MOXIE_ENDPOINT, + { + method: 'POST', + body: JSON.stringify({ + block: snapshot, + addresses + }), + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + 'x-airstack-protocol': MOXIE_API_KEY } - } - }; - - //Adding block to the queries if the snapshot is not latest - if (snapshot !== 'latest') { - protocolSubgraphQuery.portfolios.__args['block'] = { number: snapshot }; - liquidityPoolSubgraphQuery.userPools.__args['block'] = { number: snapshot }; - } - - const fetchSubgraphData = async ( - subgraphUrl, - query, - processFunction, - key, - pageLimit - ) => { - let next_page = 0; - while (next_page < pageLimit) { - query[key].__args.skip = next_page * QUERY_LIMIT; - const response = await subgraphRequest(subgraphUrl, query); - const data = response[Object.keys(response)[0]]; - - processFunction(data); - - if (data.length < QUERY_LIMIT) break; - next_page++; - } - }; - - const processProtocolData = (portfolios) => { - portfolios.forEach((portfolio) => { - const userAddress = getAddress(portfolio.user.id); - allAddressesScoreMap[userAddress] += - parseFloat(formatUnits(portfolio.unstakedBalance, MOXIE_DECIMALS)) * - UNSTAKED_FAN_TOKEN_MULTIPLIER * - portfolio.subjectToken.currentPriceInMoxie + - parseFloat(formatUnits(portfolio.stakedBalance, MOXIE_DECIMALS)) * - STAKED_FAN_TOKEN_MULTIPLIER * - portfolio.subjectToken.currentPriceInMoxie; - }); - }; - - const processLiquidityPoolData = (userPools) => { - userPools.forEach((userPool) => { - const userAddress = getAddress(userPool.user.id); - allAddressesScoreMap[userAddress] += - (MOXIE_LIQUIDITY_MULTIPLIER * - parseFloat(formatUnits(userPool.totalLPAmount, MOXIE_DECIMALS)) * - parseFloat(formatUnits(userPool.pool.moxieReserve, MOXIE_DECIMALS))) / - parseFloat(formatUnits(userPool.pool.totalSupply, MOXIE_DECIMALS)); - }); - }; - - // RPC Call to get balance of Moxie at a block for users - const fetchBalances = async () => { - const multi = new Multicaller(network, provider, abi, { blockTag }); - allAddresses.forEach((address) => - multi.call(address, MOXIE_CONTRACT_ADDRESS, 'balanceOf', [address]) - ); - const result: Record = await multi.execute(); - Object.entries(result).forEach(([address, balance]) => { - const formattedBalance = parseFloat(formatUnits(balance, MOXIE_DECIMALS)); - allAddressesScoreMap[getAddress(address)] += formattedBalance; - }); - }; - - // Fetch data from both subgraphs in parallel - await Promise.all([ - fetchSubgraphData( - MOXIE_PROTOCOL_SUBGRAPH_URL, - protocolSubgraphQuery, - processProtocolData, - 'portfolios', - PORTFOLIO_SUBGRAPH_PAGE_LIMIT - ), - fetchSubgraphData( - MOXIE_LIQUIDITY_POOL_SUBGRAPH_URL, - liquidityPoolSubgraphQuery, - processLiquidityPoolData, - 'userPools', - LIQUIDITY_POOL_SUBGRAPH_PAGE_LIMIT - ), - fetchBalances() - ]); + }, + 60000 + ); - // Now we have the score for each address we need to ensure it is added to the beneficiary address if it exists - Object.keys(allAddressesScoreMap).forEach((address) => { - const beneficiary = addressToBeneficiaryMap[address.toLowerCase()]; - if (beneficiary) { - addressesMap[getAddress(beneficiary)] += allAddressesScoreMap[address]; - } else { - addressesMap[address] += allAddressesScoreMap[address]; - } - }); + const votes = await response.json(); - return addressesMap; + return votes.scores; } From 0de704dbb0630de22d183dd3c7d629e6404dce83 Mon Sep 17 00:00:00 2001 From: Javier G Date: Thu, 7 Nov 2024 05:32:43 +0100 Subject: [PATCH 779/815] Make addresses unique (#1626) --- src/strategies/polygon-self-staked-pol/index.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/strategies/polygon-self-staked-pol/index.ts b/src/strategies/polygon-self-staked-pol/index.ts index 1574d2a8d..cf5890cf2 100644 --- a/src/strategies/polygon-self-staked-pol/index.ts +++ b/src/strategies/polygon-self-staked-pol/index.ts @@ -26,6 +26,7 @@ export async function strategy( snapshot ): Promise> { const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const uniqueAddresses = new Set(addresses); const multi = new Multicaller(network, provider, stakeManagerABI, { blockTag @@ -53,7 +54,7 @@ export async function strategy( const result = await multi.execute(); const votingPower: Record = {}; - for (const address of addresses) { + for (const address of uniqueAddresses) { votingPower[address] = BigNumber.from(0); } @@ -73,7 +74,7 @@ export async function strategy( isNotDeactivated && validatorContract !== '0x0000000000000000000000000000000000000000' ) { - for (const address of addresses) { + for (const address of uniqueAddresses) { stakesMulti.call( `${address}_${i}`, validatorContract, @@ -86,7 +87,7 @@ export async function strategy( const stakes = await stakesMulti.execute(); - for (const address of addresses) { + for (const address of uniqueAddresses) { for (let i = 0; i < validatorCount; i++) { const key = `${address}_${i}`; if (stakes[key]) { From 1e5ab4126723d6eff47d6f04546f7c3afd0bac0a Mon Sep 17 00:00:00 2001 From: Didi Date: Thu, 7 Nov 2024 08:13:15 +0100 Subject: [PATCH 780/815] [fountainhead] Add Fountainhead strategy (#1624) * added fountainhead strategy * include unlocked balance, use new method getUserLocker() * add fontaine balances * simpify code * update README * smol doc fix --- src/strategies/fountainhead/README.md | 42 ++++++ src/strategies/fountainhead/examples.json | 21 +++ src/strategies/fountainhead/index.ts | 152 ++++++++++++++++++++++ src/strategies/fountainhead/schema.json | 30 +++++ src/strategies/index.ts | 4 +- 5 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 src/strategies/fountainhead/README.md create mode 100644 src/strategies/fountainhead/examples.json create mode 100644 src/strategies/fountainhead/index.ts create mode 100644 src/strategies/fountainhead/schema.json diff --git a/src/strategies/fountainhead/README.md b/src/strategies/fountainhead/README.md new file mode 100644 index 000000000..286071d8f --- /dev/null +++ b/src/strategies/fountainhead/README.md @@ -0,0 +1,42 @@ +# Fountainhead + +Calulates the amount of tokens which are locked, staked, unlocked or in transition (stream-unlock). + +A _Locker_ is a contract holding tokens on behalf of users. Each account can have zero or one Locker. +A _Fontaine_ is a contract stream-unlocking tokens. Each Locker can have zero or more Fontaines. + +In order to calculate the amount of tokens belonging to an address, the strategy first checks if the account has a locker, using `ILockerFactory.getLockerAddress()`. +Then the Locker balance is calculated using `ILocker.getStakedBalance()` and `ILocker.getAvailableBalance()`. +Then the addresses of all Fontaines created by the Locker are fetched, and their token balances queried. + +Note: the Locker contract puts no limit on the number of Fontaines which can be created for a Locker (other than the data type of its counter). +In practive, we don't expect Lockers to have any Fontaines. But since it's theoretically possible, the strategy limits the number of Fontaines per Locker it will query. This limit is defined in `MAX_FONTAINES_PER_LOCKER`. By iterating from most to least recently created Fontaine, the probability of omitting Fontaines which are still active is minimized. + +## Dev + +Run test with +``` +yarn test --strategy=fountainhead +``` + +**cli helper commands during development using foundry's cast** + +get the owner of a locker: +``` +cast call --rpc-url $RPC "lockerOwner()" +``` + +get the locker address for an account (zero if not exists): +``` +cast call --rpc-url $RPC $LOCKER_FACTORY "getLockerAddress(address)" +``` + +create locker: +``` +cast send --account --rpc-url $RPC $LOCKER_FACTORY "createLockerContract()" +``` + +unlock with 7 days unlock period (creates a Fontaine): +``` +cast send --account --rpc-url $RPC "unlock(uint128,address)" 604800 +``` diff --git a/src/strategies/fountainhead/examples.json b/src/strategies/fountainhead/examples.json new file mode 100644 index 000000000..fd4034788 --- /dev/null +++ b/src/strategies/fountainhead/examples.json @@ -0,0 +1,21 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "fountainhead", + "params": { + "tokenAddress": "0x3A193aC8FcaCCDa817c174D04081C105154a8441", + "lockerFactoryAddress": "0x8DaF7BF1a2052B6BDA0eC46619855Cec77DfbC76" + } + }, + "network": "84532", + "addresses": [ + "0x7269B0c7C831598465a9EB17F6c5a03331353dAF", + "0x6e7A82059a9D58B4D603706D478d04D1f961107a", + "0x264Ff25e609363cf738e238CBc7B680300509BED", + "0x5782BD439d3019F61bFac53f6358C30c3566737C", + "0x4ee5D45eB79aEa04C02961a2e543bbAf5cec81B3" + ], + "snapshot": 17304060 + } +] diff --git a/src/strategies/fountainhead/index.ts b/src/strategies/fountainhead/index.ts new file mode 100644 index 000000000..a9699d459 --- /dev/null +++ b/src/strategies/fountainhead/index.ts @@ -0,0 +1,152 @@ +import { BigNumberish, BigNumber } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'd10r'; +export const version = '0.1.0'; + +// signatures of the methods we need +const abi = [ + // LockerFactory + 'function getUserLocker(address user) external view returns (bool isCreated, address lockerAddress)', + // Locker + 'function getAvailableBalance() external view returns(uint256)', + 'function getStakedBalance() external view returns(uint256)', + 'function fontaineCount() external view returns(uint16)', + 'function fontaines(uint256 unlockId) external view returns(address)', + // Token + 'function balanceOf(address account) external view returns (uint256)' +]; + +// Super Tokens always have 18 decimals +const DECIMALS = 18; + +// we must bound the number of fontaines per locker to avoid RPC timeouts +const MAX_FONTAINES_PER_LOCKER = 100; + +interface LockerState { + availableBalance: BigNumber; + stakedBalance: BigNumber; + fontaineCount: number; +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + // 1. GET UNLOCKED BALANCES + const mCall1 = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => + mCall1.call(address, options.tokenAddress, 'balanceOf', [address]) + ); + const unlockedBalances: Record = await mCall1.execute(); + + // 2. GET LOCKER ADDRESSES + const mCall2 = new Multicaller(network, provider, abi, { blockTag }); + // lockerFactory.getUserLocker(). Returns the deterministic address and a bool "exists". + addresses.forEach((address) => + mCall2.call(address, options.lockerFactoryAddress, 'getUserLocker', [address]) + ); + const mCall2Result: Record = await mCall2.execute(); + const lockerByAddress = Object.fromEntries( + Object.entries(mCall2Result) + .filter(([_, { isCreated }]) => isCreated) + .map(([addr, { lockerAddress }]) => [addr, lockerAddress]) + ); + const existingLockers = Object.values(lockerByAddress); + + // 3. GET LOCKER STATE (available balance, staked balance, fontaine count) + const mCall3 = new Multicaller(network, provider, abi, { blockTag }); + existingLockers.forEach((lockerAddress) => { + mCall3.call(`available-${lockerAddress}`, lockerAddress, 'getAvailableBalance', []); + mCall3.call(`staked-${lockerAddress}`, lockerAddress, 'getStakedBalance', []); + mCall3.call(`fontaineCount-${lockerAddress}`, lockerAddress, 'fontaineCount', []); + }); + const mCall3Result: Record = await mCall3.execute(); + // Transform raw results into structured data + const lockerStates: Record = {}; + existingLockers.forEach((lockerAddress) => { + lockerStates[lockerAddress] = { + availableBalance: BigNumber.from(mCall3Result[`available-${lockerAddress}`] || 0), + stakedBalance: BigNumber.from(mCall3Result[`staked-${lockerAddress}`] || 0), + fontaineCount: Number(mCall3Result[`fontaineCount-${lockerAddress}`]) + }; + }); + + // 4. GET ALL THE FONTAINES + const mCall4 = new Multicaller(network, provider, abi, { blockTag }); + existingLockers.forEach((lockerAddress) => { + const fontaineCount = lockerStates[lockerAddress].fontaineCount; + // iterate backwards, so we have fontaines ordered by creation time (most recent first). + // this makes it unlikely to miss fontaines which are still active. + for (let i = fontaineCount-1; i >= 0 && i >= fontaineCount-MAX_FONTAINES_PER_LOCKER; i--) { + mCall4.call(`${lockerAddress}-${i}`, lockerAddress, 'fontaines', [i]) + } + }); + const fontaineAddrs: Record = await mCall4.execute(); + + // 5. GET THE FONTAINE'S BALANCES + const mCall5 = new Multicaller(network, provider, abi, { blockTag }); + existingLockers.forEach((lockerAddress) => { + for (let i = 0; i < lockerStates[lockerAddress].fontaineCount; i++) { + const fontaineAddress = fontaineAddrs[`${lockerAddress}-${i}`]; + mCall5.call(`${lockerAddress}-${i}`, options.tokenAddress, 'balanceOf', [fontaineAddress]); + } + }); + const fontaineBalances: Record = await mCall5.execute(); + + // Note: all 5 allowed multicalls are "used". + // If needed we could "free" one by combining the balance queries of mCall1 and mCall5 + + // SUM UP ALL THE BALANCES + const balances = Object.fromEntries( + addresses.map(address => { + const lockerAddress: string = lockerByAddress[address]; + const unlockedBalance = BigNumber.from(unlockedBalances[address]); + + // if no locker -> return unlocked balance + if (!lockerAddress) return [address, unlockedBalance]; + + // else add all balances in locker and related fontaines + const availableBalance = lockerStates[lockerAddress].availableBalance; + const stakedBalance = lockerStates[lockerAddress].stakedBalance; + const fontaineBalanceSum = getFontaineBalancesForLocker( + lockerAddress, lockerStates[lockerAddress].fontaineCount, fontaineBalances); + + const totalBalance = unlockedBalance + .add(availableBalance) + .add(stakedBalance) + .add(fontaineBalanceSum); + + return [address, totalBalance]; + }) + ); + + // Return in the required format + return Object.fromEntries( + Object.entries(balances).map(([address, balance]) => [ + address, + parseFloat(formatUnits(balance, DECIMALS)) + ]) + ); +} + +// helper function to sum up the fontaine balances for a given locker +function getFontaineBalancesForLocker( + lockerAddress: string, + fontaineCount: number, + balances: Record +): BigNumber { + return Array.from({ length: fontaineCount }) + .map((_, i) => BigNumber.from(balances[`balance-${lockerAddress}-${i}`] || 0)) + .reduce( + (sum, balance) => sum.add(balance), + BigNumber.from(0) + ); +} \ No newline at end of file diff --git a/src/strategies/fountainhead/schema.json b/src/strategies/fountainhead/schema.json new file mode 100644 index 000000000..4e1d3dc5c --- /dev/null +++ b/src/strategies/fountainhead/schema.json @@ -0,0 +1,30 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "tokenAddress": { + "type": "string", + "title": "Token contract address", + "examples": ["e.g. 0x6C210F071c7246C452CAC7F8BaA6dA53907BbaE1"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "lockerFactoryAddress": { + "type": "string", + "title": "Locker factory contract address", + "examples": ["e.g. 0xAcA744453C178F3D651e06A3459E2F242aa01789"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } + }, + "required": ["tokenAddress", "lockerFactoryAddress"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 5a3ac613a..d189cae6d 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -462,6 +462,7 @@ import * as moxie from './moxie'; import * as stakingAmountDurationLinear from './staking-amount-duration-linear'; import * as stakingAmountDurationExponential from './staking-amount-duration-exponential'; import * as sacraSubgraph from './sacra-subgraph'; +import * as fountainhead from './fountainhead'; const strategies = { 'delegatexyz-erc721-balance-of': delegatexyzErc721BalanceOf, @@ -934,7 +935,8 @@ const strategies = { moxie: moxie, 'staking-amount-duration-linear': stakingAmountDurationLinear, 'staking-amount-duration-exponential': stakingAmountDurationExponential, - 'sacra-subgraph': sacraSubgraph + 'sacra-subgraph': sacraSubgraph, + fountainhead }; Object.keys(strategies).forEach(function (strategyName) { From fd38feb051b0d606c00979851b26fc148d0c6e02 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 12 Nov 2024 23:17:23 +0530 Subject: [PATCH 781/815] Automated lint (#1629) Co-authored-by: ChaituVR --- src/strategies/fountainhead/index.ts | 63 ++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 17 deletions(-) diff --git a/src/strategies/fountainhead/index.ts b/src/strategies/fountainhead/index.ts index a9699d459..df76f9911 100644 --- a/src/strategies/fountainhead/index.ts +++ b/src/strategies/fountainhead/index.ts @@ -51,7 +51,9 @@ export async function strategy( const mCall2 = new Multicaller(network, provider, abi, { blockTag }); // lockerFactory.getUserLocker(). Returns the deterministic address and a bool "exists". addresses.forEach((address) => - mCall2.call(address, options.lockerFactoryAddress, 'getUserLocker', [address]) + mCall2.call(address, options.lockerFactoryAddress, 'getUserLocker', [ + address + ]) ); const mCall2Result: Record = await mCall2.execute(); const lockerByAddress = Object.fromEntries( @@ -64,17 +66,36 @@ export async function strategy( // 3. GET LOCKER STATE (available balance, staked balance, fontaine count) const mCall3 = new Multicaller(network, provider, abi, { blockTag }); existingLockers.forEach((lockerAddress) => { - mCall3.call(`available-${lockerAddress}`, lockerAddress, 'getAvailableBalance', []); - mCall3.call(`staked-${lockerAddress}`, lockerAddress, 'getStakedBalance', []); - mCall3.call(`fontaineCount-${lockerAddress}`, lockerAddress, 'fontaineCount', []); + mCall3.call( + `available-${lockerAddress}`, + lockerAddress, + 'getAvailableBalance', + [] + ); + mCall3.call( + `staked-${lockerAddress}`, + lockerAddress, + 'getStakedBalance', + [] + ); + mCall3.call( + `fontaineCount-${lockerAddress}`, + lockerAddress, + 'fontaineCount', + [] + ); }); const mCall3Result: Record = await mCall3.execute(); // Transform raw results into structured data const lockerStates: Record = {}; existingLockers.forEach((lockerAddress) => { lockerStates[lockerAddress] = { - availableBalance: BigNumber.from(mCall3Result[`available-${lockerAddress}`] || 0), - stakedBalance: BigNumber.from(mCall3Result[`staked-${lockerAddress}`] || 0), + availableBalance: BigNumber.from( + mCall3Result[`available-${lockerAddress}`] || 0 + ), + stakedBalance: BigNumber.from( + mCall3Result[`staked-${lockerAddress}`] || 0 + ), fontaineCount: Number(mCall3Result[`fontaineCount-${lockerAddress}`]) }; }); @@ -85,8 +106,12 @@ export async function strategy( const fontaineCount = lockerStates[lockerAddress].fontaineCount; // iterate backwards, so we have fontaines ordered by creation time (most recent first). // this makes it unlikely to miss fontaines which are still active. - for (let i = fontaineCount-1; i >= 0 && i >= fontaineCount-MAX_FONTAINES_PER_LOCKER; i--) { - mCall4.call(`${lockerAddress}-${i}`, lockerAddress, 'fontaines', [i]) + for ( + let i = fontaineCount - 1; + i >= 0 && i >= fontaineCount - MAX_FONTAINES_PER_LOCKER; + i-- + ) { + mCall4.call(`${lockerAddress}-${i}`, lockerAddress, 'fontaines', [i]); } }); const fontaineAddrs: Record = await mCall4.execute(); @@ -96,7 +121,9 @@ export async function strategy( existingLockers.forEach((lockerAddress) => { for (let i = 0; i < lockerStates[lockerAddress].fontaineCount; i++) { const fontaineAddress = fontaineAddrs[`${lockerAddress}-${i}`]; - mCall5.call(`${lockerAddress}-${i}`, options.tokenAddress, 'balanceOf', [fontaineAddress]); + mCall5.call(`${lockerAddress}-${i}`, options.tokenAddress, 'balanceOf', [ + fontaineAddress + ]); } }); const fontaineBalances: Record = await mCall5.execute(); @@ -106,7 +133,7 @@ export async function strategy( // SUM UP ALL THE BALANCES const balances = Object.fromEntries( - addresses.map(address => { + addresses.map((address) => { const lockerAddress: string = lockerByAddress[address]; const unlockedBalance = BigNumber.from(unlockedBalances[address]); @@ -117,7 +144,10 @@ export async function strategy( const availableBalance = lockerStates[lockerAddress].availableBalance; const stakedBalance = lockerStates[lockerAddress].stakedBalance; const fontaineBalanceSum = getFontaineBalancesForLocker( - lockerAddress, lockerStates[lockerAddress].fontaineCount, fontaineBalances); + lockerAddress, + lockerStates[lockerAddress].fontaineCount, + fontaineBalances + ); const totalBalance = unlockedBalance .add(availableBalance) @@ -144,9 +174,8 @@ function getFontaineBalancesForLocker( balances: Record ): BigNumber { return Array.from({ length: fontaineCount }) - .map((_, i) => BigNumber.from(balances[`balance-${lockerAddress}-${i}`] || 0)) - .reduce( - (sum, balance) => sum.add(balance), - BigNumber.from(0) - ); -} \ No newline at end of file + .map((_, i) => + BigNumber.from(balances[`balance-${lockerAddress}-${i}`] || 0) + ) + .reduce((sum, balance) => sum.add(balance), BigNumber.from(0)); +} From 205c18dd6a6522cb20f0a2564f19202bc87f0fee Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 14 Nov 2024 13:36:02 +0530 Subject: [PATCH 782/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.29 (#1630) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 500e28d69..6bb7e5236 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.28", + "@snapshot-labs/snapshot.js": "^0.12.29", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index ef24071a2..20c8e5fb9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.28": - version "0.12.28" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.28.tgz#6f6644038c9df06daaea508b57d0b3d5d7a55cd9" - integrity sha512-F2rwwgkV1NtYeeOy1Tl1qemJvm7Ux/D8mM5k/+uD53ptWsX6//zlv9daajZjT+7h7pYqycKvNJJE1f7Rr0m4cQ== +"@snapshot-labs/snapshot.js@^0.12.29": + version "0.12.29" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.29.tgz#ea629acccd95afd84d62a1202de03fe2dc84ab53" + integrity sha512-pfyc6ZsuCLoitH0FqYfPiBFZEsYN+i0atWEA3ubQozA/g9sOgDKRyChHoj8A7lEkkNT7gt4J9xKoDk3jo6CTNw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 692821f01392451593efca39735e9ade3b2ae91b Mon Sep 17 00:00:00 2001 From: wizard <112275929+famouswizard@users.noreply.github.com> Date: Fri, 15 Nov 2024 08:00:44 +0300 Subject: [PATCH 783/815] Typos found in the documentation files (#1631) * Typo Update README.md The error is in the verb "use," which should be "uses" to agree with the subject "Arbitrum." * Typo Update README.md The error is in the word "proposa," which should be "proposal." --- src/validations/arbitrum/README.md | 2 +- src/validations/passport-gated/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/validations/arbitrum/README.md b/src/validations/arbitrum/README.md index 21afa8f33..b2f673e17 100644 --- a/src/validations/arbitrum/README.md +++ b/src/validations/arbitrum/README.md @@ -7,7 +7,7 @@ This validation module check the number of basis points (bps, i.e. 0.01%) of vote a delegate control, which is used to enforce the 0.01% snapshot proposer requirement specified in [The Constitution of the Arbitrum DAO](https://docs.arbitrum.foundation/dao-constitution). -Arbitrum use an EXCLUDE_ADDRESS (0x00000000000000000000000000000000000A4B86) to mark non-votable tokens, tokens delegated to the EXCLUDE_ADDRESS will be excluded from votable supply. +Arbitrum uses an EXCLUDE_ADDRESS (0x00000000000000000000000000000000000A4B86) to mark non-votable tokens, tokens delegated to the EXCLUDE_ADDRESS will be excluded from votable supply. You should use this validation module with erc20-votes strategy configured with the same token address and decimals. diff --git a/src/validations/passport-gated/README.md b/src/validations/passport-gated/README.md index fd7349598..acfd0fded 100644 --- a/src/validations/passport-gated/README.md +++ b/src/validations/passport-gated/README.md @@ -63,7 +63,7 @@ The original code utilized the Passport SDK to check if the user has a valid pas ### September 21, 2023 -Code is fully integrated with Passport API. In order to evaluate if an address is eligible for creating/voting on a proposa, It checks for passport stamp collection and minimum score using the `Unique Humanity` scoring mechanism, however it could be upgraded in the future to support other scoring algorithms. +Code is fully integrated with Passport API. In order to evaluate if an address is eligible for creating/voting on a proposal, It checks for passport stamp collection and minimum score using the `Unique Humanity` scoring mechanism, however it could be upgraded in the future to support other scoring algorithms. Unit tests now support multiple example Passports to evaluate different validation scenarios. From 57fb94af184981b83088290f38cd19226a60468e Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Tue, 19 Nov 2024 09:18:59 +0530 Subject: [PATCH 784/815] [delegation] fix add delegatioNetwork param (#1634) * [delegation] fix add delegatioNetwork param * Apply suggestions from code review --- src/strategies/delegation/examples.json | 42 ++++++++++++++++++++----- src/strategies/delegation/index.ts | 15 +++++++-- 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/src/strategies/delegation/examples.json b/src/strategies/delegation/examples.json index e2f824d51..54972f513 100644 --- a/src/strategies/delegation/examples.json +++ b/src/strategies/delegation/examples.json @@ -4,13 +4,15 @@ "strategy": { "name": "delegation", "params": { - "symbol": "POH (delegated)", + "symbol": "APE (delegated)", + "delegationSpace": "apecoin.eth", "strategies": [ { "name": "erc20-balance-of", "params": { - "address": "0x1dAD862095d40d43c2109370121cf087632874dB", - "decimals": 0 + "symbol": "APE", + "address": "0x4d224452801aced8b2f0aebe155379bb5d594381", + "decimals": 18 } } ] @@ -18,10 +20,36 @@ }, "network": "1", "addresses": [ - "0x3c13f2B56AF614aC6381265EcB3B619bA26CC641", - "0x048fee7c3279a24af0790b6b002ded42be021d2b", - "0x139a9032a46c3afe3456eb5f0a35183b5f189cae" + "0x33924aFFe6BC352C246d7f384988f7b4Ad5f9cf2", + "0x56ee461fd756c416c5d2149b3976A019D3b44cc9", + "0x5c4a0fa9Ab5cfc27d198Cab40EC079210902A948" ], - "snapshot": 15705816 + "snapshot": 21218777 + }, + { + "name": "Example query with delegationNetwork", + "strategy": { + "name": "delegation", + "params": { + "symbol": "APE (delegated)", + "delegationSpace": "apecoin.eth", + "delegationNetwork": "1", + "strategies": [ + { + "name": "eth-balance", + "params": { + "symbol": "APE" + } + } + ] + } + }, + "network": "33139", + "addresses": [ + "0x56ee461fd756c416c5d2149b3976A019D3b44cc9", + "0x68Afd61E37267Fd2898F0f965B580182e8D20e6d", + "0xCD02c8b722c8E286fbb353Fd7Bf814Bd38490C27" + ], + "snapshot": 4631281 } ] diff --git a/src/strategies/delegation/index.ts b/src/strategies/delegation/index.ts index 7ea2d7ff5..dac829af2 100644 --- a/src/strategies/delegation/index.ts +++ b/src/strategies/delegation/index.ts @@ -1,5 +1,5 @@ import { getDelegations } from '../../utils/delegation'; -import { getScoresDirect } from '../../utils'; +import { getScoresDirect, getSnapshots } from '../../utils'; export const author = 'bonustrack'; export const version = '0.1.0'; @@ -24,11 +24,20 @@ export async function strategy( ) return {}; const delegationSpace = options.delegationSpace || space; + const delegationNetwork = options.delegationNetwork || network; + let delegationSnapshot = snapshot; + if (delegationNetwork !== network) { + const snapshots = await getSnapshots(network, snapshot, provider, [ + delegationNetwork + ]); + delegationSnapshot = snapshots[delegationNetwork]; + } + const delegations = await getDelegations( delegationSpace, - network, + delegationNetwork, addresses, - snapshot + delegationSnapshot ); if (Object.keys(delegations).length === 0) return {}; From df5b86ab59ce23eac86ca174ba9f20819a2750c4 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Tue, 19 Nov 2024 09:37:14 +0530 Subject: [PATCH 785/815] Update delegation readme --- src/strategies/delegation/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/strategies/delegation/README.md b/src/strategies/delegation/README.md index c1906e369..c9bf6a967 100644 --- a/src/strategies/delegation/README.md +++ b/src/strategies/delegation/README.md @@ -8,6 +8,7 @@ In delegation strategy, the sub strategies defined in params are used to delegat | ----------- | ----------- | | strategies | list of sub strategies to calculate voting power based on delegation | | delegationSpace (optional) | Get delegations of a particular space (by default it take delegations of current space) | +| delegationNetwork | Get delegation from a particular chain instead of default chain | Here is an example of parameters: @@ -34,4 +35,4 @@ Here is an example of parameters: ] } -``` \ No newline at end of file +``` From 299ab43b854ca82ab289a3fd8aafba7faabffa3b Mon Sep 17 00:00:00 2001 From: !ruby <43858546+alexandersazonof@users.noreply.github.com> Date: Tue, 19 Nov 2024 11:17:14 +0300 Subject: [PATCH 786/815] Add new power strategy for sacra (#1632) Co-authored-by: Chaitanya --- src/strategies/sacra-subgraph/README.md | 15 ++++------ src/strategies/sacra-subgraph/index.ts | 38 ++++++++++++------------- 2 files changed, 24 insertions(+), 29 deletions(-) diff --git a/src/strategies/sacra-subgraph/README.md b/src/strategies/sacra-subgraph/README.md index dd63aaf38..8fb6bbffb 100644 --- a/src/strategies/sacra-subgraph/README.md +++ b/src/strategies/sacra-subgraph/README.md @@ -1,17 +1,14 @@ -# Sacra score power from Subgraph +# Sacra power from Subgraph -Calculates users power by hero score from Sacra subgraph. +Calculates users power by passed biomes ``` - heroEntities( + heroActions( where:{ - owner: $address - dead: false + action: 3 + owner_in: [$address] } - orderBy: score - orderDirection: desc - first: 1000 ) { - score + values } ``` \ No newline at end of file diff --git a/src/strategies/sacra-subgraph/index.ts b/src/strategies/sacra-subgraph/index.ts index b9d4d4d84..b26e538c7 100644 --- a/src/strategies/sacra-subgraph/index.ts +++ b/src/strategies/sacra-subgraph/index.ts @@ -7,7 +7,7 @@ const SUBGRAPH_URL = { }; export const author = 'alexandersazonof'; -export const version = '0.0.1'; +export const version = '0.0.2'; export async function strategy( _space, @@ -18,55 +18,53 @@ export async function strategy( snapshot ) { // initialize scores - const scores = {}; + const power = {}; // If graph doesn't exist return if (!SUBGRAPH_URL[network]) { - return scores; + return power; } const params = { - heroEntities: { + heroActions: { __args: { where: { - owner_in: addresses.map((address) => address.toLowerCase()), + action: 3, id_gt: '', - dead: false + owner_in: addresses.map((address) => address.toLowerCase()) }, orderBy: 'id', orderDirection: 'asc', first: 1000 }, - id: true, - score: true, owner: { id: true - } + }, + values: true } }; if (snapshot !== 'latest') { // @ts-ignore - params.heroEntities.__args.block = { number: snapshot }; + params.heroActions.__args.block = { number: snapshot }; } let hasNext = true; while (hasNext) { const result = await subgraphRequest(SUBGRAPH_URL[network], params); - const heroEntities = - result && result.heroEntities ? result.heroEntities : []; - const latest = heroEntities[heroEntities.length - 1]; + const heroActions = result && result.heroActions ? result.heroActions : []; + const latest = heroActions[heroActions.length - 1]; - for (const heroEntity of heroEntities) { - const userAddress = getAddress(heroEntity.owner.id); - const score = heroEntity.score; - scores[userAddress] = (scores[userAddress] ?? 0) + score; + for (const heroAction of heroActions) { + const userAddress = getAddress(heroAction.owner.id); + const userPower = 2 ** heroAction.values[0]; + power[userAddress] = (power[userAddress] ?? 0) + userPower; } - hasNext = heroEntities.length === params.heroEntities.__args.first; - params.heroEntities.__args.where.id_gt = latest ? latest.id : ''; + hasNext = heroActions.length === params.heroActions.__args.first; + params.heroActions.__args.where.id_gt = latest ? latest.id : ''; } - return scores || {}; + return power || {}; } From edd222d32c6451e1eaae3eea12395c0a5db5df82 Mon Sep 17 00:00:00 2001 From: Kevin Park Date: Thu, 21 Nov 2024 20:44:20 +0700 Subject: [PATCH 787/815] [nayms-staking] nayms staking strategy (#1636) * feat: nayms staking strategy * docs: update readme --- src/strategies/index.ts | 4 +- src/strategies/nayms-staking/README.md | 11 ++++ src/strategies/nayms-staking/examples.json | 20 ++++++ src/strategies/nayms-staking/index.ts | 72 ++++++++++++++++++++++ 4 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 src/strategies/nayms-staking/README.md create mode 100644 src/strategies/nayms-staking/examples.json create mode 100644 src/strategies/nayms-staking/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index d189cae6d..5d94fdf72 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -463,6 +463,7 @@ import * as stakingAmountDurationLinear from './staking-amount-duration-linear'; import * as stakingAmountDurationExponential from './staking-amount-duration-exponential'; import * as sacraSubgraph from './sacra-subgraph'; import * as fountainhead from './fountainhead'; +import * as naymsStaking from './nayms-staking'; const strategies = { 'delegatexyz-erc721-balance-of': delegatexyzErc721BalanceOf, @@ -936,7 +937,8 @@ const strategies = { 'staking-amount-duration-linear': stakingAmountDurationLinear, 'staking-amount-duration-exponential': stakingAmountDurationExponential, 'sacra-subgraph': sacraSubgraph, - fountainhead + fountainhead, + 'nayms-staking': naymsStaking }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/nayms-staking/README.md b/src/strategies/nayms-staking/README.md new file mode 100644 index 000000000..4b0d0f165 --- /dev/null +++ b/src/strategies/nayms-staking/README.md @@ -0,0 +1,11 @@ +# Nayms Staking Strategy + +This strategy calculates voting power based on staked NAYM tokens in the Nayms protocol. The voting power is determined by the boosted amount of a user's staked tokens. + +## Overview + +The strategy: + +* Gets the user's entity ID from their address +* Retrieves staking information using the entity ID +* Returns the boosted staking amount as voting power diff --git a/src/strategies/nayms-staking/examples.json b/src/strategies/nayms-staking/examples.json new file mode 100644 index 000000000..006650e5b --- /dev/null +++ b/src/strategies/nayms-staking/examples.json @@ -0,0 +1,20 @@ +[ + { + "name": "Nayms Staking Strategy Example", + "strategy": { + "name": "nayms-staking", + "params": { + "contractAddress": "0x546Fb1621CF8C0e8e3ED8E3508b7c5100ADdBc03", + "decimals": 18, + "entityId": "0x454e544954590000000000004d2ced07e3029ea0f98cff05d1444649e7860b81" + } + }, + "network": "8453", + "addresses": [ + "0x991c989157F99BdF0AD1B7b814F3462A14209636", + "0x127E238C42D91Fa81c5DF6a844EB9804bF6C7360", + "0x50CE06Ab2404C72fbD57620EA8aa0E282065A831" + ], + "snapshot": 21880158 + } +] \ No newline at end of file diff --git a/src/strategies/nayms-staking/index.ts b/src/strategies/nayms-staking/index.ts new file mode 100644 index 000000000..2b3ca2910 --- /dev/null +++ b/src/strategies/nayms-staking/index.ts @@ -0,0 +1,72 @@ +import { BigNumber } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'kevin-fruitful'; +export const version = '0.1.0'; + +const ENTITY_CONSTANT = '0x454e544954590000000000004d2ced07e3029ea0f98cff05d1444649e7860b81'; + +const abi = [ + 'function getEntity(bytes32 _userId) external view returns (bytes32)', + 'function getStakingAmounts(bytes32 _stakerId, bytes32 _entityId) external view returns (uint256 stakedAmount_, uint256 boostedAmount_)' +]; + +// Helper function to convert address to userId (bytes32) +function getIdForAddress(address) { + // Pad the address to 32 bytes with zeros on the right + return '0x' + address.toLowerCase().slice(2).padEnd(64, '0'); +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +) { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + // Initialize multicaller for first batch - getting entities + const entityMulti = new Multicaller(network, provider, abi, { blockTag }); + + // First, get entity for each address + addresses.forEach((address) => { + const userId = getIdForAddress(address); + entityMulti.call( + address, + options.contractAddress, + 'getEntity', + [userId] + ); + }); + + const entityResults = await entityMulti.execute(); + + // Initialize multicaller for second batch - getting staking amounts + const stakingMulti = new Multicaller(network, provider, abi, { blockTag }); + + // For each address, get staking amounts using their entity as stakerId + addresses.forEach((address) => { + const entityId = entityResults[address]; + stakingMulti.call( + address, + options.contractAddress, + 'getStakingAmounts', + [entityId, ENTITY_CONSTANT] + ); + }); + + const stakingResults = await stakingMulti.execute(); + + // Process results - use boostedAmount for voting power + return Object.fromEntries( + addresses.map((address) => { + const result = stakingResults[address] || [BigNumber.from(0), BigNumber.from(0)]; + // Use boostedAmount (second return value) for voting power + const votingPower = parseFloat(formatUnits(result[1], options.decimals || 18)); + return [address, votingPower]; + }) + ); +} \ No newline at end of file From be49f4e76193856e75a71cac907a32ed8a0c9a61 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 22 Nov 2024 00:27:51 +0530 Subject: [PATCH 788/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.30 (#1637) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 6bb7e5236..800432d9d 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.29", + "@snapshot-labs/snapshot.js": "^0.12.30", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 20c8e5fb9..dbdf36745 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.29": - version "0.12.29" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.29.tgz#ea629acccd95afd84d62a1202de03fe2dc84ab53" - integrity sha512-pfyc6ZsuCLoitH0FqYfPiBFZEsYN+i0atWEA3ubQozA/g9sOgDKRyChHoj8A7lEkkNT7gt4J9xKoDk3jo6CTNw== +"@snapshot-labs/snapshot.js@^0.12.30": + version "0.12.30" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.30.tgz#6441f906703084e24b2570d8b2f350c82cd6336f" + integrity sha512-E6LubPwtccJ8w9Ix9a/ZwAiz2BpDv35rB9hvIB8iCfOXJE3KgliLqETooVQSzmRKUDr+F9s+bwBh8uGaRdPn8w== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 0afd2c5176c20c0bb5b7eb084cd3fd0d8e8b44ce Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 22 Nov 2024 07:46:41 +0530 Subject: [PATCH 789/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.32 (#1638) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 800432d9d..24082c32e 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.30", + "@snapshot-labs/snapshot.js": "^0.12.32", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index dbdf36745..079590a86 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.30": - version "0.12.30" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.30.tgz#6441f906703084e24b2570d8b2f350c82cd6336f" - integrity sha512-E6LubPwtccJ8w9Ix9a/ZwAiz2BpDv35rB9hvIB8iCfOXJE3KgliLqETooVQSzmRKUDr+F9s+bwBh8uGaRdPn8w== +"@snapshot-labs/snapshot.js@^0.12.32": + version "0.12.32" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.32.tgz#a92522c8563cf9849706ba6ea5592672aba8adde" + integrity sha512-GRmGMjcR8qdRE94QydVQVPf93lKjJp+J/ISoSTVp3oxKrkBEzY0DZx9gFlysBqF/h69PEeykJWUOH1YfQocYHw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 12c545e0408bb23f5152363871f646182cf0292b Mon Sep 17 00:00:00 2001 From: Hopium <135053852+Hopium21@users.noreply.github.com> Date: Fri, 22 Nov 2024 15:29:16 +0100 Subject: [PATCH 790/815] Fix Grammar and Spelling Issues in Strategy Documentation (#1639) * Update README.md * Update README.md * Update README.md --- src/strategies/botto-dao/README.md | 2 +- src/strategies/brightid/README.md | 2 +- src/strategies/streamr/README.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/strategies/botto-dao/README.md b/src/strategies/botto-dao/README.md index 0aed18649..f13ad0aef 100644 --- a/src/strategies/botto-dao/README.md +++ b/src/strategies/botto-dao/README.md @@ -1,6 +1,6 @@ # Botto Dao Governance strategy -It returns the BOTTO balance of the voters participating in the governance and in the liquidiy mining program +It returns the BOTTO balance of the voters participating in the governance and in the liquidity mining program Here is an example of parameters: ```json diff --git a/src/strategies/brightid/README.md b/src/strategies/brightid/README.md index 86cc8849e..7a0500a64 100644 --- a/src/strategies/brightid/README.md +++ b/src/strategies/brightid/README.md @@ -5,7 +5,7 @@ This strategy returns a score of 1 for voters verified in a BrightID user regist - Public Registry(v5): https://github.com/BrightID/BrightID-SmartContract/blob/v5/snapshot/BrightIDSnapshot.sol - Private Registry: https://github.com/clrfund/monorepo/tree/develop/contracts/contracts/userRegistry -Public registries are maintained by BrightID and can be used if a DAO has no interest on setting one up themselves. +Public registries are maintained by BrightID and can be used if a DAO has no interest in setting one up themselves. Here is an example of parameters for using a public registry contract: Note that when using a public registry, the network is always set to IDChain(74). diff --git a/src/strategies/streamr/README.md b/src/strategies/streamr/README.md index ba2ebc7f3..0ff9e0b4d 100644 --- a/src/strategies/streamr/README.md +++ b/src/strategies/streamr/README.md @@ -2,7 +2,7 @@ The Streamr Network is a peer-to-peer network for publishing and subscribing to data in real-time. Applications use it for decentralized messaging, for example sharing data across applications or broadcasting real-time state changes to large audiences. The decentralized nature of the system makes the data transport scalable, robust, secure, tamper proof, and censorship resistant. -Operators are the node running "miners" in the Streamr Network. They run Streamr nodes, subscribe to streams, and stake DATA in the Sponsorship contract(s) of those streams. When they subscribe, they help making that stream more robust. In return, they receive DATA tokens from the Sponsorship contract, in proportion to their stake. +Operators are the node running "miners" in the Streamr Network. They run Streamr nodes, subscribe to streams, and stake DATA in the Sponsorship contract(s) of those streams. When they subscribe, they help make that stream more robust. In return, they receive DATA tokens from the Sponsorship contract, in proportion to their stake. This is why part of the Operators' DATA tokens are staked in Sponsorships (through an Operator contract that they control). Only a small portion of DATA is expected to be in the Streamr Network participants' wallets, the rest is staked or delegated into the Streamr Network. From e63eeca0c0725edd93222ce9ab1d97889f0672e3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2024 12:05:23 +0530 Subject: [PATCH 791/815] Automated lint (#1641) Co-authored-by: ChaituVR --- src/strategies/nayms-staking/examples.json | 2 +- src/strategies/nayms-staking/index.ts | 45 +++++++++++----------- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/src/strategies/nayms-staking/examples.json b/src/strategies/nayms-staking/examples.json index 006650e5b..66839ca26 100644 --- a/src/strategies/nayms-staking/examples.json +++ b/src/strategies/nayms-staking/examples.json @@ -17,4 +17,4 @@ ], "snapshot": 21880158 } -] \ No newline at end of file +] diff --git a/src/strategies/nayms-staking/index.ts b/src/strategies/nayms-staking/index.ts index 2b3ca2910..2bbfca2c7 100644 --- a/src/strategies/nayms-staking/index.ts +++ b/src/strategies/nayms-staking/index.ts @@ -5,7 +5,8 @@ import { Multicaller } from '../../utils'; export const author = 'kevin-fruitful'; export const version = '0.1.0'; -const ENTITY_CONSTANT = '0x454e544954590000000000004d2ced07e3029ea0f98cff05d1444649e7860b81'; +const ENTITY_CONSTANT = + '0x454e544954590000000000004d2ced07e3029ea0f98cff05d1444649e7860b81'; const abi = [ 'function getEntity(bytes32 _userId) external view returns (bytes32)', @@ -27,46 +28,44 @@ export async function strategy( snapshot ) { const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - + // Initialize multicaller for first batch - getting entities const entityMulti = new Multicaller(network, provider, abi, { blockTag }); - + // First, get entity for each address addresses.forEach((address) => { const userId = getIdForAddress(address); - entityMulti.call( - address, - options.contractAddress, - 'getEntity', - [userId] - ); + entityMulti.call(address, options.contractAddress, 'getEntity', [userId]); }); - + const entityResults = await entityMulti.execute(); - + // Initialize multicaller for second batch - getting staking amounts const stakingMulti = new Multicaller(network, provider, abi, { blockTag }); - + // For each address, get staking amounts using their entity as stakerId addresses.forEach((address) => { const entityId = entityResults[address]; - stakingMulti.call( - address, - options.contractAddress, - 'getStakingAmounts', - [entityId, ENTITY_CONSTANT] - ); + stakingMulti.call(address, options.contractAddress, 'getStakingAmounts', [ + entityId, + ENTITY_CONSTANT + ]); }); - + const stakingResults = await stakingMulti.execute(); - + // Process results - use boostedAmount for voting power return Object.fromEntries( addresses.map((address) => { - const result = stakingResults[address] || [BigNumber.from(0), BigNumber.from(0)]; + const result = stakingResults[address] || [ + BigNumber.from(0), + BigNumber.from(0) + ]; // Use boostedAmount (second return value) for voting power - const votingPower = parseFloat(formatUnits(result[1], options.decimals || 18)); + const votingPower = parseFloat( + formatUnits(result[1], options.decimals || 18) + ); return [address, votingPower]; }) ); -} \ No newline at end of file +} From 9dcad05a3934d8d149a2d90bec3902818a162c8c Mon Sep 17 00:00:00 2001 From: Maks Date: Mon, 25 Nov 2024 07:37:03 +0100 Subject: [PATCH 792/815] Fix Grammar and Wording Issues in Strategy Documentation (#1640) * Update README.md * Update README.md * Update README.md --------- Co-authored-by: Chaitanya --- src/strategies/eth-balance/README.md | 4 ++-- src/strategies/fight-club/README.md | 2 +- src/strategies/reliquary/README.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/strategies/eth-balance/README.md b/src/strategies/eth-balance/README.md index ab04c9e52..81f507328 100644 --- a/src/strategies/eth-balance/README.md +++ b/src/strategies/eth-balance/README.md @@ -1,6 +1,6 @@ # eth-balance -This strategy is used for use ETH balance as voting power. +This strategy is used for ETH balance as voting power. The balance displayed may vary depending on the network, and represents the balance of the main currency used on that network (e.g. ETH on Ethereum mainnet, BNB on Binance Smart Chain, etc.). @@ -10,4 +10,4 @@ This strategy does need any parameters. | Param | Type | Default | Description | | --- | --- | --- | --- | -| `symbol`(optional) | `string` | `` | The symbol of the currency to used for the balance. | +| `symbol`(optional) | `string` | `` | The symbol of the currency to be used for the balance. | diff --git a/src/strategies/fight-club/README.md b/src/strategies/fight-club/README.md index a9d4eb281..fbe17e8c7 100644 --- a/src/strategies/fight-club/README.md +++ b/src/strategies/fight-club/README.md @@ -52,6 +52,6 @@ score = glovePower * weightClassMultiplier addresses and 10 distinct weight class kudo IDs. > **Warning**: This strategy uses `ethers.utils.BigNumber.toNumber()` and will - fail if a voter's `glovePower` or `weightClassMultiplier` is is greater than + fail if a voter's `glovePower` or `weightClassMultiplier` is greater than or equal to `Number.MAX_SAFE_INTEGER` or less than or equal to `Number.MIN_SAFE_INTEGER` diff --git a/src/strategies/reliquary/README.md b/src/strategies/reliquary/README.md index 10ded2c7a..36f3e1fcf 100644 --- a/src/strategies/reliquary/README.md +++ b/src/strategies/reliquary/README.md @@ -13,7 +13,7 @@ or if we use multiplier In other words, if the nft has reached max voting level the voting power is equal to the amount deposited. -Since Relic levels only update on an interaction, we have to chose if we want to use the current 'actual' level, or the level which the relic would +Since Relic levels only update on an interaction, we have to choose if we want to use the current 'actual' level, or the level which the relic would have after an update. This can be done using the `useLevelOnUpdate` flag. Configuration: From 96e2cf312ff13ae5bd5804772d7262c89ebb467c Mon Sep 17 00:00:00 2001 From: Jean-Grimal <83286814+Jean-Grimal@users.noreply.github.com> Date: Fri, 29 Nov 2024 03:51:00 +0100 Subject: [PATCH 793/815] [morpho-delegation] morpho-delegation strategy (#1625) * feat: add morpho delegation strategy * fix: change example address * feat: update strategy * Update src/strategies/morpho-delegation/README.md Co-authored-by: Julien THOMAS <61523188+julien-devatom@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Chaitanya * fix: typo --------- Co-authored-by: Julien THOMAS <61523188+julien-devatom@users.noreply.github.com> Co-authored-by: Chaitanya --- src/strategies/index.ts | 4 +- src/strategies/morpho-delegation/README.md | 14 +++++ .../morpho-delegation/examples.json | 20 +++++++ src/strategies/morpho-delegation/index.ts | 60 +++++++++++++++++++ src/strategies/morpho-delegation/schema.json | 34 +++++++++++ 5 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 src/strategies/morpho-delegation/README.md create mode 100644 src/strategies/morpho-delegation/examples.json create mode 100644 src/strategies/morpho-delegation/index.ts create mode 100644 src/strategies/morpho-delegation/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 5d94fdf72..cb46d69f3 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -464,6 +464,7 @@ import * as stakingAmountDurationExponential from './staking-amount-duration-exp import * as sacraSubgraph from './sacra-subgraph'; import * as fountainhead from './fountainhead'; import * as naymsStaking from './nayms-staking'; +import * as morphoDelegation from './morpho-delegation'; const strategies = { 'delegatexyz-erc721-balance-of': delegatexyzErc721BalanceOf, @@ -938,7 +939,8 @@ const strategies = { 'staking-amount-duration-exponential': stakingAmountDurationExponential, 'sacra-subgraph': sacraSubgraph, fountainhead, - 'nayms-staking': naymsStaking + 'nayms-staking': naymsStaking, + 'morpho-delegation': morphoDelegation }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/morpho-delegation/README.md b/src/strategies/morpho-delegation/README.md new file mode 100644 index 000000000..9b1401fe2 --- /dev/null +++ b/src/strategies/morpho-delegation/README.md @@ -0,0 +1,14 @@ +# morpho-delegation + +This strategy allows to get any address' voting power for tokens inheriting from Morpho Labs Delegation Token. +It sums the delegated assets plus the balance of the user (if not delegated) + +Here is an example of parameters: + +```json +{ + "address": "0x3CF66a662390e37ff260D0cBAa8Af6d426D60D43", + "symbol": "MORPHO", + "decimals": 18 +} +``` diff --git a/src/strategies/morpho-delegation/examples.json b/src/strategies/morpho-delegation/examples.json new file mode 100644 index 000000000..c860b2b04 --- /dev/null +++ b/src/strategies/morpho-delegation/examples.json @@ -0,0 +1,20 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "morpho-delegation", + "params": { + "address": "0x3CF66a662390e37ff260D0cBAa8Af6d426D60D43", + "symbol": "MORPHO", + "decimals": 18 + } + }, + "network": "11155111", + "addresses": [ + "0x3857CE40B832bD339D775Ba851B35488d80a8eF9", + "0x5506ac7914BB27D06A67Fc54c08b9AACD5023634", + "0xF404dBb34f7F16BfA315daaA9a8C33c7aBe94eD1" + ], + "snapshot": 7024881 + } +] diff --git a/src/strategies/morpho-delegation/index.ts b/src/strategies/morpho-delegation/index.ts new file mode 100644 index 000000000..0fe139a5f --- /dev/null +++ b/src/strategies/morpho-delegation/index.ts @@ -0,0 +1,60 @@ +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; +import { ADDRESS_ZERO } from '@uniswap/v3-sdk'; + +export const author = 'morpho-labs'; +export const version = '0.1.0'; + +const abi = [ + 'function delegatedVotingPower(address account) external view returns (uint256)', + 'function delegatee(address delegatee) public view returns (uint256)', + 'function balanceOf(address account) external view returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const delegatedVotingPowerMulti = new Multicaller(network, provider, abi, { + blockTag + }); + const delegateeMulti = new Multicaller(network, provider, abi, { blockTag }); + const balanceOfMulti = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => { + delegatedVotingPowerMulti.call( + address, + options.address, + 'delegatedVotingPower', + [address] + ); + delegateeMulti.call(address, options.address, 'delegatee', [address]); + balanceOfMulti.call(address, options.address, 'balanceOf', [address]); + }); + const [delegatedVotingPowerResult, delegateeResult, balanceOfResult] = + await Promise.all([ + delegatedVotingPowerMulti.execute(), + delegateeMulti.execute(), + balanceOfMulti.execute() + ]); + + return Object.fromEntries( + Object.entries(delegatedVotingPowerResult).map(([address, votingData]) => [ + address, + parseFloat( + formatUnits( + delegatedVotingPowerResult[address] + + (delegateeResult[address].delegatee === ADDRESS_ZERO + ? balanceOfResult[address].balanceOf + : 0n), + options.decimals + ) + ) + ]) + ); +} diff --git a/src/strategies/morpho-delegation/schema.json b/src/strategies/morpho-delegation/schema.json new file mode 100644 index 000000000..f1c138d1a --- /dev/null +++ b/src/strategies/morpho-delegation/schema.json @@ -0,0 +1,34 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. MORPHO"], + "maxLength": 16 + }, + "address": { + "type": "string", + "title": "Contract address", + "examples": ["e.g. 0x3CF66a662390e37ff260D0cBAa8Af6d426D60D43"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 18"], + "minimum": 0 + } + }, + "required": ["address", "decimals"], + "additionalProperties": false + } + } +} From 4a23f6a08590865ebd0a4b172e6cd5095c48c734 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 29 Nov 2024 13:41:19 +0530 Subject: [PATCH 794/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.33 (#1643) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 24082c32e..25d29ee06 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.32", + "@snapshot-labs/snapshot.js": "^0.12.33", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 079590a86..e1869c983 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.32": - version "0.12.32" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.32.tgz#a92522c8563cf9849706ba6ea5592672aba8adde" - integrity sha512-GRmGMjcR8qdRE94QydVQVPf93lKjJp+J/ISoSTVp3oxKrkBEzY0DZx9gFlysBqF/h69PEeykJWUOH1YfQocYHw== +"@snapshot-labs/snapshot.js@^0.12.33": + version "0.12.33" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.33.tgz#3ce3166419931ef31f1070449318b98b9c482078" + integrity sha512-N5diNuGsglbcQ/t63EdnpUvl2bQO6TerpJE4bA+QHCEoqy/XQdqUjksosn/MWKt1gQfBjTYiN3aPGV4uj1mspA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 84e5e8b07de69a036b8781878308171884742ab7 Mon Sep 17 00:00:00 2001 From: Dmitry <98899785+mdqst@users.noreply.github.com> Date: Mon, 2 Dec 2024 12:04:10 +0300 Subject: [PATCH 795/815] Fix variable shadowing in getDelegations (#1644) --- src/utils/delegation.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/delegation.ts b/src/utils/delegation.ts index f38a02e42..b48a34665 100644 --- a/src/utils/delegation.ts +++ b/src/utils/delegation.ts @@ -5,7 +5,7 @@ const DELEGATION_DATA_CACHE = {}; // delegations with overrides export async function getDelegations(space, network, addresses, snapshot) { - const addressesLc = addresses.map((addresses) => addresses.toLowerCase()); + const addressesLc = addresses.map((address) => address.toLowerCase()); const delegatesBySpace = await getDelegatesBySpace(network, space, snapshot); const delegations = delegatesBySpace.filter( From b4f3314740218ed86dcb88711dcf490b04b48143 Mon Sep 17 00:00:00 2001 From: Jean-Grimal <83286814+Jean-Grimal@users.noreply.github.com> Date: Mon, 2 Dec 2024 13:59:33 +0100 Subject: [PATCH 796/815] [morpho-delegation] Fix: morpho-delegation strategy (#1646) * feat: add morpho delegation strategy * fix: change example address * feat: update strategy * Update src/strategies/morpho-delegation/README.md Co-authored-by: Julien THOMAS <61523188+julien-devatom@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Chaitanya * fix: typo * fix: morpho-delegation strategy --------- Co-authored-by: Julien THOMAS <61523188+julien-devatom@users.noreply.github.com> Co-authored-by: Chaitanya --- src/strategies/morpho-delegation/index.ts | 27 +++++++++++++---------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/strategies/morpho-delegation/index.ts b/src/strategies/morpho-delegation/index.ts index 0fe139a5f..81b5e74e1 100644 --- a/src/strategies/morpho-delegation/index.ts +++ b/src/strategies/morpho-delegation/index.ts @@ -1,6 +1,6 @@ import { formatUnits } from '@ethersproject/units'; import { Multicaller } from '../../utils'; -import { ADDRESS_ZERO } from '@uniswap/v3-sdk'; +import { BigNumber } from '@ethersproject/bignumber'; export const author = 'morpho-labs'; export const version = '0.1.0'; @@ -36,22 +36,25 @@ export async function strategy( delegateeMulti.call(address, options.address, 'delegatee', [address]); balanceOfMulti.call(address, options.address, 'balanceOf', [address]); }); - const [delegatedVotingPowerResult, delegateeResult, balanceOfResult] = - await Promise.all([ - delegatedVotingPowerMulti.execute(), - delegateeMulti.execute(), - balanceOfMulti.execute() - ]); + const [delegatedVotingPowerResult, delegateeResult, balanceOfResult]: Record< + string, + BigNumber + >[] = await Promise.all([ + delegatedVotingPowerMulti.execute(), + delegateeMulti.execute(), + balanceOfMulti.execute() + ]); return Object.fromEntries( - Object.entries(delegatedVotingPowerResult).map(([address, votingData]) => [ + Object.entries(delegatedVotingPowerResult).map(([address]) => [ address, parseFloat( formatUnits( - delegatedVotingPowerResult[address] + - (delegateeResult[address].delegatee === ADDRESS_ZERO - ? balanceOfResult[address].balanceOf - : 0n), + delegatedVotingPowerResult[address].add( + delegateeResult[address].isZero() + ? balanceOfResult[address] + : BigNumber.from(0) + ), options.decimals ) ) From 2a657503de1c8184ce59fb3228bdafccc224c548 Mon Sep 17 00:00:00 2001 From: Javier G Date: Tue, 3 Dec 2024 06:29:36 +0100 Subject: [PATCH 797/815] Remove split-delegation schema (#1647) --- .../subgraph-split-delegation/schema.json | 38 ------------------- 1 file changed, 38 deletions(-) delete mode 100644 src/strategies/subgraph-split-delegation/schema.json diff --git a/src/strategies/subgraph-split-delegation/schema.json b/src/strategies/subgraph-split-delegation/schema.json deleted file mode 100644 index be2118cfb..000000000 --- a/src/strategies/subgraph-split-delegation/schema.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$ref": "#/definitions/Strategy", - "definitions": { - "Strategy": { - "title": "Strategy", - "type": "object", - "properties": { - "subgraphUrl": { - "type": "string", - "title": "Subgraph endpoint" - }, - "strategies": { - "title": "Strategies", - "type": "array", - "items": { - "title": "Strategy", - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "network": { - "type": "string" - }, - "params": { - "type": "object" - } - }, - "required": ["name", "params"] - } - } - }, - "required": ["subgraphUrl", "strategies"], - "additionalProperties": false - } - } -} From cb78534f81514adcf38527502df64d633ce28eb5 Mon Sep 17 00:00:00 2001 From: Vladan Thales <78506565+vladanthales@users.noreply.github.com> Date: Tue, 3 Dec 2024 09:25:58 +0100 Subject: [PATCH 798/815] [thales] Change Base subgraph URL for Thales strategy (#1648) * Change Base subgraph URL for Thales strategy * Update src/strategies/thales/index.ts Co-authored-by: Chaitanya --------- Co-authored-by: Vladan Thales Co-authored-by: Chaitanya --- src/strategies/thales/index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/strategies/thales/index.ts b/src/strategies/thales/index.ts index 30b963540..048504420 100644 --- a/src/strategies/thales/index.ts +++ b/src/strategies/thales/index.ts @@ -2,8 +2,8 @@ import { getAddress } from '@ethersproject/address'; import { formatUnits } from '@ethersproject/units'; import { getSnapshots, subgraphRequest } from '../../utils'; -export const author = 'vpoklopic'; -export const version = '1.0.4'; +export const author = 'thales-markets'; +export const version = '1.0.5'; enum NetworkId { Optimism = 10, @@ -16,7 +16,7 @@ const THALES_SUBGRAPH_URL = { 'https://subgrapher.snapshot.org/subgraph/arbitrum/2WQ9TKJt96NUxuS2DbR7B4aAwcU9CMiaBH7fwZZfjpn1', arbitrum: 'https://subgrapher.snapshot.org/subgraph/arbitrum/GRHJHjVRzHrQoN86VyjXMDTDiw9pHNB9NqQJxQmnZcwb', - base: 'https://api.studio.thegraph.com/query/11948/thales-token-base/version/latest' + base: 'https://subgrapher.snapshot.org/subgraph/arbitrum/3cwvVz7HwAJD76gfmjfu8A92e9cELN9TEvY6rkdxyjaY' }; function returnGraphParams(addresses: string[], block: string | number) { From 1d2f9cde02ff49e4ca8de28f68485ecb89890cb0 Mon Sep 17 00:00:00 2001 From: rusttech Date: Tue, 3 Dec 2024 18:30:58 +0800 Subject: [PATCH 799/815] chore: remove redundant words in comment (#1649) Signed-off-by: rusttech --- src/strategies/masterchef-pool-balance-price/README.md | 2 +- src/strategies/masterchef-pool-balance-price/index.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/strategies/masterchef-pool-balance-price/README.md b/src/strategies/masterchef-pool-balance-price/README.md index 8b60d7f01..deae7b3b0 100644 --- a/src/strategies/masterchef-pool-balance-price/README.md +++ b/src/strategies/masterchef-pool-balance-price/README.md @@ -55,7 +55,7 @@ The price is sourced from CoinGecko. - **log:** Boolean flag to enable or disable logging to the console (used for debugging purposes during development) - **antiWhale.enable:** Boolean flag to apply an anti-whale measure reducing the effect on the voting power as the token amount increases. - - if enabled will apply the the following to the result: + - if enabled will apply the following to the result: ```none If result > antiWhale.threshold diff --git a/src/strategies/masterchef-pool-balance-price/index.ts b/src/strategies/masterchef-pool-balance-price/index.ts index 1ceb8d90e..92668d1d4 100644 --- a/src/strategies/masterchef-pool-balance-price/index.ts +++ b/src/strategies/masterchef-pool-balance-price/index.ts @@ -42,7 +42,7 @@ export const version = '0.2.0'; * - log: Boolean flag to enable or disable logging to the console (used for debugging purposes during development) * * - antiWhale.enable: Boolean flag to apply an anti-whale measure reducing the effect on the voting power as the token amount increases. - * - if enabled will apply the the following to the result: + * - if enabled will apply the following to the result: * * If result > antiWhale.threshold * result = antiWhale.inflectionPoint * ( result / antiWhale.inflectionPoint ) ^ antiWhale.exponent From c95e9d31d99b5a8c1d678cf872227bc15377dde1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 7 Dec 2024 22:18:07 +0530 Subject: [PATCH 800/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.36 (#1650) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 25d29ee06..5e9f8cb80 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.33", + "@snapshot-labs/snapshot.js": "^0.12.36", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index e1869c983..a9c64e67f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.33": - version "0.12.33" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.33.tgz#3ce3166419931ef31f1070449318b98b9c482078" - integrity sha512-N5diNuGsglbcQ/t63EdnpUvl2bQO6TerpJE4bA+QHCEoqy/XQdqUjksosn/MWKt1gQfBjTYiN3aPGV4uj1mspA== +"@snapshot-labs/snapshot.js@^0.12.36": + version "0.12.36" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.36.tgz#89ff38be1b2ab2b239ab5caf0b20c5c4e65eed4e" + integrity sha512-cCwX8mLattshjMLzb731DWDQ8/D0uHINBjTNyFhdyxwW/7B1Dr4wAIQHR+iXwJDA3aiqDJPIP6llD1HRRllvBQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From b173a93c7049efbd91dd370895b560cad4552d84 Mon Sep 17 00:00:00 2001 From: Agustin Jamardo Date: Mon, 9 Dec 2024 18:31:25 +0100 Subject: [PATCH 801/815] [botto-dao-base] version 1 botto dao base (#1651) * version 0.1 botto dao base * removed try catch not needed * Update src/strategies/botto-dao-base/index.ts * updated examples * fix in tests. --------- Co-authored-by: Chaitanya --- src/strategies/botto-dao-base/README.md | 33 +++++++++++++++ src/strategies/botto-dao-base/examples.json | 24 +++++++++++ src/strategies/botto-dao-base/index.ts | 47 +++++++++++++++++++++ src/strategies/index.ts | 2 + 4 files changed, 106 insertions(+) create mode 100644 src/strategies/botto-dao-base/README.md create mode 100644 src/strategies/botto-dao-base/examples.json create mode 100644 src/strategies/botto-dao-base/index.ts diff --git a/src/strategies/botto-dao-base/README.md b/src/strategies/botto-dao-base/README.md new file mode 100644 index 000000000..f13ad0aef --- /dev/null +++ b/src/strategies/botto-dao-base/README.md @@ -0,0 +1,33 @@ +# Botto Dao Governance strategy + +It returns the BOTTO balance of the voters participating in the governance and in the liquidity mining program + +Here is an example of parameters: +```json +[ + { + "name": "Botto Dao Governance strategy", + "strategy": { + "name": "botto-dao", + "params": { + "token": "0x9dfad1b7102d46b1b197b90095b5c4e9f5845bba", + "stakingAddress": "0x19CD3998f106eCC40eE7668c19C47e18b491e8a6", + "miningAddress": "0xf8515Cae6915838543bCD7756F39268CE8F853Fd", + "liquidityAddress": "0x9ff68f61ca5eb0c6606dc517a9d44001e564bb66", + "symbol": "BOTTO", + "decimals": 18 + } + }, + "network": "1", + "addresses": [ + "0xf2b10b41961f6bc3801e7946dabe5572158a78a5", + "0xea32cf979bdaf8d3bb4121d58515d4623a27f3e0", + "0x7173d417cfa1cdec794fa21f4ca8a71d181b2ca0", + "0x58787f1659b2fd8853918dab6d4a1565569e6044", + "0x7dbc5f88986db946f1d5987edfbf9c6917230fa2" + ], + "snapshot": 13808330 + } +] + +``` diff --git a/src/strategies/botto-dao-base/examples.json b/src/strategies/botto-dao-base/examples.json new file mode 100644 index 000000000..f4fd75d0e --- /dev/null +++ b/src/strategies/botto-dao-base/examples.json @@ -0,0 +1,24 @@ +[ + { + "name": "Botto Dao Base Governance strategy", + "strategy": { + "name": "botto-dao-base", + "params": { + "token": "0x24914cb6bd01e6a0cf2a9c0478e33c25926e6a0c", + "stakingAddress": "0x8a7a5991aAf142B43E58253Bd6791e240084F0A9", + "symbol": "BOTTO", + "decimals": 18 + } + }, + "network": "8453", + "addresses": [ + "0x85D906C217Bb4c7b7f7CDE0D4318fAfa02f6F01d", + "0x276Dfeec6F5772156B19116d76D1E3DEB3B6F0b4", + "0x56768B032Fc12D2e911eF654B0054e26a58cef74", + "0x7173d417cfa1cdec794fa21f4ca8a71d181b2ca0", + "0x58787f1659b2fd8853918dab6d4a1565569e6044", + "0x7dbc5f88986db946f1d5987edfbf9c6917230fa2" + ], + "snapshot": 23250193 + } +] diff --git a/src/strategies/botto-dao-base/index.ts b/src/strategies/botto-dao-base/index.ts new file mode 100644 index 000000000..969dd1235 --- /dev/null +++ b/src/strategies/botto-dao-base/index.ts @@ -0,0 +1,47 @@ +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'agustinjch'; +export const version = '1.0.0'; + +const abi = [ + 'function userStakes(address) external view returns(uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const _formatUnits = (value) => + parseFloat(formatUnits(value, options.decimals)); + + const multiBalances = new Multicaller(network, provider, abi, { + blockTag + }); + + addresses.forEach((address) => { + multiBalances.call( + address + '-stakedBotto', + options.stakingAddress, + 'userStakes', + [address] + ); + }); + + const balances: Record = await multiBalances.execute(); + + const result = Object.fromEntries( + addresses.map((adr) => { + const stakedBotto = _formatUnits(balances[adr + '-stakedBotto'] || 0); + return [adr, stakedBotto]; + }) + ); + + return result; +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index cb46d69f3..4f1bda327 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -238,6 +238,7 @@ import * as orangeReputationNftBasedVoting from './orange-reputation-nft-based-v import * as squidDao from './squid-dao'; import * as pathBalanceStakedAndLocked from './path-balance-staked-and-locked'; import * as bottoDao from './botto-dao'; +import * as bottoDaoBase from './botto-dao-base'; import * as genart from './genart'; import * as erc721MultiRegistryWeighted from './erc721-multi-registry-weighted'; import * as balancerPoolid from './balancer-poolid'; @@ -718,6 +719,7 @@ const strategies = { 'orange-reputation-nft-based-voting': orangeReputationNftBasedVoting, 'squid-dao': squidDao, 'botto-dao': bottoDao, + 'botto-dao-base': bottoDaoBase, genart, 'path-balance-staked-and-locked': pathBalanceStakedAndLocked, 'balancer-poolid': balancerPoolid, From dd197e87507e53b1e93a7732164be1cf1c99b885 Mon Sep 17 00:00:00 2001 From: Marsot Pierre Date: Tue, 17 Dec 2024 14:27:08 +0100 Subject: [PATCH 802/815] [sd-gauge-less-vote-boost-crosschain] Add sd-gauge-less-vote-boost-crosschain strategy (#1653) * reverse delegation * add sd-gauge-less-vote-boost-crosschain * remove sdReverseDelegation --------- Co-authored-by: Chaitanya --- src/strategies/index.ts | 2 + .../README.md | 24 ++ .../examples.json | 26 ++ .../index.ts | 253 ++++++++++++++++++ 4 files changed, 305 insertions(+) create mode 100644 src/strategies/sd-gauge-less-vote-boost-crosschain/README.md create mode 100644 src/strategies/sd-gauge-less-vote-boost-crosschain/examples.json create mode 100644 src/strategies/sd-gauge-less-vote-boost-crosschain/index.ts diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 4f1bda327..50b420287 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -383,6 +383,7 @@ import * as sdVoteBoostTWAVPV2 from './sd-vote-boost-twavp-v2'; import * as sdVoteBoostTWAVPV3 from './sd-vote-boost-twavp-v3'; import * as sdVoteBoostTWAVPV4 from './sd-vote-boost-twavp-v4'; import * as sdGaugeLessVoteBoost from './sd-gauge-less-vote-boost'; +import * as sdGaugeLessVoteBoostCrosschain from './sd-gauge-less-vote-boost-crosschain'; import * as sdVoteBalanceOfTwavpPool from './sdvote-balanceof-twavp-pool'; import * as sdVoteBoostTWAVPVsdToken from './sd-vote-boost-twavp-vsdtoken'; import * as sdVoteBoostTWAVPVCrossChain from './sd-vote-boost-twavp-vsdcrv-crosschain'; @@ -861,6 +862,7 @@ const strategies = { 'sd-vote-boost-twavp-v3': sdVoteBoostTWAVPV3, 'sd-vote-boost-twavp-v4': sdVoteBoostTWAVPV4, 'sd-gauge-less-vote-boost': sdGaugeLessVoteBoost, + 'sd-gauge-less-vote-boost-crosschain': sdGaugeLessVoteBoostCrosschain, 'sdvote-balanceof-twavp-pool': sdVoteBalanceOfTwavpPool, 'sd-vote-boost-twavp-vsdtoken': sdVoteBoostTWAVPVsdToken, 'sd-vote-boost-twavp-vsdcrv-crosschain': sdVoteBoostTWAVPVCrossChain, diff --git a/src/strategies/sd-gauge-less-vote-boost-crosschain/README.md b/src/strategies/sd-gauge-less-vote-boost-crosschain/README.md new file mode 100644 index 000000000..f9949f814 --- /dev/null +++ b/src/strategies/sd-gauge-less-vote-boost-crosschain/README.md @@ -0,0 +1,24 @@ +# sd-gauge-less-vote-boost-crosschain + +This strategy is used by Stake DAO to vote with sdToken using Time Weighted Averaged Voting Power (TWAVP) system and adapted for veSDT boost delegation with possibility to whiteliste address to by pass TWAVP. + +``` +VotingPower(user) = veToken.balanceOf(liquidLocker) * (average.sdTokenGauge.working_balances(user) / sdTokenGauge.working_supply) +``` + +>_sampleSize: in days_ +>_sampleStep: the number of block for `average` calculation (max 5)_ + +Here is an example of parameters: + +```json +{ + "sdTokenGauge": "0xE2496134149e6CD3f3A577C2B08A6f54fC23e6e4", + "symbol": "sdToken", + "decimals": 18, + "twavpDaysInterval": 10, + "twavpNumberOfBlocks": 2, + "whiteListedAddress": ["0x1c0D72a330F2768dAF718DEf8A19BAb019EEAd09", "0x931DaBf6721E47E6f5aeb19F6f5d48646144f484"], + "blocksPerDay": 28798 +} +``` \ No newline at end of file diff --git a/src/strategies/sd-gauge-less-vote-boost-crosschain/examples.json b/src/strategies/sd-gauge-less-vote-boost-crosschain/examples.json new file mode 100644 index 000000000..e9fa613f5 --- /dev/null +++ b/src/strategies/sd-gauge-less-vote-boost-crosschain/examples.json @@ -0,0 +1,26 @@ +[ + { + "name": "Stake DAO vote boost using working balance", + "strategy": { + "name": "sd-gauge-less-vote-boost-crosschain", + "params": { + "sdTokenGauge": "0xE2496134149e6CD3f3A577C2B08A6f54fC23e6e4", + "symbol": "sdToken", + "decimals": 18, + "twavpDaysInterval": 10, + "twavpNumberOfBlocks": 2, + "whiteListedAddress": ["0x1c0D72a330F2768dAF718DEf8A19BAb019EEAd09"], + "blocksPerDay": 28798 + } + }, + "network": "56", + "addresses": [ + "0xb4542526AfeE2FdA1D584213D1521272a398B42a", + "0x931DaBf6721E47E6f5aeb19F6f5d48646144f484", + "0x3FbE6216dB591372D3Bb8428ac87B162F7B8601f", + "0x803585733d4554e712dcaCc2AcEA3a23b96de1e0", + "0xD4f9FE0039Da59e6DDb21bbb6E84e0C9e83D73eD" + ], + "snapshot": 44834720 + } +] diff --git a/src/strategies/sd-gauge-less-vote-boost-crosschain/index.ts b/src/strategies/sd-gauge-less-vote-boost-crosschain/index.ts new file mode 100644 index 000000000..f450e23e4 --- /dev/null +++ b/src/strategies/sd-gauge-less-vote-boost-crosschain/index.ts @@ -0,0 +1,253 @@ +import { getAddress } from '@ethersproject/address'; +import { getProvider, multicall, subgraphRequest } from '../../utils'; +import { BigNumber } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; + +export const author = 'pierremarsotlyon1'; +export const version = '0.0.1'; + +const VE_SDT = '0x0C30476f66034E11782938DF8e4384970B6c9e8a'; +const VE_PROXY_BOOST_SDT = '0xD67bdBefF01Fc492f1864E61756E5FBB3f173506'; +const TOKENLESS_PRODUCTION = 40; + +// Used ABI +const abi = [ + 'function balanceOf(address account) external view returns (uint256)', + 'function working_supply() external view returns (uint256)', + 'function totalSupply() external view returns (uint256)', + 'function working_balances(address account) external view returns (uint256)', + 'function balances(uint256 i) external view returns (uint256)', + 'function adjusted_balance_of(address user) external view returns (uint256)' +]; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + // Maximum of 2 multicall! + if (options.twavpNumberOfBlocks > 2) { + throw new Error('maximum of 2 calls'); + } + + // Maximum of 20 whitelisted address + if (options.whiteListedAddress.length > 20) { + throw new Error('maximum of 20 whitelisted address'); + } + + // Addresses in tlc + addresses = addresses.map((addr) => addr.toLowerCase()); + + // --- Create block number list for twavp + // Obtain last block number + // Create block tag + let blockTag = 0; + if (typeof snapshot === 'number') { + blockTag = snapshot; + } else { + blockTag = await provider.getBlockNumber(); + } + + // Mainnet data + const mainnetProvider = getProvider("1"); + + // Get corresponding block number on mainnet + let mainnetBlockTag = await getIDChainBlock( + blockTag, + provider, + "1" + ); + + if (mainnetBlockTag === "latest") { + mainnetBlockTag = await mainnetProvider.getBlockNumber(); + } + + // Create block lists + const blockListMainnet = getPreviousBlocks( + mainnetBlockTag, + options.twavpNumberOfBlocks, + options.twavpDaysInterval, + 7200 + ); + + const blockList = getPreviousBlocks( + blockTag, + options.twavpNumberOfBlocks, + options.twavpDaysInterval, + options.blocksPerDay + ); + + // Queries + const ajustedBalancesMainnet = addresses.map((address: any) => [ + VE_PROXY_BOOST_SDT, + 'adjusted_balance_of', + [address] + ]); + + const sdTknGaugeBalanceCurrentChain = addresses.map((address: any) => [ + options.sdTokenGauge, + 'balanceOf', + [address] + ]); + + const responsesMainnet: any[] = []; + const responsesCurrentChain: any[] = []; + + let veSDTTotalSupply = 0; + let sdTokenGaugeTotalSupply = 0; + + for (let i = 0; i < options.twavpNumberOfBlocks; i++) { + const isEnd = i === options.twavpNumberOfBlocks - 1; + + // Mainnet + let calls: any[] = ajustedBalancesMainnet; + if (isEnd) { + // Fetch veSDT total supply + calls.push([VE_SDT, 'totalSupply']); + } + + let callResp: any[] = await multicall("1", mainnetProvider, abi, calls, { + blockTag: blockListMainnet[i] + }); + + if (isEnd) { + veSDTTotalSupply = parseFloat(formatUnits(callResp.pop()[0], 18)); + } + + responsesMainnet.push(callResp); + + // Destination chain + calls = sdTknGaugeBalanceCurrentChain; + if (isEnd) { + calls.push([options.sdTokenGauge, 'totalSupply']); + } + + callResp = await multicall( + network, + provider, + abi, + calls, + { blockTag: blockList[i] } + ); + + if (isEnd) { + sdTokenGaugeTotalSupply = parseFloat( + formatUnits(callResp.pop()[0], 18) + ); + } + + responsesCurrentChain.push(callResp); + } + + return Object.fromEntries( + Array(addresses.length) + .fill('x') + .map((_, i) => { + // Init array of working balances for user + const userWorkingBalances: number[] = []; + + for (let j = 0; j < options.twavpNumberOfBlocks; j++) { + const voting_balance = parseFloat( + formatUnits(BigNumber.from(responsesMainnet[j].shift()[0]), 18) + ); + const l = parseFloat( + formatUnits( + BigNumber.from(responsesCurrentChain[j].shift()[0]), + 18 + ) + ); + + let lim = (l * TOKENLESS_PRODUCTION) / 100; + if (veSDTTotalSupply > 0) { + lim += + (((sdTokenGaugeTotalSupply * voting_balance) / + veSDTTotalSupply) * + (100 - TOKENLESS_PRODUCTION)) / + 100; + } + + userWorkingBalances.push(Math.min(l, lim)); + } + + // Get average working balance. + const averageWorkingBalance = average( + userWorkingBalances, + addresses[i], + options.whiteListedAddress + ); + + // Return address and voting power + return [getAddress(addresses[i]), Number(averageWorkingBalance)]; + }) + ); +} + +function getPreviousBlocks( + currentBlockNumber: number, + numberOfBlocks: number, + daysInterval: number, + blocksPerDay: number +): number[] { + // Calculate total blocks interval + const totalBlocksInterval = blocksPerDay * daysInterval; + // Calculate block interval + const blockInterval = totalBlocksInterval / (numberOfBlocks - 1); + + // Init array of block numbers + const blockNumbers: number[] = []; + + for (let i = 0; i < numberOfBlocks; i++) { + // Calculate block number + const blockNumber = + currentBlockNumber - totalBlocksInterval + blockInterval * i; + + // Add block number to array + blockNumbers.push(Math.round(blockNumber)); + } + + // Return array of block numbers + return blockNumbers; +} + +function average( + numbers: number[], + address: string, + whiteListedAddress: string[] +): number { + // If no numbers, return 0 to avoid division by 0. + if (numbers.length === 0) return 0; + + // If address is whitelisted, return most recent working balance. i.e. no twavp applied. + if (whiteListedAddress.includes(address)) return numbers[numbers.length - 1]; + + // Init sum + let sum = 0; + // Loop through all elements and add them to sum + for (let i = 0; i < numbers.length; i++) { + sum += numbers[i]; + } + + // Return sum divided by array length to get mean + return sum / numbers.length; +} + +async function getIDChainBlock(snapshot, provider, chainId) { + const ts = (await provider.getBlock(snapshot)).timestamp; + const query = { + blocks: { + __args: { + where: { + ts: ts, + network_in: [chainId] + } + }, + number: true + } + }; + const url = 'https://blockfinder.snapshot.org'; + const data = await subgraphRequest(url, query); + return data.blocks[0].number; +} From 36bd2d7968bda9832e6573aa8c45a0436f744fa9 Mon Sep 17 00:00:00 2001 From: Donny <130464015+defitricks@users.noreply.github.com> Date: Tue, 17 Dec 2024 15:40:38 +0200 Subject: [PATCH 803/815] fix: Fix incorrect Promise structure in customFetch timeout logic (#1652) Co-authored-by: Chaitanya --- src/utils.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils.ts b/src/utils.ts index 4061818f6..ca35b5cd6 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -83,9 +83,10 @@ export function customFetch( } throw error; }), - new Promise(() => + new Promise((_, reject) => setTimeout(() => { controller.abort(); + reject(new Error('API request timeout')); }, timeout) ) ]); From d84af4b3acfdb87431d4d9a3c8dda2b778a61875 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 17 Dec 2024 19:13:24 +0530 Subject: [PATCH 804/815] Automated lint (#1655) Co-authored-by: ChaituVR --- src/strategies/botto-dao-base/index.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/strategies/botto-dao-base/index.ts b/src/strategies/botto-dao-base/index.ts index 969dd1235..b3481f9d4 100644 --- a/src/strategies/botto-dao-base/index.ts +++ b/src/strategies/botto-dao-base/index.ts @@ -5,9 +5,7 @@ import { Multicaller } from '../../utils'; export const author = 'agustinjch'; export const version = '1.0.0'; -const abi = [ - 'function userStakes(address) external view returns(uint256)' -]; +const abi = ['function userStakes(address) external view returns(uint256)']; export async function strategy( space, From ce75230b3525d8f8bd8943133e1f703bdd5b5047 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 17 Dec 2024 19:46:13 +0530 Subject: [PATCH 805/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.37 (#1656) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 5e9f8cb80..1def8a6ce 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.36", + "@snapshot-labs/snapshot.js": "^0.12.37", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index a9c64e67f..d81dd3359 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.36": - version "0.12.36" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.36.tgz#89ff38be1b2ab2b239ab5caf0b20c5c4e65eed4e" - integrity sha512-cCwX8mLattshjMLzb731DWDQ8/D0uHINBjTNyFhdyxwW/7B1Dr4wAIQHR+iXwJDA3aiqDJPIP6llD1HRRllvBQ== +"@snapshot-labs/snapshot.js@^0.12.37": + version "0.12.37" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.37.tgz#13fa2037c9ffb9d6a3262a43bd8970a6128ac240" + integrity sha512-tsK6Ef2KDqnInYcZNcnjLV9GBpa8jralutMc4beQexr74SQ34NPshlKah0OeaXxkM6cdtFbQH6bXLUXwz1hBhg== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 2fbc1577fff7b64d393a516a463ebfb99dddfc5e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 17 Dec 2024 21:45:22 +0530 Subject: [PATCH 806/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.38 (#1657) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 1def8a6ce..15f8b5fd1 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.37", + "@snapshot-labs/snapshot.js": "^0.12.38", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index d81dd3359..de33693b5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.37": - version "0.12.37" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.37.tgz#13fa2037c9ffb9d6a3262a43bd8970a6128ac240" - integrity sha512-tsK6Ef2KDqnInYcZNcnjLV9GBpa8jralutMc4beQexr74SQ34NPshlKah0OeaXxkM6cdtFbQH6bXLUXwz1hBhg== +"@snapshot-labs/snapshot.js@^0.12.38": + version "0.12.38" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.38.tgz#e30bdb5218bd73cc961fb7b60c68cbf322321cd8" + integrity sha512-qbN+WPZW+XUr4icFsNhVrqR/mPLCz0XVEOBnN1RJBrzKhMYPgUNwjGBOA0jaIfYKQaD94vMxrhQWKoQud/yIJA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 881ca6aff79f2d6a2564b8925ae4e05664cb33de Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 18 Dec 2024 13:17:26 +0530 Subject: [PATCH 807/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.39 (#1658) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 15f8b5fd1..027d69174 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.38", + "@snapshot-labs/snapshot.js": "^0.12.39", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index de33693b5..7ce159bc6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.38": - version "0.12.38" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.38.tgz#e30bdb5218bd73cc961fb7b60c68cbf322321cd8" - integrity sha512-qbN+WPZW+XUr4icFsNhVrqR/mPLCz0XVEOBnN1RJBrzKhMYPgUNwjGBOA0jaIfYKQaD94vMxrhQWKoQud/yIJA== +"@snapshot-labs/snapshot.js@^0.12.39": + version "0.12.39" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.39.tgz#c64796aa58ec4fef4063daab4ceb173d7fc5ad95" + integrity sha512-yKTffnft7cdoSTYH8ceQxFMjghE2ycrtGWbkC5ZBEWHuP81ZfR+ZNjlWM0TtnNM87A3umhbW1wKCJ0tgn/JAFQ== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 25bad806f1986cb6917754617293e04915a25974 Mon Sep 17 00:00:00 2001 From: Marsot Pierre Date: Wed, 18 Dec 2024 14:01:52 +0100 Subject: [PATCH 808/815] [sd-gauge-less-vote-boost-crosschain] Add bot address (#1661) * reverse delegation * add sd-gauge-less-vote-boost-crosschain * remove sdReverseDelegation * add bot address * add bot address --------- Co-authored-by: Chaitanya --- .../examples.json | 15 +++-- .../index.ts | 57 ++++++++++++++++--- 2 files changed, 60 insertions(+), 12 deletions(-) diff --git a/src/strategies/sd-gauge-less-vote-boost-crosschain/examples.json b/src/strategies/sd-gauge-less-vote-boost-crosschain/examples.json index e9fa613f5..18628c86c 100644 --- a/src/strategies/sd-gauge-less-vote-boost-crosschain/examples.json +++ b/src/strategies/sd-gauge-less-vote-boost-crosschain/examples.json @@ -5,12 +5,17 @@ "name": "sd-gauge-less-vote-boost-crosschain", "params": { "sdTokenGauge": "0xE2496134149e6CD3f3A577C2B08A6f54fC23e6e4", - "symbol": "sdToken", + "sdToken": "0x6a1c1447F97B27dA23dC52802F5f1435b5aC821A", + "veToken": "0x5692DB8177a81A6c6afc8084C2976C9933EC1bAB", + "liquidLocker": "0x1E6F87A9ddF744aF31157d8DaA1e3025648d042d", + "symbol": "sdToken-voting-power", "decimals": 18, "twavpDaysInterval": 10, "twavpNumberOfBlocks": 2, "whiteListedAddress": ["0x1c0D72a330F2768dAF718DEf8A19BAb019EEAd09"], - "blocksPerDay": 28798 + "blocksPerDay": 28798, + "pools": ["0xb8204D31379A9B317CD61C833406C972F58ecCbC"], + "botAddress": "0xb4542526AfeE2FdA1D584213D1521272a398B42a" } }, "network": "56", @@ -19,8 +24,10 @@ "0x931DaBf6721E47E6f5aeb19F6f5d48646144f484", "0x3FbE6216dB591372D3Bb8428ac87B162F7B8601f", "0x803585733d4554e712dcaCc2AcEA3a23b96de1e0", - "0xD4f9FE0039Da59e6DDb21bbb6E84e0C9e83D73eD" + "0xD4f9FE0039Da59e6DDb21bbb6E84e0C9e83D73eD", + "0x87e21De231FA9bf7cF5E30E8FF5388E781e9080C", + "0xb24B5d309a1A64135770A954496b3c408c558806" ], - "snapshot": 44834720 + "snapshot": 44392800 } ] diff --git a/src/strategies/sd-gauge-less-vote-boost-crosschain/index.ts b/src/strategies/sd-gauge-less-vote-boost-crosschain/index.ts index f450e23e4..53fce01c0 100644 --- a/src/strategies/sd-gauge-less-vote-boost-crosschain/index.ts +++ b/src/strategies/sd-gauge-less-vote-boost-crosschain/index.ts @@ -9,6 +9,7 @@ export const version = '0.0.1'; const VE_SDT = '0x0C30476f66034E11782938DF8e4384970B6c9e8a'; const VE_PROXY_BOOST_SDT = '0xD67bdBefF01Fc492f1864E61756E5FBB3f173506'; const TOKENLESS_PRODUCTION = 40; +const MIN_BOOST = 0.4; // Used ABI const abi = [ @@ -98,6 +99,9 @@ export async function strategy( let veSDTTotalSupply = 0; let sdTokenGaugeTotalSupply = 0; + let sdTokenTotalSupply = 0; + let sumPoolsBalance = 0; + let lockerVotingPower = 0; for (let i = 0; i < options.twavpNumberOfBlocks; i++) { const isEnd = i === options.twavpNumberOfBlocks - 1; @@ -123,6 +127,15 @@ export async function strategy( calls = sdTknGaugeBalanceCurrentChain; if (isEnd) { calls.push([options.sdTokenGauge, 'totalSupply']); + calls.push([options.sdToken, 'totalSupply']); + calls.push([options.veToken, 'balanceOf', [options.liquidLocker]]); + + // Fetch pools balance + if (options.pools && Array.isArray(options.pools)) { + for (const pool of options.pools) { + calls.push([options.sdToken, 'balanceOf', [pool]]); + } + } } callResp = await multicall( @@ -134,6 +147,21 @@ export async function strategy( ); if (isEnd) { + if (options.pools && Array.isArray(options.pools)) { + const poolsReverse = [...options.pools].reverse() + for (let i = 0; i < poolsReverse.length; i++) { + sumPoolsBalance += parseFloat(formatUnits(callResp.pop()[0], 18)); + } + } + + lockerVotingPower = parseFloat( + formatUnits(callResp.pop()[0], 18) + ); + + sdTokenTotalSupply = parseFloat( + formatUnits(callResp.pop()[0], 18) + ); + sdTokenGaugeTotalSupply = parseFloat( formatUnits(callResp.pop()[0], 18) ); @@ -142,6 +170,11 @@ export async function strategy( responsesCurrentChain.push(callResp); } + const liquidityVoteFee = + (MIN_BOOST * sumPoolsBalance * lockerVotingPower) / sdTokenTotalSupply; + + const totalUserVotes = lockerVotingPower - liquidityVoteFee; + return Object.fromEntries( Array(addresses.length) .fill('x') @@ -172,15 +205,23 @@ export async function strategy( userWorkingBalances.push(Math.min(l, lim)); } - // Get average working balance. - const averageWorkingBalance = average( - userWorkingBalances, - addresses[i], - options.whiteListedAddress - ); + let userVote = 0; + if(options.botAddress && addresses[i].toLowerCase() === options.botAddress.toLowerCase()) { + userVote = liquidityVoteFee * totalUserVotes; + } else { + // Get average working balance. + const averageWorkingBalance = average( + userWorkingBalances, + addresses[i], + options.whiteListedAddress + ); + + userVote = averageWorkingBalance * totalUserVotes; + } // Return address and voting power - return [getAddress(addresses[i]), Number(averageWorkingBalance)]; + userVote /= 10_000; + return [getAddress(addresses[i]), Number(userVote)]; }) ); } @@ -194,7 +235,7 @@ function getPreviousBlocks( // Calculate total blocks interval const totalBlocksInterval = blocksPerDay * daysInterval; // Calculate block interval - const blockInterval = totalBlocksInterval / (numberOfBlocks - 1); + const blockInterval = totalBlocksInterval / (numberOfBlocks > 1 ? numberOfBlocks - 1 : numberOfBlocks); // Init array of block numbers const blockNumbers: number[] = []; From 47c9072917268fb8c6b47857b17c86873d1f2aa5 Mon Sep 17 00:00:00 2001 From: Basil Gorin <2195281+vgorin@users.noreply.github.com> Date: Thu, 19 Dec 2024 07:37:15 +0200 Subject: [PATCH 809/815] A voting strategy for Lizard Labs' Lizcoin ERC20 Token (LIZ) (#1662) --- src/strategies/index.ts | 4 +- .../lizcoin-strategy-2024/README.md | 36 ++++ .../lizcoin-strategy-2024/examples.json | 44 +++++ src/strategies/lizcoin-strategy-2024/index.ts | 161 ++++++++++++++++++ .../lizcoin-strategy-2024/schema.json | 109 ++++++++++++ 5 files changed, 353 insertions(+), 1 deletion(-) create mode 100644 src/strategies/lizcoin-strategy-2024/README.md create mode 100644 src/strategies/lizcoin-strategy-2024/examples.json create mode 100644 src/strategies/lizcoin-strategy-2024/index.ts create mode 100644 src/strategies/lizcoin-strategy-2024/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 50b420287..512bbe9ca 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -467,6 +467,7 @@ import * as sacraSubgraph from './sacra-subgraph'; import * as fountainhead from './fountainhead'; import * as naymsStaking from './nayms-staking'; import * as morphoDelegation from './morpho-delegation'; +import * as lizcoinStrategy2024 from './lizcoin-strategy-2024'; const strategies = { 'delegatexyz-erc721-balance-of': delegatexyzErc721BalanceOf, @@ -944,7 +945,8 @@ const strategies = { 'sacra-subgraph': sacraSubgraph, fountainhead, 'nayms-staking': naymsStaking, - 'morpho-delegation': morphoDelegation + 'morpho-delegation': morphoDelegation, + 'lizcoin-strategy-2024': lizcoinStrategy2024 }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/lizcoin-strategy-2024/README.md b/src/strategies/lizcoin-strategy-2024/README.md new file mode 100644 index 000000000..f569ca54f --- /dev/null +++ b/src/strategies/lizcoin-strategy-2024/README.md @@ -0,0 +1,36 @@ +# Lizcoin Voting Strategy 2024 +lizcoin-strategy-2024 + +A voting strategy for Lizard Labs' Lizcoin ERC20 Token (LIZ). + +The strategy is based on the quadratic voting formula. The strategy counts only staked and vested tokens – details +follow bellow. + +## Eligible $LIZ forms: +* Staked $LIZ +* Staked LP tokens (converted back to their value in $LIZ) +* vLIZ pre-tokens (investors) in a wallet +* veLIZ pre-tokens (team) in a wallet +* ANY position in the pre-token vesting contract, whether it came from vLIZ, veLIZ, or was set manually for e.g. KOLs + +## Ineligible $LIZ forms: +* Regular $LIZ or LP tokens in a wallet +* cLIZ tokens in a wallet +* Staking or loot box rewards that are unclaimed + +Here is an example of parameters: + +```json +{ + "lizcoinAddress": "0xAF4144cd943ed5362Fed2BaE6573184659CBe6FF", + "cLIZAddress": "0x0F9dc0c0A46733c8b9a6C2E4850913Ed31d31205", + "vLIZAddress": "0xe20C4edb8440CaDD4001c144B4F38576d1AA3820", + "veLIZAddress": "0xC817C0B518e8Fc98034ad867d679d4f8A284BFBE", + "cLIZConversionRate": 0.01, + "vLIZConversionRate": 0.01, + "veLIZConversionRate": 0.01, + "uniswapV2PoolAddress": "0xD47B93360EAADBA2678c30F64209a42b9800cEE4", + "stakingContractAddress": "0xEf2E841AA9F49cc0E54697A4Afa6361eA24d682F", + "vestingContractAddress": "0x895ecdCAC6431272946Ec615eD368d2f42fC2b44" +} +``` diff --git a/src/strategies/lizcoin-strategy-2024/examples.json b/src/strategies/lizcoin-strategy-2024/examples.json new file mode 100644 index 000000000..8ea76d147 --- /dev/null +++ b/src/strategies/lizcoin-strategy-2024/examples.json @@ -0,0 +1,44 @@ +[ + { + "name": "Example query for Lizcoin Voting Strategy 2024", + "strategy": { + "name": "lizcoin-strategy-2024", + "params": { + "lizcoinAddress": "0xAF4144cd943ed5362Fed2BaE6573184659CBe6FF", + "cLIZAddress": "0x0F9dc0c0A46733c8b9a6C2E4850913Ed31d31205", + "vLIZAddress": "0xe20C4edb8440CaDD4001c144B4F38576d1AA3820", + "veLIZAddress": "0xC817C0B518e8Fc98034ad867d679d4f8A284BFBE", + "cLIZConversionRate": 0.01, + "vLIZConversionRate": 0.01, + "veLIZConversionRate": 0.01, + "uniswapV2PoolAddress": "0xD47B93360EAADBA2678c30F64209a42b9800cEE4", + "stakingContractAddress": "0xEf2E841AA9F49cc0E54697A4Afa6361eA24d682F", + "vestingContractAddress": "0x895ecdCAC6431272946Ec615eD368d2f42fC2b44" + } + }, + "network": "1", + "addresses": [ + "0xC5015Af75881b4aBed54043B46561ca829EC2468", + "0x11619E71E2B53AF33e1CFEAaab51d4E570aFC299", + "0x922dfB7092BB3A14A1335c843C1760f88A406E99", + "0xAe8513960374736fAe8CBA47e1A2Ae1Cd842e439", + "0xc9b95B403dC5C9E2A8cB6A703A78016A537DBAE3", + "0xAB12253171A0d73df64B115cD43Fe0A32Feb9dAA", + "0x7C175168d76849Aba1EAD344AD30AC94f120a077", + "0xC1305f9Df23799596a12E6C7cCD8D2663B875D61", + "0x601071a8fB7890bAda13E24c6Bf7838e90778A78", + "0xc6184b7e9C896f5035F7A670BBeA5A445fDA6E1C", + "0xf102978E0C95207AD6Ee2d39d18f1e7497d89EAD", + "0xf91D65180d0e5eD3C5a56B9211b6B4b26E24C2d5", + "0xf02b4c61Bb87817690034667186EF9836F4F0898", + "0xdD020966b963FFC7623498dF5B8Ed14b11AF7B2A", + "0x6C6a234D1806F7d0baC872eD49933A6852424467", + "0x3cC31eFcEEFAdC2A86716A3BeE91D1917418E29a", + "0x8f60501dE5b9b01F9EAf1214dbE1924aA97F7fd0", + "0x9B8e8dD9151260c21CB6D7cc59067cd8DF306D58", + "0x17ea92D6FfbAA1c7F6B117c1E9D0c88ABdc8b84C", + "0x38C0039247A31F3939baE65e953612125cB88268" + ], + "snapshot": 21428809 + } +] diff --git a/src/strategies/lizcoin-strategy-2024/index.ts b/src/strategies/lizcoin-strategy-2024/index.ts new file mode 100644 index 000000000..6ae3bf1a5 --- /dev/null +++ b/src/strategies/lizcoin-strategy-2024/index.ts @@ -0,0 +1,161 @@ +import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; +import { StaticJsonRpcProvider } from '@ethersproject/providers'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'ethlizards'; +export const version = '0.1.0'; + +const abi = [ + 'function decimals() external view returns (uint8)', + 'function totalSupply() external view returns (uint256)', + 'function balanceOf(address account) external view returns (uint256)', + 'function sumDepositAmounts(address depositToken, address rewardToken, address accountAddress) external view returns (uint96)', + // TODO: introduce sumVestedAmounts(address holder) function + 'function getVestingSchedulesArray(address holder) external view returns (tuple(uint32 startDate, uint32 duration, uint96 amountVested, uint96 amountClaimed)[])' +]; + +interface Options { + lizcoinAddress: string; + cLIZAddress: string; + vLIZAddress: string; + veLIZAddress: string; + cLIZConversionRate: number; + vLIZConversionRate: number; + veLIZConversionRate: number; + uniswapV2PoolAddress: string; + stakingContractAddress: string; + vestingContractAddress: string; +} + +interface VestingSchedule { + startDate: number; + duration: number; + amountVested: BigNumber; + amountClaimed: BigNumber; +} + +export async function strategy( + space: string, + network: string, + provider: StaticJsonRpcProvider, + addresses: string[], + options: Options, + snapshot: number | 'latest' +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const multi = new Multicaller(network, provider, abi, { blockTag }); + + // Fetch decimals for LIZ, vLIZ, veLIZ, and LP + multi.call('lizcoinDecimals', options.lizcoinAddress, 'decimals'); + multi.call('vLIZDecimals', options.vLIZAddress, 'decimals'); + multi.call('veLIZDecimals', options.veLIZAddress, 'decimals'); + multi.call('lpDecimals', options.uniswapV2PoolAddress, 'decimals'); + // Fetch LP/LIZ conversion rate + multi.call('lpSupply', options.uniswapV2PoolAddress, 'totalSupply'); + multi.call('lpLizcoinBalance', options.lizcoinAddress, 'balanceOf', [ + options.uniswapV2PoolAddress + ]); + + // Fetch balances for LIZ, vLIZ, and veLIZ + addresses.forEach((address: string) => { + // Staked $LIZ + multi.call( + `stakedLIZ_${address}`, + options.stakingContractAddress, + 'sumDepositAmounts', + [options.lizcoinAddress, options.lizcoinAddress, address] + ); + // Staked LP tokens + multi.call( + `stakedLP_${address}`, + options.stakingContractAddress, + 'sumDepositAmounts', + [options.uniswapV2PoolAddress, options.lizcoinAddress, address] + ); + // vLIZ pre-tokens (investors) in a wallet + multi.call(`vLIZ_${address}`, options.vLIZAddress, 'balanceOf', [address]); + // veLIZ pre-tokens (team) in a wallet + multi.call(`veLIZ_${address}`, options.veLIZAddress, 'balanceOf', [ + address + ]); + // ANY position in the pre-token vesting contract, whether it came from vLIZ, veLIZ, or was set manually for e.g. KOLs + multi.call( + `vestingSchedules_${address}`, + options.vestingContractAddress, + 'getVestingSchedulesArray', + [address] + ); + }); + + const result: Record = await multi.execute(); + + // decimals + const lizcoinDecimals = result['lizcoinDecimals']; + const vLIZDecimals = result['vLIZDecimals']; + const veLIZDecimals = result['veLIZDecimals']; + const lpDecimals = result['lpDecimals']; + // LP/LIZ conversion rate + const lpSupply = parseFloat(formatUnits(result['lpSupply'], lpDecimals)); + const lpLizcoinBalance = parseFloat( + formatUnits(result['lpLizcoinBalance'], lpDecimals) + ); + const lpLizcoinConvRate = lpSupply / lpLizcoinBalance / 2; + + // derive the voting power as an address:number mapping + const votingPower = Object.fromEntries( + addresses.map(function (address) { + // Staked $LIZ + const stakedLizcoinBalance = parseFloat( + formatUnits(result[`stakedLIZ_${address}`], lizcoinDecimals) + ); + + // Staked LP tokens (converted back to their value in $LIZ) + const stakedLpBalance = + parseFloat( + formatUnits(result[`stakedLP_${address}`], lizcoinDecimals) + ) / lpLizcoinConvRate; + + // vLIZ pre-tokens (investors) in a wallet (converted to their value in $LIZ) + const vLIZBalance = + parseFloat(formatUnits(result[`vLIZ_${address}`], vLIZDecimals)) / + options.vLIZConversionRate; + + // veLIZ pre-tokens (team) in a wallet (converted to their value in $LIZ) + const veLIZBalance = + parseFloat(formatUnits(result[`veLIZ_${address}`], veLIZDecimals)) / + options.veLIZConversionRate; + + // ANY position in the pre-token vesting contract, whether it came from vLIZ, veLIZ, or was set manually for e.g. KOLs + const schedules: VestingSchedule[] = result[ + `vestingSchedules_${address}` + ] as unknown as VestingSchedule[]; + const vestedAmountsSum = schedules.reduce( + (accumulator, currentValue) => + BigNumber.from(accumulator).add( + BigNumber.from(currentValue.amountVested).sub( + BigNumber.from(currentValue.amountClaimed) + ) + ), + BigNumber.from(0) + ); + const vestedLizcoinBalance = parseFloat( + formatUnits(vestedAmountsSum, lizcoinDecimals) + ); + + // sum all the balances (already converted to LIZ equivalents) + const totalBalance = + stakedLizcoinBalance + + stakedLpBalance + + vLIZBalance + + veLIZBalance + + vestedLizcoinBalance; + + // apply the quadratic voting formula and return + return [address, Math.sqrt(totalBalance)]; + }) + ); + // console.log(votingPower); + return votingPower; +} diff --git a/src/strategies/lizcoin-strategy-2024/schema.json b/src/strategies/lizcoin-strategy-2024/schema.json new file mode 100644 index 000000000..a267ab166 --- /dev/null +++ b/src/strategies/lizcoin-strategy-2024/schema.json @@ -0,0 +1,109 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Lizcoin Voting Strategy 2024", + "type": "object", + "properties": { + "lizcoinAddress": { + "type": "string", + "title": "Lizcoin ERC20 Token (LIZ) Address", + "default": "0xAF4144cd943ed5362Fed2BaE6573184659CBe6FF", + "examples": ["e.g. 0xAF4144cd943ed5362Fed2BaE6573184659CBe6FF"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "cLIZAddress": { + "type": "string", + "title": "cLIZ Convertable Coin Address", + "default": "0x0F9dc0c0A46733c8b9a6C2E4850913Ed31d31205", + "examples": ["e.g. 0x0F9dc0c0A46733c8b9a6C2E4850913Ed31d31205"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "vLIZAddress": { + "type": "string", + "title": "vLIZ Convertable Coin Address", + "default": "0xe20C4edb8440CaDD4001c144B4F38576d1AA3820", + "examples": ["e.g. 0xe20C4edb8440CaDD4001c144B4F38576d1AA3820"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "veLIZAddress": { + "type": "string", + "title": "veLIZ Convertable Coin Address", + "default": "0xC817C0B518e8Fc98034ad867d679d4f8A284BFBE", + "examples": ["e.g. 0xC817C0B518e8Fc98034ad867d679d4f8A284BFBE"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "cLIZConversionRate": { + "type": "number", + "title": "cLIZ to LIZ Conversion Rate", + "default": 0.01, + "examples": [0.01], + "minimum": 0.000000001, + "maximum": 1000000000 + }, + "vLIZConversionRate": { + "type": "number", + "title": "vLIZ to LIZ Conversion Rate", + "default": 0.01, + "examples": [0.01], + "minimum": 0.000000001, + "maximum": 1000000000 + }, + "veLIZConversionRate": { + "type": "number", + "title": "veLIZ to LIZ Conversion Rate", + "default": 0.01, + "examples": [0.01], + "minimum": 0.000000001, + "maximum": 1000000000 + }, + "uniswapV2PoolAddress": { + "type": "string", + "title": "Voting Eligible Uniswap V2 LP Address", + "examples": ["e.g. 0xD47B93360EAADBA2678c30F64209a42b9800cEE4"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "stakingContractAddress": { + "type": "string", + "title": "Voting Eligible Staking Contract Address", + "examples": ["e.g. 0xEf2E841AA9F49cc0E54697A4Afa6361eA24d682F"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "vestingContractAddress": { + "type": "string", + "title": "Voting Eligible Vesting Contract Address", + "examples": ["e.g. 0x895ecdCAC6431272946Ec615eD368d2f42fC2b44"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + } + }, + "required": [ + "lizcoinAddress", + "cLIZAddress", + "vLIZAddress", + "veLIZAddress", + "cLIZConversionRate", + "vLIZConversionRate", + "veLIZConversionRate", + "uniswapV2PoolAddress", + "stakingContractAddress", + "vestingContractAddress" + ], + "additionalProperties": false + } + } +} From 97e9e93656f71cbd636ed4cc245baca505c0744e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 23 Dec 2024 22:08:18 +0530 Subject: [PATCH 810/815] Automated lint (#1663) Co-authored-by: ChaituVR --- .../index.ts | 53 +++++++------------ 1 file changed, 20 insertions(+), 33 deletions(-) diff --git a/src/strategies/sd-gauge-less-vote-boost-crosschain/index.ts b/src/strategies/sd-gauge-less-vote-boost-crosschain/index.ts index 53fce01c0..18e25e03c 100644 --- a/src/strategies/sd-gauge-less-vote-boost-crosschain/index.ts +++ b/src/strategies/sd-gauge-less-vote-boost-crosschain/index.ts @@ -53,16 +53,12 @@ export async function strategy( } // Mainnet data - const mainnetProvider = getProvider("1"); + const mainnetProvider = getProvider('1'); // Get corresponding block number on mainnet - let mainnetBlockTag = await getIDChainBlock( - blockTag, - provider, - "1" - ); + let mainnetBlockTag = await getIDChainBlock(blockTag, provider, '1'); - if (mainnetBlockTag === "latest") { + if (mainnetBlockTag === 'latest') { mainnetBlockTag = await mainnetProvider.getBlockNumber(); } @@ -113,7 +109,7 @@ export async function strategy( calls.push([VE_SDT, 'totalSupply']); } - let callResp: any[] = await multicall("1", mainnetProvider, abi, calls, { + let callResp: any[] = await multicall('1', mainnetProvider, abi, calls, { blockTag: blockListMainnet[i] }); @@ -138,33 +134,23 @@ export async function strategy( } } - callResp = await multicall( - network, - provider, - abi, - calls, - { blockTag: blockList[i] } - ); + callResp = await multicall(network, provider, abi, calls, { + blockTag: blockList[i] + }); if (isEnd) { if (options.pools && Array.isArray(options.pools)) { - const poolsReverse = [...options.pools].reverse() + const poolsReverse = [...options.pools].reverse(); for (let i = 0; i < poolsReverse.length; i++) { sumPoolsBalance += parseFloat(formatUnits(callResp.pop()[0], 18)); } } - lockerVotingPower = parseFloat( - formatUnits(callResp.pop()[0], 18) - ); + lockerVotingPower = parseFloat(formatUnits(callResp.pop()[0], 18)); - sdTokenTotalSupply = parseFloat( - formatUnits(callResp.pop()[0], 18) - ); + sdTokenTotalSupply = parseFloat(formatUnits(callResp.pop()[0], 18)); - sdTokenGaugeTotalSupply = parseFloat( - formatUnits(callResp.pop()[0], 18) - ); + sdTokenGaugeTotalSupply = parseFloat(formatUnits(callResp.pop()[0], 18)); } responsesCurrentChain.push(callResp); @@ -187,17 +173,13 @@ export async function strategy( formatUnits(BigNumber.from(responsesMainnet[j].shift()[0]), 18) ); const l = parseFloat( - formatUnits( - BigNumber.from(responsesCurrentChain[j].shift()[0]), - 18 - ) + formatUnits(BigNumber.from(responsesCurrentChain[j].shift()[0]), 18) ); let lim = (l * TOKENLESS_PRODUCTION) / 100; if (veSDTTotalSupply > 0) { lim += - (((sdTokenGaugeTotalSupply * voting_balance) / - veSDTTotalSupply) * + (((sdTokenGaugeTotalSupply * voting_balance) / veSDTTotalSupply) * (100 - TOKENLESS_PRODUCTION)) / 100; } @@ -206,7 +188,10 @@ export async function strategy( } let userVote = 0; - if(options.botAddress && addresses[i].toLowerCase() === options.botAddress.toLowerCase()) { + if ( + options.botAddress && + addresses[i].toLowerCase() === options.botAddress.toLowerCase() + ) { userVote = liquidityVoteFee * totalUserVotes; } else { // Get average working balance. @@ -235,7 +220,9 @@ function getPreviousBlocks( // Calculate total blocks interval const totalBlocksInterval = blocksPerDay * daysInterval; // Calculate block interval - const blockInterval = totalBlocksInterval / (numberOfBlocks > 1 ? numberOfBlocks - 1 : numberOfBlocks); + const blockInterval = + totalBlocksInterval / + (numberOfBlocks > 1 ? numberOfBlocks - 1 : numberOfBlocks); // Init array of block numbers const blockNumbers: number[] = []; From e9efb364fc6719dbacdc4426c9aa1efa8c1b4ea1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 25 Dec 2024 13:15:49 +0530 Subject: [PATCH 811/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.40 (#1665) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 027d69174..e0d169ff2 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.39", + "@snapshot-labs/snapshot.js": "^0.12.40", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index 7ce159bc6..e7dac6cf3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.39": - version "0.12.39" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.39.tgz#c64796aa58ec4fef4063daab4ceb173d7fc5ad95" - integrity sha512-yKTffnft7cdoSTYH8ceQxFMjghE2ycrtGWbkC5ZBEWHuP81ZfR+ZNjlWM0TtnNM87A3umhbW1wKCJ0tgn/JAFQ== +"@snapshot-labs/snapshot.js@^0.12.40": + version "0.12.40" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.40.tgz#ab07a35f057de380cf0c5f6f661370001dce2a50" + integrity sha512-pZb3xERF6w8n6p8tm9pD5OIwJMPklrFA8UzOKZQvJFH+nn3CMJdlbp1rp496oVzd6tArrHrQ6sLI0Nbo59nBCw== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From f2fd8f11d0b671d1a74ceaf34008e7b097c154f0 Mon Sep 17 00:00:00 2001 From: Noel <103109678+neutiyoo@users.noreply.github.com> Date: Fri, 27 Dec 2024 15:34:38 +0900 Subject: [PATCH 812/815] [realt] feat: realt (#1666) * feat: realt * feat: skip if address is reALT strategy --- src/strategies/index.ts | 4 ++- src/strategies/realt/README.md | 5 +++ src/strategies/realt/examples.json | 20 ++++++++++++ src/strategies/realt/index.ts | 52 ++++++++++++++++++++++++++++++ src/strategies/realt/schema.json | 34 +++++++++++++++++++ 5 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 src/strategies/realt/README.md create mode 100644 src/strategies/realt/examples.json create mode 100644 src/strategies/realt/index.ts create mode 100644 src/strategies/realt/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 512bbe9ca..e46ecf2e3 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -468,6 +468,7 @@ import * as fountainhead from './fountainhead'; import * as naymsStaking from './nayms-staking'; import * as morphoDelegation from './morpho-delegation'; import * as lizcoinStrategy2024 from './lizcoin-strategy-2024'; +import * as realt from './realt'; const strategies = { 'delegatexyz-erc721-balance-of': delegatexyzErc721BalanceOf, @@ -946,7 +947,8 @@ const strategies = { fountainhead, 'nayms-staking': naymsStaking, 'morpho-delegation': morphoDelegation, - 'lizcoin-strategy-2024': lizcoinStrategy2024 + 'lizcoin-strategy-2024': lizcoinStrategy2024, + realt }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/realt/README.md b/src/strategies/realt/README.md new file mode 100644 index 000000000..bc38be178 --- /dev/null +++ b/src/strategies/realt/README.md @@ -0,0 +1,5 @@ +# reALT + +## Description + +The reALT strategy calculates the total balance of a user's holdings in the reALT token and their shares in the reALT Strategy on the Ethereum mainnet. diff --git a/src/strategies/realt/examples.json b/src/strategies/realt/examples.json new file mode 100644 index 000000000..161df7e3e --- /dev/null +++ b/src/strategies/realt/examples.json @@ -0,0 +1,20 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "realt", + "params": { + "address": "0xf96798f49936efb1a56f99ceae924b6b8359affb", + "symbol": "reALT", + "decimals": 18 + } + }, + "network": "1", + "addresses": [ + "0x15de7B6a83ee7735EA00Dc4a0506059cDA4Bef49", + "0x16Ce1B15ed1278921d7Cae34Bf60a81227CFC295", + "0x16f665dA6D806760aFC317ee29Ef2feF2Ff4976E" + ], + "snapshot": 21488157 + } +] diff --git a/src/strategies/realt/index.ts b/src/strategies/realt/index.ts new file mode 100644 index 000000000..e3f3bea3b --- /dev/null +++ b/src/strategies/realt/index.ts @@ -0,0 +1,52 @@ +import { BigNumberish, BigNumber } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'altlayer'; +export const version = '0.1.0'; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const reAltStrategy = "0x6075546538c3eFbD607ea6aFC24149fCcFb2edF4"; // reALT Strategy Mainnet + + const balanceOfMulticaller = new Multicaller(network, provider, [ + 'function balanceOf(address account) external view returns (uint256)', + ], { blockTag }); + addresses.forEach((address) => { + if (address !== reAltStrategy) { + balanceOfMulticaller.call(address, options.address, 'balanceOf', [address]); + } + }); + + const sharesMulticaller = new Multicaller(network, provider, [ + 'function shares(address user) external view returns (uint256)', + ], { blockTag }); + + addresses.forEach((address) => + sharesMulticaller.call(address, reAltStrategy, 'shares', [address]) + ); + + const [balanceOfResults, sharesResults]: [Record, Record] = await Promise.all([ + balanceOfMulticaller.execute(), + sharesMulticaller.execute() + ]); + + return Object.fromEntries( + addresses.map((address) => { + const balanceOf = balanceOfResults[address] || BigNumber.from(0); + const shares = sharesResults[address] || BigNumber.from(0); + const totalBalance = BigNumber.from(balanceOf).add(BigNumber.from(shares)); + return [ + address, + parseFloat(formatUnits(totalBalance, options.decimals)) + ]; + }) + ); +} diff --git a/src/strategies/realt/schema.json b/src/strategies/realt/schema.json new file mode 100644 index 000000000..e5beefb92 --- /dev/null +++ b/src/strategies/realt/schema.json @@ -0,0 +1,34 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. reALT"], + "maxLength": 16 + }, + "address": { + "type": "string", + "title": "Contract address", + "examples": ["e.g. 0xf96798f49936efb1a56f99ceae924b6b8359affb"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 18"], + "minimum": 0 + } + }, + "required": ["address", "decimals"], + "additionalProperties": false + } + } +} From 7c4e0c9bcc291a56226f534f498d5b573c69d4d5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 30 Dec 2024 10:46:04 +0530 Subject: [PATCH 813/815] Automated lint (#1667) Co-authored-by: ChaituVR --- src/strategies/realt/index.ts | 38 ++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/src/strategies/realt/index.ts b/src/strategies/realt/index.ts index e3f3bea3b..48f8ebde2 100644 --- a/src/strategies/realt/index.ts +++ b/src/strategies/realt/index.ts @@ -14,26 +14,37 @@ export async function strategy( snapshot ): Promise> { const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - const reAltStrategy = "0x6075546538c3eFbD607ea6aFC24149fCcFb2edF4"; // reALT Strategy Mainnet + const reAltStrategy = '0x6075546538c3eFbD607ea6aFC24149fCcFb2edF4'; // reALT Strategy Mainnet - const balanceOfMulticaller = new Multicaller(network, provider, [ - 'function balanceOf(address account) external view returns (uint256)', - ], { blockTag }); + const balanceOfMulticaller = new Multicaller( + network, + provider, + ['function balanceOf(address account) external view returns (uint256)'], + { blockTag } + ); addresses.forEach((address) => { if (address !== reAltStrategy) { - balanceOfMulticaller.call(address, options.address, 'balanceOf', [address]); + balanceOfMulticaller.call(address, options.address, 'balanceOf', [ + address + ]); } }); - const sharesMulticaller = new Multicaller(network, provider, [ - 'function shares(address user) external view returns (uint256)', - ], { blockTag }); + const sharesMulticaller = new Multicaller( + network, + provider, + ['function shares(address user) external view returns (uint256)'], + { blockTag } + ); addresses.forEach((address) => sharesMulticaller.call(address, reAltStrategy, 'shares', [address]) ); - const [balanceOfResults, sharesResults]: [Record, Record] = await Promise.all([ + const [balanceOfResults, sharesResults]: [ + Record, + Record + ] = await Promise.all([ balanceOfMulticaller.execute(), sharesMulticaller.execute() ]); @@ -42,11 +53,10 @@ export async function strategy( addresses.map((address) => { const balanceOf = balanceOfResults[address] || BigNumber.from(0); const shares = sharesResults[address] || BigNumber.from(0); - const totalBalance = BigNumber.from(balanceOf).add(BigNumber.from(shares)); - return [ - address, - parseFloat(formatUnits(totalBalance, options.decimals)) - ]; + const totalBalance = BigNumber.from(balanceOf).add( + BigNumber.from(shares) + ); + return [address, parseFloat(formatUnits(totalBalance, options.decimals))]; }) ); } From 67416ece46999a619bf4848d3c6b2cc05b95e8fa Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 3 Jan 2025 22:21:56 +0530 Subject: [PATCH 814/815] fix(deps): update dependency @snapshot-labs/snapshot.js to ^0.12.41 (#1672) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index e0d169ff2..257523dff 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@ethersproject/strings": "^5.6.1", "@ethersproject/units": "^5.6.1", "@ethersproject/wallet": "^5.6.2", - "@snapshot-labs/snapshot.js": "^0.12.40", + "@snapshot-labs/snapshot.js": "^0.12.41", "@spruceid/didkit-wasm-node": "^0.2.1", "@uniswap/sdk-core": "^3.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/yarn.lock b/yarn.lock index e7dac6cf3..07b0cfb4e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1239,10 +1239,10 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@snapshot-labs/snapshot.js@^0.12.40": - version "0.12.40" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.40.tgz#ab07a35f057de380cf0c5f6f661370001dce2a50" - integrity sha512-pZb3xERF6w8n6p8tm9pD5OIwJMPklrFA8UzOKZQvJFH+nn3CMJdlbp1rp496oVzd6tArrHrQ6sLI0Nbo59nBCw== +"@snapshot-labs/snapshot.js@^0.12.41": + version "0.12.41" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.41.tgz#3a0a2866a78f14368eb0648ef2e22a8e66422b26" + integrity sha512-Deikl21gUzeY/2TE8xTNsHbwTNcSqvxDnrzA1LcLwyqAzA6tigwNBlqaS5E35v7t5z7Iz62j+CPEFzxv1ta6cA== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4" From 6b17a4242a540b78e900f6736916f9cb89ba6b73 Mon Sep 17 00:00:00 2001 From: Didi Date: Tue, 7 Jan 2025 11:37:54 +0100 Subject: [PATCH 815/815] [superfluid-vesting] Added strategy for Superfluid Vesting Schedules (#1671) * added strategy for vesting scheduler * added subgraph urls, more accurate accounting --- src/strategies/index.ts | 4 +- src/strategies/superfluid-vesting/README.md | 28 ++++++ .../superfluid-vesting/examples.json | 21 ++++ src/strategies/superfluid-vesting/index.ts | 96 +++++++++++++++++++ src/strategies/superfluid-vesting/schema.json | 35 +++++++ 5 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 src/strategies/superfluid-vesting/README.md create mode 100644 src/strategies/superfluid-vesting/examples.json create mode 100644 src/strategies/superfluid-vesting/index.ts create mode 100644 src/strategies/superfluid-vesting/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index e46ecf2e3..100a05eb8 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -469,6 +469,7 @@ import * as naymsStaking from './nayms-staking'; import * as morphoDelegation from './morpho-delegation'; import * as lizcoinStrategy2024 from './lizcoin-strategy-2024'; import * as realt from './realt'; +import * as superfluidVesting from './superfluid-vesting'; const strategies = { 'delegatexyz-erc721-balance-of': delegatexyzErc721BalanceOf, @@ -948,7 +949,8 @@ const strategies = { 'nayms-staking': naymsStaking, 'morpho-delegation': morphoDelegation, 'lizcoin-strategy-2024': lizcoinStrategy2024, - realt + realt, + 'superfluid-vesting': superfluidVesting }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/superfluid-vesting/README.md b/src/strategies/superfluid-vesting/README.md new file mode 100644 index 000000000..cd178443d --- /dev/null +++ b/src/strategies/superfluid-vesting/README.md @@ -0,0 +1,28 @@ +# Superfluid Vesting + +Superfluid Vesting is done in the typical Superfluid way, not requiring prior capital lockup. +The Vesting Scheduler contract allows for the creation of Vesting Schedules which are then automatically executed. + +Vesting Schedules are created by the _vesting sender_. +This sender, by creating a schedule, expresses the intent to provide the promised funds, as specified in the schedule. +In order for this intent to become executable, the sender also needs to +- grant the necessary ACL permissions to the VestingScheduler contract +- have enough funds available when needed + +Note: In order to create a vesting schedule with hard guarantees of successful execution, a vesting sender needs to be a contract which is pre-funded and has no means to withdraw funds. + +## Voting + +In order to map vesting schedules to voting power, we need to monitor vesting schedules. +We need to restrict the schedules taken into consideration to those originating from a known and trusted vesting sender. Otherwise anybody could trivially cheat and gain more voting power by creating schedules for themselves. + +With a trusted vesting sender defined, we can enumerate the vesting schedules created by it (where it is the _sender_) via subgraph query. +The total vesting amount of a vesting schedule is to be calculated as `cliffAmount + (endDate - startDate) * flowRate)`. +We need to subtract from this amount the already vested amount in order to not double-count it. This is assuming that another strategy accounts for the voting power of the already vested portion. + +## Dev + +Run test with +``` +yarn test --strategy=superfluid-vesting +``` diff --git a/src/strategies/superfluid-vesting/examples.json b/src/strategies/superfluid-vesting/examples.json new file mode 100644 index 000000000..b46b537bd --- /dev/null +++ b/src/strategies/superfluid-vesting/examples.json @@ -0,0 +1,21 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "superfluid-vesting", + "params": { + "superTokenAddress": "0xe58267cd7299c29a1b77F4E66Cd12Dd24a2Cd2FD", + "vestingSenderAddress": "0xd7086bf0754383c065d81b62fc2e874373660caa" + } + }, + "network": "8453", + "addresses": [ + "0xf8a025B42B07db05638FE596cce339707ec3cC71", + "0x389E3d1c46595aF7335F8C6D3e403ce2E8a9cf8A", + "0x264Ff25e609363cf738e238CBc7B680300509BED", + "0x5782BD439d3019F61bFac53f6358C30c3566737C", + "0x4ee5D45eB79aEa04C02961a2e543bbAf5cec81B3" + ], + "snapshot": 24392394 + } +] diff --git a/src/strategies/superfluid-vesting/index.ts b/src/strategies/superfluid-vesting/index.ts new file mode 100644 index 000000000..1e4a2a404 --- /dev/null +++ b/src/strategies/superfluid-vesting/index.ts @@ -0,0 +1,96 @@ +import { subgraphRequest } from '../../utils'; +import { getAddress } from '@ethersproject/address'; + +export const author = 'd10r'; +export const version = '0.1.0'; + +const SUBGRAPH_URL_MAP = { + '10': + 'https://subgrapher.snapshot.org/subgraph/arbitrum/6YMD95vYriDkmTJewC2vYubqVZrc6vdk3Sp3mR3YCQUw', + '8453': + 'https://subgrapher.snapshot.org/subgraph/arbitrum/4Zp6n8jcsJMBNa3GY9RZwoK4SLjoagwXGq6GhUQNMgSM', + '11155420': + 'https://subgrapher.snapshot.org/subgraph/arbitrum/5UctBWuaQgr2HVSG6XtAKt5shyjg9snGvD6F424FcjMN' +}; + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + + const subgraphUrl = options.subgraphUrl || SUBGRAPH_URL_MAP[network]; + if (!subgraphUrl) { + throw new Error('Subgraph URL not specified'); + } + + const query = { + vestingSchedules: { + __args: { + where: { + superToken: options.superTokenAddress, + sender: options.vestingSenderAddress, + endExecutedAt: null, + failedAt: null, + deletedAt: null + }, + orderBy: 'cliffAndFlowDate', + orderDirection: 'asc' + }, + cliffAmount: true, + cliffAndFlowDate: true, + endDate: true, + flowRate: true, + cliffAndFlowExecutedAt: true, + receiver: true, + remainderAmount: true + } + }; + + if (snapshot !== 'latest') { + // @ts-ignore + query.vestingSchedules.__args.block = { number: snapshot }; + } + + // Get block timestamp - needed for calculating the remaining amount + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + const block = await provider.getBlock(blockTag); + const timestamp = block.timestamp; + + const subgraphResult = await subgraphRequest(subgraphUrl, query); + + const processedMap = subgraphResult.vestingSchedules.map((schedule) => { + const endDate = BigInt(schedule.endDate); + const cliffAndFlowDate = BigInt(schedule.cliffAndFlowDate); + const flowRate = BigInt(schedule.flowRate); + const cliffAmount = BigInt(schedule.cliffAmount); + const remainderAmount = BigInt(schedule.remainderAmount); + + // the initial vesting amount + const fullAmount = cliffAmount + flowRate * (endDate - cliffAndFlowDate) + remainderAmount; + + // the remaining amount which hasn't yet vested + let remainingAmount = fullAmount; + if (schedule.cliffAndFlowExecutedAt !== null) { + remainingAmount -= cliffAmount + flowRate * (BigInt(timestamp) - cliffAndFlowDate); + } + + return { + schedule: schedule, + fullAmount: fullAmount, + remainingAmount: remainingAmount + } + }); + + // create a map of the remaining amounts + return Object.fromEntries( + processedMap.map(item => [ + getAddress(item.schedule.receiver), + // in theory remainingAmount could become negative, thus we cap at 0 + Math.max(Number(item.remainingAmount) / 1e18, 0) + ]) + ); +} diff --git a/src/strategies/superfluid-vesting/schema.json b/src/strategies/superfluid-vesting/schema.json new file mode 100644 index 000000000..b761a2c15 --- /dev/null +++ b/src/strategies/superfluid-vesting/schema.json @@ -0,0 +1,35 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "superTokenAddress": { + "type": "string", + "title": "Super Token contract address", + "examples": ["e.g. 0x6C210F071c7246C452CAC7F8BaA6dA53907BbaE1"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "vestingSenderAddress": { + "type": "string", + "title": "Vesting sender address", + "examples": ["e.g. 0x6C210F071c7246C452CAC7F8BaA6dA53907BbaE1"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "subgraphUrl": { + "type": "string", + "title": "Subgraph URL (optional - if not already known to the strategy)", + "examples": ["e.g. https://subgrapher.snapshot.org/subgraph/arbitrum/4Zp6n8jcsJMBNa3GY9RZwoK4SLjoagwXGq6GhUQNMgSM"] + } + }, + "required": ["superTokenAddress", "vestingSenderAddress"], + "additionalProperties": false + } + } +}