forked from snapshot-labs/snapshot-strategies
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[hopr-bridged-balance] Hopr bridged balance (snapshot-labs#75)
* Add strategies for staking program and wx/x/-/hopr tokens. Work despite network (1 or 100) * Keep only bridged balance * Reduce function ABI to minimum Co-authored-by: Chaitanya <[email protected]> Co-authored-by: Chaitanya <[email protected]>
- Loading branch information
1 parent
fc4d950
commit da5a137
Showing
3 changed files
with
248 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
[ | ||
{ | ||
"name": "Get bridged HOPR token balance", | ||
"strategy": { | ||
"name": "hopr-bridged-balance", | ||
"params": { | ||
"xHopr": "0xd057604a14982fe8d88c5fc25aac3267ea142a08", | ||
"wxHopr": "0xD4fdec44DB9D44B8f2b6d529620f9C0C7066A2c1", | ||
"hopr": "0xf5581dfefd8fb0e4aec526be659cfab1f8c781da" | ||
} | ||
}, | ||
"network": "100", | ||
"addresses": [ | ||
"0x04BBB7eA18EA570aE47d4489991645E4E49bBf37", | ||
"0x2aF80738aC01e7883d11c912dFe8322C129ae5C5", | ||
"0x0bb43EFc1a613658177D8f67CcF9CFFD8B25b906", | ||
"0x53e85186ebF5A7d4BD06324F7b9D8B3623EF0307", | ||
"0x2DCDB99930E279f1e9Ad11F491163051432542A0", | ||
"0x4326990033eCd87A5444383Cf8c715E696301910", | ||
"0xEd6a59A7C1D5a88b7cb5eb877A7A6078A7e801C7", | ||
"0xeFC05B0D0C8bE8D4Cb3a220ef582E9f7E6FBCd00", | ||
"0xC7B169b108c5e75991C520AEA97140534291C81D", | ||
"0x04Be52434EB64aDdF373137310551ac42013677c", | ||
"0xBE8C93a8C18AF63aAB449994AFAc13E71240ccC4", | ||
"0xf813773eBDD4759c1B780d745081f046A5B776fB", | ||
"0x7F26C34Ed10bF66602009231bBFF24f2f84e9270", | ||
"0x4abd7276C53279b3aBFFF2B5D8A47c0AFc84833B", | ||
"0x3e1A12a6019ee26418F22B656926fE38F5e58C5f", | ||
"0x7A27A4D91231aCB3282b410Cc784517B417FA0DA" | ||
], | ||
"snapshot": 18200908 | ||
}, | ||
{ | ||
"name": "Get bridged HOPR token balance", | ||
"strategy": { | ||
"name": "hopr-bridged-balance", | ||
"params": { | ||
"xHopr": "0xd057604a14982fe8d88c5fc25aac3267ea142a08", | ||
"wxHopr": "0xD4fdec44DB9D44B8f2b6d529620f9C0C7066A2c1", | ||
"hopr": "0xf5581dfefd8fb0e4aec526be659cfab1f8c781da" | ||
} | ||
}, | ||
"network": "1", | ||
"addresses": [ | ||
"0x04BBB7eA18EA570aE47d4489991645E4E49bBf37", | ||
"0x2aF80738aC01e7883d11c912dFe8322C129ae5C5", | ||
"0x0bb43EFc1a613658177D8f67CcF9CFFD8B25b906", | ||
"0x53e85186ebF5A7d4BD06324F7b9D8B3623EF0307", | ||
"0x2DCDB99930E279f1e9Ad11F491163051432542A0", | ||
"0x4326990033eCd87A5444383Cf8c715E696301910", | ||
"0xEd6a59A7C1D5a88b7cb5eb877A7A6078A7e801C7", | ||
"0xeFC05B0D0C8bE8D4Cb3a220ef582E9f7E6FBCd00", | ||
"0xC7B169b108c5e75991C520AEA97140534291C81D", | ||
"0x04Be52434EB64aDdF373137310551ac42013677c", | ||
"0xBE8C93a8C18AF63aAB449994AFAc13E71240ccC4", | ||
"0xf813773eBDD4759c1B780d745081f046A5B776fB", | ||
"0x7F26C34Ed10bF66602009231bBFF24f2f84e9270", | ||
"0x4abd7276C53279b3aBFFF2B5D8A47c0AFc84833B", | ||
"0x3e1A12a6019ee26418F22B656926fE38F5e58C5f", | ||
"0x7A27A4D91231aCB3282b410Cc784517B417FA0DA" | ||
], | ||
"snapshot": 13269966 | ||
} | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
import { formatUnits } from '@ethersproject/units'; | ||
import { BigNumber } from '@ethersproject/bignumber'; | ||
import { multicall, subgraphRequest } from '../../utils'; | ||
|
||
export const author = 'QYuQianchen'; | ||
export const version = '0.1.0'; | ||
|
||
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'; | ||
const HOPR_XDAI_SUBGRAPH_URL = | ||
'https://api.thegraph.com/subgraphs/name/hoprnet/hopr-on-xdai'; | ||
const HOPR_MAINNET_SUBGRAPH_URL = | ||
'https://api.thegraph.com/subgraphs/name/hoprnet/hopr-on-mainnet'; | ||
const LIMIT = 1000; // 1000 addresses per query in Subgraph | ||
|
||
async function getXdaiBlockNumber(timestamp: number): Promise<number> { | ||
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 getMainnetBlockNumber(timestamp: number): Promise<number> { | ||
const query = { | ||
blocks: { | ||
__args: { | ||
first: 1, | ||
orderBy: 'number', | ||
orderDirection: 'desc', | ||
where: { | ||
timestamp_lte: timestamp | ||
} | ||
}, | ||
number: true, | ||
timestamp: true | ||
} | ||
}; | ||
const data = await subgraphRequest(MAINNET_BLOCK_SUBGRAPH_URL, query); | ||
return Number(data.blocks[0].number); | ||
} | ||
|
||
async function xHoprSubgraphQuery( | ||
addresses: string[], | ||
blockNumber: number | ||
): Promise<{ [propName: string]: number }> { | ||
const query = { | ||
accounts: { | ||
__args: { | ||
first: LIMIT, | ||
block: { | ||
number: blockNumber | ||
}, | ||
where: { | ||
id_in: addresses.map((adr) => adr.toLowerCase()) | ||
} | ||
}, | ||
id: true, | ||
totalBalance: true | ||
} | ||
}; | ||
const data = await subgraphRequest(HOPR_XDAI_SUBGRAPH_URL, query); | ||
// map result (data.accounts) to addresses | ||
const entries = data.accounts.map((d) => [d.id, Number(d.totalBalance)]); | ||
return Object.fromEntries(entries); | ||
} | ||
|
||
async function hoprSubgraphQuery( | ||
addresses: string[], | ||
blockNumber: number | ||
): Promise<{ [propName: string]: number }> { | ||
const query = { | ||
accounts: { | ||
__args: { | ||
first: LIMIT, | ||
block: { | ||
number: blockNumber | ||
}, | ||
where: { | ||
id_in: addresses.map((adr) => adr.toLowerCase()) | ||
} | ||
}, | ||
id: true, | ||
amount: true | ||
} | ||
}; | ||
const data = await subgraphRequest(HOPR_MAINNET_SUBGRAPH_URL, query); | ||
// map result (data.accounts) to addresses | ||
const entries = data.accounts.map((d) => [d.id, Number(d.amount)]); | ||
return Object.fromEntries(entries); | ||
} | ||
|
||
export async function strategy( | ||
space, | ||
network, | ||
provider, | ||
addresses, | ||
options, | ||
snapshot | ||
) { | ||
const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; | ||
const isEth = network === '1'; // either ETH mainnet or xDAI | ||
|
||
const [res, block] = await Promise.all([ | ||
multicall( | ||
network, | ||
provider, | ||
tokenAbi, | ||
addresses | ||
.map((address: any) => [ | ||
isEth ? options.hopr : options.xHopr, | ||
'balanceOf', | ||
[address] | ||
]) | ||
.concat( | ||
isEth | ||
? [] | ||
: addresses.map((address: any) => [ | ||
options.wxHopr, | ||
'balanceOf', | ||
[address] | ||
]) | ||
), | ||
{ blockTag } | ||
), | ||
provider.getBlock(blockTag) | ||
]); | ||
|
||
const currentNetwork: BigNumber[] = isEth | ||
? res.map((r) => r[0] as BigNumber) | ||
: addresses.map((r, i) => | ||
(res[i][0] as BigNumber).add(res[i + addresses.length][0] as BigNumber) | ||
); | ||
const subgraphBlock = isEth | ||
? await getXdaiBlockNumber(block.timestamp) | ||
: await getMainnetBlockNumber(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 = isEth | ||
? await Promise.all( | ||
addressSubsets.map((subset) => | ||
xHoprSubgraphQuery(subset, subgraphBlock) | ||
) | ||
) | ||
: await Promise.all( | ||
addressSubsets.map((subset) => hoprSubgraphQuery(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( | ||
currentNetwork.map((value, i) => [ | ||
addresses[i], // current network balance | ||
parseFloat(formatUnits(value, 18)) + subgraphScore[i] // subgraph balance | ||
]) | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters