Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(NexusViewer): add pool manager NXM locked for MV timestamp #1280

Open
wants to merge 4 commits into
base: feat/assessment-stake-lockup-expiry
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions contracts/interfaces/INexusViewer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ interface INexusViewer {
uint assessmentStake; // Claimable assessment stake in NXM
uint stakingPoolTotalRewards; // Total staking pool rewards in NXM
uint stakingPoolTotalExpiredStake; // Total staking pool expired stake in NXM
uint stakingPoolManagerIsNXMLockedForMV; // Staking pool manager NXM locked for MV
uint managerTotalRewards; // Pool manager total staking rewards in NXM
uint legacyPooledStakeRewards; // Legacy pooled staking rewards in NXM
uint legacyPooledStakeDeposits; // Legacy pooled staking deposits in NXM
Expand Down
35 changes: 31 additions & 4 deletions contracts/modules/viewer/NexusViewer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ import {IAssessmentViewer} from "../../interfaces/IAssessmentViewer.sol";
import {IGovernance} from "../../interfaces/IGovernance.sol";
import {INexusViewer} from "../../interfaces/INexusViewer.sol";
import {INXMMaster} from "../../interfaces/INXMMaster.sol";
import {INXMToken} from "../../interfaces/INXMToken.sol";
import {IPooledStaking} from "../../interfaces/IPooledStaking.sol";
import {IStakingViewer} from "../../interfaces/IStakingViewer.sol";
import {ITokenController} from "../../interfaces/ITokenController.sol";
import {IStakingPool} from "../../interfaces/IStakingPool.sol";

/// @title NexusViewer Contract
/// @notice This contract provides a unified view of system-wide data from various contracts within the Nexus Mutual protocol.
Expand All @@ -19,11 +21,13 @@ contract NexusViewer is INexusViewer, Multicall {
INXMMaster public immutable master;
IStakingViewer public immutable stakingViewer;
IAssessmentViewer public immutable assessmentViewer;
INXMToken public immutable nxm;

constructor(INXMMaster _master, IStakingViewer _stakingViewer, IAssessmentViewer _assessmentViewer) {
constructor(INXMMaster _master, IStakingViewer _stakingViewer, IAssessmentViewer _assessmentViewer, INXMToken _nxm) {
master = _master;
stakingViewer = _stakingViewer;
assessmentViewer = _assessmentViewer;
nxm = _nxm;
}

/// @notice Retrieves the claimable NXM tokens across the protocol for a given member.
Expand All @@ -38,12 +42,34 @@ contract NexusViewer is INexusViewer, Multicall {

// Assessment
IAssessmentViewer.AssessmentRewards memory assessmentRewards = assessmentViewer.getRewards(member);
(uint assessmentStake, IAssessmentViewer.AssessmentStakeLockedState memory stakeLockedState) = _getAssessmentStake(member);
uint assessmentStakeValue = 0;
// Workaround for stack too deep error
{
(uint assessmentStake, IAssessmentViewer.AssessmentStakeLockedState memory stakeLockedState) = _getAssessmentStake(member);
assessmentStakeValue = stakeLockedState.isStakeLocked ? 0 : assessmentStake;
}

// Staking Pool
IStakingViewer.AggregatedTokens memory aggregatedTokens = stakingViewer.getAggregatedTokens(tokenIds);
uint managerTotalRewards = stakingViewer.getManagerTotalRewards(member);


uint poolManagerNXMLockedForMV = 0;
// Workaround for stack too deep error
{
IStakingViewer.TokenPoolMap[] memory tokenPools = stakingViewer.getStakingPoolsOf(tokenIds);
// for each token, get the pool and manager
for (uint i = 0; i < tokenPools.length; i++) {
IStakingPool _stakingPool = stakingViewer.stakingPool(tokenPools[i].poolId);
address poolManager = _stakingPool.manager();
// check if pool manager is locked for MV
uint lockedForMV = nxm.isLockedForMV(poolManager);
// get the latest date locked for MV
if (lockedForMV > 0 && lockedForMV > poolManagerNXMLockedForMV) {
poolManagerNXMLockedForMV = lockedForMV;
}
}
}

// V1
uint legacyPooledStakeRewards = _legacyPooledStaking().stakerReward(member);
uint legacyPooledStakeDeposits = _legacyPooledStaking().stakerDeposit(member);
Expand All @@ -53,9 +79,10 @@ contract NexusViewer is INexusViewer, Multicall {
return ClaimableNXM({
governanceRewards: governanceRewards,
assessmentRewards: assessmentRewards.withdrawableAmountInNXM,
assessmentStake: stakeLockedState.isStakeLocked ? 0 : assessmentStake,
assessmentStake: assessmentStakeValue,
stakingPoolTotalRewards: aggregatedTokens.totalRewards,
stakingPoolTotalExpiredStake: aggregatedTokens.totalExpiredStake,
stakingPoolManagerIsNXMLockedForMV: poolManagerNXMLockedForMV,
managerTotalRewards: managerTotalRewards,
legacyPooledStakeRewards: legacyPooledStakeRewards,
legacyPooledStakeDeposits: legacyPooledStakeDeposits,
Expand Down
6 changes: 5 additions & 1 deletion scripts/deploy/assessment-and-nexus-viewer-deploy.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const { ethers, network } = require('hardhat');

const STV = '0xcafea5E8a7a54dd14Bb225b66C7a016dfd7F236b'; // StakingViewer
const MS = '0x01BFd82675DBCc7762C84019cA518e701C0cD07e'; // NXMaster
const NXM = '0xd7c49CEE7E9188cCa6AD8FF264C1DA2e69D4Cf3B'; // NXMToken

const main = async () => {
console.log(`Starting deploy script on ${network.name} network`);
Expand All @@ -13,12 +14,15 @@ const main = async () => {
const assessmentViewerImplementation = await ethers.deployContract('AssessmentViewer', [MS], signer);
const nexusViewerImplementation = await ethers.deployContract(
'NexusViewer',
[MS, STV, assessmentViewerImplementation.address],
[MS, STV, assessmentViewerImplementation.address, NXM],
signer,
);

console.log('AssessmentViewer implementation address:', assessmentViewerImplementation.address);
console.log('NexusViewer implementation address:', nexusViewerImplementation.address);
console.log('NexusViewer ABI', nexusViewerImplementation.interface.format(ethers.utils.FormatTypes.json));

console.log('Done');
};
main()
.then(() => process.exit(0))
Expand Down
137 changes: 137 additions & 0 deletions scripts/ui-data-fetching/get-claimable-nxm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
require('dotenv').config();
const { ethers } = require('hardhat');

const NexusViewerABI = [
{
type: 'constructor',
payable: false,
inputs: [
{ type: 'address', name: '_master' },
{ type: 'address', name: '_stakingViewer' },
{ type: 'address', name: '_assessmentViewer' },
{ type: 'address', name: '_nxm' },
],
},
{ type: 'error', name: 'RevertedWithoutReason', inputs: [{ type: 'uint256', name: 'index' }] },
{
type: 'function',
name: 'assessmentViewer',
constant: true,
stateMutability: 'view',
payable: false,
gas: 11000000,
inputs: [],
outputs: [{ type: 'address' }],
},
{
type: 'function',
name: 'getClaimableNXM',
constant: true,
stateMutability: 'view',
payable: false,
gas: 11000000,
inputs: [
{ type: 'address', name: 'member' },
{ type: 'uint256[]', name: 'tokenIds' },
],
outputs: [
{
type: 'tuple',
components: [
{ type: 'uint256', name: 'governanceRewards' },
{ type: 'uint256', name: 'assessmentRewards' },
{ type: 'uint256', name: 'assessmentStake' },
{ type: 'uint256', name: 'stakingPoolTotalRewards' },
{ type: 'uint256', name: 'stakingPoolTotalExpiredStake' },
{ type: 'uint256', name: 'stakingPoolManagerIsNXMLockedForMV' },
{ type: 'uint256', name: 'managerTotalRewards' },
{ type: 'uint256', name: 'legacyPooledStakeRewards' },
{ type: 'uint256', name: 'legacyPooledStakeDeposits' },
{ type: 'uint256', name: 'legacyClaimAssessmentTokens' },
{ type: 'uint256', name: 'legacyCoverNoteDeposits' },
],
},
],
},
{
type: 'function',
name: 'getStakedNXM',
constant: true,
stateMutability: 'view',
payable: false,
gas: 11000000,
inputs: [
{ type: 'address', name: 'member' },
{ type: 'uint256[]', name: 'tokenIds' },
],
outputs: [
{
type: 'tuple',
components: [
{ type: 'uint256', name: 'stakingPoolTotalActiveStake' },
{ type: 'uint256', name: 'assessmentStake' },
{ type: 'uint256', name: 'assessmentStakeLockupExpiry' },
{ type: 'uint256', name: 'assessmentRewards' },
],
},
],
},
{
type: 'function',
name: 'master',
constant: true,
stateMutability: 'view',
payable: false,
gas: 11000000,
inputs: [],
outputs: [{ type: 'address' }],
},
{
type: 'function',
name: 'multicall',
constant: false,
payable: false,
gas: 11000000,
inputs: [{ type: 'bytes[]', name: 'data' }],
outputs: [{ type: 'bytes[]', name: 'results' }],
},
{
type: 'function',
name: 'nxm',
constant: true,
stateMutability: 'view',
payable: false,
gas: 11000000,
inputs: [],
outputs: [{ type: 'address' }],
},
{
type: 'function',
name: 'stakingViewer',
constant: true,
stateMutability: 'view',
payable: false,
gas: 11000000,
inputs: [],
outputs: [{ type: 'address' }],
},
];
const NexusViewerAddress = '0xF62eEc897fa5ef36a957702AA4a45B58fE8Fe312';

const member = '0xd6CE9335f5A68e885271CdbE460b7A4FED5FeDA9';
const tokenIds = [34, 35, 36, 103, 136];

async function main() {
const viewer = await ethers.getContractAt(NexusViewerABI, NexusViewerAddress);

const claimableNXM = await viewer.getClaimableNXM(member, tokenIds);

console.log('Claimable NXM:', claimableNXM);
}

main()
.then(() => process.exit(0))
.catch(error => {
console.error(error);
process.exit(1);
});
Loading