-
Notifications
You must be signed in to change notification settings - Fork 66
feat: v1 NXM push #1232
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
feat: v1 NXM push #1232
Changes from all commits
Commits
Show all changes
34 commits
Select commit
Hold shift + click to select a range
0cc7083
Add v1 nxm data and scripts
rackstar c63f784
Add v1 nxm push estimate gas script
rackstar 48de15b
Add v1 NXM amounts calculation
rackstar 3734cd7
Update v1 nxm scripts
rackstar d07a0e3
Rename v1 nxm data json files
rackstar bf2e9a2
Add v1 nxm push script
rackstar 00a190b
Add v1-nxm-coordinator script
rackstar 3e882d2
Update v1 nxm scripts
rackstar 1e16d00
Update .eslintrc ecmaVersion to 2021
rackstar 41622b8
Drop unneccesary data files
rackstar 44cbbb8
Update output file name
rackstar 22c18ac
Add docs, logs and clean up
rackstar 93df65c
Rename file
rackstar e43c434
Add logs for failed memberIds
rackstar 49f34e8
Fix linting issues + clean up
rackstar 88eaab3
Rename file and remove unused file
rackstar 277a439
Move functions to v1-nxm-push-utils
rackstar 33f8912
Code clean up
rackstar ff518b2
Code clean up
rackstar 10c112f
Remove v1-nxm-total in favour of v1-nxm-accounting
rackstar b79f841
Add failed members logs
rackstar 1d7c460
Add tx.wait after sending txs
rackstar 187f218
Move processing member logging after gas fee validation
rackstar e464a35
Set explicit gasFees
rackstar df5e67e
Push staking rewards first
rackstar a45e80e
Set pushV1StakingStake manual gasLimit
rackstar bd93484
Clean up v1 nxm push scripts
rackstar 622401c
Clean up v1-nxm-accounting script
rackstar d5aa374
Drop redundant dotenv config
rackstar cd7295d
Add manual gasLimit from previous estimate
rackstar 065c51e
Fix nxm accounting
rackstar 42e5941
Fixes
rackstar 3207a6d
Send tx synchronously to avoid having same nonce
rackstar ad17a34
Add manual / auto nonce feature
rackstar File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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
This file contains hidden or 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,72 @@ | ||
const { inspect } = require('node:util'); | ||
const fs = require('node:fs'); | ||
|
||
const { Sema } = require('async-sema'); | ||
const { ethers } = require('hardhat'); | ||
|
||
const { getContract } = require('./v1-nxm-push-utils'); | ||
|
||
const OUTPUT_FILE = 'v1-cla-locked-amount.json'; | ||
const ROLE_MEMBER = 2; | ||
|
||
async function getMemberCLA(memberId, claReason, mr, tc) { | ||
process.stdout.write(`\rProcessing memberId ${memberId}`); | ||
|
||
const [member, active] = await mr.memberAtIndex(ROLE_MEMBER, memberId); | ||
|
||
if (!active) { | ||
return { member, amount: '0' }; | ||
} | ||
|
||
const amount = await tc.tokensLocked(member, claReason); | ||
|
||
return { member, amount: amount.toString() }; | ||
} | ||
|
||
const main = async () => { | ||
const v1ClaimAssessment = []; | ||
|
||
const mr = getContract('MemberRoles'); | ||
const tc = getContract('TokenController'); | ||
|
||
const claReason = ethers.utils.formatBytes32String('CLA'); | ||
const memberCount = (await mr.membersLength(ROLE_MEMBER)).toNumber(); | ||
const membersSemaphore = new Sema(100, { capacity: memberCount }); | ||
|
||
console.log('Fetching V1 Pooled Staking stake / rewards for all members...'); | ||
const failedMemberIds = []; | ||
|
||
const memberPromises = Array.from({ length: memberCount }).map(async (_, memberId) => { | ||
await membersSemaphore.acquire(); | ||
|
||
try { | ||
const result = await getMemberCLA(memberId, claReason, mr, tc); | ||
if (result.amount !== '0') { | ||
v1ClaimAssessment.push(result); | ||
} | ||
} catch (e) { | ||
console.error(`Error processing memberId ${memberId}: ${e.message}`); | ||
failedMemberIds.push(memberId); | ||
} | ||
|
||
membersSemaphore.release(); | ||
}); | ||
|
||
await Promise.all(memberPromises); | ||
|
||
console.log(`Found ${v1ClaimAssessment.length} members with locked v1 NXM for CLA`); | ||
console.log(`Failed members: ${inspect(failedMemberIds, { depth: null })}`); | ||
|
||
console.log(`Writing output to ${OUTPUT_FILE}...`); | ||
fs.writeFileSync(OUTPUT_FILE, JSON.stringify(v1ClaimAssessment, null, 2), 'utf8'); | ||
console.log('Done.'); | ||
}; | ||
|
||
if (require.main === module) { | ||
main() | ||
.then(() => process.exit(0)) | ||
.catch(e => { | ||
console.log('Unhandled error encountered: ', e.stack); | ||
process.exit(1); | ||
}); | ||
} |
This file contains hidden or 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,103 @@ | ||
const { inspect } = require('node:util'); | ||
const fs = require('node:fs'); | ||
|
||
const { Sema } = require('async-sema'); | ||
const { ethers } = require('hardhat'); | ||
|
||
const { getContract } = require('./v1-nxm-push-utils'); | ||
|
||
const { BigNumber } = ethers; | ||
|
||
const OUTPUT_FILE = 'v1-cn-locked-amount.json'; | ||
const ROLE_MEMBER = 2; | ||
|
||
async function getMemberCN(memberId, mr, tc) { | ||
try { | ||
const [member, active] = await mr.memberAtIndex(ROLE_MEMBER, memberId); | ||
|
||
if (!active) { | ||
return { member, amount: '0' }; | ||
} | ||
|
||
const { coverIds, lockReasons, withdrawableAmount } = await tc.getWithdrawableCoverNotes(member); | ||
const memberLockReasons = await tc.getLockReasons(member); | ||
|
||
const lockReasonIndexCover = {}; | ||
let coverIndex = 0; | ||
for (const lockReason of lockReasons) { | ||
const lockReasonIndex = memberLockReasons.indexOf(lockReason); | ||
lockReasonIndexCover[lockReasonIndex] = BigNumber.from(coverIds[coverIndex++]).toString(); | ||
} | ||
|
||
const sortedIndexes = Object.keys(lockReasonIndexCover).sort((a, b) => a - b); | ||
const sortedCoverIds = []; | ||
for (const index of sortedIndexes) { | ||
sortedCoverIds.push(lockReasonIndexCover[index]); | ||
} | ||
|
||
return { | ||
member, | ||
coverIds: sortedCoverIds, | ||
lockReasonIndexes: sortedIndexes, | ||
amount: withdrawableAmount.toString(), | ||
}; | ||
} catch (error) { | ||
console.error(`Error processing memberId ${memberId}: ${error.message}`); | ||
return { member: 'unknown', amount: '0', error: error.message }; | ||
} | ||
} | ||
|
||
const main = async () => { | ||
const tc = getContract('TokenController'); | ||
const mr = getContract('MemberRoles'); | ||
|
||
const memberCount = (await mr.membersLength(ROLE_MEMBER)).toNumber(); | ||
const membersSemaphore = new Sema(100, { capacity: memberCount }); | ||
const memberLockedCN = []; | ||
const failedMemberIds = []; | ||
|
||
console.log('Fetching locked CN amounts for all members...'); | ||
|
||
const memberPromises = Array.from({ length: memberCount }).map(async (_, memberId) => { | ||
await membersSemaphore.acquire(); | ||
|
||
try { | ||
process.stdout.write(`\rProcessing memberId ${memberId}`); | ||
const lockedCN = await getMemberCN(memberId, mr, tc); | ||
|
||
if (lockedCN.amount !== '0') { | ||
memberLockedCN.push(lockedCN); | ||
} | ||
if (lockedCN.error) { | ||
console.error(`\nError event for memberId ${memberId}: ${lockedCN.error}`); | ||
failedMemberIds.push(memberId); | ||
} | ||
} catch (e) { | ||
console.error(`\nError event for memberId ${memberId}: ${e.message}`); | ||
failedMemberIds.push(memberId); | ||
} finally { | ||
membersSemaphore.release(); | ||
} | ||
}); | ||
|
||
await Promise.all(memberPromises); | ||
|
||
console.log(`\nFound ${memberLockedCN.length} members with locked v1 NXM for CN`); | ||
console.log(`Failed members: ${inspect(failedMemberIds, { depth: null })}`); | ||
|
||
console.log(`Writing output to ${OUTPUT_FILE}...`); | ||
fs.writeFileSync(OUTPUT_FILE, JSON.stringify(memberLockedCN, null, 2), 'utf8'); | ||
console.log('Done.'); | ||
}; | ||
|
||
if (require.main === module) { | ||
const provider = new ethers.providers.JsonRpcProvider(process.env.TEST_ENV_FORK); | ||
main(provider) | ||
.then(() => process.exit(0)) | ||
.catch(e => { | ||
console.log('Unhandled error encountered: ', e.stack); | ||
process.exit(1); | ||
}); | ||
} | ||
|
||
module.exports = main; |
This file contains hidden or 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,86 @@ | ||
const deployments = require('@nexusmutual/deployments'); | ||
const { ethers } = require('hardhat'); | ||
|
||
const { getContract } = require('./v1-nxm-push-utils'); | ||
|
||
async function logPoolBalances() { | ||
const tokenController = getContract('TokenController'); | ||
const nxm = getContract('NXMToken'); | ||
const stakingPoolFactory = getContract('StakingPoolFactory'); | ||
|
||
let totalDeposits = ethers.BigNumber.from(0); | ||
let totalRewards = ethers.BigNumber.from(0); | ||
|
||
const stakingPoolCount = await stakingPoolFactory.stakingPoolCount(); | ||
|
||
for (let poolId = 1; poolId <= stakingPoolCount.toNumber(); poolId++) { | ||
const { rewards, deposits } = await tokenController.stakingPoolNXMBalances(poolId); | ||
const depositsNXM = ethers.utils.formatEther(deposits); | ||
const rewardsNXM = ethers.utils.formatEther(rewards); | ||
|
||
console.log(`Pool ${poolId}: Deposits: ${depositsNXM} NXM, Rewards: ${rewardsNXM} NXM`); | ||
|
||
totalDeposits = totalDeposits.add(deposits); | ||
totalRewards = totalRewards.add(rewards); | ||
} | ||
|
||
const cnData = require('../../v1-cn-locked-amount.json'); | ||
const claData = require('../../v1-cla-locked-amount.json'); | ||
const cnBalance = cnData.reduce((acc, data) => acc.add(data.amount), ethers.BigNumber.from(0)); | ||
const claBalance = claData.reduce((acc, data) => acc.add(data.amount), ethers.BigNumber.from(0)); | ||
|
||
const totalDepositsNXM = ethers.utils.formatEther(totalDeposits); | ||
const totalRewardsNXM = ethers.utils.formatEther(totalRewards); | ||
const totalCnBalanceNXM = ethers.utils.formatEther(cnBalance); | ||
const totalClaBalanceNXM = ethers.utils.formatEther(claBalance); | ||
|
||
console.log(`Total Deposits: ${totalDepositsNXM} NXM`); | ||
console.log(`Total Rewards: ${totalRewardsNXM} NXM`); | ||
console.log(`CN Balance: ${totalCnBalanceNXM} NXM`); | ||
console.log(`CLA Balance: ${totalClaBalanceNXM} NXM`); | ||
|
||
const totalPoolBalance = totalDeposits.add(totalRewards).add(cnBalance).add(claBalance); | ||
console.log(`EXPECTED Total Pool Balance: ${ethers.utils.formatEther(totalPoolBalance)} NXM`); | ||
|
||
const tokenControllerBalance = await nxm.balanceOf(deployments.addresses.TokenController); | ||
console.log(`ACTUAL Token Controller Balance: ${ethers.utils.formatEther(tokenControllerBalance)} NXM`); | ||
|
||
const difference = tokenControllerBalance.sub(totalPoolBalance); | ||
const differenceNXM = ethers.utils.formatEther(difference); | ||
|
||
console.log(`Difference: ${differenceNXM} NXM`); | ||
} | ||
|
||
/* Get total v1 NXM amounts that is owed to members */ | ||
const getAmounts = (label, usersAndAmounts) => { | ||
const totalAmountNxm = usersAndAmounts.reduce((acc, data) => acc.add(data.amount), ethers.BigNumber.from(0)); | ||
const totalNxm = ethers.utils.formatEther(totalAmountNxm); | ||
console.log(`${label} ${totalNxm} NXM`); | ||
return totalNxm; | ||
}; | ||
|
||
async function legacyPooledStakingAccounting() { | ||
const nxm = getContract('NXMToken'); | ||
|
||
const psBal = await nxm.balanceOf(deployments.addresses.LegacyPooledStaking); | ||
const psBalNxm = ethers.utils.formatEther(psBal); | ||
|
||
const stakeData = require('../../v1-pooled-staking-stake.json'); | ||
const rewardsData = require('../../v1-pooled-staking-rewards.json'); | ||
const v1NxmStake = getAmounts('Stake', stakeData); | ||
const v1NxmRewards = getAmounts('Rewards', rewardsData); | ||
console.log(`LegacyPooledStaking ${psBalNxm} NXM`); | ||
|
||
console.log(`LegacyPooledStaking Difference ${psBalNxm - v1NxmRewards - v1NxmStake} NXM`); | ||
} | ||
|
||
if (require.main === module) { | ||
legacyPooledStakingAccounting() | ||
.then(() => console.log('\n--------------------\n')) | ||
.then(() => logPoolBalances()) | ||
.then(() => process.exit(0)) | ||
.catch(e => { | ||
console.log('Unhandled error encountered: ', e.stack); | ||
process.exit(1); | ||
}); | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.