├── .editorconfig ├── .env.sample ├── .eslintrc ├── .gitattributes ├── .github ├── config │ └── conventional-bump-setup.js └── workflows │ ├── checks.yml │ ├── release-next.yml │ └── release.yml ├── .gitignore ├── .husky ├── commit-msg ├── pre-commit └── pre-push ├── .prettierrc ├── .solcover.js ├── .solhint.json ├── LICENSE ├── README.md ├── commitlint.config.js ├── contracts ├── abstract │ ├── LegacyMasterAware.sol │ ├── MasterAware.sol │ ├── MasterAwareV2.sol │ └── Multicall.sol ├── external │ ├── Deployer.sol │ ├── WETH9.sol │ ├── cover │ │ └── CoverBroker.sol │ ├── cow │ │ └── GPv2Order.sol │ ├── enzyme │ │ ├── IAddressRegistryList.sol │ │ ├── IEnzymeFundValueCalculatorRouter.sol │ │ ├── IEnzymePolicyManager.sol │ │ ├── IEnzymeV4Comptroller.sol │ │ ├── IEnzymeV4DepositWrapper.sol │ │ └── IEnzymeV4Vault.sol │ └── wNXM.sol ├── interfaces │ ├── IAssessment.sol │ ├── IAssessmentViewer.sol │ ├── ICompleteStakingPoolFactory.sol │ ├── ICover.sol │ ├── ICoverBroker.sol │ ├── ICoverNFT.sol │ ├── ICoverNFTDescriptor.sol │ ├── ICoverProducts.sol │ ├── ICowSettlement.sol │ ├── IERC20.sol │ ├── IERC20Detailed.sol │ ├── IERC721Mock.sol │ ├── IFailedStakingPool.sol │ ├── IGovernance.sol │ ├── IIndividualClaims.sol │ ├── ILegacyClaims.sol │ ├── ILegacyClaimsData.sol │ ├── ILegacyClaimsReward.sol │ ├── ILegacyCover.sol │ ├── ILegacyIncidents.sol │ ├── ILegacyPool.sol │ ├── ILimitOrders.sol │ ├── IMCR.sol │ ├── IMasterAware.sol │ ├── IMasterAwareV2.sol │ ├── IMemberRoles.sol │ ├── IMemberRolesErrors.sol │ ├── INXMMaster.sol │ ├── INXMToken.sol │ ├── INexusViewer.sol │ ├── IPool.sol │ ├── IPriceFeedOracle.sol │ ├── IProposalCategory.sol │ ├── IQuotation.sol │ ├── IQuotationData.sol │ ├── IRamm.sol │ ├── ISafeTracker.sol │ ├── IStakingNFT.sol │ ├── IStakingNFTDescriptor.sol │ ├── IStakingPool.sol │ ├── IStakingPoolBeacon.sol │ ├── IStakingPoolFactory.sol │ ├── IStakingProducts.sol │ ├── IStakingViewer.sol │ ├── ISwapOperator.sol │ ├── ITokenController.sol │ ├── ITokenControllerErrors.sol │ ├── ITokenData.sol │ └── IWeth.sol ├── libraries │ ├── DateTime.sol │ ├── FloatingPoint.sol │ ├── Math.sol │ ├── SafeUintCast.sol │ ├── StakingPoolLibrary.sol │ ├── UncheckedMath.sol │ └── external │ │ └── SafeMath.sol ├── mocks │ ├── SafeTracker │ │ ├── STMockPool.sol │ │ └── STMockSwapOperator.sol │ ├── common │ │ ├── ChainlinkAggregatorMock.sol │ │ ├── ERC20Detailed.sol │ │ ├── ERC20Mintable.sol │ │ ├── EtherRejecterMock.sol │ │ ├── MasterMock.sol │ │ ├── MemberRolesMock.sol │ │ ├── NXMTokenMock.sol │ │ ├── PoolEtherRejecterMock.sol │ │ ├── PoolMock.sol │ │ ├── PriceFeedOracleMock.sol │ │ ├── ProxySignatureCollider.sol │ │ ├── RammMock.sol │ │ ├── ReentrancyExploiter.sol │ │ ├── Stub.sol │ │ └── TokenControllerMock.sol │ ├── disposables │ │ ├── DisposableGovernance.sol │ │ ├── DisposableMCR.sol │ │ ├── DisposableMemberRoles.sol │ │ ├── DisposableNXMaster.sol │ │ ├── DisposableProposalCategory.sol │ │ └── DisposableRamm.sol │ ├── generic │ │ ├── AssessmentGeneric.sol │ │ ├── CoverGeneric.sol │ │ ├── CoverNFTDescriptorGeneric.sol │ │ ├── CoverNFTGeneric.sol │ │ ├── CoverProductsGeneric.sol │ │ ├── GovernanceGeneric.sol │ │ ├── IndividualClaimsGeneric.sol │ │ ├── MCRGeneric.sol │ │ ├── MemberRolesGeneric.sol │ │ ├── MulticallMock.sol │ │ ├── NXMMasterGeneric.sol │ │ ├── PoolGeneric.sol │ │ ├── PriceFeedOracleGeneric.sol │ │ ├── RammGeneric.sol │ │ ├── StakingNFTDescriptorGeneric.sol │ │ ├── StakingNFTGeneric.sol │ │ ├── StakingPoolFactoryGeneric.sol │ │ ├── StakingPoolGeneric.sol │ │ ├── StakingProductsGeneric.sol │ │ ├── SwapOperatorGeneric.sol │ │ └── TokenControllerGeneric.sol │ ├── modules │ │ ├── Assessment │ │ │ ├── ASMockIndividualClaims.sol │ │ │ ├── ASMockMemberRoles.sol │ │ │ └── ASMockTokenController.sol │ │ ├── AssessmentViewer │ │ │ └── AVMockAssessment.sol │ │ ├── Claims │ │ │ ├── CLMockAssessment.sol │ │ │ ├── CLMockCover.sol │ │ │ ├── CLMockCoverNFT.sol │ │ │ ├── CLMockCoverProducts.sol │ │ │ └── CLMockTokenController.sol │ │ ├── Cover │ │ │ ├── COMockCoverNFT.sol │ │ │ ├── COMockMCR.sol │ │ │ ├── COMockStakingNFT.sol │ │ │ ├── COMockStakingPool.sol │ │ │ └── COMockStakingProducts.sol │ │ ├── CoverProducts │ │ │ ├── CPMockCover.sol │ │ │ └── CPMockStakingPoolFactory.sol │ │ ├── CoverViewer │ │ │ └── CVMockCover.sol │ │ ├── LimitOrders │ │ │ └── LimitOrdersCoverMock.sol │ │ ├── MCR │ │ │ ├── MCRMockCover.sol │ │ │ ├── MCRMockPool.sol │ │ │ └── MCRMockPriceFeedOracle.sol │ │ ├── Master │ │ │ ├── MSMockGovernance.sol │ │ │ └── MSMockNewContract.sol │ │ ├── MemberRoles │ │ │ ├── MRMockAssessment.sol │ │ │ ├── MRMockCover.sol │ │ │ ├── MRMockCoverNFT.sol │ │ │ ├── MRMockGovernance.sol │ │ │ └── MRMockStakingNFT.sol │ │ ├── NexusViewer │ │ │ ├── NVMockAssessmentViewer.sol │ │ │ └── NVMockStakingViewer.sol │ │ ├── Pool │ │ │ ├── P1MockLido.sol │ │ │ ├── P1MockMCR.sol │ │ │ ├── P1MockOldPool.sol │ │ │ └── P1MockSwapOperator.sol │ │ ├── Ramm │ │ │ ├── RAMockMCR.sol │ │ │ ├── RAMockMemberRoles.sol │ │ │ └── RAMockTokenController.sol │ │ ├── StakingNFT │ │ │ └── SNFTMockCover.sol │ │ ├── StakingPool │ │ │ ├── SKMockCover.sol │ │ │ ├── SKMockCoverProducts.sol │ │ │ ├── SKMockStakingNFT.sol │ │ │ └── SKMockStakingProducts.sol │ │ ├── StakingProducts │ │ │ ├── SPMockCover.sol │ │ │ ├── SPMockCoverProducts.sol │ │ │ └── SPMockStakingProducts.sol │ │ ├── SwapOperator │ │ │ ├── SOMockEnzymeFundValueCalculatorRouter.sol │ │ │ ├── SOMockEnzymeV4Comptroller.sol │ │ │ ├── SOMockEnzymeV4DepositWrapper.sol │ │ │ ├── SOMockEnzymeV4Vault.sol │ │ │ ├── SOMockSettlement.sol │ │ │ ├── SOMockVaultRelayer.sol │ │ │ └── SOMockWeth.sol │ │ └── TokenController │ │ │ ├── TCMockAssessment.sol │ │ │ ├── TCMockGovernance.sol │ │ │ ├── TCMockStakingNFT.sol │ │ │ └── TCMockStakingPool.sol │ ├── testnet │ │ ├── TestnetClaimProofs.sol │ │ ├── TestnetClaimsData.sol │ │ ├── TestnetMemberRoles.sol │ │ └── TestnetNXMaster.sol │ └── tokens │ │ ├── ERC20BlacklistableMock.sol │ │ ├── ERC20CustomDecimalsMock.sol │ │ ├── ERC20MintableDetailed.sol │ │ ├── ERC20Mock.sol │ │ ├── ERC20MockNameable.sol │ │ ├── ERC20NonRevertingMock.sol │ │ ├── ERC20PermitMock.sol │ │ ├── ERC20RevertingBalanceOfMock.sol │ │ ├── ERC721.sol │ │ └── ERC721Mock.sol └── modules │ ├── assessment │ ├── Assessment.sol │ ├── AssessmentViewer.sol │ └── IndividualClaims.sol │ ├── capital │ ├── MCR.sol │ ├── Pool.sol │ ├── PriceFeedOracle.sol │ ├── Ramm.sol │ ├── SafeTracker.sol │ └── SwapOperator.sol │ ├── cover │ ├── Cover.sol │ ├── CoverNFT.sol │ ├── CoverNFTDescriptor.sol │ ├── CoverProducts.sol │ ├── CoverViewer.sol │ └── LimitOrders.sol │ ├── governance │ ├── Governance.sol │ ├── MemberRoles.sol │ ├── NXMaster.sol │ ├── ProposalCategory.sol │ ├── VotePower.sol │ └── external │ │ ├── Governed.sol │ │ ├── OwnedUpgradeabilityProxy.sol │ │ ├── Proxy.sol │ │ └── UpgradeabilityProxy.sol │ ├── legacy │ ├── LegacyClaimProofs.sol │ ├── LegacyClaimsData.sol │ └── LegacyPool.sol │ ├── staking │ ├── MinimalBeaconProxy.sol │ ├── StakingNFT.sol │ ├── StakingNFTDescriptor.sol │ ├── StakingPool.sol │ ├── StakingPoolFactory.sol │ ├── StakingProducts.sol │ ├── StakingTypesLib.sol │ └── StakingViewer.sol │ ├── token │ ├── NXMToken.sol │ ├── TokenController.sol │ └── external │ │ ├── Context.sol │ │ ├── ERC20.sol │ │ ├── LockHandler.sol │ │ ├── OZIERC20.sol │ │ └── OZSafeMath.sol │ └── viewer │ └── NexusViewer.sol ├── deployments ├── .gitignore ├── README.md ├── build.js ├── package-lock.json ├── package.json ├── src │ ├── addresses.json │ └── index.ts └── tsconfig.json ├── docs ├── contracts │ ├── Assessment.md │ ├── Cover.md │ ├── IndividualClaims.md │ ├── Pool.md │ ├── Ramm.md │ ├── StakingPool.md │ ├── StakingPoolFactory.md │ ├── StakingProducts.md │ └── TokenController.md ├── diagrams │ ├── contracts │ │ ├── capital.md │ │ ├── claims-assessment.md │ │ ├── cover.md │ │ ├── governance-membership.md │ │ ├── staking.md │ │ └── token.md │ ├── nexus-mutual.md │ └── user-flows │ │ ├── cover-buyer.md │ │ ├── staker.md │ │ └── staking-manager.md └── user-flows │ ├── cover-buyer.md │ ├── manager.md │ └── staker.md ├── hardhat-config ├── index.js ├── networks.js ├── solidity.js └── tasks.js ├── hardhat.config.js ├── lib ├── constants.js ├── helpers.js ├── index.js └── proposal-categories.js ├── package-lock.json ├── package.json ├── scripts ├── create2 │ ├── deploy.js │ ├── find-salt.js │ ├── get-signer.js │ └── worker.js ├── deploy │ ├── .gitignore │ ├── deploy.js │ ├── start.js │ ├── verifier.js │ └── whitelist.js ├── extract-lock-reasons.js ├── extract-storage-layout.js ├── governance │ ├── get-createProposalWithSolution-txdata.js │ ├── get-decoded-action-data.js │ ├── get-encoded-action-data.js │ ├── helpers.js │ └── proposal-sample.json ├── migrate-cover-data.js ├── migrate-cover-products-metadata.js ├── mocks │ ├── buyV1Covers.js │ ├── buyV2Covers.js │ ├── createStakingPools.js │ ├── depositToStakingPools.js │ └── fund.js ├── patch-staking-pool-library.js ├── staking-fees.js ├── staking-nfts.js ├── staking-search.js ├── staking-set-initial-pools-metadata.js ├── staking-update.js ├── timetravel.js └── total-active-cover.js └── test ├── fork ├── abi │ └── aave │ │ ├── AavePool.json │ │ ├── AaveProtocolDataProvider.json │ │ ├── VariableDebtToken.json │ │ └── WETHGateway.json ├── add-asset-cbbtc.js ├── add-asset-usdc.js ├── basic-functionality-tests.js ├── cover-broker-upgrade.js ├── cover-broker.js ├── cover-edits.js ├── cover-products.js ├── cover-re.js ├── cowswap-swaps.js ├── evm.js ├── execute-governance-proposal.js ├── index.js ├── limit-orders.js ├── long-term-limit-order.js ├── march2025-release.js ├── migrated-claims.js ├── migration-v2.js ├── price-drop.js ├── process-expiration.js ├── product-pricing-updates.js ├── recalculate-effective-weights-bug-fix.js ├── recalculate-effective-weights.js ├── reject-actions.js ├── run-basic-functionality-tests.js ├── setup.js ├── staked-product-allowed-pools.js ├── staking-pool-rewards.js ├── staking-pool-utils.js ├── tokenomics.js ├── utils.js ├── withdraw-enzyme-shares.js ├── withdraw-nxm.js └── withdraw-switch-membership-restrictions.js ├── integration ├── Assessment │ └── processFraud.js ├── Cover │ ├── buyCover.js │ ├── changeCoverNFTDescriptor.js │ ├── changeStakingNFTDescriptor.js │ ├── coverNFTDescriptor.js │ ├── expireCover.js │ └── totalActiveCover.js ├── CoverBroker │ └── switchMembership.js ├── Governance │ ├── categorizeProposal.js │ ├── closeProposal.js │ ├── createProposal.js │ ├── createProposalwithSolution.js │ ├── proposalFixture.js │ ├── state.js │ ├── submitProposalWithSolution.js │ ├── submitVote.js │ ├── submitVoteWithoutDelegations.js │ ├── updateProposal.js │ └── updateUintParametars.js ├── IndividualClaims │ └── submitClaim.js ├── LimitOrders │ └── executeOrder.js ├── MCR │ ├── getMCR.js │ ├── getTotalActiveCoverAmount.js │ └── updateMCR.js ├── Master │ ├── emergency-pause.js │ └── master.js ├── MemberRoles │ ├── join.js │ ├── switchMembership.js │ ├── switchMembershipAndAssets.js │ └── withdrawMembership.js ├── NexusViewer │ ├── getClaimableNxm.js │ ├── getStakedNxm.js │ └── setup.js ├── Pool │ └── pool.js ├── Ramm │ └── swap.js ├── StakingPool │ └── stakingNFTDescriptor.js ├── StakingProducts │ ├── changeStakingPoolFactoryOperator.js │ ├── recalculateEffectiveWeightsForAllProducts.js │ └── setProducts.js ├── TokenController │ ├── setup.js │ └── withdrawNXM.js ├── setup.js └── utils │ ├── assetPricing.js │ ├── cover.js │ ├── enroll.js │ ├── incidents.js │ ├── index.js │ ├── staking.js │ └── voteClaim.js ├── layout ├── selectors.js ├── slots.js └── storage │ ├── mainnetLayout.json │ ├── v1.json │ ├── v2.11.0.json │ └── v2.6.2.json ├── unit ├── Assessment │ ├── castVotes.js │ ├── constructor.js │ ├── getAssessmentsCount.js │ ├── getPoll.js │ ├── getRewards.js │ ├── getVoteCountOfAssessor.js │ ├── helpers.js │ ├── processFraud.js │ ├── setup.js │ ├── stake.js │ ├── startAssessment.js │ ├── submitFraud.js │ ├── unstake.js │ ├── unstakeAllFor.js │ ├── withdrawRewards.js │ └── withdrawRewardsTo.js ├── AssessmentViewer │ ├── getRewards.js │ ├── getStakeLocked.js │ └── setup.js ├── Cover │ ├── burnStake.js │ ├── buyCover.js │ ├── constructor.js │ ├── editCover.js │ ├── helpers.js │ ├── setup.js │ ├── totalActiveCoverInAsset.js │ └── updateTotalActiveCoverAmount.js ├── CoverBroker │ ├── rescueFunds.js │ └── setup.js ├── CoverNFT │ ├── coverNFT.js │ └── setup.js ├── CoverProducts │ ├── setProductTypes.js │ ├── setProductTypesMetadata.js │ ├── setProducts.js │ ├── setProductsMetadata.js │ └── setup.js ├── CoverViewer │ ├── setup.js │ └── views.js ├── IndividualClaims │ ├── constructor.js │ ├── getAssessmentDepositAndReward.js │ ├── getClaimsCount.js │ ├── getClaimsToDisplay.js │ ├── helpers.js │ ├── redeemClaimPayout.js │ ├── setup.js │ └── submitClaim.js ├── LimitOrders │ ├── cancelOrder.js │ ├── getOrderId.js │ └── setup.js ├── MCR │ ├── common.js │ ├── getGearedMCR.js │ ├── getMCR.js │ ├── setup.js │ ├── teleportMCR.js │ ├── updateMCR.js │ └── updateParameters.js ├── MemberRoles │ ├── changeAuthorized.js │ ├── changeDependentContractAddress.js │ ├── changeMaxABCount.js │ ├── join.js │ ├── setup.js │ ├── stateManagement.js │ ├── swapABMember.js │ ├── switchMembership.js │ ├── switchMembershipAndAssets.js │ ├── switchMembershipOf.js │ ├── updateRole.js │ └── withdrawMembership.js ├── NXMaster │ ├── addNewInternalContracts.js │ ├── getters.js │ ├── removeContracts.js │ ├── setup.js │ ├── updateOwnerParameters.js │ └── upgradeMultipleContracts.js ├── NexusViewer │ ├── getStakedNXM.js │ └── setup.js ├── Pool │ ├── addAsset.js │ ├── getInternalTokenPriceInAsset.js │ ├── getMCRRatio.js │ ├── getPoolValueInEth.js │ ├── getTokenPrice.js │ ├── sendEth.js │ ├── sendPayout.js │ ├── setAssetDetails.js │ ├── setSwapAssetAmount.js │ ├── setSwapDetailsLastSwapTime.js │ ├── setup.js │ ├── transferAsset.js │ ├── transferAssetToSwapOperator.js │ ├── updateParameters.js │ └── upgradeCapitalPool.js ├── PriceFeedOracle │ ├── getAssetForEth.js │ ├── getAssetToEthRate.js │ ├── getEthForAsset.js │ └── setup.js ├── Ramm │ ├── getBookValue.js │ ├── getInternalPrice.js │ ├── getInternalPriceAndUpdateTwap.js │ ├── getObservation.js │ ├── getReserves.js │ ├── getSpotPrices.js │ ├── helpers.js │ ├── loadState.js │ ├── removeBudget.js │ ├── setCircuitBreakerLimits.js │ ├── setEmergencySwapPause.js │ ├── setup.js │ ├── storeState.js │ ├── swap.js │ └── updateTwap.js ├── SafeTracker │ ├── allowance.js │ ├── approve.js │ ├── balanceOf.js │ ├── setup.js │ ├── totalSupply.js │ ├── transfer.js │ ├── transferFrom.js │ └── updateCoverReInvestmentUSDC.js ├── StakingNFT │ ├── setup.js │ └── stakingNFT.js ├── StakingPool │ ├── burnStake.js │ ├── calculatePremium.js │ ├── constructor.js │ ├── depositTo.js │ ├── extendDeposit.js │ ├── helpers.js │ ├── initialize.js │ ├── multicall.js │ ├── processExpirations.js │ ├── requestAllocation.js │ ├── setPoolFee.js │ ├── setPoolPrivacy.js │ ├── setup.js │ └── withdraw.js ├── StakingPoolFactory │ ├── setup.js │ └── stakingPoolFactory.js ├── StakingProducts │ ├── createStakingPool.js │ ├── getEffectiveWeight.js │ ├── helpers.js │ ├── initializeProducts.js │ ├── recalculateEffectiveWeight.js │ ├── setPoolMetadata.js │ ├── setProducts.js │ └── setup.js ├── StakingViewer │ ├── getManagedStakingPools.js │ ├── getManagerPoolsAndRewards.js │ ├── getManagerTokenRewards.js │ ├── getPool.js │ ├── processExpirationsFor.js │ └── setup.js ├── SwapOperator │ ├── closeOrder.js │ ├── helpers.js │ ├── placeOrder.js │ ├── recoverAsset.js │ ├── requestAsset.js │ ├── setup.js │ ├── swapETHForEnzymeVaultShare.js │ ├── swapEnzymeVaultShareForETH.js │ └── transferRequestedAsset.js ├── TokenController │ ├── acceptStakingPoolOwnershipOffer.js │ ├── assignStakingPoolManager.js │ ├── burnFrom.js │ ├── burnStakedNXM.js │ ├── burnStakingPoolNXMRewards.js │ ├── cancelStakingPoolOwnershipOffer.js │ ├── changeOperator.js │ ├── createStakingPoolOwnershipOffer.js │ ├── depositStakedNXM.js │ ├── mint.js │ ├── mintStakingPoolNXMRewards.js │ ├── operatorTransfer.js │ ├── setup.js │ ├── totalBalanceOf.js │ ├── transferStakingPoolOwnership.js │ ├── withdrawGovernanceRewards.js │ ├── withdrawGovernanceRewardsTo.js │ └── withdrawNXMStakeAndRewards.js └── utils.js └── utils ├── accounts.js ├── addresses.js ├── bnMath.js ├── buyCover.js ├── errors.js ├── events.js ├── evm.js ├── governance.js ├── index.js ├── membership.js ├── rammCalculations.js ├── results.js └── stakingPool.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | -------------------------------------------------------------------------------- /.env.sample: -------------------------------------------------------------------------------- 1 | KOVAN_ACCOUNT=0x0000000000000000000000000000000000000000 2 | KOVAN_ACCOUNT_KEY=0xprivatekey 3 | KOVAN_PROVIDER_URL=https://kovan.infura.io/v3/apikey 4 | KOVAN_GAS_PRICE=1 5 | KOVAN_GAS_LIMIT=12000000 6 | 7 | RINKEBY_ACCOUNT=0x0000000000000000000000000000000000000000 8 | RINKEBY_ACCOUNT_KEY=0xprivatekey 9 | RINKEBY_PROVIDER_URL=https://rinkeby.infura.io/v3/apikey 10 | RINKEBY_GAS_PRICE=1 11 | RINKEBY_GAS_LIMIT=12000000 12 | 13 | MAINNET_ACCOUNT=0x0000000000000000000000000000000000000000 14 | MAINNET_ACCOUNT_KEY=0xprivatekey 15 | MAINNET_PROVIDER_URL=https://mainnet.infura.io/v3/apikey 16 | MAINNET_GAS_PRICE=1 17 | MAINNET_GAS_LIMIT=12000000 18 | 19 | LOCALHOST_ACCOUNT=0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266 20 | LOCALHOST_ACCOUNT_KEY=ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 21 | LOCALHOST_PROVIDER_URL=http://localhost:8545 22 | LOCALHOST_GAS_PRICE=1 23 | LOCALHOST_GAS_LIMIT=12000000 24 | 25 | ETHERSCAN_API_KEY= 26 | ENABLE_OPTIMIZER=true 27 | 28 | PROVIDER_URL=https://mainnet.infura.io/v3/apikey 29 | NETWORK=localhost 30 | 31 | AWS_KMS_KEY_ID=KMS_KEY_UUID 32 | AWS_REGION= 33 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "commonjs": true, 4 | "es6": true, 5 | "node": true, 6 | "mocha": true 7 | }, 8 | "extends": [ 9 | "semistandard", 10 | "eslint:recommended", 11 | "plugin:prettier/recommended" 12 | ], 13 | "plugins": ["mocha"], 14 | "globals" : { 15 | "artifacts": true, 16 | "assert": true, 17 | "contract": true 18 | }, 19 | "ignorePatterns": ["node_modules/", "artifacts", "coverage", "!.solcover.js", "deployments/dist"], 20 | "parserOptions": { 21 | "ecmaVersion": 2020 22 | }, 23 | "rules": { 24 | "comma-dangle": ["warn", "always-multiline"], 25 | "curly": ["error", "all"], 26 | "max-len": ["error", { "code": 120 }], 27 | "mocha/no-async-describe": "error", 28 | "mocha/no-exclusive-tests": "error", 29 | "no-nested-ternary": "error", 30 | "no-unused-vars": ["warn", { "varsIgnorePattern": "^_unused" }], 31 | "padded-blocks": "off" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sol linguist-language=Solidity -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | .idea/ 3 | .vscode/ 4 | .DS_Store 5 | artifacts/ 6 | /build/ 7 | cache/ 8 | types/ 9 | node_modules/ 10 | coverage/ 11 | coverage.json 12 | tenderly.yaml 13 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | npx commitlint --edit 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | BRANCH=$(git rev-parse --abbrev-ref HEAD) 4 | REGEX="^(master|dev|release-candidate|((audit|breaking|build|chore|ci|docs|feat|fix|perf|refactor|release|revert|test|wip)/.+))$" 5 | 6 | if ! echo "$BRANCH" | grep -Eq "$REGEX"; then 7 | echo "Your commit was rejected due to invalid branch name: '$BRANCH'" 8 | echo "Please rename your branch to follow one of the accepted formats:" 9 | echo " - audit/*, breaking/*, build/*, chore/*, ci/*, docs/*, feat/*, fix/*, perf/*, refactor/*, release/*, revert/*, test/*, wip/*" 10 | exit 1 11 | fi 12 | -------------------------------------------------------------------------------- /.husky/pre-push: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | npm run lint 5 | 6 | if [ "$PRE_PUSH_RUN_TEST" = "true" ]; then 7 | npm test 8 | fi 9 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "trailingComma": "all", 4 | "tabWidth": 2, 5 | "semi": true, 6 | "singleQuote": true, 7 | "arrowParens": "avoid", 8 | "overrides": [ 9 | { 10 | "files": "*.sol", 11 | "options": { 12 | "singleQuote": false, 13 | "explicitTypes": "never" 14 | } 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /.solhint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "solhint:recommended", 3 | "plugins": [], 4 | "rules": { 5 | "avoid-suicide": "error", 6 | "avoid-sha3": "warn", 7 | "compiler-version": ["warn", "^0.5.0"], 8 | "const-name-snakecase": "off", 9 | "mark-callable-contracts": "off", 10 | "max-line-length": ["warn", 100], 11 | "max-states-count": "off", 12 | "not-rely-on-time": "off", 13 | "reason-string": "off", 14 | "var-name-mixedcase": "off" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Nexus Mutual](https://app.nexusmutual.io/) 2 | 3 | [![Coverage Status](https://coveralls.io/repos/github/NexusMutual/smart-contracts/badge.svg)](https://coveralls.io/github/NexusMutual/smart-contracts) 4 | 5 | ## Getting Started 6 | 7 | - **Requirements**: `Node >= 18` 8 | - **Install**: `npm i` 9 | - **Test**: `npm test` 10 | - **Deploy**: `npm run deploy-local` 11 | 12 | ## Smart Contracts Details 13 | 14 | - [Mainnet Addresses](https://sdk.nexusmutual.io) 15 | 16 | ## Audits 17 | 18 | - [Check the docs for a full list of security audits](https://docs.nexusmutual.io/resources/audits-and-security) 19 | 20 | ## Bug Bounty 21 | 22 | - [Smart Contracts Bug Bounty](https://immunefi.com/bounty/nexusmutual/) 23 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parserPreset: 'conventional-changelog-conventionalcommits', 3 | rules: { 4 | 'body-leading-blank': [1, 'always'], 5 | 'footer-leading-blank': [1, 'always'], 6 | 'footer-max-line-length': [2, 'always', 100], 7 | 'header-max-length': [2, 'always', 100], 8 | 'subject-case': [2, 'never', ['sentence-case', 'start-case', 'pascal-case', 'upper-case']], 9 | 'subject-empty': [2, 'never'], 10 | 'subject-full-stop': [2, 'never', '.'], 11 | 'type-case': [2, 'always', 'lower-case'], 12 | 'type-empty': [2, 'never'], 13 | 'type-enum': [ 14 | 2, 15 | 'always', 16 | ['build', 'breaking', 'chore', 'ci', 'docs', 'feat', 'fix', 'perf', 'refactor', 'revert', 'style', 'test'], 17 | ], 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /contracts/abstract/LegacyMasterAware.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | import "../interfaces/INXMMaster.sol"; 6 | 7 | contract LegacyMasterAware { 8 | 9 | INXMMaster public ms; 10 | address public nxMasterAddress; 11 | 12 | modifier onlyInternal { 13 | require(ms.isInternal(msg.sender)); 14 | _; 15 | } 16 | 17 | modifier onlyGovernance { 18 | require(msg.sender == ms.getLatestAddress("GV")); 19 | _; 20 | } 21 | 22 | 23 | modifier isMemberAndcheckPause { 24 | require(ms.isPause() == false && ms.isMember(msg.sender) == true); 25 | _; 26 | } 27 | 28 | modifier checkPause { 29 | require(ms.isPause() == false); 30 | _; 31 | } 32 | 33 | /** 34 | * @dev change master address 35 | * @param _masterAddress is the new address 36 | */ 37 | function changeMasterAddress(address _masterAddress) public { 38 | if (address(ms) != address(0)) { 39 | require(address(ms) == msg.sender, "Not master"); 40 | } 41 | 42 | ms = INXMMaster(_masterAddress); 43 | nxMasterAddress = _masterAddress; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /contracts/abstract/MasterAware.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../interfaces/INXMMaster.sol"; 6 | 7 | contract MasterAware { 8 | 9 | INXMMaster public master; 10 | 11 | modifier onlyMember { 12 | require(master.isMember(msg.sender), "Caller is not a member"); 13 | _; 14 | } 15 | 16 | modifier onlyInternal { 17 | require(master.isInternal(msg.sender), "Caller is not an internal contract"); 18 | _; 19 | } 20 | 21 | modifier onlyMaster { 22 | if (address(master) != address(0)) { 23 | require(address(master) == msg.sender, "Not master"); 24 | } 25 | _; 26 | } 27 | 28 | modifier onlyGovernance { 29 | require( 30 | master.checkIsAuthToGoverned(msg.sender), 31 | "Caller is not authorized to govern" 32 | ); 33 | _; 34 | } 35 | 36 | modifier whenPaused { 37 | require(master.isPause(), "System is not paused"); 38 | _; 39 | } 40 | 41 | modifier whenNotPaused { 42 | require(!master.isPause(), "System is paused"); 43 | _; 44 | } 45 | 46 | function changeMasterAddress(address masterAddress) public onlyMaster { 47 | master = INXMMaster(masterAddress); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /contracts/abstract/Multicall.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | abstract contract Multicall { 6 | 7 | error RevertedWithoutReason(uint index); 8 | 9 | // WARNING: Do not set this function as payable 10 | function multicall(bytes[] calldata data) external returns (bytes[] memory results) { 11 | 12 | uint callCount = data.length; 13 | results = new bytes[](callCount); 14 | 15 | for (uint i = 0; i < callCount; i++) { 16 | (bool ok, bytes memory result) = address(this).delegatecall(data[i]); 17 | 18 | if (!ok) { 19 | 20 | uint length = result.length; 21 | 22 | // 0 length returned from empty revert() / require(false) 23 | if (length == 0) { 24 | revert RevertedWithoutReason(i); 25 | } 26 | 27 | assembly { 28 | revert(add(result, 0x20), length) 29 | } 30 | } 31 | 32 | results[i] = result; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /contracts/external/Deployer.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | contract Deployer { 6 | 7 | function deploy(bytes memory code, uint256 salt) external { 8 | address deploymentAddress; 9 | assembly { deploymentAddress := create2(0, add(code, 0x20), mload(code), salt) } 10 | require(deploymentAddress != address(0), "Contract creation failed"); 11 | } 12 | 13 | function deployAt(bytes memory code, uint256 salt, address expectedAddress) external { 14 | address deploymentAddress; 15 | assembly { deploymentAddress := create2(0, add(code, 0x20), mload(code), salt) } 16 | require(deploymentAddress != address(0), "Contract creation failed"); 17 | require(deploymentAddress == expectedAddress, "Contract deployed at an unexpected address"); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /contracts/external/enzyme/IAddressRegistryList.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | interface IAddressListRegistry { 6 | function isInList(uint id, address member) external view returns (bool); 7 | } 8 | -------------------------------------------------------------------------------- /contracts/external/enzyme/IEnzymeFundValueCalculatorRouter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | interface IEnzymeFundValueCalculatorRouter { 6 | function calcGrossShareValue(address _vaultProxy) 7 | external 8 | returns (address denominationAsset_, uint256 grossShareValue_); 9 | 10 | function calcNetShareValue(address _vaultProxy) 11 | external 12 | returns (address denominationAsset_, uint256 netShareValue_); 13 | } 14 | 15 | 16 | -------------------------------------------------------------------------------- /contracts/external/enzyme/IEnzymePolicyManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | interface IPolicyManager { 6 | function updatePolicySettingsForFund( 7 | address _comptrollerProxy, 8 | address _policy, 9 | bytes calldata _settingsData 10 | ) external; 11 | } 12 | 13 | 14 | -------------------------------------------------------------------------------- /contracts/external/enzyme/IEnzymeV4Comptroller.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | interface IEnzymeV4Comptroller { 6 | function getDenominationAsset() external view returns (address denominationAsset_); 7 | function redeemSharesForSpecificAssets( 8 | address _recipient, 9 | uint256 _sharesQuantity, 10 | address[] calldata _payoutAssets, 11 | uint256[] calldata _payoutAssetPercentages 12 | ) external returns (uint256[] memory payoutAmounts_); 13 | 14 | function vaultCallOnContract( 15 | address _contract, 16 | bytes4 _selector, 17 | bytes calldata _encodedArgs 18 | ) external; 19 | 20 | function buyShares(uint _investmentAmount, uint _minSharesQuantity) external; 21 | } 22 | -------------------------------------------------------------------------------- /contracts/external/enzyme/IEnzymeV4DepositWrapper.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | interface IEnzymeV4DepositWrapper { 6 | function exchangeEthAndBuyShares( 7 | address comptrollerProxy, 8 | address denominationAsset, 9 | uint256 minSharesQuantity, 10 | address exchange, 11 | address exchangeApproveTarget, 12 | bytes calldata exchangeData, 13 | uint256 minInvestmentAmount) external payable returns (uint256 sharesReceived_); 14 | } 15 | -------------------------------------------------------------------------------- /contracts/external/enzyme/IEnzymeV4Vault.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | interface IEnzymeV4Vault { 6 | function getAccessor() external view returns (address); 7 | 8 | function getOwner() external view returns (address); 9 | 10 | function mintShares(address, uint256) external; 11 | } 12 | -------------------------------------------------------------------------------- /contracts/interfaces/IAssessmentViewer.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | interface IAssessmentViewer { 6 | 7 | struct AssessmentRewards { 8 | uint totalPendingAmountInNXM; 9 | uint withdrawableAmountInNXM; 10 | uint withdrawableUntilIndex; 11 | } 12 | 13 | struct AssessmentStakeLockedState { 14 | bool isStakeLocked; 15 | uint stakeLockupExpiry; 16 | } 17 | 18 | function getRewards(address user) external view returns (AssessmentRewards memory); 19 | 20 | function getStakeLocked(address member) external view returns (AssessmentStakeLockedState memory); 21 | } 22 | -------------------------------------------------------------------------------- /contracts/interfaces/ICompleteStakingPoolFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | import "./IStakingPoolFactory.sol"; 6 | 7 | /** 8 | * @dev IStakingPoolFactory is missing the changeOperator() and operator() functions. 9 | * @dev Any change to the original interface will affect staking pool addresses 10 | * @dev This interface is created to add the missing functions so it can be used in other contracts. 11 | */ 12 | interface ICompleteStakingPoolFactory is IStakingPoolFactory { 13 | 14 | function operator() external view returns (address); 15 | 16 | function changeOperator(address newOperator) external; 17 | } 18 | -------------------------------------------------------------------------------- /contracts/interfaces/ICoverBroker.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | import "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol"; 6 | 7 | import "../interfaces/ICover.sol"; 8 | 9 | interface ICoverBroker { 10 | 11 | /* ==== FUNCTIONS ==== */ 12 | 13 | function buyCover( 14 | BuyCoverParams calldata params, 15 | PoolAllocationRequest[] calldata poolAllocationRequests 16 | ) external payable returns (uint coverId); 17 | 18 | function maxApproveCoverContract(IERC20 token) external; 19 | 20 | function switchMembership(address newAddress) external; 21 | 22 | function rescueFunds(address assetAddress) external; 23 | 24 | /* ==== ERRORS ==== */ 25 | 26 | error TransferFailed(address to, uint value, address token); 27 | error ZeroBalance(address token); 28 | error InvalidOwnerAddress(); 29 | error InvalidPaymentAsset(); 30 | error InvalidPayment(); 31 | } 32 | -------------------------------------------------------------------------------- /contracts/interfaces/ICoverNFT.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | import "@openzeppelin/contracts-v4/token/ERC721/IERC721.sol"; 6 | 7 | interface ICoverNFT is IERC721 { 8 | 9 | function isApprovedOrOwner(address spender, uint tokenId) external returns (bool); 10 | 11 | function mint(address to) external returns (uint tokenId); 12 | 13 | function changeOperator(address newOperator) external; 14 | 15 | function changeNFTDescriptor(address newNFTDescriptor) external; 16 | 17 | function totalSupply() external view returns (uint); 18 | 19 | function name() external view returns (string memory); 20 | 21 | error NotOperator(); 22 | error NotMinted(); 23 | error WrongFrom(); 24 | error InvalidRecipient(); 25 | error InvalidNewOperatorAddress(); 26 | error InvalidNewNFTDescriptorAddress(); 27 | error NotAuthorized(); 28 | error UnsafeRecipient(); 29 | error AlreadyMinted(); 30 | 31 | } 32 | -------------------------------------------------------------------------------- /contracts/interfaces/ICoverNFTDescriptor.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | interface ICoverNFTDescriptor { 6 | 7 | function tokenURI(uint tokenId) external view returns (string memory); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /contracts/interfaces/ICowSettlement.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | import "./IERC20Detailed.sol"; 6 | 7 | interface ICowSettlement { 8 | 9 | struct GPv2TradeData { 10 | uint256 sellTokenIndex; 11 | uint256 buyTokenIndex; 12 | address receiver; 13 | uint256 sellAmount; 14 | uint256 buyAmount; 15 | uint32 validTo; 16 | bytes32 appData; 17 | uint256 feeAmount; 18 | uint256 flags; 19 | uint256 executedAmount; 20 | bytes signature; 21 | } 22 | 23 | struct GPv2InteractionData { 24 | address target; 25 | uint256 value; 26 | bytes callData; 27 | } 28 | 29 | function setPreSignature(bytes calldata orderUid, bool signed) external; 30 | 31 | function invalidateOrder(bytes calldata orderUid) external; 32 | 33 | function filledAmount(bytes calldata orderUid) external view returns (uint256); 34 | 35 | function vaultRelayer() external view returns (address); 36 | 37 | function domainSeparator() external view returns (bytes32); 38 | 39 | function settle( 40 | IERC20Detailed[] calldata tokens, 41 | uint256[] calldata clearingPrices, 42 | GPv2TradeData[] calldata trades, 43 | GPv2InteractionData[][3] calldata interactions 44 | ) external; 45 | 46 | function preSignature(bytes memory) external returns (uint); 47 | } 48 | -------------------------------------------------------------------------------- /contracts/interfaces/IERC20Detailed.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | interface IERC20Detailed { 6 | 7 | function totalSupply() external view returns (uint256); 8 | 9 | function balanceOf(address account) external view returns (uint256); 10 | 11 | function transfer(address recipient, uint256 amount) external returns (bool); 12 | 13 | function allowance(address owner, address spender) external view returns (uint256); 14 | 15 | function approve(address spender, uint256 amount) external returns (bool); 16 | 17 | function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); 18 | 19 | event Transfer(address indexed from, address indexed to, uint256 value); 20 | 21 | event Approval(address indexed owner, address indexed spender, uint256 value); 22 | 23 | function decimals() external view returns (uint8); 24 | 25 | function symbol() external view returns (string memory); 26 | } 27 | -------------------------------------------------------------------------------- /contracts/interfaces/IERC721Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | import "@openzeppelin/contracts-v4/token/ERC721/IERC721.sol"; 6 | 7 | interface IERC721Mock is IERC721 { 8 | 9 | function mint(address to) external; 10 | 11 | function isApprovedOrOwner(address spender, uint tokenId) external returns (bool); 12 | } 13 | -------------------------------------------------------------------------------- /contracts/interfaces/IFailedStakingPool.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | import "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol"; 6 | 7 | interface IFailedStakingPool is IERC20 { 8 | 9 | struct AllocateCapacityParams { 10 | uint productId; 11 | uint coverAmount; 12 | uint rewardsDenominator; 13 | uint period; 14 | uint globalCapacityRatio; 15 | uint globalRewardsRatio; 16 | uint capacityReductionRatio; 17 | uint initialPrice; 18 | } 19 | 20 | function initialize(address _manager, uint _poolId) external; 21 | 22 | function operatorTransferFrom(address from, address to, uint256 amount) external; 23 | 24 | function allocateCapacity(AllocateCapacityParams calldata params) external returns (uint, uint); 25 | 26 | function freeCapacity( 27 | uint productId, 28 | uint previousPeriod, 29 | uint previousStartTime, 30 | uint previousRewardAmount, 31 | uint periodReduction, 32 | uint coveredAmount 33 | ) external; 34 | 35 | function getAvailableCapacity(uint productId, uint capacityFactor) external view returns (uint); 36 | function getCapacity(uint productId, uint capacityFactor) external view returns (uint); 37 | function getUsedCapacity(uint productId) external view returns (uint); 38 | function getTargetPrice(uint productId) external view returns (uint); 39 | function getStake(uint productId) external view returns (uint); 40 | function manager() external view returns (address); 41 | } 42 | -------------------------------------------------------------------------------- /contracts/interfaces/ILegacyClaims.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | interface ILegacyClaims { 6 | 7 | function setClaimStatus(uint claimId, uint stat) external; 8 | 9 | function getCATokens(uint claimId, uint member) external view returns (uint tokens); 10 | 11 | function submitClaimAfterEPOff() external pure; 12 | 13 | function submitCAVote(uint claimId, int8 verdict) external; 14 | 15 | function submitMemberVote(uint claimId, int8 verdict) external; 16 | 17 | function pauseAllPendingClaimsVoting() external pure; 18 | 19 | function startAllPendingClaimsVoting() external pure; 20 | 21 | function checkVoteClosing(uint claimId) external view returns (int8 close); 22 | } 23 | -------------------------------------------------------------------------------- /contracts/interfaces/ILegacyClaimsReward.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | interface ILegacyClaimsReward { 6 | 7 | /// @dev Decides the next course of action for a given claim. 8 | function changeClaimStatus(uint claimid) external; 9 | 10 | function transferRewards() external; 11 | 12 | function getCurrencyAssetAddress(bytes4 currency) external view returns (address); 13 | 14 | function upgrade(address _newAdd) external; 15 | } 16 | -------------------------------------------------------------------------------- /contracts/interfaces/ILegacyCover.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | import "./ICoverProducts.sol"; 6 | 7 | interface ILegacyCover { 8 | 9 | function stakingPoolFactory() external view returns (address); 10 | 11 | function getProducts() external view returns (Product[] memory); 12 | 13 | function productTypesCount() external view returns (uint); 14 | 15 | function productNames(uint productId) external view returns (string memory); 16 | 17 | function allowedPools(uint productId, uint index) external view returns (uint); 18 | 19 | function productTypes(uint id) external view returns (ProductType memory); 20 | 21 | function productTypeNames(uint id) external view returns (string memory); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /contracts/interfaces/ILegacyIncidents.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | interface ILegacyIncidents { 6 | 7 | function underlyingToken(address) external view returns (address); 8 | 9 | function coveredToken(address) external view returns (address); 10 | 11 | function claimPayout(uint) external view returns (uint); 12 | 13 | function incidentCount() external view returns (uint); 14 | 15 | function addIncident( 16 | address productId, 17 | uint incidentDate, 18 | uint priceBefore 19 | ) external; 20 | 21 | function redeemPayoutForMember( 22 | uint coverId, 23 | uint incidentId, 24 | uint coveredTokenAmount, 25 | address member 26 | ) external returns (uint claimId, uint payoutAmount, address payoutToken); 27 | 28 | function redeemPayout( 29 | uint coverId, 30 | uint incidentId, 31 | uint coveredTokenAmount 32 | ) external returns (uint claimId, uint payoutAmount, address payoutToken); 33 | 34 | function pushBurns(address productId, uint maxIterations) external; 35 | 36 | function withdrawAsset(address asset, address destination, uint amount) external; 37 | } 38 | -------------------------------------------------------------------------------- /contracts/interfaces/IMCR.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | interface IMCR { 6 | 7 | function updateMCRInternal(bool forceUpdate) external; 8 | 9 | function getMCR() external view returns (uint); 10 | 11 | function mcr() external view returns (uint80); 12 | 13 | function desiredMCR() external view returns (uint80); 14 | 15 | function lastUpdateTime() external view returns (uint32); 16 | 17 | function maxMCRIncrement() external view returns (uint16); 18 | 19 | function gearingFactor() external view returns (uint24); 20 | 21 | function minUpdateTime() external view returns (uint16); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /contracts/interfaces/IMasterAware.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | interface IMasterAware { 6 | 7 | function changeMasterAddress(address masterAddress) external; 8 | 9 | function changeDependentContractAddress() external; 10 | 11 | } 12 | -------------------------------------------------------------------------------- /contracts/interfaces/IMasterAwareV2.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | interface IMasterAwareV2 { 6 | 7 | // TODO: if you update this enum, update lib/constants.js as well 8 | enum ID { 9 | TC, // TokenController.sol 10 | P1, // Pool.sol 11 | MR, // MemberRoles.sol 12 | MC, // MCR.sol 13 | CO, // Cover.sol 14 | SP, // StakingProducts.sol 15 | UNUSED_PS, // LegacyPooledStaking.sol - removed 16 | GV, // Governance.sol 17 | UNUSED_GW, // LegacyGateway.sol - removed 18 | UNUSED_CL, // CoverMigrator.sol - removed 19 | AS, // Assessment.sol 20 | CI, // IndividualClaims.sol - Claims for Individuals 21 | UNUSED_CG, // YieldTokenIncidents.sol - Claims for Groups -- removed 22 | RA, // Ramm.sol 23 | ST, // SafeTracker.sol 24 | CP, // CoverProducts.sol 25 | LO // CoverOrders.sol - Limit Orders 26 | } 27 | 28 | function changeMasterAddress(address masterAddress) external; 29 | 30 | function changeDependentContractAddress() external; 31 | 32 | function internalContracts(uint) external view returns (address payable); 33 | } 34 | -------------------------------------------------------------------------------- /contracts/interfaces/IMemberRolesErrors.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | /// @dev this interface is needed because IMemberRoles interface is imported in contracts that must be compiled with 6 | /// lower solidity version, which does not support custom errors 7 | interface IMemberRolesErrors { 8 | error NotAuthorized(); 9 | error UserAddressCantBeZero(); 10 | error Paused(); 11 | error AddressIsAlreadyMember(); 12 | error TransactionValueDifferentFromJoiningFee(); 13 | error SignatureAlreadyUsed(); 14 | error InvalidSignature(); 15 | error TransferToPoolFailed(); 16 | error OnlyMember(); 17 | error LockedForVoting(); 18 | error CantBeStakingPoolManager(); 19 | error HasNXMStakedInClaimAssessmentV1(); 20 | error MemberHasPendingRewardsInTokenController(); 21 | error MemberHasAssessmentStake(); 22 | error NewAddressIsAlreadyMember(); 23 | error MemberAlreadyHasRole(); 24 | error MemberDoesntHaveRole(); 25 | } 26 | -------------------------------------------------------------------------------- /contracts/interfaces/INXMMaster.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | interface INXMMaster { 6 | 7 | function tokenAddress() external view returns (address); 8 | 9 | function owner() external view returns (address); 10 | 11 | function emergencyAdmin() external view returns (address); 12 | 13 | function masterInitialized() external view returns (bool); 14 | 15 | function isInternal(address _add) external view returns (bool); 16 | 17 | function isPause() external view returns (bool check); 18 | 19 | function isMember(address _add) external view returns (bool); 20 | 21 | function checkIsAuthToGoverned(address _add) external view returns (bool); 22 | 23 | function getLatestAddress(bytes2 _contractName) external view returns (address payable contractAddress); 24 | 25 | function contractAddresses(bytes2 code) external view returns (address payable); 26 | 27 | function upgradeMultipleContracts( 28 | bytes2[] calldata _contractCodes, 29 | address payable[] calldata newAddresses 30 | ) external; 31 | 32 | function removeContracts(bytes2[] calldata contractCodesToRemove) external; 33 | 34 | function addNewInternalContracts( 35 | bytes2[] calldata _contractCodes, 36 | address payable[] calldata newAddresses, 37 | uint[] calldata _types 38 | ) external; 39 | 40 | function updateOwnerParameters(bytes8 code, address payable val) external; 41 | } 42 | -------------------------------------------------------------------------------- /contracts/interfaces/INexusViewer.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import {IAssessmentViewer} from "./IAssessmentViewer.sol"; 6 | import {IStakingViewer} from "./IStakingViewer.sol"; 7 | 8 | interface INexusViewer { 9 | 10 | struct ClaimableNXM { 11 | uint governanceRewards; // Governance rewards in NXM 12 | uint assessmentRewards; // Claimable assessment reward in NXM 13 | uint assessmentStake; // Claimable assessment stake in NXM 14 | uint stakingPoolTotalRewards; // Total staking pool rewards in NXM 15 | uint stakingPoolTotalExpiredStake; // Total staking pool expired stake in NXM 16 | uint managerTotalRewards; // Pool manager total staking rewards in NXM 17 | uint legacyClaimAssessmentTokens; // Legacy claim assessment tokens in NXM 18 | } 19 | 20 | struct StakedNXM { 21 | uint stakingPoolTotalActiveStake; // Total amount of active stake in staking pools in NXM 22 | uint assessmentStake; // Locked assessment stake in NXM 23 | uint assessmentStakeLockupExpiry; // Locked stake expiry timestamp 24 | uint assessmentRewards; // Locked assessment rewards in NXM 25 | } 26 | 27 | function getClaimableNXM(address member, uint[] calldata tokenIds) external view returns (ClaimableNXM memory); 28 | 29 | function getStakedNXM(address member, uint[] calldata tokenIds) external view returns (StakedNXM memory); 30 | } 31 | -------------------------------------------------------------------------------- /contracts/interfaces/IPriceFeedOracle.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | interface Aggregator { 6 | function decimals() external view returns (uint8); 7 | function latestAnswer() external view returns (int); 8 | } 9 | 10 | interface IPriceFeedOracle { 11 | 12 | enum AggregatorType { ETH, USD } 13 | 14 | struct AssetInfo { 15 | Aggregator aggregator; 16 | AggregatorType aggregatorType; 17 | uint8 decimals; 18 | } 19 | 20 | function ETH() external view returns (address); 21 | function assets(address) external view returns (Aggregator, uint8); 22 | function assetsMap(address) external view returns (Aggregator, AggregatorType, uint8); 23 | 24 | function getAssetToEthRate(address asset) external view returns (uint); 25 | function getAssetForEth(address asset, uint ethIn) external view returns (uint); 26 | function getEthForAsset(address asset, uint amount) external view returns (uint); 27 | 28 | /* ========== ERRORS ========== */ 29 | 30 | error EmptyAssetAddresses(); 31 | error ArgumentLengthMismatch(uint assetAddressesLength, uint aggregatorsLength, uint typesLength, uint decimalsLength); 32 | error ZeroAddress(string parameter); 33 | error ZeroDecimals(address asset); 34 | error IncompatibleAggregatorDecimals(address aggregator, uint8 aggregatorDecimals, uint8 expectedDecimals); 35 | error UnknownAggregatorType(uint8 aggregatorType); 36 | error EthUsdAggregatorNotSet(); 37 | error InvalidEthAggregatorType(AggregatorType actual, AggregatorType expected); 38 | error UnknownAsset(address asset); 39 | error NonPositiveRate(address aggregator, int rate); 40 | } 41 | -------------------------------------------------------------------------------- /contracts/interfaces/IQuotation.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | interface IQuotation { 6 | function verifyCoverDetails( 7 | address payable from, 8 | address scAddress, 9 | bytes4 coverCurr, 10 | uint[] calldata coverDetails, 11 | uint16 coverPeriod, 12 | uint8 _v, 13 | bytes32 _r, 14 | bytes32 _s 15 | ) external; 16 | 17 | function createCover( 18 | address payable from, 19 | address scAddress, 20 | bytes4 currency, 21 | uint[] calldata coverDetails, 22 | uint16 coverPeriod, 23 | uint8 _v, 24 | bytes32 _r, 25 | bytes32 _s 26 | ) external; 27 | } 28 | -------------------------------------------------------------------------------- /contracts/interfaces/ISafeTracker.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | import "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol"; 6 | 7 | interface ISafeTracker is IERC20 { 8 | 9 | function symbol() external view returns (string memory); 10 | 11 | function decimals() external view returns (uint8); 12 | 13 | function safe() external view returns (address); 14 | 15 | event CoverReInvestmentUSDCUpdated(uint investedUSDC); 16 | 17 | error OnlySafe(); 18 | error InvestmentSurpassesLimit(); 19 | } 20 | -------------------------------------------------------------------------------- /contracts/interfaces/IStakingNFT.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | import "@openzeppelin/contracts-v4/token/ERC721/IERC721.sol"; 6 | 7 | interface IStakingNFT is IERC721 { 8 | 9 | function isApprovedOrOwner(address spender, uint tokenId) external returns (bool); 10 | 11 | function mint(uint poolId, address to) external returns (uint tokenId); 12 | 13 | function changeOperator(address newOperator) external; 14 | 15 | function changeNFTDescriptor(address newNFTDescriptor) external; 16 | 17 | function totalSupply() external returns (uint); 18 | 19 | function tokenInfo(uint tokenId) external view returns (uint poolId, address owner); 20 | 21 | function stakingPoolOf(uint tokenId) external view returns (uint poolId); 22 | 23 | function stakingPoolFactory() external view returns (address); 24 | 25 | function name() external view returns (string memory); 26 | 27 | error NotOperator(); 28 | error NotMinted(); 29 | error WrongFrom(); 30 | error InvalidRecipient(); 31 | error InvalidNewOperatorAddress(); 32 | error InvalidNewNFTDescriptorAddress(); 33 | error NotAuthorized(); 34 | error UnsafeRecipient(); 35 | error AlreadyMinted(); 36 | error NotStakingPool(); 37 | 38 | } 39 | -------------------------------------------------------------------------------- /contracts/interfaces/IStakingNFTDescriptor.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | interface IStakingNFTDescriptor { 6 | 7 | struct StakeData { 8 | uint poolId; 9 | uint stakeAmount; 10 | uint tokenId; 11 | } 12 | 13 | function tokenURI(uint tokenId) external view returns (string memory); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /contracts/interfaces/IStakingPoolBeacon.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | /** 6 | * @dev This is the interface that {BeaconProxy} expects of its beacon. 7 | */ 8 | interface IStakingPoolBeacon { 9 | /** 10 | * @dev Must return an address that can be used as a delegate call target. 11 | * 12 | * {BeaconProxy} will check that this address is a contract. 13 | */ 14 | function stakingPoolImplementation() external view returns (address); 15 | } 16 | -------------------------------------------------------------------------------- /contracts/interfaces/IStakingPoolFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | interface IStakingPoolFactory { 6 | 7 | function stakingPoolCount() external view returns (uint); 8 | 9 | function beacon() external view returns (address); 10 | 11 | function create(address beacon) external returns (uint poolId, address stakingPoolAddress); 12 | 13 | event StakingPoolCreated(uint indexed poolId, address indexed stakingPoolAddress); 14 | } 15 | -------------------------------------------------------------------------------- /contracts/interfaces/ITokenControllerErrors.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | /// @dev this interface is needed because ITokenController interface is imported in contracts that must be compiled with 6 | /// lower solidity version, which does not support custom errors 7 | interface ITokenControllerErrors { 8 | error CantMintToNonMemberAddress(); 9 | error NoWithdrawableGovernanceRewards(); 10 | error OnlyStakingPoolManager(); 11 | error DeadlinePassed(); 12 | error ManagerIsLockedForVoting(); 13 | error OnlyProposedManager(); 14 | error OwnershipOfferHasExpired(); 15 | error OnlyStakingPool(); 16 | } 17 | -------------------------------------------------------------------------------- /contracts/interfaces/ITokenData.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | interface ITokenData { 6 | 7 | function walletAddress() external view returns (address payable); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /contracts/interfaces/IWeth.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | interface IWeth { 6 | function deposit() external payable; 7 | 8 | function withdraw(uint256 wad) external; 9 | 10 | function approve(address spender, uint256 value) external; 11 | 12 | function balanceOf(address account) external view returns (uint256); 13 | 14 | function transfer(address recipient, uint256 amount) external returns (bool); 15 | 16 | function transferFrom(address sender, address recipient, uint amount) external returns (bool); 17 | } 18 | -------------------------------------------------------------------------------- /contracts/libraries/Math.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | /** 6 | * @dev Simple library that defines min, max and babylonian sqrt functions 7 | */ 8 | library Math { 9 | 10 | function min(uint a, uint b) internal pure returns (uint) { 11 | return a < b ? a : b; 12 | } 13 | 14 | function max(uint a, uint b) internal pure returns (uint) { 15 | return a > b ? a : b; 16 | } 17 | 18 | function sum(uint[] memory items) internal pure returns (uint) { 19 | uint count = items.length; 20 | uint total; 21 | 22 | for (uint i = 0; i < count; i++) { 23 | total += items[i]; 24 | } 25 | 26 | return total; 27 | } 28 | 29 | function divRound(uint a, uint b) internal pure returns (uint) { 30 | return (a + b / 2) / b; 31 | } 32 | 33 | function divCeil(uint a, uint b) internal pure returns (uint) { 34 | return (a + b - 1) / b; 35 | } 36 | 37 | function roundUp(uint a, uint b) internal pure returns (uint) { 38 | return divCeil(a, b) * b; 39 | } 40 | 41 | // babylonian method 42 | function sqrt(uint y) internal pure returns (uint) { 43 | 44 | if (y > 3) { 45 | uint z = y; 46 | uint x = y / 2 + 1; 47 | while (x < z) { 48 | z = x; 49 | x = (y / x + x) / 2; 50 | } 51 | return z; 52 | } 53 | 54 | if (y != 0) { 55 | return 1; 56 | } 57 | 58 | return 0; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /contracts/libraries/StakingPoolLibrary.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | /** 6 | * @dev Simple library to derive the staking pool address from the pool id without external calls 7 | */ 8 | library StakingPoolLibrary { 9 | 10 | function getAddress(address factory, uint poolId) internal pure returns (address) { 11 | 12 | bytes32 hash = keccak256( 13 | abi.encodePacked( 14 | hex'ff', 15 | factory, 16 | poolId, // salt 17 | // init code hash of the MinimalBeaconProxy 18 | // updated using patch-staking-pool-library.js script 19 | hex'1eb804b66941a2e8465fa0951be9c8b855b7794ee05b0789ab22a02ee1298ebe' // init code hash 20 | ) 21 | ); 22 | 23 | // cast last 20 bytes of hash to address 24 | return address(uint160(uint(hash))); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /contracts/libraries/UncheckedMath.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | /** 6 | * @dev Simple library that defines basic math functions that allow overflow 7 | */ 8 | library UncheckedMath { 9 | 10 | function uncheckedAdd(uint a, uint b) internal pure returns (uint) { 11 | unchecked { return a + b; } 12 | } 13 | 14 | function uncheckedSub(uint a, uint b) internal pure returns (uint) { 15 | unchecked { return a - b; } 16 | } 17 | 18 | function uncheckedMul(uint a, uint b) internal pure returns (uint) { 19 | unchecked { return a * b; } 20 | } 21 | 22 | function uncheckedDiv(uint a, uint b) internal pure returns (uint) { 23 | unchecked { return a / b; } 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /contracts/mocks/SafeTracker/STMockPool.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../common/PoolMock.sol"; 6 | import "../../interfaces/IPriceFeedOracle.sol"; 7 | 8 | contract STMockPool is PoolMock { 9 | 10 | IPriceFeedOracle public override priceFeedOracle; 11 | 12 | constructor(address _priceFeedOracle, address _swapOperator) { 13 | priceFeedOracle = IPriceFeedOracle(_priceFeedOracle); 14 | swapOperator = _swapOperator; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /contracts/mocks/SafeTracker/STMockSwapOperator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../generic/SwapOperatorGeneric.sol"; 6 | 7 | contract STMockSwapOperator is SwapOperatorGeneric { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /contracts/mocks/common/ChainlinkAggregatorMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | contract ChainlinkAggregatorMock { 6 | 7 | uint public latestAnswer; 8 | uint public decimals = 18; 9 | 10 | function setDecimals(uint _decimals) public { 11 | decimals = _decimals; 12 | } 13 | 14 | function setLatestAnswer(uint _latestAnswer) public { 15 | latestAnswer = _latestAnswer; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /contracts/mocks/common/ERC20Detailed.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "../../interfaces/IERC20.sol"; 4 | 5 | /** 6 | * @dev Optional functions from the ERC20 standard. 7 | */ 8 | contract ERC20Detailed is IERC20 { 9 | string private _name; 10 | string private _symbol; 11 | uint8 private _decimals; 12 | 13 | /** 14 | * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of 15 | * these values are immutable: they can only be set once during 16 | * construction. 17 | */ 18 | constructor (string memory name, string memory symbol, uint8 decimals) public { 19 | _name = name; 20 | _symbol = symbol; 21 | _decimals = decimals; 22 | } 23 | 24 | /** 25 | * @dev Returns the name of the token. 26 | */ 27 | function name() public view returns (string memory) { 28 | return _name; 29 | } 30 | 31 | /** 32 | * @dev Returns the symbol of the token, usually a shorter version of the 33 | * name. 34 | */ 35 | function symbol() public view returns (string memory) { 36 | return _symbol; 37 | } 38 | 39 | /** 40 | * @dev Returns the number of decimals used to get its user representation. 41 | * For example, if `decimals` equals `2`, a balance of `505` tokens should 42 | * be displayed to a user as `5,05` (`505 / 10 ** 2`). 43 | * 44 | * Tokens usually opt for a value of 18, imitating the relationship between 45 | * Ether and Wei. 46 | * 47 | * NOTE: This information is only used for _display_ purposes: it in 48 | * no way affects any of the arithmetic of the contract, including 49 | * {IERC20-balanceOf} and {IERC20-transfer}. 50 | */ 51 | function decimals() public view returns (uint8) { 52 | return _decimals; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /contracts/mocks/common/ERC20Mintable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "../../modules/token/external/ERC20.sol"; 4 | 5 | /** 6 | * @dev Extension of {ERC20} that adds a set of accounts with the {MinterRole}, 7 | * which have permission to mint (create) new tokens as they see fit. 8 | * 9 | * At construction, the deployer of the contract is the only minter. 10 | */ 11 | contract ERC20Mintable is ERC20 { 12 | /** 13 | * @dev See {ERC20-_mint}. 14 | * 15 | * Requirements: 16 | * 17 | * - the caller must have the {MinterRole}. 18 | */ 19 | function mint(address account, uint256 amount) public returns (bool) { 20 | _mint(account, amount); 21 | return true; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /contracts/mocks/common/EtherRejecterMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | contract EtherRejecterMock { 6 | 7 | receive() external payable { 8 | revert("I secretly hate ether"); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /contracts/mocks/common/MemberRolesMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../interfaces/IMemberRoles.sol"; 6 | 7 | contract MemberRolesMock { 8 | 9 | enum Role { Unassigned, AdvisoryBoard, Member, Owner } 10 | 11 | mapping(address => Role) roles; 12 | 13 | function memberAtIndex(uint, uint) external pure returns (address, bool) { 14 | revert("Unexpected MemberRolesMock call"); 15 | } 16 | 17 | function membersLength(uint) external pure returns (uint) { 18 | return 0; 19 | } 20 | 21 | function checkRole(address memberAddress, uint roleId) external view returns (bool) { 22 | return uint(roles[memberAddress]) == roleId; 23 | } 24 | 25 | function setRole(address memberAddress, uint roleId) public { 26 | roles[memberAddress] = Role(uint8(roleId)); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /contracts/mocks/common/PoolEtherRejecterMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "./PoolMock.sol"; 6 | 7 | contract PoolEtherRejecterMock is PoolMock { 8 | 9 | receive() external payable override { 10 | revert("I secretly hate ether"); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /contracts/mocks/common/PriceFeedOracleMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../interfaces/IPriceFeedOracle.sol"; 6 | 7 | contract PriceFeedOracleMock is IPriceFeedOracle { 8 | 9 | address public constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; 10 | mapping(address => AssetInfo) public assetsMap; 11 | 12 | uint public ethRate; 13 | 14 | constructor(uint _ethRate) { 15 | ethRate = _ethRate; 16 | } 17 | 18 | function getAssetToEthRate(address) public view returns (uint) { 19 | return ethRate; 20 | } 21 | 22 | function getAssetForEth(address, uint ethIn) external view returns (uint) { 23 | return ethIn * ethRate; 24 | } 25 | 26 | function getEthForAsset(address, uint amount) external view returns (uint) { 27 | return amount / ethRate; 28 | } 29 | 30 | function assets(address assetAddress) external view returns (Aggregator, uint8) { 31 | AssetInfo memory asset = assetsMap[assetAddress]; 32 | return (asset.aggregator, asset.decimals); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /contracts/mocks/common/ProxySignatureCollider.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | contract ProxySignatureCollider { 6 | 7 | function upgradeTo(address) external pure { 8 | // noop 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /contracts/mocks/common/RammMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../interfaces/IRamm.sol"; 6 | 7 | contract RammMock is IRamm { 8 | 9 | event TwapUpdateTriggered(); 10 | 11 | function updateTwap() external override { 12 | emit TwapUpdateTriggered(); 13 | } 14 | 15 | function getInternalPriceAndUpdateTwap() external override pure returns (uint) { 16 | return 1e18; 17 | } 18 | 19 | function getInternalPrice() external override pure returns (uint) { 20 | return 1e18; 21 | } 22 | 23 | function getSpotPrices() external override pure returns (uint, uint) { 24 | return (2e18, 1e18); 25 | } 26 | 27 | /* ====== NOT NEEDED FUNCTIONS ====== */ 28 | 29 | function getReserves() public pure returns (uint, uint, uint, uint){ 30 | revert("Unsupported"); 31 | } 32 | 33 | function getBookValue() external override pure returns (uint) { 34 | revert("Unsupported"); 35 | } 36 | 37 | function swap(uint, uint, uint) external payable returns (uint) { 38 | revert("Unsupported"); 39 | } 40 | 41 | function removeBudget() external pure { 42 | revert("Unsupported"); 43 | } 44 | 45 | function setEmergencySwapPause(bool) external pure { 46 | revert("Unsupported"); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /contracts/mocks/common/ReentrancyExploiter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | contract ReentrancyExploiter { 6 | 7 | // re-entrancy attack params 8 | address public target; 9 | uint public value; 10 | bytes public data; 11 | 12 | bool public hasReentered = false; 13 | 14 | /** 15 | * @notice Sets the reentrancy attack params 16 | * @dev Call this separately if re-entracy attack entry point is different from the initial call 17 | */ 18 | function setReentrancyParams(address _target, uint _value, bytes memory _data) public { 19 | target = _target; 20 | value = _value; 21 | data = _data; 22 | } 23 | 24 | /** 25 | * @notice Executes the reentrancy exploit 26 | */ 27 | function execute(address _target, uint _value, bytes memory _data) public { 28 | 29 | // if re-entrancy attack params are not set, use the same params as the initial call 30 | if (address(target) == address(0) && value == 0 && data.length == 0) { 31 | setReentrancyParams(_target, _value, _data); 32 | } 33 | 34 | (bool ok, bytes memory returndata) = _target.call{value: _value}(_data); 35 | 36 | if (!ok) { 37 | // pass revert reason 38 | if (returndata.length > 0) { 39 | assembly { 40 | let returndata_size := mload(returndata) 41 | revert(add(32, returndata), returndata_size) 42 | } 43 | } 44 | 45 | revert("Low-level call failed"); 46 | } 47 | } 48 | 49 | receive() external payable { 50 | if (!hasReentered) { 51 | hasReentered = true; 52 | execute(target, value, data); 53 | hasReentered = false; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /contracts/mocks/common/Stub.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | contract Stub { 6 | // stub contract 7 | } 8 | -------------------------------------------------------------------------------- /contracts/mocks/disposables/DisposableGovernance.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.5.17; 4 | 5 | import "../../modules/governance/Governance.sol"; 6 | 7 | contract DisposableGovernance is Governance { 8 | 9 | /* disposable initialization function */ 10 | 11 | // mainnet param values added in comments 12 | function initialize( 13 | uint _tokenHoldingTime, // 3 days 14 | uint _maxDraftTime, // 14 days 15 | uint _maxVoteWeigthPer, // 5 16 | uint _maxFollowers, // 40 17 | uint _specialResolutionMajPerc, // 75 18 | uint _actionWaitingTime // 1 day 19 | ) external { 20 | 21 | require(!constructorCheck); 22 | constructorCheck = true; 23 | 24 | totalProposals = 1; 25 | allVotes.push(ProposalVote(address(0), 0, 0)); 26 | allDelegation.push(DelegateVote(address(0), address(0), now)); 27 | roleIdAllowedToCatgorize = uint(IMemberRoles.Role.AdvisoryBoard); 28 | 29 | tokenHoldingTime = _tokenHoldingTime; 30 | maxDraftTime = _maxDraftTime; 31 | maxVoteWeigthPer = _maxVoteWeigthPer; 32 | maxFollowers = _maxFollowers; 33 | specialResolutionMajPerc = _specialResolutionMajPerc; 34 | actionWaitingTime = _actionWaitingTime; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /contracts/mocks/disposables/DisposableRamm.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../modules/capital/Ramm.sol"; 6 | 7 | contract DisposableRamm is Ramm { 8 | 9 | uint internal poolValue; 10 | uint internal supply; 11 | uint internal bondingCurveTokenPrice; 12 | 13 | constructor(uint spotPriceB) Ramm(spotPriceB) { 14 | // 15 | } 16 | 17 | function initialize( 18 | uint _poolValue, 19 | uint _totalSupply, 20 | uint _bondingCurveTokenPrice 21 | ) external { 22 | 23 | require(slot1.updatedAt == 0, "DisposableRamm: Already initialized"); 24 | 25 | // initialize values 26 | poolValue = _poolValue; 27 | supply = _totalSupply; 28 | bondingCurveTokenPrice = _bondingCurveTokenPrice; 29 | 30 | // set dependencies to point to self 31 | internalContracts[uint(ID.P1)] = payable(address(this)); 32 | internalContracts[uint(ID.TC)] = payable(address(this)); 33 | internalContracts[uint(ID.MC)] = payable(address(this)); 34 | 35 | super.initialize(); 36 | 37 | slot1.swapPaused = false; 38 | } 39 | 40 | // fake pool functions 41 | function getPoolValueInEth() external view returns (uint) { 42 | return poolValue; 43 | } 44 | 45 | function totalSupply() external view returns (uint) { 46 | return supply; 47 | } 48 | 49 | function getTokenPrice() external view returns (uint) { 50 | return bondingCurveTokenPrice; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /contracts/mocks/generic/CoverNFTDescriptorGeneric.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | import "../../interfaces/ICoverNFTDescriptor.sol"; 6 | 7 | contract CoverNFTDescriptorGeneric is ICoverNFTDescriptor { 8 | 9 | function tokenURI(uint) external pure returns (string memory) { 10 | revert("Unsupported"); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /contracts/mocks/generic/IndividualClaimsGeneric.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../interfaces/IIndividualClaims.sol"; 6 | 7 | contract IndividualClaimsGeneric is IIndividualClaims { 8 | Claim[] public claims; 9 | 10 | function getClaimsCount() external pure returns (uint) { 11 | revert("Unsupported"); 12 | } 13 | 14 | function getPayoutRedemptionPeriod() external pure override virtual returns (uint) { 15 | revert("Unsupported"); 16 | } 17 | 18 | function getMinAssessmentDepositRatio() external pure override virtual returns (uint) { 19 | revert("Unsupported"); 20 | } 21 | 22 | function getMaxRewardInNxm() external pure override virtual returns (uint) { 23 | revert("Unsupported"); 24 | } 25 | 26 | function getRewardRatio() external pure override virtual returns (uint) { 27 | revert("Unsupported"); 28 | } 29 | 30 | function submitClaim(uint32, uint96, string calldata) external payable virtual returns (Claim memory) { 31 | revert("Unsupported"); 32 | } 33 | 34 | function redeemClaimPayout(uint104) external pure { 35 | revert("Unsupported"); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /contracts/mocks/generic/MCRGeneric.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../interfaces/IMCR.sol"; 6 | 7 | contract MCRGeneric is IMCR { 8 | function setPool(address) public virtual { 9 | revert("Unsupported"); 10 | } 11 | 12 | function getMCR() external virtual view returns (uint) { 13 | revert("Unsupported"); 14 | } 15 | 16 | function updateMCR(uint) public virtual { 17 | revert("Unsupported"); 18 | } 19 | 20 | function updateMCRInternal(bool) public virtual { 21 | revert("Unsupported"); 22 | } 23 | 24 | function mcr() external virtual view returns (uint80) { 25 | revert("Unsupported"); 26 | } 27 | 28 | function desiredMCR() external virtual pure returns (uint80) { 29 | revert("Unsupported"); 30 | } 31 | 32 | function lastUpdateTime() external virtual pure returns (uint32) { 33 | revert("Unsupported"); 34 | } 35 | 36 | function gearingFactor() external pure returns (uint24) { 37 | revert("Unsupported"); 38 | } 39 | 40 | function maxMCRIncrement() external pure returns (uint16) { 41 | revert("Unsupported"); 42 | } 43 | 44 | function minUpdateTime() external pure returns (uint16) { 45 | revert("Unsupported"); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /contracts/mocks/generic/PriceFeedOracleGeneric.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | import "../../interfaces/IPriceFeedOracle.sol"; 6 | 7 | contract PriceFeedOracleGeneric is IPriceFeedOracle { 8 | 9 | function ETH() external virtual view returns (address) { 10 | revert("Unsupported"); 11 | } 12 | 13 | function assets(address) external virtual view returns (Aggregator, uint8) { 14 | revert("Unsupported"); 15 | } 16 | 17 | function assetsMap(address) external virtual view returns (Aggregator, AggregatorType, uint8) { 18 | revert("Unsupported"); 19 | } 20 | 21 | function getAssetToEthRate(address) external virtual view returns (uint) { 22 | revert("Unsupported"); 23 | } 24 | 25 | function getAssetForEth(address, uint) external virtual view returns (uint) { 26 | revert("Unsupported"); 27 | } 28 | 29 | function getEthForAsset(address, uint) external virtual view returns (uint) { 30 | revert("Unsupported"); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /contracts/mocks/generic/RammGeneric.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../interfaces/IRamm.sol"; 6 | 7 | contract RammGeneric is IRamm { 8 | function updateTwap() external override pure { 9 | revert("Unsupported"); 10 | } 11 | 12 | function getInternalPriceAndUpdateTwap() external override pure returns (uint) { 13 | revert("Unsupported"); 14 | } 15 | 16 | function getInternalPrice() external override pure returns (uint) { 17 | revert("Unsupported"); 18 | } 19 | 20 | function getSpotPrices() external override pure returns (uint, uint) { 21 | revert("Unsupported"); 22 | } 23 | 24 | function getReserves() public pure returns (uint, uint, uint, uint){ 25 | revert("Unsupported"); 26 | } 27 | 28 | function getBookValue() external override pure returns (uint) { 29 | revert("Unsupported"); 30 | } 31 | 32 | function swap(uint, uint, uint) external payable returns (uint) { 33 | revert("Unsupported"); 34 | } 35 | 36 | function removeBudget() external pure { 37 | revert("Unsupported"); 38 | } 39 | 40 | function setEmergencySwapPause(bool) external pure { 41 | revert("Unsupported"); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /contracts/mocks/generic/StakingNFTDescriptorGeneric.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | import "../../interfaces/IStakingNFTDescriptor.sol"; 6 | 7 | contract StakingNFTDescriptorGeneric is IStakingNFTDescriptor { 8 | 9 | function tokenURI(uint) external pure returns (string memory) { 10 | revert("Unsupported"); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /contracts/mocks/generic/StakingPoolFactoryGeneric.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | import "../../interfaces/IStakingPoolFactory.sol"; 6 | 7 | contract StakingPoolFactoryGeneric is IStakingPoolFactory { 8 | 9 | function stakingPoolCount() external virtual view returns (uint) { 10 | revert("Unsupported"); 11 | } 12 | 13 | function beacon() external virtual view returns (address) { 14 | revert("Unsupported"); 15 | } 16 | 17 | function create(address) external virtual returns (uint, address) { 18 | revert("Unsupported"); 19 | } 20 | 21 | function setStakingPoolCount(uint) public virtual { 22 | revert("Unsupported"); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /contracts/mocks/modules/Assessment/ASMockIndividualClaims.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../../interfaces/INXMToken.sol"; 6 | import "../../../interfaces/IIndividualClaims.sol"; 7 | import "../../../interfaces/IAssessment.sol"; 8 | import "../../../abstract/MasterAwareV2.sol"; 9 | import "../../generic/IndividualClaimsGeneric.sol"; 10 | 11 | contract ASMockIndividualClaims is MasterAwareV2, IndividualClaimsGeneric { 12 | 13 | uint constant public MIN_ASSESSMENT_DEPOSIT_RATIO = 500; // bps 14 | uint constant public MIN_ASSESSMENT_DEPOSIT_DENOMINATOR = 10000; 15 | 16 | uint constant public REWARD_RATIO = 130; // bps 17 | uint constant public REWARD_DENOMINATOR = 10000; 18 | 19 | function assessment() internal view returns (IAssessment) { 20 | return IAssessment(getInternalContractAddress(ID.AS)); 21 | } 22 | 23 | function getRewardRatio() external pure override returns (uint) { 24 | return REWARD_RATIO; 25 | } 26 | 27 | function submitClaim( 28 | uint32 coverId, 29 | uint96 requestedAmount, 30 | string calldata /*ipfsMetadata*/ 31 | ) external payable override returns (Claim memory) { 32 | 33 | uint totalReward = requestedAmount * REWARD_RATIO / REWARD_DENOMINATOR; 34 | uint assessmentId = assessment().startAssessment(totalReward, 0); 35 | 36 | Claim memory claim = Claim( 37 | uint80(assessmentId), 38 | coverId, 39 | 0, // ex segment id 40 | requestedAmount, 41 | 0, 42 | false // payoutRedeemed 43 | ); 44 | 45 | claims.push(claim); 46 | 47 | return claim; 48 | } 49 | 50 | function changeDependentContractAddress() external override { 51 | internalContracts[uint(ID.AS)] = master.getLatestAddress("AS"); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /contracts/mocks/modules/Assessment/ASMockMemberRoles.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../../interfaces/INXMMaster.sol"; 6 | import "../../../interfaces/IMemberRoles.sol"; 7 | import "../../generic/MemberRolesGeneric.sol"; 8 | 9 | contract ASMockMemberRoles is MemberRolesGeneric { 10 | mapping(address => uint) public _members; 11 | 12 | function enrollMember(address newMember, uint role) public { 13 | _members[newMember] = role; 14 | } 15 | 16 | function checkRole(address user, uint role) public override view returns (bool) { 17 | return _members[user] == role; 18 | } 19 | 20 | function isMember(address user) external view returns (bool) { 21 | return checkRole(user, uint(IMemberRoles.Role.Member)); 22 | } 23 | 24 | function members(address user) external view returns (uint roleId) { 25 | return _members[user]; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /contracts/mocks/modules/Assessment/ASMockTokenController.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../../interfaces/INXMToken.sol"; 6 | import "../../generic/TokenControllerGeneric.sol"; 7 | 8 | contract ASMockTokenController is TokenControllerGeneric { 9 | 10 | address public addToWhitelistLastCalledWith; 11 | 12 | constructor(address tokenAddres) { 13 | token = INXMToken(tokenAddres); 14 | } 15 | 16 | function operatorTransfer(address _from, address _to, uint _value) override external returns (bool) { 17 | token.operatorTransfer(_from, _value); 18 | token.transfer(_to, _value); 19 | return true; 20 | } 21 | 22 | function mint(address _to, uint _value) override external { 23 | token.mint(_to, _value); 24 | } 25 | 26 | function addToWhitelist(address _member) override public { 27 | addToWhitelistLastCalledWith = _member; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /contracts/mocks/modules/Claims/CLMockCoverNFT.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../tokens/ERC721Mock.sol"; 6 | 7 | contract CLMockCoverNFT is ERC721Mock { 8 | 9 | constructor() ERC721Mock("", "") {} 10 | 11 | function mint(address to) external returns (uint tokenId) { 12 | tokenId = ++totalSupply; 13 | _mint(to, tokenId); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /contracts/mocks/modules/Claims/CLMockTokenController.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../../interfaces/INXMToken.sol"; 6 | import "../../generic/TokenControllerGeneric.sol"; 7 | 8 | contract CLMockTokenController is TokenControllerGeneric { 9 | 10 | constructor(address tokenAddres) { 11 | token = INXMToken(tokenAddres); 12 | } 13 | 14 | function operatorTransfer(address _from, address _to, uint _value) external override returns (bool) { 15 | token.operatorTransfer(_from, _value); 16 | token.transfer(_to, _value); 17 | return true; 18 | } 19 | 20 | function mint(address _to, uint _value) external override { 21 | token.mint(_to, _value); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /contracts/mocks/modules/Cover/COMockCoverNFT.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../tokens/ERC721Mock.sol"; 6 | 7 | contract COMockCoverNFT is ERC721Mock { 8 | 9 | constructor() ERC721Mock("", "") {} 10 | 11 | function mint(address to) external returns (uint tokenId) { 12 | tokenId = ++totalSupply; 13 | _mint(to, tokenId); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /contracts/mocks/modules/Cover/COMockMCR.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../generic/MCRGeneric.sol"; 6 | 7 | contract COMockMCR is MCRGeneric { 8 | 9 | uint public mockMCRValue; 10 | 11 | function getMCR() external override view returns (uint) { 12 | return mockMCRValue; 13 | } 14 | 15 | function setMCR(uint _mcrValue) external { 16 | mockMCRValue = _mcrValue; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /contracts/mocks/modules/Cover/COMockStakingNFT.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../tokens/ERC721Mock.sol"; 6 | 7 | contract COMockStakingNFT is ERC721Mock { 8 | 9 | constructor() ERC721Mock("", "") {} 10 | 11 | function mint(address to) external returns (uint tokenId) { 12 | tokenId = ++totalSupply; 13 | _mint(to, tokenId); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /contracts/mocks/modules/CoverProducts/CPMockStakingPoolFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | import "../../generic/StakingPoolFactoryGeneric.sol"; 6 | 7 | contract CPMockStakingPoolFactory is StakingPoolFactoryGeneric { 8 | 9 | uint96 internal _stakingPoolCount; 10 | 11 | function stakingPoolCount() external override view returns (uint) { 12 | return _stakingPoolCount; 13 | } 14 | 15 | function setStakingPoolCount(uint count) public override { 16 | _stakingPoolCount = uint96(count); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /contracts/mocks/modules/CoverViewer/CVMockCover.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../generic/CoverGeneric.sol"; 6 | 7 | contract CVMockCover is CoverGeneric { 8 | 9 | mapping(uint => CoverData) public _coverData; 10 | mapping(uint => CoverReference) public _coverReference; 11 | 12 | function addCoverData(uint coverId, CoverData memory newCoverData) public { 13 | _coverData[coverId] = newCoverData; 14 | } 15 | 16 | function addCoverDataWithReference(uint coverId, CoverData memory newCoverData, CoverReference memory newCoverReference) public { 17 | _coverData[coverId] = newCoverData; 18 | _coverReference[coverId] = newCoverReference; 19 | } 20 | 21 | function getCoverData(uint coverId) external override view returns (CoverData memory) { 22 | return _coverData[coverId]; 23 | } 24 | 25 | function getCoverDataWithReference(uint coverId) external override view returns (CoverData memory, CoverReference memory) { 26 | return (_coverData[coverId], _coverReference[coverId]); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /contracts/mocks/modules/LimitOrders/LimitOrdersCoverMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | import "../../generic/CoverGeneric.sol"; 5 | 6 | contract LimitOrdersCoverMock is CoverGeneric { 7 | 8 | function executeCoverBuy( 9 | BuyCoverParams memory, 10 | PoolAllocationRequest[] memory, 11 | address 12 | ) external payable override returns (uint coverId) { 13 | return 1; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /contracts/mocks/modules/MCR/MCRMockCover.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../../interfaces/ICover.sol"; 6 | import "../../generic/CoverGeneric.sol"; 7 | 8 | contract MCRMockCover is CoverGeneric { 9 | 10 | mapping(uint => uint) public _totalActiveCoverInAsset; 11 | 12 | function getTotalActiveCoverInAsset(uint coverAsset) external view returns (uint) { 13 | return _totalActiveCoverInAsset[coverAsset]; 14 | } 15 | 16 | function setTotalActiveCoverInAsset(uint asset, uint amount) public { 17 | _totalActiveCoverInAsset[asset] = amount; 18 | } 19 | 20 | function totalActiveCoverInAsset(uint coverAsset) external override view returns (uint) { 21 | return _totalActiveCoverInAsset[coverAsset]; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /contracts/mocks/modules/MCR/MCRMockPool.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../common/PoolMock.sol"; 6 | import "../../../interfaces/IPriceFeedOracle.sol"; 7 | 8 | contract MCRMockPool is PoolMock { 9 | 10 | IPriceFeedOracle public _priceFeedOracle; 11 | 12 | constructor(address priceFeedOracleAddress) { 13 | _priceFeedOracle = IPriceFeedOracle(priceFeedOracleAddress); 14 | } 15 | 16 | function priceFeedOracle() external override view returns (IPriceFeedOracle) { 17 | return _priceFeedOracle; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /contracts/mocks/modules/MCR/MCRMockPriceFeedOracle.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../generic/PriceFeedOracleGeneric.sol"; 6 | 7 | contract MCRMockPriceFeedOracle is PriceFeedOracleGeneric { 8 | 9 | address public daiAddress; 10 | uint public daiToEthRate; 11 | 12 | constructor(address _daiAddress, uint _daiToEthRate) { 13 | daiAddress = _daiAddress; 14 | daiToEthRate = _daiToEthRate; 15 | } 16 | 17 | function getAssetToEthRate(address asset) external override view returns (uint) { 18 | require(asset == daiAddress); 19 | return daiToEthRate; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /contracts/mocks/modules/Master/MSMockGovernance.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../../abstract/MasterAware.sol"; 6 | import "../../../interfaces/ITokenController.sol"; 7 | import "../../generic/GovernanceGeneric.sol"; 8 | 9 | contract MSMockGovernance is GovernanceGeneric, MasterAware { 10 | 11 | ITokenController tc; 12 | 13 | constructor() { } 14 | 15 | function changeDependentContractAddress() external { 16 | tc = ITokenController(master.getLatestAddress("TC")); 17 | } 18 | 19 | function upgradeMultipleContracts( 20 | bytes2[] memory _contractCodes, 21 | address payable[] memory newAddresses 22 | ) public { 23 | master.upgradeMultipleContracts(_contractCodes, newAddresses); 24 | } 25 | 26 | function removeContracts(bytes2[] memory contractCodesToRemove) public { 27 | master.removeContracts(contractCodesToRemove); 28 | } 29 | 30 | function updateOwnerParameters(bytes8 code, address payable val) public { 31 | master.updateOwnerParameters(code, val); 32 | } 33 | 34 | function addNewInternalContracts( 35 | bytes2[] memory _contractCodes, 36 | address payable[] memory newAddresses, 37 | uint[] memory _types 38 | ) public { 39 | master.addNewInternalContracts(_contractCodes, newAddresses, _types); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /contracts/mocks/modules/Master/MSMockNewContract.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../../abstract/MasterAwareV2.sol"; 6 | import "../../../interfaces/ITokenController.sol"; 7 | 8 | contract MSMockNewContract is MasterAwareV2 { 9 | 10 | constructor() { } 11 | 12 | function changeDependentContractAddress() external { 13 | internalContracts[uint(ID.TC)] = master.getLatestAddress("TC"); 14 | } 15 | 16 | function mint(address _member, uint _amount) public { 17 | ITokenController(internalContracts[uint(ID.TC)]).mint(_member, _amount); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /contracts/mocks/modules/MemberRoles/MRMockAssessment.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | import "../../generic/AssessmentGeneric.sol"; 5 | 6 | contract MRMockAssessment is AssessmentGeneric { 7 | function setStakeOf(address staker, uint96 stakeAmount) external { 8 | stakeOf[staker] = IAssessment.Stake(stakeAmount, 0 /* rewardWithdrawableFromIndex */ , 0 /* fraudCount */); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /contracts/mocks/modules/MemberRoles/MRMockCoverNFT.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../tokens/ERC721Mock.sol"; 6 | 7 | contract MRMockCoverNFT is ERC721Mock { 8 | 9 | constructor(string memory name, string memory symbol) ERC721Mock(name, symbol) { 10 | /* noop */ 11 | } 12 | 13 | function mint(address to) external returns (uint tokenId) { 14 | tokenId = ++totalSupply; 15 | _mint(to, tokenId); 16 | } 17 | 18 | function operatorTransferFrom(address from, address to, uint256 tokenId) external { 19 | _operatorTransferFrom(from, to, tokenId); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /contracts/mocks/modules/MemberRoles/MRMockGovernance.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../generic/GovernanceGeneric.sol"; 6 | 7 | contract MRMockGovernance is GovernanceGeneric { 8 | function removeDelegation(address) public {} 9 | } 10 | -------------------------------------------------------------------------------- /contracts/mocks/modules/MemberRoles/MRMockStakingNFT.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../tokens/ERC721Mock.sol"; 6 | 7 | contract MRMockStakingNFT is ERC721Mock { 8 | 9 | constructor(string memory name, string memory symbol) ERC721Mock(name, symbol) { 10 | /* noop */ 11 | } 12 | 13 | function mint(address to) external { 14 | _mint(to, ++totalSupply); 15 | } 16 | 17 | function operatorTransferFrom(address from, address to, uint256 tokenId) external { 18 | _operatorTransferFrom(from, to, tokenId); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /contracts/mocks/modules/NexusViewer/NVMockAssessmentViewer.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import {IAssessment} from "../../../interfaces/IAssessment.sol"; 6 | import {IAssessmentViewer} from "../../../interfaces/IAssessmentViewer.sol"; 7 | import {INXMMaster} from "../../../interfaces/INXMMaster.sol"; 8 | import {INXMToken} from "../../../interfaces/INXMToken.sol"; 9 | 10 | contract NVMockAssessmentViewer is IAssessmentViewer { 11 | 12 | AssessmentStakeLockedState stakeLockedState; 13 | AssessmentRewards assessmentRewards; 14 | 15 | /* ========== SETTERS ========== */ 16 | 17 | function setStakeLocked(AssessmentStakeLockedState memory _stakeLockedState) external { 18 | stakeLockedState = _stakeLockedState; 19 | } 20 | 21 | function setRewards( 22 | uint _totalPendingAmountInNXM, 23 | uint _withdrawableAmountInNXM, 24 | uint _withdrawableUntilIndex 25 | ) external { 26 | assessmentRewards = AssessmentRewards({ 27 | totalPendingAmountInNXM: _totalPendingAmountInNXM, 28 | withdrawableAmountInNXM: _withdrawableAmountInNXM, 29 | withdrawableUntilIndex: _withdrawableUntilIndex 30 | }); 31 | } 32 | 33 | /* ========== VIEWS ========== */ 34 | 35 | function getStakeLocked(address) external view returns (AssessmentStakeLockedState memory) { 36 | return stakeLockedState; 37 | } 38 | 39 | function getRewards(address) external view returns (AssessmentRewards memory) { 40 | return assessmentRewards; 41 | } 42 | 43 | /* ========== NOT YET IMPLEMENTED ========== */ 44 | 45 | function assessment() public pure returns (IAssessment) { 46 | revert("assessment not yet implemented"); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /contracts/mocks/modules/Pool/P1MockLido.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.5.17; 4 | 5 | import "../../common/ERC20Detailed.sol"; 6 | import "../../common/ERC20Mintable.sol"; 7 | 8 | contract P1MockLido is ERC20Mintable, ERC20Detailed { 9 | 10 | uint public ethToStETHRate = 10000; 11 | 12 | constructor() ERC20Detailed("Lido", "LIDO", 18) public { 13 | /* noop */ 14 | } 15 | 16 | // fallback 17 | function() external payable { 18 | // protection against accidental submissions by calling non-existent function 19 | require(msg.data.length == 0, "NON_EMPTY_DATA"); 20 | _mint(msg.sender, msg.value * ethToStETHRate / 10000); 21 | } 22 | 23 | function setETHToStETHRate(uint _ethToStETHRate) public { 24 | ethToStETHRate = _ethToStETHRate; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /contracts/mocks/modules/Pool/P1MockMCR.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../generic/MCRGeneric.sol"; 6 | 7 | contract P1MockMCR is MCRGeneric { 8 | uint public _mcr; 9 | 10 | function getMCR() external override view returns (uint) { 11 | return _mcr; 12 | } 13 | 14 | function setMCR(uint80 value) public { 15 | _mcr = value; 16 | } 17 | 18 | function mcr() external override view returns (uint80) { 19 | return uint80(_mcr); 20 | } 21 | 22 | function updateMCR(uint) public override { 23 | // no-op 24 | } 25 | 26 | function updateMCRInternal(bool) public override { 27 | // no-op 28 | } 29 | 30 | function changeDependentContractAddress() external { 31 | // no-op 32 | } 33 | 34 | function changeMasterAddress(address) external { 35 | // no-op 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /contracts/mocks/modules/Pool/P1MockOldPool.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | 6 | interface P1MockOldPool { 7 | function twapOracle() external view returns (address); 8 | function getTokenPrice(address asset) external view returns (uint tokenPrice); 9 | function getPoolValueInEth() external view returns (uint); 10 | function priceFeedOracle() external view returns (address); 11 | } 12 | -------------------------------------------------------------------------------- /contracts/mocks/modules/Pool/P1MockSwapOperator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../generic/SwapOperatorGeneric.sol"; 6 | 7 | contract P1MockSwapOperator is SwapOperatorGeneric { 8 | 9 | function orderInProgress() external override pure returns (bool) { 10 | return false; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /contracts/mocks/modules/Ramm/RAMockMCR.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../../interfaces/IMCR.sol"; 6 | import "../../../interfaces/INXMToken.sol"; 7 | import "../../../interfaces/IPool.sol"; 8 | import "../../../abstract/MasterAwareV2.sol"; 9 | import "../../../libraries/Math.sol"; 10 | import "../../generic/MCRGeneric.sol"; 11 | 12 | contract RAMockMCR is MCRGeneric { 13 | 14 | uint public mockMCRValue; 15 | uint public lastMCRUpdateTime; 16 | 17 | INXMMaster public master; 18 | IPool public pool; 19 | 20 | constructor (address _masterAddress) { 21 | master = INXMMaster(_masterAddress); 22 | lastMCRUpdateTime = block.timestamp; 23 | } 24 | 25 | function setPool(address _poolAddress) public override { 26 | pool = IPool(_poolAddress); 27 | } 28 | 29 | function getMCR() external override view returns (uint) { 30 | return mockMCRValue; 31 | } 32 | 33 | function updateMCR(uint newMCRValue) public override { 34 | mockMCRValue = newMCRValue; 35 | } 36 | 37 | function updateMCRInternal(bool) public override { 38 | lastMCRUpdateTime = block.timestamp; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /contracts/mocks/modules/Ramm/RAMockMemberRoles.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../../interfaces/INXMMaster.sol"; 6 | import "../../generic/MemberRolesGeneric.sol"; 7 | 8 | contract RAMockMemberRoles is MemberRolesGeneric { 9 | mapping(address => uint) public membersData; 10 | 11 | function enrollMember(address newMember, uint role) public { 12 | membersData[newMember] = role; 13 | } 14 | 15 | function checkRole(address user, uint role) external override view returns (bool) { 16 | return membersData[user] == role; 17 | } 18 | 19 | function isMember(address user) external view returns (bool) { 20 | return membersData[user] == uint(IMemberRoles.Role.Member); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /contracts/mocks/modules/Ramm/RAMockTokenController.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../../interfaces/INXMToken.sol"; 6 | import "../../../interfaces/ITokenController.sol"; 7 | import "../../generic/TokenControllerGeneric.sol"; 8 | 9 | contract RAMockTokenController is TokenControllerGeneric { 10 | 11 | constructor(address tokenAddres) { 12 | token = INXMToken(tokenAddres); 13 | } 14 | 15 | function operatorTransfer(address _from, address _to, uint _value) external override returns (bool) { 16 | token.operatorTransfer(_from, _value); 17 | token.transfer(_to, _value); 18 | return true; 19 | } 20 | 21 | function mint(address _to, uint _value) external override { 22 | token.mint(_to, _value); 23 | } 24 | 25 | function burnFrom(address _from, uint _value) external override returns (bool) { 26 | token.burnFrom(_from, _value); 27 | return true; 28 | } 29 | 30 | function totalSupply() public override view returns (uint256) { 31 | return token.totalSupply(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /contracts/mocks/modules/StakingNFT/SNFTMockCover.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../../interfaces/IStakingNFT.sol"; 6 | import "../../../interfaces/IStakingPool.sol"; 7 | import "../../../interfaces/IStakingPoolFactory.sol"; 8 | import "../../../libraries/StakingPoolLibrary.sol"; 9 | import "../../generic/CoverGeneric.sol"; 10 | /** 11 | * @dev Simple library to derive the staking pool address from the pool id without external calls 12 | */ 13 | 14 | contract SNFTMockCover is CoverGeneric { 15 | IStakingPoolFactory stakingPoolFactory; 16 | IStakingNFT stakingNFT; 17 | 18 | constructor(address _stakingPoolFactory) { 19 | stakingPoolFactory = IStakingPoolFactory(_stakingPoolFactory); 20 | } 21 | 22 | function setStakingNFT(address _stakingNFT) public { 23 | stakingNFT = IStakingNFT(_stakingNFT); 24 | } 25 | 26 | function transferFrom(address from, address to, uint id) external { 27 | // get staking nft from factory 28 | stakingNFT.transferFrom(from, to, id); 29 | } 30 | 31 | function stakingPool(uint256 poolId) public view returns (IStakingPool) { 32 | return IStakingPool( 33 | StakingPoolLibrary.getAddress(address(stakingPoolFactory), poolId) 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /contracts/mocks/modules/StakingPool/SKMockStakingNFT.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../tokens/ERC721Mock.sol"; 6 | 7 | contract SKMockStakingNFT is ERC721Mock { 8 | 9 | constructor() ERC721Mock("", "") {} 10 | 11 | mapping(uint => uint) public _stakingPoolOf; 12 | 13 | function mint(uint poolId, address to) external returns (uint) { 14 | uint tokenId = ++totalSupply; 15 | _mint(to, tokenId); 16 | _stakingPoolOf[tokenId] = poolId; 17 | return tokenId; 18 | } 19 | 20 | function stakingPoolOf(uint tokenId) external view returns (uint) { 21 | // ownerOf will revert for non-existing tokens which is what we want here 22 | ownerOf(tokenId); 23 | return _stakingPoolOf[tokenId]; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /contracts/mocks/modules/StakingProducts/SPMockStakingProducts.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../../modules/staking/StakingProducts.sol"; 6 | 7 | contract SPMockStakingProducts is StakingProducts { 8 | 9 | constructor( 10 | address _coverContract, 11 | address _stakingPoolFactory 12 | ) StakingProducts(_coverContract, _stakingPoolFactory) { 13 | // noop 14 | } 15 | 16 | function setInitialProducts(uint poolId, ProductInitializationParams[] memory params) public { 17 | _setInitialProducts(poolId, params); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /contracts/mocks/modules/SwapOperator/SOMockEnzymeFundValueCalculatorRouter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../../external/enzyme/IEnzymeFundValueCalculatorRouter.sol"; 6 | 7 | contract SOMockEnzymeFundValueCalculatorRouter is IEnzymeFundValueCalculatorRouter { 8 | 9 | address weth; 10 | 11 | constructor (address _weth) { 12 | weth = _weth; 13 | } 14 | 15 | function calcGrossShareValue( 16 | address /* _vaultProxy */ 17 | ) external view returns (address denominationAsset_, uint256 grossShareValue_) { 18 | return (weth, 1e18); 19 | } 20 | 21 | function calcNetShareValue( 22 | address /* _vaultProxy */ 23 | ) external view returns (address denominationAsset_, uint256 netShareValue_) { 24 | return (weth, 1e18); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /contracts/mocks/modules/SwapOperator/SOMockEnzymeV4Comptroller.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.5.17; 4 | 5 | import "../../../external/enzyme/IEnzymeV4Comptroller.sol"; 6 | import "./SOMockEnzymeV4Vault.sol"; 7 | 8 | contract SOMockEnzymeV4Comptroller is IEnzymeV4Comptroller { 9 | 10 | address weth; 11 | SOMockEnzymeV4Vault private vault; 12 | 13 | uint public ethToSharesRate = 10000; 14 | 15 | constructor(address _weth) public { 16 | weth = _weth; 17 | } 18 | 19 | function getDenominationAsset() external view returns (address denominationAsset_) { 20 | return weth; 21 | } 22 | 23 | function redeemSharesForSpecificAssets( 24 | address _recipient, 25 | uint256 _sharesQuantity, 26 | address[] calldata /* _payoutAssets */, 27 | uint256[] calldata /* _payoutAssetPercentages */ 28 | ) external returns (uint256[] memory payoutAmounts_) { 29 | payoutAmounts_ = new uint256[](0); 30 | 31 | vault.burn(_recipient, _sharesQuantity); 32 | IERC20(weth).transfer(_recipient, _sharesQuantity * 10000 / ethToSharesRate); 33 | } 34 | 35 | function vaultCallOnContract( 36 | address _contract, 37 | bytes4 _selector, 38 | bytes calldata _encodedArgs 39 | ) external { 40 | // no-op 41 | } 42 | 43 | function buyShares(uint _investmentAmount, uint /* _minSharesQuantity */) external { 44 | uint shares = _investmentAmount * ethToSharesRate / 10000; 45 | vault.mint(msg.sender, shares); 46 | } 47 | 48 | function setETHToVaultSharesRate(uint _ethToSharesRate) public { 49 | ethToSharesRate = _ethToSharesRate; 50 | } 51 | 52 | function setVault(SOMockEnzymeV4Vault _vault) public { 53 | vault = _vault; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /contracts/mocks/modules/SwapOperator/SOMockEnzymeV4DepositWrapper.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.5.17; 4 | 5 | import "./SOMockEnzymeV4Vault.sol"; 6 | import "../../../external/enzyme/IEnzymeV4DepositWrapper.sol"; 7 | 8 | contract SOMockEnzymeV4DepositWrapper is IEnzymeV4DepositWrapper { 9 | 10 | uint public ethToSharesRate = 10000; 11 | 12 | SOMockEnzymeV4Vault private vault; 13 | 14 | constructor(SOMockEnzymeV4Vault _vault) public { 15 | vault = _vault; 16 | } 17 | 18 | function exchangeEthAndBuyShares( 19 | address /* comptrollerProxy */, 20 | address /* denominationAsset */, 21 | uint256 /* minSharesQuantity */, 22 | address /* exchange */, 23 | address /* exchangeApproveTarget */, 24 | bytes calldata /* exchangeData */, 25 | uint256 /* minInvestmentAmount */ 26 | ) external payable returns (uint256) { 27 | 28 | // require(msg.data.length == 0, "NON_EMPTY_DATA"); 29 | uint shares = msg.value * ethToSharesRate / 10000; 30 | vault.mint(msg.sender, shares); 31 | return shares; 32 | } 33 | 34 | function setETHToVaultSharesRate(uint _ethToSharesRate) public { 35 | ethToSharesRate = _ethToSharesRate; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /contracts/mocks/modules/SwapOperator/SOMockEnzymeV4Vault.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.5.17; 4 | 5 | 6 | import "../../../external/enzyme/IEnzymeV4Vault.sol"; 7 | import "../../../modules/token/external/ERC20.sol"; 8 | import "../../common/ERC20Detailed.sol"; 9 | 10 | contract SOMockEnzymeV4Vault is IEnzymeV4Vault, ERC20Detailed, ERC20 { 11 | 12 | address accessor; 13 | 14 | constructor( 15 | address _accessor, 16 | string memory name, 17 | string memory symbol, 18 | uint8 decimals 19 | ) ERC20Detailed(name, symbol, decimals) public { 20 | accessor = _accessor; 21 | } 22 | 23 | function getAccessor() external view returns (address) { 24 | return accessor; 25 | } 26 | 27 | function mint(address account, uint256 amount) public returns (bool) { 28 | _mint(account, amount); 29 | return true; 30 | } 31 | 32 | function burn(address account, uint256 amount) public returns (bool) { 33 | _burn(account, amount); 34 | return true; 35 | } 36 | 37 | function getOwner() public view returns (address) { 38 | return address(0); 39 | } 40 | 41 | 42 | function mintShares(address, uint256) external { 43 | revert("Unexpected SOMockEnzymeV4Vault call"); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /contracts/mocks/modules/SwapOperator/SOMockSettlement.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-or-later 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import './SOMockVaultRelayer.sol'; 6 | import '../../../external/cow/GPv2Order.sol'; 7 | 8 | contract SOMockSettlement { 9 | SOMockVaultRelayer public immutable vaultRelayer; 10 | mapping(bytes => uint256) public filledAmount; 11 | mapping(bytes => bool) public presignatures; 12 | bytes32 public immutable domainSeparator; 13 | 14 | bytes32 private constant DOMAIN_TYPE_HASH = 15 | keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'); 16 | bytes32 private constant DOMAIN_NAME = keccak256('Gnosis Protocol'); 17 | bytes32 private constant DOMAIN_VERSION = keccak256('v2'); 18 | 19 | constructor(address _vault) { 20 | vaultRelayer = SOMockVaultRelayer(_vault); 21 | domainSeparator = keccak256( 22 | abi.encode(DOMAIN_TYPE_HASH, DOMAIN_NAME, DOMAIN_VERSION, block.chainid, address(this)) 23 | ); 24 | } 25 | 26 | function setPreSignature(bytes memory orderUID, bool signed) external { 27 | presignatures[orderUID] = signed; 28 | } 29 | 30 | function fill( 31 | GPv2Order.Data calldata order, 32 | bytes memory orderUID, 33 | uint256 sellAmount, 34 | uint256 feeAmount, 35 | uint256 buyAmount 36 | ) public { 37 | require(presignatures[orderUID], 'not presigned'); 38 | filledAmount[orderUID] += sellAmount; 39 | vaultRelayer.transfer(order.sellToken, order.receiver, address(vaultRelayer), sellAmount + feeAmount); 40 | vaultRelayer.transfer(order.buyToken, address(vaultRelayer), order.receiver, buyAmount); 41 | } 42 | 43 | function invalidateOrder(bytes calldata orderUid) external { 44 | filledAmount[orderUid] = type(uint256).max; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /contracts/mocks/modules/SwapOperator/SOMockVaultRelayer.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import '@openzeppelin/contracts-v4/token/ERC20/IERC20.sol'; 6 | 7 | contract SOMockVaultRelayer { 8 | constructor() {} 9 | 10 | function transfer( 11 | IERC20 token, 12 | address from, 13 | address to, 14 | uint256 amount 15 | ) external { 16 | if (from == address(this)) { 17 | token.transfer(to, amount); 18 | } else { 19 | token.transferFrom(from, to, amount); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /contracts/mocks/modules/SwapOperator/SOMockWeth.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import '@openzeppelin/contracts-v4/token/ERC20/ERC20.sol'; 6 | 7 | contract SOMockWeth is ERC20 { 8 | constructor() ERC20('WETH', 'WETH') {} 9 | 10 | function deposit() public payable { 11 | _mint(msg.sender, msg.value); 12 | } 13 | 14 | function withdraw(uint256 wad) public { 15 | require(balanceOf(msg.sender) >= wad, 'no balance'); 16 | _burn(msg.sender, wad); 17 | payable(msg.sender).transfer(wad); 18 | } 19 | 20 | function mint(address who, uint256 amount) public { 21 | _mint(who, amount); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /contracts/mocks/modules/TokenController/TCMockAssessment.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | import "../../../interfaces/IAssessment.sol"; 5 | import "../../generic/AssessmentGeneric.sol"; 6 | 7 | contract TCMockAssessment is AssessmentGeneric { 8 | 9 | mapping(address => uint) public unclaimedGovernanceRewards; 10 | address public withdrawRewardsLastCalledWithStaker; 11 | uint public withdrawRewardsLastCalledWithBatchSize; 12 | 13 | function setStakeOf(address staker, uint96 stakeAmount) external { 14 | stakeOf[staker] = IAssessment.Stake(stakeAmount, 0 /* rewardWithdrawableFromIndex */ , 0 /* fraudCount */); 15 | } 16 | 17 | function withdrawRewards( 18 | address staker, 19 | uint104 batchSize 20 | ) external override returns (uint /* withdrawn */, uint /*withdrawnUntilIndex*/) { 21 | withdrawRewardsLastCalledWithStaker = staker; 22 | withdrawRewardsLastCalledWithBatchSize = batchSize; 23 | 24 | return (0, 0); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /contracts/mocks/modules/TokenController/TCMockGovernance.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.5.0; 4 | 5 | 6 | contract TCMockGovernance { 7 | mapping(address => uint) public unclaimedGovernanceRewards; 8 | address public claimRewardLastCalledWithMemberAddress; 9 | uint public claimRewardLastCalledWithMaxRecords; 10 | 11 | function claimReward( 12 | address _memberAddress, 13 | uint _maxRecords 14 | ) external returns (uint pendingDAppReward) { 15 | pendingDAppReward = unclaimedGovernanceRewards[_memberAddress]; 16 | claimRewardLastCalledWithMemberAddress = _memberAddress; 17 | claimRewardLastCalledWithMaxRecords = _maxRecords; 18 | unclaimedGovernanceRewards[_memberAddress] = 0; 19 | } 20 | 21 | function getPendingReward(address _memberAddress) external view returns(uint) { 22 | return unclaimedGovernanceRewards[_memberAddress]; 23 | } 24 | 25 | function setUnclaimedGovernanceRewards(address _memberAddress, uint amount) public { 26 | unclaimedGovernanceRewards[_memberAddress] = amount; 27 | } 28 | 29 | function claimRewardLastCalledWith() public view returns (uint maxRecords, address memberAddress) { 30 | maxRecords = claimRewardLastCalledWithMaxRecords; 31 | memberAddress = claimRewardLastCalledWithMemberAddress; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /contracts/mocks/modules/TokenController/TCMockStakingNFT.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../tokens/ERC721Mock.sol"; 6 | 7 | contract TCMockStakingNFT is ERC721Mock { 8 | 9 | constructor() ERC721Mock("", "") {} 10 | 11 | mapping(uint => uint) public _stakingPoolOf; 12 | 13 | function mint(uint poolId, address to) external returns (uint) { 14 | uint tokenId = ++totalSupply; 15 | _mint(to, tokenId); 16 | _stakingPoolOf[tokenId] = poolId; 17 | return tokenId; 18 | } 19 | 20 | function stakingPoolOf(uint tokenId) external view returns (uint) { 21 | // ownerOf will revert for non-existing tokens which is what we want here 22 | ownerOf(tokenId); 23 | return _stakingPoolOf[tokenId]; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /contracts/mocks/modules/TokenController/TCMockStakingPool.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../generic/StakingProductsGeneric.sol"; 6 | 7 | contract TCMockStakingPool is StakingProductsGeneric { 8 | uint public calls; 9 | mapping(uint => uint) public withdrawCalledWithTokenId; 10 | mapping(uint => bool) public withdrawCalledWithStake; 11 | mapping(uint => bool) public withdrawCalledWithRewards; 12 | mapping(uint => uint[]) public withdrawCalledWithTrancheIds; 13 | 14 | function withdraw( 15 | uint tokenId, 16 | bool withdrawStake, 17 | bool withdrawRewards, 18 | uint[] memory trancheIds 19 | ) external returns (uint /* withdrawnStake */, uint /* withdrawnRewards*/) { 20 | calls++; 21 | withdrawCalledWithTokenId[calls] = tokenId; 22 | withdrawCalledWithStake[calls] = withdrawStake; 23 | withdrawCalledWithRewards[calls] = withdrawRewards; 24 | withdrawCalledWithTrancheIds[calls] = trancheIds; 25 | 26 | return (0, 0); 27 | } 28 | 29 | function withdrawCalledWith(uint callId) external view returns (uint, bool, bool, uint[] memory) { 30 | return ( 31 | withdrawCalledWithTokenId[callId], 32 | withdrawCalledWithStake[callId], 33 | withdrawCalledWithRewards[callId], 34 | withdrawCalledWithTrancheIds[callId] 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /contracts/mocks/testnet/TestnetClaimProofs.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../modules/legacy/LegacyClaimProofs.sol"; 6 | 7 | contract TestnetClaimProofs is LegacyClaimProofs { 8 | 9 | function addMockProof(uint _coverId, address member, string calldata _ipfsHash) external { 10 | emit ProofAdded(_coverId, member, _ipfsHash); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /contracts/mocks/testnet/TestnetClaimsData.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.5.0; 4 | 5 | import "../../modules/legacy/LegacyClaimsData.sol"; 6 | 7 | contract TestnetClaimsData is LegacyClaimsData { 8 | 9 | function addMockClaim( 10 | uint claimId, 11 | uint coverId, 12 | address coverOwner, 13 | uint timestamp 14 | ) external { 15 | allClaims.push(Claim(coverId, timestamp)); 16 | allClaimsByAddress[coverOwner].push(claimId); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /contracts/mocks/testnet/TestnetMemberRoles.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../modules/governance/MemberRoles.sol"; 6 | 7 | contract TestnetMemberRoles is MemberRoles { 8 | 9 | constructor(address tokenAddress) MemberRoles(tokenAddress) { 10 | } 11 | 12 | function joinOnTestnet(address _userAddress) public { 13 | 14 | require(!isMember(_userAddress), "MemberRoles: This address is already a member"); 15 | 16 | tokenController().addToWhitelist(_userAddress); 17 | _updateRole(_userAddress, uint(Role.Member), true); 18 | 19 | emit MemberJoined(_userAddress, 0); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /contracts/mocks/testnet/TestnetNXMaster.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../modules/governance/NXMaster.sol"; 6 | 7 | contract TestnetNXMaster is NXMaster { 8 | 9 | address public governanceOwner; 10 | 11 | modifier onlyGovernanceOwner() { 12 | require(msg.sender == governanceOwner, "Ownable: caller is not the owner"); 13 | _; 14 | } 15 | 16 | function initializeGovernanceOwner() public { 17 | if (governanceOwner != address(0)) { 18 | revert("Already initialized"); 19 | } 20 | governanceOwner = msg.sender; 21 | } 22 | 23 | function switchGovernanceAddress(address payable newGV) external onlyGovernanceOwner { 24 | address currentGV = contractAddresses["GV"]; 25 | contractAddresses["GV"] = newGV; 26 | contractsActive[currentGV] = false; 27 | contractsActive[newGV] = true; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /contracts/mocks/tokens/ERC20BlacklistableMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.5.0; 4 | 5 | import "./ERC20Mock.sol"; 6 | 7 | contract ERC20BlacklistableMock is ERC20Mock { 8 | 9 | mapping(address => bool) isBlacklisted; 10 | mapping(address => bool) isSenderBlacklisted; 11 | 12 | 13 | // Blacklist functionality to be able to make transactions fail 14 | function transfer(address recipient, uint256 amount) public returns (bool) { 15 | require(!isBlacklisted[recipient], "ERC20Mock: recipient is blacklisted"); 16 | require(!isSenderBlacklisted[_msgSender()], "ERC20Mock: sender is blacklisted"); 17 | _transfer(_msgSender(), recipient, amount); 18 | return true; 19 | } 20 | 21 | function whitelist(address recipient) public { 22 | isBlacklisted[recipient] = false; 23 | } 24 | 25 | function whitelistSender(address sender) public { 26 | isSenderBlacklisted[sender] = false; 27 | } 28 | 29 | function blacklist(address recipient) public { 30 | isBlacklisted[recipient] = true; 31 | } 32 | 33 | function blacklistSender(address sender) public { 34 | isSenderBlacklisted[sender] = true; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /contracts/mocks/tokens/ERC20CustomDecimalsMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.5.0; 4 | 5 | import "../common/ERC20Detailed.sol"; 6 | import "../common/ERC20Mintable.sol"; 7 | 8 | contract ERC20CustomDecimalsMock is ERC20Mintable, ERC20Detailed { 9 | constructor(uint8 decimals) public 10 | ERC20Detailed("ERC20CustomDecimalsMock", "USDC", decimals) { 11 | /* noop */ 12 | } 13 | 14 | function setBalance(address account, uint256 amount) public { 15 | _burn(account, balanceOf(account)); 16 | _mint(account, amount); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /contracts/mocks/tokens/ERC20MintableDetailed.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.5.0; 4 | 5 | import "../common/ERC20Detailed.sol"; 6 | import "../common/ERC20Mintable.sol"; 7 | 8 | contract ERC20MintableDetailed is ERC20Mintable, ERC20Detailed { 9 | 10 | constructor(string memory name, string memory symbol, uint8 decimals) ERC20Detailed(name, symbol, decimals) public { 11 | /* noop */ 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /contracts/mocks/tokens/ERC20Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.5.0; 4 | 5 | import "../common/ERC20Detailed.sol"; 6 | import "../common/ERC20Mintable.sol"; 7 | 8 | contract ERC20Mock is ERC20Mintable, ERC20Detailed { 9 | constructor() public ERC20Detailed("ERC20 mock", "MOCK", 18) { 10 | /* noop */ 11 | } 12 | 13 | function setBalance(address account, uint256 amount) public { 14 | _burn(account, balanceOf(account)); 15 | _mint(account, amount); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /contracts/mocks/tokens/ERC20MockNameable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.5.0; 4 | 5 | import "../common/ERC20Detailed.sol"; 6 | import "../common/ERC20Mintable.sol"; 7 | 8 | contract ERC20MockNameable is ERC20Mintable, ERC20Detailed { 9 | constructor(string memory name, string memory symbol) public ERC20Detailed(name, symbol, 18) { 10 | /* noop */ 11 | } 12 | 13 | function setBalance(address account, uint256 amount) public { 14 | _burn(account, balanceOf(account)); 15 | _mint(account, amount); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /contracts/mocks/tokens/ERC20NonRevertingMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | /// This contract doesn't implement ERC20 correctly on purpose to be able to test 6 | /// what happens when returndata length from the transfer function differs from what 7 | /// is usually expected. 8 | contract ERC20NonRevertingMock { 9 | 10 | function balanceOf(address) public pure returns (uint) { 11 | return 0 ether; 12 | } 13 | 14 | function transfer(address, uint256) public { 15 | // noop 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /contracts/mocks/tokens/ERC20PermitMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "@openzeppelin/contracts-v4/token/ERC20/extensions/draft-ERC20Permit.sol"; 6 | 7 | contract ERC20PermitMock is ERC20Permit { 8 | 9 | constructor(string memory name_, string memory symbol_) ERC20(name_, symbol_) ERC20Permit(name_) { 10 | /* noop */ 11 | } 12 | 13 | function mint(address account, uint256 amount) external { 14 | _mint(account, amount); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /contracts/mocks/tokens/ERC20RevertingBalanceOfMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.5.0; 4 | 5 | import "../common/ERC20Detailed.sol"; 6 | import "../common/ERC20Mintable.sol"; 7 | 8 | contract ERC20RevertingBalanceOfMock is ERC20Mintable, ERC20Detailed { 9 | 10 | bool isReverting = false; 11 | 12 | constructor() ERC20Detailed("ERC20 mock", "MOCK", 18) public { 13 | /* noop */ 14 | } 15 | 16 | function balanceOf(address account) public view returns (uint) { 17 | 18 | if (isReverting) { 19 | revert("ERC20RevertingBalanceOfMock: balanceOf reverted"); 20 | } 21 | 22 | return super.balanceOf(account); 23 | } 24 | 25 | function setIsReverting(bool _isReverting) public { 26 | isReverting = _isReverting; 27 | } 28 | 29 | function setBalance(address account, uint256 amount) public { 30 | _burn(account, balanceOf(account)); 31 | _mint(account, amount); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /contracts/mocks/tokens/ERC721Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "./ERC721.sol"; 6 | 7 | contract ERC721Mock is ERC721 { 8 | 9 | uint public totalSupply; 10 | 11 | constructor(string memory name, string memory symbol) ERC721(name, symbol) { 12 | /* noop */ 13 | } 14 | 15 | function isApprovedOrOwner(address spender, uint256 tokenId) external view returns (bool) { 16 | address owner = ownerOf(tokenId); 17 | return spender == owner || isApprovedForAll[owner][spender] || spender == getApproved[tokenId]; 18 | } 19 | 20 | function tokenURI(uint) public pure override returns (string memory) { 21 | return ""; 22 | } 23 | 24 | function _operatorTransferFrom(address from, address to, uint256 tokenId) internal { 25 | 26 | require(from == _ownerOf[tokenId], "WRONG_FROM"); 27 | require(to != address(0), "INVALID_RECIPIENT"); 28 | 29 | // Underflow of the sender's balance is impossible because we check for 30 | // ownership above and the recipient's balance can't realistically overflow. 31 | unchecked { 32 | _balanceOf[from]--; 33 | _balanceOf[to]++; 34 | } 35 | 36 | _ownerOf[tokenId] = to; 37 | delete getApproved[tokenId]; 38 | 39 | emit Transfer(from, to, tokenId); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /contracts/modules/cover/CoverViewer.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../interfaces/ICover.sol"; 6 | import "../../interfaces/INXMMaster.sol"; 7 | 8 | contract CoverViewer { 9 | 10 | struct Cover { 11 | uint coverId; 12 | uint productId; 13 | uint coverAsset; 14 | uint amount; 15 | uint start; 16 | uint period; // seconds 17 | uint gracePeriod; // seconds 18 | uint originalCoverId; 19 | uint latestCoverId; 20 | } 21 | 22 | INXMMaster internal immutable master; 23 | 24 | constructor(address masterAddress) { 25 | master = INXMMaster(masterAddress); 26 | } 27 | 28 | function cover() internal view returns (ICover) { 29 | return ICover(master.contractAddresses('CO')); 30 | } 31 | 32 | function getCovers(uint[] calldata coverIds) external view returns (Cover[] memory) { 33 | Cover[] memory covers = new Cover[](coverIds.length); 34 | ICover _cover = cover(); 35 | 36 | for (uint i = 0; i < coverIds.length; i++) { 37 | uint coverId = coverIds[i]; 38 | 39 | (CoverData memory coverData, CoverReference memory coverReference) = _cover.getCoverDataWithReference(coverId); 40 | covers[i].coverId = coverId; 41 | covers[i].productId = coverData.productId; 42 | covers[i].coverAsset = coverData.coverAsset; 43 | covers[i].start = coverData.start; 44 | covers[i].period = coverData.period; 45 | covers[i].gracePeriod = coverData.gracePeriod; 46 | covers[i].amount = coverData.amount; 47 | covers[i].originalCoverId = coverReference.originalCoverId; 48 | covers[i].latestCoverId = coverReference.latestCoverId; 49 | } 50 | 51 | return covers; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /contracts/modules/governance/external/Governed.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity >=0.5.0; 4 | 5 | interface IMaster { 6 | function getLatestAddress(bytes2 _module) external view returns (address); 7 | } 8 | 9 | contract Governed { 10 | 11 | address public masterAddress; // Name of the dApp, needs to be set by contracts inheriting this contract 12 | 13 | /// @dev modifier that allows only the authorized addresses to execute the function 14 | modifier onlyAuthorizedToGovern() { 15 | IMaster ms = IMaster(masterAddress); 16 | require(ms.getLatestAddress("GV") == msg.sender, "Not authorized"); 17 | _; 18 | } 19 | 20 | /// @dev checks if an address is authorized to govern 21 | function isAuthorizedToGovern(address _toCheck) public view returns (bool) { 22 | IMaster ms = IMaster(masterAddress); 23 | return (ms.getLatestAddress("GV") == _toCheck); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /contracts/modules/governance/external/Proxy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | /** 6 | * @title Proxy 7 | * @dev Gives the possibility to delegate any call to a foreign implementation. 8 | */ 9 | abstract contract Proxy { 10 | 11 | /** 12 | * @dev Delegates the current call to `implementation`. 13 | */ 14 | function _delegate() internal { 15 | address _impl = implementation(); 16 | require(_impl != address(0)); 17 | 18 | // solhint-disable-next-line no-inline-assembly 19 | assembly { 20 | let ptr := mload(0x40) 21 | calldatacopy(ptr, 0, calldatasize()) 22 | let result := delegatecall(gas(), _impl, ptr, calldatasize(), 0, 0) 23 | let size := returndatasize() 24 | returndatacopy(ptr, 0, size) 25 | 26 | switch result 27 | case 0 {revert(ptr, size)} 28 | default {return (ptr, size)} 29 | } 30 | } 31 | 32 | /** 33 | * @dev Fallback function allowing to perform a delegatecall to the given implementation. 34 | * This function will return whatever the implementation call returns 35 | */ 36 | fallback() external payable { 37 | _delegate(); 38 | } 39 | 40 | /** 41 | * @dev Receive function allowing to perform a delegatecall to the given implementation. 42 | * This function will return whatever the implementation call returns 43 | */ 44 | receive() external payable { 45 | _delegate(); 46 | } 47 | 48 | /** 49 | * @dev Tells the address of the implementation where every call will be delegated. 50 | * @return address of the implementation to which it will be delegated 51 | */ 52 | function implementation() virtual public view returns (address); 53 | } 54 | -------------------------------------------------------------------------------- /contracts/modules/legacy/LegacyClaimProofs.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | contract LegacyClaimProofs { 6 | 7 | event ProofAdded(uint indexed coverId, address indexed owner, string ipfsHash); 8 | 9 | function addProof(uint _coverId, string calldata _ipfsHash) external { 10 | emit ProofAdded(_coverId, msg.sender, _ipfsHash); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /contracts/modules/staking/MinimalBeaconProxy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "@openzeppelin/contracts-v4/proxy/Proxy.sol"; 6 | import "../../interfaces/IStakingPoolBeacon.sol"; 7 | import "../../interfaces/IStakingPoolFactory.sol"; 8 | 9 | /** 10 | * @dev This contract implements a proxy that gets the implementation address for each call from a {UpgradeableBeacon}. 11 | * 12 | * The beacon address is stored as an immutable field. 13 | * 14 | */ 15 | contract MinimalBeaconProxy is Proxy { 16 | 17 | /** 18 | * @dev The beacon address. 19 | */ 20 | address immutable public beacon; 21 | 22 | /** 23 | * @dev Initializes the proxy with `beacon`. 24 | * 25 | */ 26 | constructor() { 27 | beacon = IStakingPoolFactory(msg.sender).beacon(); 28 | } 29 | 30 | /** 31 | * @dev Returns the current beacon address. 32 | */ 33 | function _beacon() internal view virtual returns (address) { 34 | return beacon; 35 | } 36 | 37 | /** 38 | * @dev Returns the current implementation address of the associated beacon. 39 | */ 40 | function _implementation() internal view virtual override returns (address) { 41 | return IStakingPoolBeacon(beacon).stakingPoolImplementation(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /contracts/modules/staking/StakingPoolFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | import "../../interfaces/IStakingPoolFactory.sol"; 6 | import "./MinimalBeaconProxy.sol"; 7 | 8 | contract StakingPoolFactory is IStakingPoolFactory { 9 | 10 | address public operator; 11 | uint96 internal _stakingPoolCount; 12 | 13 | // temporary beacon address storage to avoid constructor arguments in the proxy 14 | address public beacon; 15 | 16 | constructor(address _operator) { 17 | operator = _operator; 18 | } 19 | 20 | function changeOperator(address newOperator) public { 21 | require(msg.sender == operator, "StakingPoolFactory: Not operator"); 22 | require(newOperator != address(0), "StakingPoolFactory: Invalid operator"); 23 | operator = newOperator; 24 | } 25 | 26 | function stakingPoolCount() external view returns (uint) { 27 | return _stakingPoolCount; 28 | } 29 | 30 | function create(address _beacon) external returns (uint poolId, address stakingPoolAddress) { 31 | 32 | require(msg.sender == operator, "StakingPoolFactory: Not operator"); 33 | 34 | beacon = _beacon; 35 | poolId = ++_stakingPoolCount; 36 | 37 | stakingPoolAddress = address( 38 | new MinimalBeaconProxy{salt : bytes32(poolId)}() 39 | ); 40 | 41 | require( 42 | stakingPoolAddress != address(0), 43 | "StakingPoolFactory: Failed to create staking pool" 44 | ); 45 | 46 | emit StakingPoolCreated(poolId, stakingPoolAddress); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /contracts/modules/token/external/Context.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | /* 4 | * @dev Provides information about the current execution context, including the 5 | * sender of the transaction and its data. While these are generally available 6 | * via msg.sender and msg.data, they should not be accessed in such a direct 7 | * manner, since when dealing with GSN meta-transactions the account sending and 8 | * paying for execution may not be the actual sender (as far as an application 9 | * is concerned). 10 | * 11 | * This contract is only required for intermediate, library-like contracts. 12 | */ 13 | contract Context { 14 | // Empty internal constructor, to prevent people from mistakenly deploying 15 | // an instance of this contract, which should be used via inheritance. 16 | constructor () internal { } 17 | // solhint-disable-previous-line no-empty-blocks 18 | 19 | function _msgSender() internal view returns (address payable) { 20 | return msg.sender; 21 | } 22 | 23 | function _msgData() internal view returns (bytes memory) { 24 | this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 25 | return msg.data; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /contracts/modules/token/external/LockHandler.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.8.18; 4 | 5 | /** 6 | * @title ERC1132 interface 7 | * @dev see https://github.com/ethereum/EIPs/issues/1132 8 | */ 9 | contract LockHandler { 10 | /** 11 | * @dev Reasons why a user's tokens have been locked 12 | */ 13 | mapping(address => bytes32[]) public lockReason; 14 | 15 | /** 16 | * @dev locked token structure 17 | */ 18 | struct LockToken { 19 | uint256 amount; 20 | uint256 validity; 21 | bool claimed; 22 | } 23 | 24 | /** 25 | * @dev Holds number & validity of tokens locked for a given reason for 26 | * a specified address 27 | */ 28 | mapping(address => mapping(bytes32 => LockToken)) public locked; 29 | 30 | event Locked(address indexed _of, bytes32 indexed _reason, uint256 _amount, uint256 _validity); 31 | 32 | event Unlocked(address indexed _of, bytes32 indexed _reason, uint256 _amount); 33 | 34 | } 35 | -------------------------------------------------------------------------------- /contracts/modules/token/external/OZIERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | 3 | pragma solidity ^0.5.0; 4 | 5 | /** 6 | * @title ERC20 interface 7 | * @dev see https://github.com/ethereum/EIPs/issues/20 8 | */ 9 | interface OZIERC20 { 10 | function transfer(address to, uint256 value) external returns (bool); 11 | 12 | function approve(address spender, uint256 value) 13 | external returns (bool); 14 | 15 | function transferFrom(address from, address to, uint256 value) 16 | external returns (bool); 17 | 18 | function totalSupply() external view returns (uint256); 19 | 20 | function balanceOf(address who) external view returns (uint256); 21 | 22 | function allowance(address owner, address spender) 23 | external view returns (uint256); 24 | 25 | event Transfer( 26 | address indexed from, 27 | address indexed to, 28 | uint256 value 29 | ); 30 | 31 | event Approval( 32 | address indexed owner, 33 | address indexed spender, 34 | uint256 value 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /deployments/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | generated/ 3 | -------------------------------------------------------------------------------- /deployments/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nexusmutual/deployments", 3 | "version": "2.12.3", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "@nexusmutual/deployments", 9 | "version": "2.12.3", 10 | "license": "GPL-3.0" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /deployments/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nexusmutual/deployments", 3 | "version": "2.12.3", 4 | "description": "Nexus Mutual deployed contract addresses and abis", 5 | "typings": "./dist/index.d.ts", 6 | "main": "./dist/index.js", 7 | "module": "./dist/index.mjs", 8 | "files": [ 9 | "dist" 10 | ], 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/NexusMutual/smart-contracts.git" 14 | }, 15 | "keywords": [ 16 | "nexusmutual", 17 | "nexus", 18 | "mutual", 19 | "deployments", 20 | "contracts" 21 | ], 22 | "author": "nexusmutual", 23 | "license": "GPL-3.0", 24 | "bugs": { 25 | "url": "https://github.com/NexusMutual/smart-contracts/issues" 26 | }, 27 | "homepage": "https://github.com/NexusMutual/smart-contracts#readme" 28 | } 29 | -------------------------------------------------------------------------------- /deployments/src/index.ts: -------------------------------------------------------------------------------- 1 | export { default as addresses } from './addresses.json'; 2 | export * from '../generated/abis'; 3 | -------------------------------------------------------------------------------- /deployments/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2016", 4 | "module": "commonjs", 5 | "esModuleInterop": true, 6 | "resolveJsonModule": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "strict": true, 9 | "skipLibCheck": true, 10 | "noUncheckedIndexedAccess": true, 11 | "noEmit": true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /hardhat-config/networks.js: -------------------------------------------------------------------------------- 1 | const ether = n => `${n}${'0'.repeat(18)}`; 2 | const networks = { 3 | hardhat: { 4 | accounts: { count: 100, accountsBalance: ether(1000000000) }, 5 | allowUnlimitedContractSize: true, 6 | blockGasLimit: 30e6, 7 | gas: 30e6, 8 | chainId: process.env.FORK_CHAIN_ID ? Number(process.env.FORK_CHAIN_ID) : 31337, 9 | }, 10 | localhost: { blockGasLimit: 30e6, gas: 30e6 }, 11 | }; 12 | 13 | if (process.env.TEST_ENV_FORK) { 14 | networks.hardhat.forking = { url: process.env.TEST_ENV_FORK }; 15 | } 16 | 17 | const getenv = (network, key, fallback, parser = i => i) => { 18 | const value = process.env[`${network}_${key}`]; 19 | return value ? parser(value) : fallback; 20 | }; 21 | 22 | for (const network of ['MAINNET', 'GOERLI', 'SEPOLIA', 'GNOSIS', 'TENDERLY', 'LOCALHOST']) { 23 | const url = getenv(network, 'PROVIDER_URL', false); 24 | if (!url) { 25 | continue; 26 | } 27 | const accounts = getenv(network, 'ACCOUNT_KEY', undefined, v => v.split(/[^0-9a-fx]+/i)); 28 | const gasPrice = getenv(network, 'GAS_PRICE', undefined, v => parseInt(v, 10) * 1e9); 29 | const gas = getenv(network, 'GAS_LIMIT', undefined, v => parseInt(v, 10)); 30 | networks[network.toLowerCase()] = { accounts, gasPrice, gas, url }; 31 | } 32 | 33 | module.exports = networks; 34 | -------------------------------------------------------------------------------- /hardhat-config/solidity.js: -------------------------------------------------------------------------------- 1 | const optimizer = { enabled: true, runs: 200 }; 2 | const compilerSettings = process.env.ENABLE_OPTIMIZER ? { optimizer } : {}; 3 | 4 | const compilers = [ 5 | { settings: { ...compilerSettings }, version: '0.5.17' }, // nexus mutual v1 6 | { settings: { ...compilerSettings, evmVersion: 'cancun' }, version: '0.8.28' }, // nexus mutual v2 7 | ]; 8 | 9 | // override version AND optimizer to always get the same bytecode 10 | const customConfig = { 11 | version: '0.8.18', 12 | settings: { optimizer: { enabled: true, runs: 200 } }, 13 | }; 14 | 15 | const overrides = { 16 | 'contracts/modules/governance/NXMaster.sol': customConfig, 17 | 'contracts/modules/governance/external/OwnedUpgradeabilityProxy.sol': customConfig, 18 | 'contracts/modules/staking/MinimalBeaconProxy.sol': customConfig, 19 | 'contracts/modules/staking/StakingPoolFactory.sol': customConfig, 20 | }; 21 | 22 | module.exports = { 23 | compilers, 24 | overrides, 25 | }; 26 | -------------------------------------------------------------------------------- /hardhat.config.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./hardhat-config'); 2 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | const constants = require('./constants'); 2 | const helpers = require('./helpers'); 3 | const proposalCategories = require('./proposal-categories'); 4 | 5 | module.exports = { 6 | constants, 7 | helpers, 8 | proposalCategories, 9 | }; 10 | -------------------------------------------------------------------------------- /scripts/create2/get-signer.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat'); 2 | const { AwsKmsSigner } = require('@nexusmutual/ethers-v5-aws-kms-signer'); 3 | 4 | const SIGNER_TYPE = { 5 | LOCAL: 'local', 6 | AWS_KMS: 'aws-kms', 7 | }; 8 | 9 | const getSigner = async (kind = SIGNER_TYPE.LOCAL) => { 10 | if (kind === SIGNER_TYPE.LOCAL) { 11 | const [signer] = await ethers.getSigners(); 12 | return signer; 13 | } 14 | 15 | const provider = ethers.provider; 16 | const { AWS_KMS_KEY_ID, AWS_REGION } = process.env; 17 | 18 | if (kind === SIGNER_TYPE.AWS_KMS) { 19 | return new AwsKmsSigner(AWS_KMS_KEY_ID, AWS_REGION, provider); 20 | } 21 | 22 | throw new Error(`Invalid signer type: ${kind}`); 23 | }; 24 | 25 | module.exports = { SIGNER_TYPE, getSigner }; 26 | 27 | if (require.main === module) { 28 | (async () => { 29 | const testMessage = 'Hello, mutants!'; 30 | 31 | // get signer and sign message 32 | const signer = await getSigner(SIGNER_TYPE.AWS_KMS); 33 | const [signature, ethAddress] = await Promise.all([signer.signMessage(testMessage), signer.getAddress()]); 34 | 35 | // recover address from signature 36 | const eip191Hash = ethers.utils.hashMessage(testMessage); 37 | const recoveredAddress = ethers.utils.recoverAddress(eip191Hash, signature); 38 | 39 | if (recoveredAddress !== ethAddress) { 40 | throw new Error(`Recovered address ${recoveredAddress} does not match signer address ${ethAddress}`); 41 | } 42 | 43 | console.log(`Recovered address matches signature address (${recoveredAddress})`); 44 | process.exit(); 45 | })().catch(console.error); 46 | } 47 | -------------------------------------------------------------------------------- /scripts/create2/worker.js: -------------------------------------------------------------------------------- 1 | const workerpool = require('workerpool'); 2 | const { keccak256 } = require('ethereum-cryptography/keccak'); 3 | const { bytesToHex, hexToBytes } = require('ethereum-cryptography/utils'); 4 | const { toChecksumAddress } = require('ethereumjs-util'); 5 | 6 | const Position = { 7 | start: 'start', 8 | end: 'end', 9 | any: 'any', 10 | }; 11 | 12 | const worker = (config, batchNumber, size) => { 13 | const from = batchNumber * size; 14 | const to = from + size; 15 | const results = []; 16 | 17 | for (let salt = from; salt < to; salt++) { 18 | // assemble input 19 | const saltHex = salt.toString(16).padStart(64, '0'); 20 | const input = hexToBytes(`ff${config.factory}${saltHex}${config.bytecodeHash}`); 21 | const create2Hash = keccak256(input); 22 | const address = bytesToHex(create2Hash.slice(32 - 20)); 23 | const checksumedAddress = toChecksumAddress(`0x${address}`); 24 | 25 | const output = config.ignoreCase ? address.toLowerCase() : checksumedAddress.slice(2); 26 | 27 | if ( 28 | (config.position === Position.start && output.startsWith(config.search)) || 29 | (config.position === Position.end && output.endsWith(config.search)) || 30 | (config.position === Position.any && output.includes(config.search)) 31 | ) { 32 | results.push({ salt, address: checksumedAddress }); 33 | } 34 | } 35 | 36 | return results; 37 | }; 38 | 39 | workerpool.worker({ worker }); 40 | -------------------------------------------------------------------------------- /scripts/deploy/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | !*.js 4 | -------------------------------------------------------------------------------- /scripts/deploy/start.js: -------------------------------------------------------------------------------- 1 | const main = async () => { 2 | process.env.ENABLE_OPTIMIZER = '1'; 3 | 4 | const { network, run } = require('hardhat'); 5 | const { task } = require('hardhat/config'); 6 | const deploy = require('./deploy'); 7 | 8 | if (network.name !== 'hardhat') { 9 | console.log('[>] Starting the deployment'); 10 | return deploy(); 11 | } 12 | 13 | const getServer = () => { 14 | return new Promise(resolve => { 15 | task('node:server-ready', (args, _, runSuper) => { 16 | runSuper(); 17 | resolve(args.server); 18 | }); 19 | }); 20 | }; 21 | 22 | console.log('[>] Starting hardhat node'); 23 | run('node').catch(e => { 24 | console.error(e); 25 | process.exit(1); 26 | }); 27 | 28 | console.log('[>] Waiting for hardhat node to be ready'); 29 | const server = await getServer(); 30 | 31 | console.log('[>] Starting the deployment'); 32 | await deploy(); 33 | 34 | const { hostname, port } = server._config; 35 | console.log(`[i] RPC listening at http://${hostname}:${port}`); 36 | console.log(`[i] Chain ID ${network.config.chainId}`); 37 | 38 | await server.waitUntilClosed(); 39 | }; 40 | 41 | main() 42 | .then(() => process.exit(0)) 43 | .catch(error => { 44 | console.error('An unexpected error encountered:', error); 45 | process.exit(1); 46 | }); 47 | -------------------------------------------------------------------------------- /scripts/deploy/whitelist.js: -------------------------------------------------------------------------------- 1 | const { ethers, network } = require('hardhat'); 2 | 3 | const MR = '0x055CC48f7968FD8640EF140610dd4038e1b03926'; 4 | const TK = '0xd7c49CEE7E9188cCa6AD8FF264C1DA2e69D4Cf3B'; 5 | 6 | const main = async () => { 7 | console.log(`Starting patch script on ${network.name} network`); 8 | 9 | const mrProxy = await ethers.getContractAt('OwnedUpgradeabilityProxy', MR); 10 | 11 | console.log('Reading owner'); 12 | const owner = await mrProxy.proxyOwner(); 13 | 14 | console.log('Getting a signer'); 15 | const [signer] = await ethers.getSigners(); 16 | 17 | console.log('Deploying new implementation contract'); 18 | const mrImplementation = await ethers.deployContract('TestnetMemberRoles', [TK], signer); 19 | 20 | console.log('Upgrading proxy'); 21 | const provider = new ethers.providers.JsonRpcProvider(network.config.url); 22 | const mrProxyAsOwner = new ethers.Contract(MR, mrProxy.interface, provider.getSigner(owner)); 23 | await mrProxyAsOwner.upgradeTo(mrImplementation.address); 24 | }; 25 | main() 26 | .then(() => process.exit(0)) 27 | .catch(error => { 28 | console.error(error); 29 | process.exit(1); 30 | }); 31 | -------------------------------------------------------------------------------- /scripts/extract-lock-reasons.js: -------------------------------------------------------------------------------- 1 | const { artifacts } = require('hardhat'); 2 | const { to } = require('../lib/helpers'); 3 | 4 | async function main() { 5 | const TokenController = artifacts.require('TokenController'); 6 | const MemberRoles = artifacts.require('MemberRoles'); 7 | 8 | const tc = await TokenController.at('0x5407381b6c251cfd498ccd4a1d877739cb7960b8'); 9 | const mr = await MemberRoles.at('0x055cc48f7968fd8640ef140610dd4038e1b03926'); 10 | 11 | const ROLE_MEMBER = 2; 12 | const memberCount = await mr.membersLength(ROLE_MEMBER); 13 | const reasons = {}; 14 | 15 | for (let i = 0; i < memberCount; i++) { 16 | const { 0: member, 1: active } = await mr.memberAtIndex(ROLE_MEMBER, i); 17 | 18 | if (!active) { 19 | console.log(`Skipping inactive member ${member}`); 20 | continue; 21 | } 22 | 23 | console.log(`Fetching reasons of ${member}`); 24 | 25 | reasons[member] = []; 26 | 27 | for (let j = 0; j < 3000; j++) { 28 | const [reason, err] = await to(tc.lockReason(member, j)); 29 | 30 | if (err) { 31 | console.log(`Failed to fetch log reason: ${err.message}. Skipping.`); 32 | break; 33 | } 34 | 35 | reasons[member].push(reason); 36 | console.log(`Found reason ${reason}`); 37 | } 38 | } 39 | 40 | require('fs').writeFileSync('reasons.json', JSON.stringify(reasons, null, 2)); 41 | console.log(JSON.stringify(reasons, null, 2)); 42 | } 43 | 44 | main().catch(e => { 45 | console.error(e); 46 | process.exit(1); 47 | }); 48 | -------------------------------------------------------------------------------- /scripts/governance/proposal-sample.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "title": "", 3 | "shortDescription": "", 4 | "description": "" 5 | }] 6 | -------------------------------------------------------------------------------- /scripts/migrate-cover-data.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat'); 2 | const { addresses, Cover } = require('@nexusmutual/deployments'); 3 | 4 | // set/change env MAINNET_ACCOUNT_KEY and MAINNET_GAS_PRICE 5 | // run command: HARDHAT_NETWORK=mainnet node scripts/migrate-cover-data.js 6 | 7 | const { MAX_FEE_GWEI = '10' } = process.env; 8 | 9 | async function main() { 10 | const signer = await ethers.getSigner(); 11 | const cover = await ethers.getContractAt(Cover, addresses.Cover, signer); 12 | 13 | const totalCovers = await cover.getCoverDataCount(); 14 | const allCoverIds = new Array(totalCovers).fill(0).map((_, i) => i + 1); 15 | 16 | const coversPerTx = 100; 17 | const gasLimit = 15000000; 18 | const maxFeePerGas = ethers.utils.parseUnits(MAX_FEE_GWEI, 'gwei'); 19 | const maxPriorityFeePerGas = ethers.utils.parseUnits('0.5', 'gwei'); 20 | 21 | while (allCoverIds.length > 0) { 22 | const coverIds = allCoverIds.splice(0, coversPerTx); 23 | console.log(`Migrating cover ids: ${coverIds}`); 24 | 25 | const overrides = { gasLimit, maxFeePerGas, maxPriorityFeePerGas }; 26 | const tx = await cover.migrateCoverDataAndPoolAllocations(coverIds, overrides); 27 | 28 | console.log(`Sent tx: ${tx.hash}`); 29 | await tx.wait(); 30 | } 31 | 32 | console.log('All covers migrated'); 33 | } 34 | 35 | main() 36 | .then(() => process.exit(0)) 37 | .catch(error => { 38 | console.error(error); 39 | process.exit(1); 40 | }); 41 | -------------------------------------------------------------------------------- /scripts/mocks/buyV1Covers.js: -------------------------------------------------------------------------------- 1 | const { config, network, ethers } = require('hardhat'); 2 | const { CONTRACTS_ADDRESSES: Addresses } = require(process.env.CONFIG_FILE); 3 | 4 | function zeroPadRight(bytes, length) { 5 | return new Uint8Array(length).fill(0).map((x, i) => bytes[i] || x); 6 | } 7 | 8 | async function main() { 9 | console.log(`Using network: ${network.name}`); 10 | console.log('Network config:', config.networks[network.name]); 11 | 12 | const [owner] = await ethers.getSigners(); 13 | const ETH = zeroPadRight(Buffer.from('ETH'), 4); 14 | 15 | const quotationData = await ethers.getContractAt('TestnetQuotationData', Addresses.LegacyQuotationData); 16 | 17 | await quotationData.addV1Cover( 18 | 30, 19 | 123, 20 | owner.address, // owner 21 | ETH, 22 | '0x6354e79f21b56c11f48bcd7c451be456d7102a36', // scAddress 23 | 0, 24 | 0, 25 | ); 26 | 27 | await quotationData.addV1Cover( 28 | 30, 29 | 123, 30 | owner.address, // owner 31 | ETH, 32 | '0x575409F8d77c12B05feD8B455815f0e54797381c', // scAddress 33 | 0, 34 | 0, 35 | ); 36 | 37 | await quotationData.addV1Cover( 38 | 30, 39 | 123, 40 | owner.address, // owner 41 | ETH, 42 | '0x8B3d70d628Ebd30D4A2ea82DB95bA2e906c71633', // scAddress 43 | 0, 44 | 0, 45 | ); 46 | 47 | console.log('Done!'); 48 | process.exit(0); 49 | } 50 | 51 | main().catch(error => { 52 | console.error('An unexpected error encountered:', error); 53 | process.exit(1); 54 | }); 55 | -------------------------------------------------------------------------------- /scripts/mocks/fund.js: -------------------------------------------------------------------------------- 1 | const { network, ethers } = require('hardhat'); 2 | 3 | const { BigNumber } = ethers; 4 | const { hexValue, isAddress, formatEther, parseEther } = ethers.utils; 5 | 6 | // this hex function produces evm-compatible hex strings: 7 | // - strips leading zeroes (0x01 -> 0x1) 8 | // - keeps one zero if the value is zero (0x00 -> 0x0) 9 | const hex = n => hexValue(BigNumber.from(n)); 10 | 11 | const send = ethers.provider.send.bind(ethers.provider); 12 | 13 | const tests = [ 14 | { node: 'hardhat', regex: /HardhatNetwork/ }, 15 | { node: 'tenderly', regex: /Tenderly/ }, 16 | ]; 17 | 18 | async function main() { 19 | console.log(`Using network: ${network.name}`); 20 | 21 | const charities = process.argv.slice(2); 22 | const invalidAddresses = charities.filter(charity => !isAddress(charity)); 23 | 24 | if (invalidAddresses.length > 0) { 25 | console.log(`Invalid addresses: ${invalidAddresses.join(', ')}`); 26 | process.exit(2); 27 | } 28 | 29 | const clientVersion = await send('web3_clientVersion', []); 30 | const test = tests.find(test => test.regex.test(clientVersion)); 31 | 32 | if (test === undefined) { 33 | console.log('Error: Can only fund accounts on hardhat or tenderly'); 34 | process.exit(3); 35 | } 36 | 37 | const { node } = test; 38 | const setBalance = async (account, value) => send(`${node}_setBalance`, [account, hex(value)]); 39 | const amount = parseEther('100'); 40 | 41 | for (const charity of charities) { 42 | console.log(`Funding ${charity} with ${formatEther(amount)} ETH`); 43 | await setBalance(charity, amount); 44 | } 45 | 46 | console.log('Done!'); 47 | process.exit(0); 48 | } 49 | 50 | main().catch(error => { 51 | console.error('An unexpected error encountered:', error); 52 | process.exit(1); 53 | }); 54 | -------------------------------------------------------------------------------- /scripts/staking-nfts.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat'); 2 | const { addresses, StakingNFT, StakingPoolFactory } = require('@nexusmutual/deployments'); 3 | 4 | async function main() { 5 | const stakingNFT = await ethers.getContractAt(StakingNFT, addresses.StakingNFT); 6 | const factory = await ethers.getContractAt(StakingPoolFactory, addresses.StakingPoolFactory); 7 | 8 | const poolCount = (await factory.stakingPoolCount()).toNumber(); 9 | const poolIds = new Array(poolCount).fill('').map((_, i) => i + 1); 10 | const poolTokens = poolIds.reduce((acc, id) => ({ ...acc, [id]: [] }), {}); 11 | 12 | const tokenCount = (await stakingNFT.totalSupply()).toNumber(); 13 | const tokenIds = new Array(tokenCount).fill('').map((_, i) => i + 1); 14 | 15 | for (const tokenId of tokenIds) { 16 | process.stdout.write('.'); 17 | const poolId = (await stakingNFT.stakingPoolOf(tokenId)).toNumber(); 18 | poolTokens[poolId].push(tokenId); 19 | } 20 | 21 | console.log('\nPool Tokens:'); 22 | 23 | for (const poolId of poolIds) { 24 | console.log(`${poolId}: [${poolTokens[poolId].join(', ')}]`); 25 | } 26 | } 27 | 28 | main() 29 | .then(() => process.exit(0)) 30 | .catch(error => { 31 | console.error(error); 32 | process.exit(1); 33 | }); 34 | -------------------------------------------------------------------------------- /scripts/staking-set-initial-pools-metadata.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat'); 2 | const { addresses, StakingPool, StakingPoolFactory } = require('@nexusmutual/deployments'); 3 | 4 | async function main() { 5 | const factory = await ethers.getContractAt(StakingPoolFactory, addresses.StakingPoolFactory); 6 | const stakingPoolCount = (await factory.stakingPoolCount()).toNumber(); 7 | const stakingPoolIds = new Array(stakingPoolCount).fill('').map((_, i) => i + 1); 8 | const cover = await ethers.getContractAt('Cover', addresses.Cover); 9 | 10 | const ipfsHashes = []; 11 | 12 | for (const poolId of stakingPoolIds) { 13 | const stakingPoolAddress = await cover.stakingPool(poolId); 14 | const stakingPool = await ethers.getContractAt(StakingPool, stakingPoolAddress); 15 | 16 | const filter = stakingPool.filters.PoolDescriptionSet(); 17 | const events = await stakingPool.queryFilter(filter, 0, 'latest'); 18 | 19 | const hash = events.length > 0 ? events[events.length - 1].args.ipfsDescriptionHash : ''; 20 | console.log(`Pool ${poolId}: ${hash}`); 21 | 22 | ipfsHashes.push(hash); 23 | } 24 | 25 | const encodedData = ethers.utils.defaultAbiCoder.encode(['string[]'], [ipfsHashes]); 26 | const functionSignature = ethers.utils.id('setInitialMetadata(string[])').slice(0, 10); 27 | const data = functionSignature + encodedData.slice(2); 28 | 29 | console.log('Tx details:'); 30 | console.log('from: [any ab member]'); 31 | console.log('to:', addresses.StakingProducts); 32 | console.log('msg.data', data); 33 | } 34 | 35 | main() 36 | .then(() => process.exit(0)) 37 | .catch(error => { 38 | console.error(error); 39 | process.exit(1); 40 | }); 41 | -------------------------------------------------------------------------------- /scripts/timetravel.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat'); 2 | 3 | const [numOfDays] = process.argv.slice(2); 4 | 5 | const main = async () => { 6 | await ethers.provider.send('evm_increaseTime', numOfDays ? [86400 * numOfDays] : [86400 * 3]); 7 | await ethers.provider.send('evm_mine', []); 8 | }; 9 | 10 | main().catch(error => { 11 | console.error('An unexpected error encountered:', error); 12 | process.exit(1); 13 | }); 14 | -------------------------------------------------------------------------------- /scripts/total-active-cover.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config(); 2 | const { 3 | ethers: { getContractAt }, 4 | } = require('hardhat'); 5 | const { addresses } = require('@nexusmutual/deployments'); 6 | 7 | const main = async () => { 8 | const Cover = await getContractAt('Cover', addresses.Cover); 9 | const Pool = await getContractAt('Pool', addresses.Pool); 10 | 11 | const assets = await Pool.getAssets(); 12 | // const coverCount = await Cover.coverDataCount(); 13 | 14 | // console.log(assetIds); 15 | // console.log(coverCount); 16 | const totalActiveCovers = []; 17 | for (let i = 0; i < assets.length; i++) { 18 | const totalActiveCoverInAsset = await Cover.totalActiveCoverInAsset(i); 19 | totalActiveCovers.push(totalActiveCoverInAsset); 20 | } 21 | 22 | for (let i = 0; i < totalActiveCovers.length; i++) { 23 | if (totalActiveCovers[i].gt(0)) { 24 | const { lastBucketUpdateId } = await Cover.activeCover(i); 25 | console.log(lastBucketUpdateId); 26 | } 27 | } 28 | }; 29 | 30 | if (require.main === module) { 31 | main(process.argv[1]).catch(e => { 32 | console.log('Unhandled error encountered: ', e.stack); 33 | process.exit(1); 34 | }); 35 | } 36 | 37 | module.exports = main; 38 | -------------------------------------------------------------------------------- /test/fork/index.js: -------------------------------------------------------------------------------- 1 | describe('fork tests', function () { 2 | require('./recalculate-effective-weights-bug-fix'); 3 | require('./staked-product-allowed-pools'); 4 | require('./migrated-claims'); 5 | require('./recalculate-effective-weights'); 6 | require('./withdraw-switch-membership-restrictions'); 7 | require('./run-basic-functionality-tests'); 8 | require('./cowswap-swaps'); 9 | require('./withdraw-enzyme-shares'); 10 | }); 11 | -------------------------------------------------------------------------------- /test/integration/Cover/changeCoverNFTDescriptor.js: -------------------------------------------------------------------------------- 1 | const { expect } = require('chai'); 2 | const { ethers } = require('hardhat'); 3 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 4 | 5 | const setup = require('../setup'); 6 | 7 | describe('changeCoverNFTDescriptor', function () { 8 | it('should change coverNFTDescriptor address', async function () { 9 | const fixture = await loadFixture(setup); 10 | const { cover, master, coverNFT } = fixture.contracts; 11 | const { 12 | advisoryBoardMembers: [abMember], 13 | } = fixture.accounts; 14 | 15 | const coverNFTDescriptorAddressBefore = await coverNFT.nftDescriptor(); 16 | 17 | const coverNFTDescriptor = await ethers.deployContract('CoverNFTDescriptor', [master.address]); 18 | 19 | await cover.connect(abMember).changeCoverNFTDescriptor(coverNFTDescriptor.address); 20 | 21 | const coverNFTDescriptorAddressAfter = await coverNFT.nftDescriptor(); 22 | 23 | expect(coverNFTDescriptorAddressAfter).to.not.be.equal(coverNFTDescriptorAddressBefore); 24 | expect(coverNFTDescriptorAddressAfter).to.equal(coverNFTDescriptor.address); 25 | }); 26 | 27 | it('should fail to change coverNFTDescriptor address if the caller is not ab member', async function () { 28 | const fixture = await loadFixture(setup); 29 | const { cover, master } = fixture.contracts; 30 | const { 31 | members: [member], 32 | } = fixture.accounts; 33 | 34 | const coverNFTDescriptor = await ethers.deployContract('CoverNFTDescriptor', [master.address]); 35 | 36 | await expect(cover.connect(member).changeCoverNFTDescriptor(coverNFTDescriptor.address)).to.be.revertedWith( 37 | 'Caller is not an advisory board member', 38 | ); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /test/integration/Cover/changeStakingNFTDescriptor.js: -------------------------------------------------------------------------------- 1 | const { expect } = require('chai'); 2 | const { ethers } = require('hardhat'); 3 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 4 | 5 | const setup = require('../setup'); 6 | 7 | describe('changeStakingNFTDescriptor', function () { 8 | it('should change stakingNFTDescriptor address', async function () { 9 | const fixture = await loadFixture(setup); 10 | const { cover, stakingNFT } = fixture.contracts; 11 | const { 12 | advisoryBoardMembers: [abMember], 13 | } = fixture.accounts; 14 | 15 | const coverNFTDescriptorAddressBefore = await stakingNFT.nftDescriptor(); 16 | 17 | const stakingNFTDescriptor = await ethers.deployContract('StakingNFTDescriptor'); 18 | 19 | await cover.connect(abMember).changeStakingNFTDescriptor(stakingNFTDescriptor.address); 20 | 21 | const coverNFTDescriptorAddressAfter = await stakingNFT.nftDescriptor(); 22 | 23 | expect(coverNFTDescriptorAddressAfter).to.not.be.equal(coverNFTDescriptorAddressBefore); 24 | expect(coverNFTDescriptorAddressAfter).to.equal(stakingNFTDescriptor.address); 25 | }); 26 | 27 | it('should fail to change stakingNFTDescriptor address if the caller is not ab member', async function () { 28 | const fixture = await loadFixture(setup); 29 | const { cover } = fixture.contracts; 30 | const { 31 | members: [member], 32 | } = fixture.accounts; 33 | 34 | const stakingNFTDescriptor = await ethers.deployContract('StakingNFTDescriptor'); 35 | 36 | await expect(cover.connect(member).changeStakingNFTDescriptor(stakingNFTDescriptor.address)).to.be.revertedWith( 37 | 'Caller is not an advisory board member', 38 | ); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /test/integration/Governance/proposalFixture.js: -------------------------------------------------------------------------------- 1 | const { hex } = require('../../../lib/helpers'); 2 | const { ethers } = require('hardhat'); 3 | const { 4 | utils: { defaultAbiCoder }, 5 | } = ethers; 6 | 7 | module.exports = { 8 | proposalTitle: 'Title', 9 | proposalSD: 'SD', 10 | proposalDescHash: 'Description', 11 | categoryId: 3, 12 | solutionHash: 'Solution', 13 | action: defaultAbiCoder.encode( 14 | [ 15 | 'string', 16 | 'uint256', 17 | 'uint256', 18 | 'uint256', 19 | 'uint256[]', 20 | 'uint256', 21 | 'string', 22 | 'address', 23 | 'bytes2', 24 | 'uint256[]', 25 | 'string', 26 | ], 27 | ['Test Proposal', 2, 60, 15, [2], 300, '', '0x' + '0'.repeat(40), hex('GV'), [0, 0, 60, 0], 'proposalFunction()'], 28 | ), 29 | }; 30 | -------------------------------------------------------------------------------- /test/integration/Governance/submitProposalWithSolution.js: -------------------------------------------------------------------------------- 1 | const { expect } = require('chai'); 2 | const { proposalTitle, proposalDescHash, proposalSD, categoryId, solutionHash, action } = require('./proposalFixture'); 3 | const setup = require('../setup'); 4 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 5 | 6 | async function submitProposalWithSolutionSetup() { 7 | const fixture = await loadFixture(setup); 8 | const { gv: governance } = fixture.contracts; 9 | const [member] = fixture.accounts.members; 10 | const proposalId = await governance.getProposalLength(); 11 | 12 | await governance.connect(member).createProposal(proposalTitle, proposalSD, proposalDescHash, categoryId); 13 | 14 | return { 15 | ...fixture, 16 | proposalId, 17 | }; 18 | } 19 | 20 | describe('submitProposalWithSolution', function () { 21 | it('should fail to submit proposal proposal if sender role is not authorized', async function () { 22 | const fixture = await loadFixture(submitProposalWithSolutionSetup); 23 | const { proposalId } = fixture; 24 | const { gv: governance } = fixture.contracts; 25 | const [, member] = fixture.accounts.members; 26 | 27 | await expect( 28 | governance.connect(member).submitProposalWithSolution(proposalId, solutionHash, action), 29 | ).to.revertedWith('Not allowed'); 30 | }); 31 | 32 | it('should submit a solution for a proposal', async function () { 33 | const fixture = await loadFixture(submitProposalWithSolutionSetup); 34 | const { proposalId } = fixture; 35 | const { gv: governance } = fixture.contracts; 36 | const [member] = fixture.accounts.members; 37 | await governance.connect(member).submitProposalWithSolution(proposalId, solutionHash, action); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /test/integration/StakingProducts/changeStakingPoolFactoryOperator.js: -------------------------------------------------------------------------------- 1 | const { expect } = require('chai'); 2 | const { ethers } = require('hardhat'); 3 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 4 | 5 | const setup = require('../setup'); 6 | const { getGovernanceSigner } = require('../utils/enroll'); 7 | 8 | describe('changeStakingPoolFactoryOperator', function () { 9 | it('should change Staking Pool Factory operator', async function () { 10 | const fixture = await loadFixture(setup); 11 | const { stakingProducts, spf, gv } = fixture.contracts; 12 | const governanceSigner = await getGovernanceSigner(gv); 13 | const operator = ethers.Wallet.createRandom(); 14 | 15 | const stakingPoolFactoryOperatorBefore = await spf.operator(); 16 | 17 | await stakingProducts.connect(governanceSigner).changeStakingPoolFactoryOperator(operator.address); 18 | 19 | const stakingPoolFactoryOperatorAfter = await spf.operator(); 20 | 21 | expect(stakingPoolFactoryOperatorAfter).to.not.be.equal(stakingPoolFactoryOperatorBefore); 22 | expect(stakingPoolFactoryOperatorAfter).to.equal(operator.address); 23 | }); 24 | 25 | it('should fail to change Staking Pool Factory operator if the caller is not internal', async function () { 26 | const fixture = await loadFixture(setup); 27 | const { stakingProducts } = fixture.contracts; 28 | const { 29 | members: [member], 30 | } = fixture.accounts; 31 | const operator = ethers.Wallet.createRandom(); 32 | 33 | await expect(stakingProducts.connect(member).changeStakingPoolFactoryOperator(operator.address)).to.be.revertedWith( 34 | 'Caller is not an internal contract', 35 | ); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /test/integration/utils/assetPricing.js: -------------------------------------------------------------------------------- 1 | const { BigNumber } = require('ethers'); 2 | const { divCeil } = require('../utils').bnMath; 3 | const { roundUpToNearestAllocationUnit } = require('../../unit/StakingPool/helpers'); 4 | 5 | // Set assetToEthRate to 0 for ETH 6 | async function assetToEthWithPrecisionLoss(coverAmountInAsset, assetToEthRate, config, nxmEthPrice) { 7 | let expectedAmountETH = coverAmountInAsset; 8 | 9 | // convert to ETH if there is an exchange rate 10 | if (!BigNumber.from(assetToEthRate).isZero()) { 11 | expectedAmountETH = roundUpToNearestAllocationUnit( 12 | BigNumber.from(assetToEthRate).mul(coverAmountInAsset).div(config.ONE_NXM), 13 | config.NXM_PER_ALLOCATION_UNIT, 14 | ); 15 | } 16 | 17 | // convert to NXM and back to ETH with same precision loss as contracts 18 | const coverAmountInNXM = roundUpToNearestAllocationUnit( 19 | divCeil(BigNumber.from(expectedAmountETH).mul(config.ONE_NXM), nxmEthPrice), 20 | config.NXM_PER_ALLOCATION_UNIT, 21 | ); 22 | 23 | return coverAmountInNXM.mul(nxmEthPrice).div(config.ONE_NXM); 24 | } 25 | 26 | // Replicates the amount stored when buying cover with asset other than NXM 27 | async function assetWithPrecisionLoss(pool, amountInAsset, assetID, config) { 28 | const nxmPriceInCoverAsset = await pool.getInternalTokenPriceInAsset(assetID); 29 | const amountInNXM = roundUpToNearestAllocationUnit( 30 | divCeil(amountInAsset.mul(config.ONE_NXM), nxmPriceInCoverAsset), 31 | config.NXM_PER_ALLOCATION_UNIT, 32 | ); 33 | return amountInNXM.mul(nxmPriceInCoverAsset).div(config.ONE_NXM); 34 | } 35 | 36 | module.exports = { 37 | assetToEthWithPrecisionLoss, 38 | assetWithPrecisionLoss, 39 | }; 40 | -------------------------------------------------------------------------------- /test/integration/utils/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('../../utils'); 2 | -------------------------------------------------------------------------------- /test/layout/selectors.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat'); 2 | const { expect } = require('chai'); 3 | 4 | const proxyContracts = [ 5 | 'NXMaster', 6 | 'Governance', 7 | 'MemberRoles', 8 | 'ProposalCategory', 9 | 'TokenController', 10 | 'IndividualClaims', 11 | 'Assessment', 12 | 'Cover', 13 | 'CoverProducts', 14 | 'StakingProducts', 15 | 'Ramm', 16 | 'SafeTracker', 17 | ]; 18 | 19 | describe('Selector collisions', function () { 20 | it('compare selectors of proxy and upgradable contracts', async function () { 21 | // get proxy selectors 22 | const { interface: proxyInterface } = await ethers.getContractFactory('OwnedUpgradeabilityProxy'); 23 | const protectedFunctions = ['proxyOwner', 'transferProxyOwnership', 'upgradeTo']; 24 | const protectedSelectors = protectedFunctions.map(fn => proxyInterface.getSighash(fn)); 25 | 26 | // check it fails with a known collision 27 | const { interface: collidingInterface } = await ethers.getContractFactory('ProxySignatureCollider'); 28 | 29 | const foundClashes = protectedSelectors.map(selector => { 30 | try { 31 | return collidingInterface.getFunction(selector); 32 | } catch (e) { 33 | return false; 34 | } 35 | }); 36 | 37 | expect(foundClashes.filter(f => f !== false).length).to.equal(1); 38 | 39 | // make sure all protected selectors are not present in the proxy contracts 40 | for (const contract of proxyContracts) { 41 | const { interface: contractInterface } = await ethers.getContractFactory(contract); 42 | for (const signature of protectedSelectors) { 43 | expect(() => contractInterface.getFunction(signature)).to.throw('no matching function'); 44 | } 45 | } 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /test/layout/storage/mainnetLayout.json: -------------------------------------------------------------------------------- 1 | v2.11.0.json -------------------------------------------------------------------------------- /test/unit/Assessment/constructor.js: -------------------------------------------------------------------------------- 1 | const { expect } = require('chai'); 2 | const { ethers } = require('hardhat'); 3 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 4 | const { setup } = require('./setup'); 5 | 6 | describe('constructor', function () { 7 | it('should set nxm address correctly', async function () { 8 | const fixture = await loadFixture(setup); 9 | const { nxm } = fixture.contracts; 10 | 11 | const Assessment = await ethers.getContractFactory('Assessment'); 12 | const assessment = await Assessment.deploy(nxm.address); 13 | const nxmAddress = await assessment.nxm(); 14 | 15 | expect(nxmAddress).to.be.equal(nxm.address); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /test/unit/Assessment/getAssessmentsCount.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat'); 2 | const { expect } = require('chai'); 3 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 4 | const { setup } = require('./setup'); 5 | const { parseEther } = ethers.utils; 6 | 7 | describe('getAssessmentsCount', function () { 8 | it('returns the total number of claims', async function () { 9 | const fixture = await loadFixture(setup); 10 | const { assessment, individualClaims } = fixture.contracts; 11 | { 12 | const count = await assessment.getAssessmentsCount(); 13 | expect(count).to.be.equal(0); 14 | } 15 | await individualClaims.submitClaim(0, parseEther('100'), ''); 16 | { 17 | const count = await assessment.getAssessmentsCount(); 18 | expect(count).to.be.equal(1); 19 | } 20 | await individualClaims.submitClaim(0, parseEther('100'), ''); 21 | { 22 | const count = await assessment.getAssessmentsCount(); 23 | expect(count).to.be.equal(2); 24 | } 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /test/unit/Assessment/getPoll.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat'); 2 | const { expect } = require('chai'); 3 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 4 | const { setup } = require('./setup'); 5 | const { parseEther } = ethers.utils; 6 | 7 | describe('getPoll', function () { 8 | it('returns the poll of a given assessment', async function () { 9 | const fixture = await loadFixture(setup); 10 | const { assessment, individualClaims } = fixture.contracts; 11 | const user = fixture.accounts.members[0]; 12 | await assessment.connect(user).stake(parseEther('100')); 13 | await individualClaims.submitClaim(0, parseEther('100'), ''); 14 | { 15 | const targetAssessment = await assessment.assessments(0); 16 | const poll = await assessment.getPoll(0); 17 | expect(poll.accepted).to.be.equal(targetAssessment.poll.accepted); 18 | expect(poll.denied).to.be.equal(targetAssessment.poll.denied); 19 | expect(poll.start).to.be.equal(targetAssessment.poll.start); 20 | expect(poll.end).to.be.equal(targetAssessment.poll.end); 21 | } 22 | await assessment.connect(user).castVotes([0], [true], ['Assessment data hash'], 0); 23 | { 24 | const targetAssessment = await assessment.assessments(0); 25 | const poll = await assessment.getPoll(0); 26 | expect(poll.accepted).to.be.equal(targetAssessment.poll.accepted); 27 | expect(poll.denied).to.be.equal(targetAssessment.poll.denied); 28 | expect(poll.start).to.be.equal(targetAssessment.poll.start); 29 | expect(poll.end).to.be.equal(targetAssessment.poll.end); 30 | } 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /test/unit/AssessmentViewer/getRewards.js: -------------------------------------------------------------------------------- 1 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 2 | const { ethers } = require('hardhat'); 3 | const { expect } = require('chai'); 4 | 5 | const { setup } = require('./setup'); 6 | 7 | const { parseEther } = ethers.utils; 8 | 9 | describe('getRewards', function () { 10 | it('getRewards return assessmentRewards', async function () { 11 | const fixture = await loadFixture(setup); 12 | const [member] = fixture.accounts.members; 13 | const { assessment, assessmentViewer } = fixture.contracts; 14 | 15 | const totalPendingAmountInNXM = parseEther('1'); 16 | const withdrawableAmountInNXM = parseEther('2'); 17 | const withdrawableUntilIndex = 1; 18 | await assessment.setRewards(totalPendingAmountInNXM, withdrawableAmountInNXM, withdrawableUntilIndex); 19 | 20 | const assessmentRewards = await assessmentViewer.getRewards(member.address); 21 | expect(assessmentRewards.totalPendingAmountInNXM).to.equal(totalPendingAmountInNXM); 22 | expect(assessmentRewards.withdrawableAmountInNXM).to.equal(withdrawableAmountInNXM); 23 | expect(assessmentRewards.withdrawableUntilIndex.toString()).to.equal('1'); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /test/unit/AssessmentViewer/setup.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat'); 2 | 3 | const { hex } = require('../../../lib/helpers'); 4 | const { getAccounts } = require('../utils').accounts; 5 | 6 | const daysToSeconds = days => days * 24 * 60 * 60; 7 | 8 | async function setup() { 9 | const accounts = await getAccounts(); 10 | const master = await ethers.deployContract('MasterMock'); 11 | const stakeLockupPeriod = daysToSeconds(2); 12 | const assessment = await ethers.deployContract('AVMockAssessment', [stakeLockupPeriod]); 13 | 14 | await master.setLatestAddress(hex('AS'), assessment.address); 15 | 16 | const assessmentViewer = await ethers.deployContract('AssessmentViewer', [master.address]); 17 | 18 | return { 19 | accounts, 20 | contracts: { assessment, assessmentViewer }, 21 | config: { stakeLockupPeriod }, 22 | }; 23 | } 24 | 25 | module.exports = { 26 | setup, 27 | }; 28 | -------------------------------------------------------------------------------- /test/unit/Cover/constructor.js: -------------------------------------------------------------------------------- 1 | const { expect } = require('chai'); 2 | const { ethers } = require('hardhat'); 3 | 4 | describe('constructor', function () { 5 | it('should set variables correctly', async function () { 6 | const coverNFT = '0x0000000000000000000000000000000000000001'; 7 | const stakingNFT = '0x0000000000000000000000000000000000000002'; 8 | const stakingPoolFactory = '0x0000000000000000000000000000000000000003'; 9 | const stakingPoolImplementation = '0x0000000000000000000000000000000000000004'; 10 | 11 | const Cover = await ethers.getContractFactory('Cover'); 12 | const cover = await Cover.deploy(coverNFT, stakingNFT, stakingPoolFactory, stakingPoolImplementation); 13 | 14 | expect(await cover.coverNFT()).to.equal(coverNFT); 15 | expect(await cover.stakingNFT()).to.equal(stakingNFT); 16 | expect(await cover.stakingPoolFactory()).to.equal(stakingPoolFactory); 17 | expect(await cover.stakingPoolImplementation()).to.equal(stakingPoolImplementation); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /test/unit/CoverBroker/setup.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat'); 2 | 3 | const { setEtherBalance } = require('../utils').evm; 4 | const { AddressZero } = ethers.constants; 5 | const { parseEther } = ethers.utils; 6 | 7 | async function setup() { 8 | const coverBrokerOwner = ethers.Wallet.createRandom().connect(ethers.provider); 9 | await setEtherBalance(coverBrokerOwner.address, parseEther('1000000')); 10 | 11 | const dai = await ethers.deployContract('ERC20Mock'); 12 | const memberRoles = await ethers.deployContract('MemberRolesMock'); 13 | const coverBroker = await ethers.deployContract('CoverBroker', [ 14 | AddressZero, 15 | memberRoles.address, 16 | AddressZero, 17 | AddressZero, 18 | coverBrokerOwner.address, 19 | ]); 20 | 21 | await memberRoles.setRole(coverBroker.address, 2); 22 | 23 | return { 24 | coverBrokerOwner, 25 | contracts: { 26 | dai, 27 | coverBroker, 28 | }, 29 | }; 30 | } 31 | 32 | module.exports = { setup }; 33 | -------------------------------------------------------------------------------- /test/unit/CoverNFT/setup.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat'); 2 | const { getAccounts } = require('../../utils/accounts'); 3 | 4 | async function setup() { 5 | const accounts = await getAccounts(); 6 | const [operator] = accounts.members; 7 | 8 | const master = await ethers.deployContract('MasterMock'); 9 | 10 | const coverNFTDescriptor = await ethers.deployContract('CoverNFTDescriptor', [master.address]); 11 | const coverNFT = await ethers.deployContract('CoverNFT', [ 12 | 'NexusMutual Cover', 13 | 'NXMC', 14 | operator.address, 15 | coverNFTDescriptor.address, 16 | ]); 17 | 18 | return { 19 | coverNFT, 20 | accounts, 21 | }; 22 | } 23 | 24 | module.exports = setup; 25 | -------------------------------------------------------------------------------- /test/unit/CoverViewer/setup.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat'); 2 | const { hex } = require('../utils').helpers; 3 | 4 | async function setup() { 5 | const MasterMock = await ethers.getContractFactory('MasterMock'); 6 | const Cover = await ethers.getContractFactory('CVMockCover'); 7 | const CoverViewer = await ethers.getContractFactory('CoverViewer'); 8 | 9 | const master = await MasterMock.deploy(); 10 | const cover = await Cover.deploy(); 11 | const coverViewer = await CoverViewer.deploy(master.address); 12 | 13 | // set contract addresses 14 | await master.setLatestAddress(hex('CO'), cover.address); 15 | 16 | return { 17 | master, 18 | cover, 19 | coverViewer, 20 | }; 21 | } 22 | 23 | module.exports = setup; 24 | -------------------------------------------------------------------------------- /test/unit/IndividualClaims/constructor.js: -------------------------------------------------------------------------------- 1 | const { expect } = require('chai'); 2 | const { ethers } = require('hardhat'); 3 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 4 | const { setup } = require('./setup'); 5 | 6 | describe('constructor', function () { 7 | it('should set nxm and coverNFT addresses correctly', async function () { 8 | const fixture = await loadFixture(setup); 9 | const { coverNFT } = fixture.contracts; 10 | 11 | const individualClaims = await ethers.deployContract('IndividualClaims', [coverNFT.address]); 12 | await individualClaims.deployed(); 13 | 14 | const coverNFTAddress = await individualClaims.coverNFT(); 15 | expect(coverNFTAddress).to.be.equal(coverNFT.address); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /test/unit/IndividualClaims/getClaimsCount.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat'); 2 | const { expect } = require('chai'); 3 | 4 | const { createMockCover, submitClaim } = require('./helpers'); 5 | const { mineNextBlock, setNextBlockTime } = require('../../utils/evm'); 6 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 7 | const { setup } = require('./setup'); 8 | 9 | const daysToSeconds = days => days * 24 * 60 * 60; 10 | 11 | const setTime = async timestamp => { 12 | await setNextBlockTime(timestamp); 13 | await mineNextBlock(); 14 | }; 15 | 16 | describe('getClaimsCount', function () { 17 | it('returns the total number of claims', async function () { 18 | const fixture = await loadFixture(setup); 19 | const { individualClaims, cover } = fixture.contracts; 20 | const [coverOwner] = fixture.accounts.members; 21 | 22 | await createMockCover(cover, { 23 | owner: coverOwner.address, 24 | period: daysToSeconds(365), 25 | gracePeriod: daysToSeconds(30), 26 | }); 27 | 28 | { 29 | const count = await individualClaims.getClaimsCount(); 30 | expect(count).to.be.equal(0); 31 | } 32 | 33 | await submitClaim(fixture)({ coverId: 1, sender: coverOwner }); 34 | 35 | { 36 | const count = await individualClaims.getClaimsCount(); 37 | expect(count).to.be.equal(1); 38 | } 39 | 40 | for (let i = 0; i < 6; i++) { 41 | const latestBlock = await ethers.provider.getBlock('latest'); 42 | await setTime(latestBlock.timestamp + daysToSeconds(30)); 43 | await submitClaim(fixture)({ coverId: 1, sender: coverOwner }); 44 | } 45 | 46 | { 47 | const count = await individualClaims.getClaimsCount(); 48 | expect(count).to.be.equal(7); 49 | } 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /test/unit/MCR/common.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat'); 2 | const { BigNumber } = ethers; 3 | const { hex } = require('../utils').helpers; 4 | 5 | const MAX_PERCENTAGE_ADJUSTMENT = BigNumber.from('100'); 6 | 7 | async function initMCR(params) { 8 | const { mcrValue, desiredMCR, lastUpdateTime, maxMCRIncrement, gearingFactor, minUpdateTime, master } = params; 9 | const { timestamp: currentTime } = await ethers.provider.getBlock('latest'); 10 | 11 | const DisposableMCR = await ethers.getContractFactory('DisposableMCR'); 12 | const MCR = await ethers.getContractFactory('MCR'); 13 | 14 | // deploy disposable mcr and initialize values 15 | const disposableMCR = await DisposableMCR.deploy( 16 | mcrValue, 17 | desiredMCR, 18 | lastUpdateTime || currentTime, 19 | maxMCRIncrement, 20 | gearingFactor, 21 | minUpdateTime, 22 | ); 23 | 24 | const block = await ethers.provider.getBlock('latest'); 25 | const mcrUpdateDeadline = block.timestamp + 30 * 24 * 3600; 26 | 27 | // deploy mcr with fake master 28 | const mcr = await MCR.deploy(disposableMCR.address, mcrUpdateDeadline); 29 | 30 | // trigger initialize and switch master address 31 | await disposableMCR.initializeNextMcr(mcr.address, master.address); 32 | 33 | // set mcr address on master 34 | await master.setLatestAddress(hex('MC'), mcr.address); 35 | 36 | return mcr; 37 | } 38 | 39 | module.exports = { 40 | initMCR, 41 | MAX_PERCENTAGE_ADJUSTMENT, 42 | }; 43 | -------------------------------------------------------------------------------- /test/unit/MemberRoles/changeMaxABCount.js: -------------------------------------------------------------------------------- 1 | const { expect } = require('chai'); 2 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 3 | const { setup } = require('./setup'); 4 | 5 | describe('changeMaxABCount', function () { 6 | const newMaxABCount = 2; 7 | 8 | it('should change max AB count', async function () { 9 | const fixture = await loadFixture(setup); 10 | const { memberRoles } = fixture.contracts; 11 | const { governanceContracts } = fixture.accounts; 12 | 13 | const maxABCountBefore = await memberRoles.maxABCount(); 14 | await memberRoles.connect(governanceContracts[0]).changeMaxABCount(newMaxABCount); 15 | const maxABCountAfter = await memberRoles.maxABCount(); 16 | 17 | expect(maxABCountBefore).not.to.be.eq(maxABCountAfter); 18 | expect(maxABCountAfter).to.be.eq(newMaxABCount); 19 | }); 20 | 21 | it('should revert if the caller is not authorized to govern', async function () { 22 | const fixture = await loadFixture(setup); 23 | const { memberRoles } = fixture.contracts; 24 | const { defaultSender } = fixture.accounts; 25 | 26 | await expect(memberRoles.connect(defaultSender).changeMaxABCount(newMaxABCount)).to.be.revertedWith( 27 | 'Caller is not authorized to govern', 28 | ); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /test/unit/MemberRoles/swapABMember.js: -------------------------------------------------------------------------------- 1 | const { Role } = require('../utils').constants; 2 | const { expect } = require('chai'); 3 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 4 | const { setup } = require('./setup'); 5 | 6 | describe('swapABMember', function () { 7 | it('removes address from AdvisoryBoard and add another one', async function () { 8 | const fixture = await loadFixture(setup); 9 | const { memberRoles } = fixture.contracts; 10 | const { advisoryBoardMembers, governanceContracts } = fixture.accounts; 11 | const [oldABMember, newABMember] = advisoryBoardMembers; 12 | 13 | await memberRoles.connect(governanceContracts[0]).swapABMember(newABMember.address, oldABMember.address); 14 | const hasABMemberRoleOldMember = await memberRoles.checkRole(oldABMember.address, Role.AdvisoryBoard); 15 | const hasABMemberRoleNewMember = await memberRoles.checkRole(newABMember.address, Role.AdvisoryBoard); 16 | 17 | expect(hasABMemberRoleOldMember).to.be.equal(false); 18 | expect(hasABMemberRoleNewMember).to.be.equal(true); 19 | }); 20 | 21 | it('should allow only authorized addresses to swap AB member', async function () { 22 | const fixture = await loadFixture(setup); 23 | const { memberRoles } = fixture.contracts; 24 | const { advisoryBoardMembers } = fixture.accounts; 25 | const [oldABMember, newABMember] = advisoryBoardMembers; 26 | 27 | await expect( 28 | memberRoles.connect(newABMember).swapABMember(newABMember.address, oldABMember.address), 29 | ).to.be.revertedWithCustomError(memberRoles, 'NotAuthorized'); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /test/unit/MemberRoles/switchMembershipOf.js: -------------------------------------------------------------------------------- 1 | const { Role } = require('../utils').constants; 2 | const { expect } = require('chai'); 3 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 4 | const { setup } = require('./setup'); 5 | 6 | describe('switchMembershipOf', function () { 7 | it('changes membership to another address', async function () { 8 | const fixture = await loadFixture(setup); 9 | const { master, memberRoles } = fixture.contracts; 10 | const [oldMember] = fixture.accounts.members; 11 | const [newMember] = fixture.accounts.nonMembers; 12 | const [internalContract] = fixture.accounts.internalContracts; 13 | 14 | expect(await memberRoles.checkRole(oldMember.address, Role.Member)).to.be.equal(true); 15 | expect(await memberRoles.checkRole(newMember.address, Role.Member)).to.be.equal(false); 16 | 17 | await master.enrollInternal(internalContract.address); 18 | await memberRoles.connect(internalContract).switchMembershipOf(oldMember.address, newMember.address); 19 | 20 | expect(await memberRoles.checkRole(oldMember.address, Role.Member)).to.be.equal(false); 21 | expect(await memberRoles.checkRole(newMember.address, Role.Member)).to.be.equal(true); 22 | }); 23 | 24 | it('should revert if not called by internal contract', async function () { 25 | const fixture = await loadFixture(setup); 26 | const { memberRoles } = fixture.contracts; 27 | const [oldMember] = fixture.accounts.members; 28 | const [newMember] = fixture.accounts.nonMembers; 29 | 30 | await expect(memberRoles.switchMembershipOf(oldMember.address, newMember.address)).to.be.revertedWith( 31 | 'Caller is not an internal contract', 32 | ); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /test/unit/MemberRoles/updateRole.js: -------------------------------------------------------------------------------- 1 | const { Role } = require('../utils').constants; 2 | const { expect } = require('chai'); 3 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 4 | const { setup } = require('./setup'); 5 | 6 | describe('updateRole', function () { 7 | it('should update a role of a member', async function () { 8 | const fixture = await loadFixture(setup); 9 | const { memberRoles } = fixture.contracts; 10 | const { advisoryBoardMembers, governanceContracts } = fixture.accounts; 11 | const [member] = advisoryBoardMembers; 12 | 13 | await memberRoles.connect(governanceContracts[0]).updateRole(member.address, Role.Member, false); 14 | }); 15 | 16 | it('should revert if role already active', async function () { 17 | const fixture = await loadFixture(setup); 18 | const { memberRoles } = fixture.contracts; 19 | const { advisoryBoardMembers, governanceContracts } = fixture.accounts; 20 | const [member] = advisoryBoardMembers; 21 | 22 | await expect(memberRoles.connect(governanceContracts[0]).updateRole(member.address, Role.Member, true)).to.be 23 | .reverted; 24 | }); 25 | it('should revert if role already inactive', async function () { 26 | const fixture = await loadFixture(setup); 27 | const { memberRoles } = fixture.contracts; 28 | const { advisoryBoardMembers, governanceContracts } = fixture.accounts; 29 | const [member] = advisoryBoardMembers; 30 | 31 | await memberRoles.connect(governanceContracts[0]).updateRole(member.address, Role.Member, false); 32 | await expect(memberRoles.connect(governanceContracts[0]).updateRole(member.address, Role.Member, false)).to.be 33 | .reverted; 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /test/unit/NXMaster/getters.js: -------------------------------------------------------------------------------- 1 | const { assert } = require('chai'); 2 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 3 | const setup = require('./setup'); 4 | const { hex } = require('../utils').helpers; 5 | 6 | describe('getters', function () { 7 | it('retrieves existing contracts using getInternalContracts', async function () { 8 | const fixture = await loadFixture(setup); 9 | const { master, governance } = fixture; 10 | 11 | const { _contractCodes, _contractAddresses } = await master.getInternalContracts(); 12 | 13 | assert.equal(_contractCodes.length, 1); 14 | assert.equal(_contractAddresses.length, 1); 15 | assert.equal(_contractCodes[0], hex('GV')); 16 | assert.equal(_contractAddresses[0], governance.address); 17 | }); 18 | 19 | it('retrieves existing contracts using getLatestAddress', async function () { 20 | const fixture = await loadFixture(setup); 21 | const { master, governance } = fixture; 22 | 23 | const address = await master.getLatestAddress(hex('GV')); 24 | 25 | assert.equal(address, governance.address); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /test/unit/NXMaster/setup.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat'); 2 | const { getAccounts } = require('../../utils/accounts'); 3 | 4 | const { ContractTypes } = require('../utils').constants; 5 | const { hex } = require('../utils').helpers; 6 | 7 | async function setup() { 8 | const accounts = await getAccounts(); 9 | const master = await ethers.deployContract('DisposableNXMaster'); 10 | const governance = await ethers.deployContract('MSMockGovernance'); 11 | const token = await ethers.deployContract('NXMTokenMock'); 12 | 13 | const { defaultSender } = accounts; 14 | 15 | await governance.changeMasterAddress(master.address); 16 | 17 | const codes = ['GV']; 18 | const addresses = [governance.address]; 19 | const contractTypes = [ContractTypes.Replaceable]; 20 | await master.initialize( 21 | defaultSender.address, 22 | token.address, 23 | defaultSender.address, 24 | codes.map(hex), // codes 25 | contractTypes, // types 26 | addresses, // addresses 27 | ); 28 | 29 | return { 30 | master, 31 | token, 32 | governance, 33 | accounts, 34 | }; 35 | } 36 | 37 | module.exports = setup; 38 | -------------------------------------------------------------------------------- /test/unit/NXMaster/updateOwnerParameters.js: -------------------------------------------------------------------------------- 1 | const { 2 | constants: { AddressZero }, 3 | } = require('ethers'); 4 | const { assert, expect } = require('chai'); 5 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 6 | const setup = require('./setup'); 7 | 8 | const { NXMasterOwnerParamType } = require('../utils').constants; 9 | 10 | describe('updateOwnerParameters', function () { 11 | it('should revert when called by non governance addresses', async function () { 12 | const fixture = await loadFixture(setup); 13 | const { master, accounts } = fixture; 14 | const param = NXMasterOwnerParamType.kycAuthority; 15 | const [nonMember] = accounts.nonMembers; 16 | 17 | await expect(master.connect(nonMember).updateOwnerParameters(param, AddressZero)).to.be.revertedWith( 18 | 'Not authorized', 19 | ); 20 | }); 21 | 22 | it('should correctly update emergency admin parameter', async function () { 23 | const fixture = await loadFixture(setup); 24 | const { master, governance } = fixture; 25 | 26 | const newAdmin = '0x0000000000000000000000000000000000000001'; 27 | await governance.updateOwnerParameters(NXMasterOwnerParamType.emergencyAdmin, newAdmin); 28 | 29 | const emergencyAdmin = await master.emergencyAdmin(); 30 | assert.equal(emergencyAdmin, newAdmin); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /test/unit/NXMaster/upgradeMultipleContracts.js: -------------------------------------------------------------------------------- 1 | const { 2 | constants: { AddressZero }, 3 | } = require('ethers'); 4 | const { hex } = require('../utils').helpers; 5 | const { expect } = require('chai'); 6 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 7 | const setup = require('./setup'); 8 | 9 | describe('upgradeMultipleContracts', function () { 10 | it('reverts when not called by governance', async function () { 11 | const fixture = await loadFixture(setup); 12 | const { master } = fixture; 13 | await expect(master.upgradeMultipleContracts([], [])).to.be.revertedWith('Not authorized'); 14 | }); 15 | 16 | it('reverts when contract code does not exist', async function () { 17 | const fixture = await loadFixture(setup); 18 | const { governance } = fixture; 19 | 20 | await expect( 21 | governance.upgradeMultipleContracts([hex('XX')], ['0x0000000000000000000000000000000000000001']), 22 | ).to.be.revertedWith('NXMaster: Non-existant or non-upgradeable contract code'); 23 | }); 24 | 25 | it('reverts when contract address is 0t', async function () { 26 | const fixture = await loadFixture(setup); 27 | const { governance } = fixture; 28 | 29 | await expect(governance.upgradeMultipleContracts([hex('GV')], [AddressZero])).to.be.revertedWith( 30 | 'NXMaster: Contract address is 0', 31 | ); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /test/unit/NexusViewer/setup.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat'); 2 | 3 | const { hex } = require('../../../lib/helpers'); 4 | const { getAccounts } = require('../utils').accounts; 5 | 6 | async function setup() { 7 | const accounts = await getAccounts(); 8 | const nxm = await ethers.deployContract('NXMTokenMock'); 9 | const master = await ethers.deployContract('MasterMock'); 10 | const assessment = await ethers.deployContract('AVMockAssessment', [1]); 11 | const stakingViewer = await ethers.deployContract('NVMockStakingViewer'); 12 | 13 | await master.setLatestAddress(hex('AS'), assessment.address); 14 | 15 | const assessmentViewer = await ethers.deployContract('NVMockAssessmentViewer'); 16 | const nexusViewer = await ethers.deployContract('NexusViewer', [ 17 | master.address, 18 | stakingViewer.address, 19 | assessmentViewer.address, 20 | ]); 21 | 22 | return { 23 | accounts, 24 | contracts: { 25 | nxm, 26 | assessment, 27 | assessmentViewer, 28 | stakingViewer, 29 | nexusViewer, 30 | }, 31 | }; 32 | } 33 | 34 | module.exports = { 35 | setup, 36 | }; 37 | -------------------------------------------------------------------------------- /test/unit/Pool/getMCRRatio.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat'); 2 | const { expect } = require('chai'); 3 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 4 | 5 | const setup = require('./setup'); 6 | const { BigNumber } = ethers; 7 | 8 | describe('getMCRRatio', function () { 9 | it('gets MCR ratio value', async function () { 10 | const fixture = await loadFixture(setup); 11 | const { pool, mcr } = fixture; 12 | const [member] = fixture.accounts.members; 13 | 14 | const initialAssetValue = BigNumber.from('210959924071154460525457'); 15 | const mcrEth = BigNumber.from('162424730681679380000000'); 16 | 17 | await mcr.setMCR(mcrEth); 18 | await member.sendTransaction({ to: pool.address, value: initialAssetValue }); 19 | 20 | const expectedMCRRatio = initialAssetValue.mul(10000).div(mcrEth); 21 | const calculatedMCRRatio = await pool.getMCRRatio(); 22 | 23 | expect(calculatedMCRRatio).to.be.equal(expectedMCRRatio); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /test/unit/Pool/getTokenPrice.js: -------------------------------------------------------------------------------- 1 | const { expect } = require('chai'); 2 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 3 | 4 | const setup = require('./setup'); 5 | 6 | describe('getTokenPrice', function () { 7 | it('should return the current token price (NXM sell price)', async function () { 8 | const fixture = await loadFixture(setup); 9 | const { pool, ramm } = fixture; 10 | 11 | const tokenPrice = await pool.getTokenPrice(); 12 | const spotPrices = await ramm.getSpotPrices(); 13 | 14 | expect(tokenPrice).to.be.equal(spotPrices[1]); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /test/unit/PriceFeedOracle/setup.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat'); 2 | 3 | const { AggregatorType, Assets } = require('../utils').constants; 4 | 5 | async function setup() { 6 | const ERC20Mock = await ethers.getContractFactory('ERC20Mock'); 7 | const ChainlinkAggregatorMock = await ethers.getContractFactory('ChainlinkAggregatorMock'); 8 | const PriceFeedOracle = await ethers.getContractFactory('PriceFeedOracle'); 9 | 10 | // Deploy ERC20 test tokens 11 | const [dai, wbtc, cbBTC, st] = await Promise.all([ 12 | ERC20Mock.deploy(), 13 | ERC20Mock.deploy(), 14 | ERC20Mock.deploy(), 15 | ERC20Mock.deploy(), 16 | ]); 17 | 18 | // Deploy price aggregators 19 | const [daiAggregator, wbtcAggregator, cbBTCAggregator, ethAggregator] = await Promise.all([ 20 | ChainlinkAggregatorMock.deploy(), 21 | ChainlinkAggregatorMock.deploy(), 22 | ChainlinkAggregatorMock.deploy(), 23 | ChainlinkAggregatorMock.deploy(), 24 | ]); 25 | await Promise.all([cbBTCAggregator.setDecimals(8), ethAggregator.setDecimals(8)]); 26 | 27 | // Deploy PriceFeedOracle 28 | const priceFeedOracle = await PriceFeedOracle.deploy( 29 | [dai.address, wbtc.address, cbBTC.address, Assets.ETH], // assetAddresses 30 | [daiAggregator.address, wbtcAggregator.address, cbBTCAggregator.address, ethAggregator.address], // assetAggregators 31 | [AggregatorType.ETH, AggregatorType.ETH, AggregatorType.USD, AggregatorType.USD], // aggregatorTypes 32 | [18, 8, 8, 18], // assetDecimals 33 | st.address, 34 | ); 35 | 36 | return { 37 | dai, 38 | st, 39 | wbtc, 40 | cbBTC, 41 | daiAggregator, 42 | wbtcAggregator, 43 | cbBTCAggregator, 44 | ethAggregator, 45 | priceFeedOracle, 46 | }; 47 | } 48 | 49 | module.exports = setup; 50 | -------------------------------------------------------------------------------- /test/unit/Ramm/getBookValue.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat'); 2 | const { expect } = require('chai'); 3 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 4 | 5 | const { setup } = require('./setup'); 6 | 7 | const { parseEther } = ethers.utils; 8 | 9 | describe('getBookValue', function () { 10 | it('should return the correct book value', async function () { 11 | const fixture = await loadFixture(setup); 12 | const { ramm, pool, tokenController } = fixture.contracts; 13 | 14 | const bookValue = await ramm.getBookValue(); 15 | const capital = await pool.getPoolValueInEth(); 16 | const supply = await tokenController.totalSupply(); 17 | 18 | expect(bookValue).to.be.equal(parseEther('1').mul(capital).div(supply)); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /test/unit/Ramm/getSpotPrices.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat'); 2 | const { expect } = require('chai'); 3 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 4 | 5 | const { setup } = require('./setup'); 6 | const { setNextBlockTime, mineNextBlock } = require('../../utils/evm'); 7 | 8 | const { provider } = ethers; 9 | const { parseEther } = ethers.utils; 10 | 11 | describe('getSpotPrices', function () { 12 | it('should return current buy / sell spot prices', async function () { 13 | const fixture = await loadFixture(setup); 14 | const { ramm, pool, tokenController, mcr } = fixture.contracts; 15 | 16 | const { timestamp } = await provider.getBlock('latest'); 17 | const elapsed = 1 * 60 * 60; // 1 hour elapsed 18 | const nextBlockTimestamp = timestamp + elapsed; 19 | await setNextBlockTime(nextBlockTimestamp); 20 | await mineNextBlock(); 21 | 22 | const { spotPriceA, spotPriceB } = await ramm.getSpotPrices(); 23 | 24 | const initialState = await ramm.loadState(); 25 | const context = { 26 | capital: await pool.getPoolValueInEth(), 27 | supply: await tokenController.totalSupply(), 28 | mcr: await mcr.getMCR(), 29 | }; 30 | 31 | const [{ eth, nxmA, nxmB }] = await ramm._getReserves(initialState, context, nextBlockTimestamp); 32 | 33 | // buy price 34 | const expectedSpotPriceA = parseEther('1').mul(eth).div(nxmA); 35 | expect(spotPriceA).to.be.equal(expectedSpotPriceA); 36 | // sell price 37 | const expectedSpotPriceB = parseEther('1').mul(eth).div(nxmB); 38 | expect(spotPriceB).to.be.equal(expectedSpotPriceB); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /test/unit/Ramm/loadState.js: -------------------------------------------------------------------------------- 1 | const { expect } = require('chai'); 2 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 3 | 4 | const { setup } = require('./setup'); 5 | 6 | describe('loadState', function () { 7 | it('should correctly return the current state', async function () { 8 | const fixture = await loadFixture(setup); 9 | const { ramm } = fixture.contracts; 10 | 11 | const state = await ramm.loadState(); 12 | 13 | // Expected state 14 | const { nxmReserveA, nxmReserveB } = await ramm.slot0(); 15 | const { ethReserve, budget, updatedAt } = await ramm.slot1(); 16 | const ratchetSpeedB = await ramm.ratchetSpeedB(); 17 | 18 | expect(state.nxmA).to.be.equal(nxmReserveA); 19 | expect(state.nxmB).to.be.equal(nxmReserveB); 20 | expect(state.eth).to.equal(ethReserve); 21 | expect(state.budget).to.equal(budget); 22 | expect(state.ratchetSpeedB).to.equal(ratchetSpeedB); 23 | expect(state.timestamp).to.equal(updatedAt); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /test/unit/Ramm/removeBudget.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat'); 2 | const { expect } = require('chai'); 3 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 4 | 5 | const { setup } = require('./setup'); 6 | 7 | describe('removeBudget', function () { 8 | it('should set the budget to 0', async function () { 9 | const fixture = await loadFixture(setup); 10 | const { ramm } = fixture.contracts; 11 | const [governance] = fixture.accounts.governanceContracts; 12 | 13 | const before = await ramm.slot1(); 14 | const governanceSigner = await ethers.provider.getSigner(governance.address); 15 | await ramm.connect(governanceSigner).removeBudget(); // onlyGovernance 16 | const after = await ramm.slot1(); 17 | 18 | expect(before.budget).to.be.not.equal(0); 19 | expect(after.budget).to.be.equal(0); 20 | }); 21 | 22 | it('should emit event BudgetRemoved', async function () { 23 | const fixture = await loadFixture(setup); 24 | const { ramm } = fixture.contracts; 25 | const [governance] = fixture.accounts.governanceContracts; 26 | 27 | const governanceSigner = await ethers.provider.getSigner(governance.address); 28 | 29 | await expect(ramm.connect(governanceSigner).removeBudget()).to.emit(ramm, 'BudgetRemoved'); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /test/unit/Ramm/setCircuitBreakerLimits.js: -------------------------------------------------------------------------------- 1 | const { expect } = require('chai'); 2 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 3 | 4 | const { setup } = require('./setup'); 5 | 6 | describe('setCircuitBreakerLimits', function () { 7 | it('should only be callable by emergencyAdmin', async function () { 8 | const fixture = await loadFixture(setup); 9 | const { ramm } = fixture.contracts; 10 | const { emergencyAdmin } = fixture.accounts; 11 | 12 | for (const member of fixture.accounts.members) { 13 | const setLimits = ramm.connect(member).setCircuitBreakerLimits(0, 0); 14 | await expect(setLimits).to.be.revertedWith('Caller is not emergency admin'); 15 | } 16 | 17 | const setLimits = ramm.connect(emergencyAdmin).setCircuitBreakerLimits(0, 0); 18 | await expect(setLimits).to.not.be.revertedWith('Caller is not emergency admin'); 19 | }); 20 | 21 | it('should successfully set new limits', async function () { 22 | const fixture = await loadFixture(setup); 23 | const { ramm } = fixture.contracts; 24 | const { emergencyAdmin } = fixture.accounts; 25 | 26 | const initialEthLimit = await ramm.ethLimit(); 27 | const initialNxmLimit = await ramm.nxmLimit(); 28 | 29 | await ramm.connect(emergencyAdmin).setCircuitBreakerLimits(1, 2); 30 | 31 | const finalEthLimit = await ramm.ethLimit(); 32 | const finalNxmLimit = await ramm.nxmLimit(); 33 | 34 | expect(initialEthLimit).to.not.equal(finalEthLimit); 35 | expect(initialNxmLimit).to.not.equal(finalNxmLimit); 36 | 37 | expect(finalEthLimit).to.equal(1); 38 | expect(finalNxmLimit).to.equal(2); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /test/unit/SafeTracker/allowance.js: -------------------------------------------------------------------------------- 1 | const { expect } = require('chai'); 2 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 3 | 4 | const { setup } = require('./setup'); 5 | 6 | describe('allowance', function () { 7 | it('should always return 0', async function () { 8 | const fixture = await loadFixture(setup); 9 | const { safeTracker } = fixture.contracts; 10 | const { accounts } = fixture; 11 | 12 | const allowance = await safeTracker.allowance(accounts.members[0].address, accounts.members[1].address); 13 | expect(allowance).to.be.equal(0); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /test/unit/SafeTracker/approve.js: -------------------------------------------------------------------------------- 1 | const { expect } = require('chai'); 2 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 3 | 4 | const { setup } = require('./setup'); 5 | 6 | describe('approve', function () { 7 | it('should emit Approval event if value is 0', async function () { 8 | const fixture = await loadFixture(setup); 9 | const { safeTracker } = fixture.contracts; 10 | const { 11 | defaultSender, 12 | members: [member], 13 | } = fixture.accounts; 14 | 15 | await expect(safeTracker.connect(defaultSender).approve(member.address, 100)).to.emit(safeTracker, 'Approval'); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /test/unit/SafeTracker/totalSupply.js: -------------------------------------------------------------------------------- 1 | const { expect } = require('chai'); 2 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 3 | 4 | const { setup } = require('./setup'); 5 | const { ethers } = require('hardhat'); 6 | 7 | describe('totalSupply', function () { 8 | it('should return safe balance', async function () { 9 | const fixture = await loadFixture(setup); 10 | const { safeTracker, priceFeedOracle } = fixture.contracts; 11 | const { weth, aweth, usdc, dai, debtUsdc } = fixture.tokens; 12 | const { defaultSender } = fixture.accounts; 13 | 14 | const ethBalance = await ethers.provider.getBalance(defaultSender.address); 15 | const wethBalance = await weth.balanceOf(defaultSender.address); 16 | const awethBalance = await aweth.balanceOf(defaultSender.address); 17 | const daiBalance = await dai.balanceOf(defaultSender.address); 18 | const daiBalanceInEth = await priceFeedOracle.getEthForAsset(dai.address, daiBalance); 19 | const usdcBalance = await usdc.balanceOf(defaultSender.address); 20 | const usdcBalanceInEth = await priceFeedOracle.getEthForAsset(usdc.address, usdcBalance); 21 | const debtUsdcAmount = await debtUsdc.balanceOf(defaultSender.address); 22 | const debtUsdcValueInEth = await priceFeedOracle.getEthForAsset(usdc.address, debtUsdcAmount); 23 | 24 | const expectedBalance = ethBalance 25 | .add(wethBalance) 26 | .add(awethBalance) 27 | .add(daiBalanceInEth) 28 | .add(usdcBalanceInEth) 29 | .sub(debtUsdcValueInEth); 30 | 31 | const totalSupply = await safeTracker.totalSupply(); 32 | expect(totalSupply).to.be.equal(expectedBalance); // add calculation 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /test/unit/StakingNFT/setup.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat'); 2 | const { setEtherBalance } = require('../../utils/evm'); 3 | const { getAccounts } = require('../../utils/accounts'); 4 | 5 | async function setup() { 6 | const accounts = await getAccounts(); 7 | const [operator] = accounts.members; 8 | 9 | const stakingPoolFactory = await ethers.deployContract('StakingPoolFactory', [operator.address]); 10 | const cover = await ethers.deployContract('SNFTMockCover', [stakingPoolFactory.address]); 11 | const stakingNFTDescriptor = await ethers.deployContract('StakingNFTDescriptor'); 12 | 13 | const stakingNFT = await ethers.deployContract('StakingNFT', [ 14 | 'NexusMutual Staking', 15 | 'NXMS', 16 | stakingPoolFactory.address, 17 | cover.address, 18 | stakingNFTDescriptor.address, 19 | ]); 20 | 21 | await cover.setStakingNFT(stakingNFT.address); 22 | 23 | // impersonate staking pool address 24 | const poolId = 50; 25 | const stakingAddress = await cover.stakingPool(poolId); 26 | await setEtherBalance(stakingAddress, ethers.utils.parseEther('1000')); 27 | await setEtherBalance(cover.address, ethers.utils.parseEther('1000')); 28 | const stakingPoolSigner = await ethers.getImpersonatedSigner(stakingAddress); 29 | const coverSigner = await ethers.getImpersonatedSigner(cover.address); 30 | 31 | return { 32 | contracts: { 33 | nftDescriptor: stakingNFTDescriptor, 34 | cover, 35 | stakingPoolFactory, 36 | stakingNFT, 37 | }, 38 | accounts, 39 | stakingPoolSigner, 40 | coverSigner, 41 | poolId, 42 | }; 43 | } 44 | 45 | module.exports = setup; 46 | -------------------------------------------------------------------------------- /test/unit/StakingPool/constructor.js: -------------------------------------------------------------------------------- 1 | const { expect } = require('chai'); 2 | const { ethers } = require('hardhat'); 3 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 4 | 5 | const setup = require('./setup'); 6 | 7 | describe('constructor', function () { 8 | it('should set nxm, cover and tokenController addresses correctly', async function () { 9 | const fixture = await loadFixture(setup); 10 | const { stakingProducts, stakingNFT, nxm, cover, tokenController, master } = fixture; 11 | 12 | const stakingPool = await ethers.deployContract( 13 | 'StakingPool', 14 | [stakingNFT, nxm, cover, tokenController, master, stakingProducts].map(c => c.address), 15 | ); 16 | 17 | const stakingNFTAddress = await stakingPool.stakingNFT(); 18 | const nxmAddress = await stakingPool.nxm(); 19 | const coverAddress = await stakingPool.coverContract(); 20 | const tokenControllerAddress = await stakingPool.tokenController(); 21 | const masterAddress = await stakingPool.masterContract(); 22 | const stakingProductsAddress = await stakingPool.stakingProducts(); 23 | 24 | expect(stakingNFTAddress).to.be.equal(stakingNFT.address); 25 | expect(nxmAddress).to.be.equal(nxm.address); 26 | expect(coverAddress).to.be.equal(cover.address); 27 | expect(tokenControllerAddress).to.be.equal(tokenController.address); 28 | expect(masterAddress).to.be.equal(master.address); 29 | expect(stakingProductsAddress).to.be.equal(stakingProducts.address); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /test/unit/StakingPoolFactory/setup.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat'); 2 | const { getAccounts } = require('../utils').accounts; 3 | 4 | async function setup() { 5 | const accounts = await getAccounts(); 6 | const [operator] = accounts.nonMembers; 7 | 8 | const stakingPoolFactory = await ethers.deployContract('StakingPoolFactory', [operator.address]); 9 | 10 | return { 11 | operator, 12 | stakingPoolFactory, 13 | accounts, 14 | }; 15 | } 16 | 17 | module.exports = setup; 18 | -------------------------------------------------------------------------------- /test/unit/StakingViewer/getManagedStakingPools.js: -------------------------------------------------------------------------------- 1 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 2 | const { expect } = require('chai'); 3 | 4 | const { setup } = require('./setup'); 5 | 6 | describe('getManagedStakingPools', function () { 7 | it('getManagedStakingPools should return the correct staking pools for the manager', async function () { 8 | const fixture = await loadFixture(setup); 9 | const [manager, otherManager] = fixture.accounts.members; 10 | const { stakingViewer, stakingProducts, tokenController } = fixture.contracts; 11 | const { stakedNxmAmount } = fixture.stakingPool; 12 | 13 | // create a 2nd staking pool that does not belong to the manager 14 | const params = [false, 5, 5, [], 'ipfs hash']; 15 | const [othersPoolId] = await stakingProducts.connect(otherManager).callStatic.createStakingPool(...params); 16 | await stakingProducts.connect(otherManager).createStakingPool(...params); 17 | await tokenController.setStakingPoolManager(othersPoolId, otherManager.address); 18 | 19 | const [managedStakingPool] = await stakingViewer.getManagedStakingPools(manager.address); 20 | 21 | expect(managedStakingPool.poolId).to.not.equal(othersPoolId); 22 | expect(managedStakingPool.poolId.toString()).to.equal('1'); 23 | expect(managedStakingPool.isPrivatePool).to.equal(false); 24 | expect(managedStakingPool.manager).to.equal(manager.address); 25 | expect(managedStakingPool.poolFee.toString()).to.equal('5'); 26 | expect(managedStakingPool.maxPoolFee.toString()).to.equal('5'); 27 | expect(managedStakingPool.activeStake).to.equal(stakedNxmAmount); 28 | expect(managedStakingPool.currentAPY.toString()).to.equal('0'); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /test/unit/StakingViewer/getManagerTokenRewards.js: -------------------------------------------------------------------------------- 1 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 2 | const { expect } = require('chai'); 3 | 4 | const { setup } = require('./setup'); 5 | const { calculateCurrentTrancheId } = require('../utils').stakingPool; 6 | 7 | describe('getManagerTokenRewardsByAddr', function () { 8 | it('getManagerTokenRewardsByAddr should return the correct rewards for the manager', async function () { 9 | const fixture = await loadFixture(setup); 10 | const [manager] = fixture.accounts.members; 11 | const { stakingViewer } = fixture.contracts; 12 | 13 | const [tokenReward] = await stakingViewer.getManagerTokenRewardsByAddr(manager.address); 14 | 15 | expect(tokenReward.tokenId.toString()).to.equal('0'); 16 | expect(tokenReward.poolId.toString()).to.equal('1'); 17 | expect(tokenReward.activeStake.toString()).to.equal('0'); 18 | expect(tokenReward.expiredStake.toString()).to.equal('0'); 19 | expect(tokenReward.rewards.toString()).to.equal('0'); 20 | 21 | const expectedTrancheId = await calculateCurrentTrancheId(); 22 | tokenReward.deposits.forEach(deposit => { 23 | expect(deposit.tokenId.toString()).to.equal('0'); 24 | expect(deposit.stake.toString()).to.equal('0'); 25 | expect(deposit.trancheId.toString()).to.equal(expectedTrancheId.toString()); 26 | expect(deposit.stakeShares.toString()).to.equal('0'); 27 | expect(deposit.reward.toString()).to.equal('0'); 28 | }); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /test/unit/StakingViewer/getPool.js: -------------------------------------------------------------------------------- 1 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 2 | const { expect } = require('chai'); 3 | 4 | const { setup } = require('./setup'); 5 | 6 | describe('getPool', function () { 7 | it('should retrieve pool info for the given poolId', async function () { 8 | const fixture = await loadFixture(setup); 9 | const { stakingPool, stakingViewer } = fixture.contracts; 10 | const { poolId } = fixture.stakingPool; 11 | 12 | const poolInfo = await stakingViewer.getPool(poolId); 13 | 14 | expect(poolInfo.poolId.toString()).to.equal(poolId.toString()); 15 | expect(poolInfo.isPrivatePool).to.equal(await stakingPool.isPrivatePool()); 16 | expect(poolInfo.manager).to.equal(await stakingPool.manager()); 17 | expect(poolInfo.poolFee).to.equal(await stakingPool.getPoolFee()); 18 | expect(poolInfo.maxPoolFee).to.equal(await stakingPool.getMaxPoolFee()); 19 | expect(poolInfo.activeStake).to.equal(await stakingPool.getActiveStake()); 20 | expect(poolInfo.currentAPY.toString()).to.equal('0'); 21 | expect(poolInfo.metadataIpfsHash).to.equal('ipfs hash'); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test/unit/TokenController/burnFrom.js: -------------------------------------------------------------------------------- 1 | const { expect } = require('chai'); 2 | const { parseEther } = require('ethers/lib/utils'); 3 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 4 | const setup = require('./setup'); 5 | 6 | describe('burnFrom', function () { 7 | it('reverts if caller is not an internal contract', async function () { 8 | const fixture = await loadFixture(setup); 9 | const { tokenController } = fixture.contracts; 10 | const [member1] = fixture.accounts.members; 11 | 12 | const amount = parseEther('10'); 13 | await expect(tokenController.connect(member1).burnFrom(member1.address, amount)).to.be.revertedWith( 14 | 'Caller is not an internal contract', 15 | ); 16 | }); 17 | 18 | it('burns nxm from member', async function () { 19 | const fixture = await loadFixture(setup); 20 | const { tokenController, nxm } = fixture.contracts; 21 | const [internalContract] = fixture.accounts.internalContracts; 22 | const [member1] = fixture.accounts.members; 23 | 24 | const initialBalanceMember1 = await nxm.balanceOf(member1.address); 25 | 26 | const amount = parseEther('10'); 27 | await tokenController.connect(internalContract).burnFrom(member1.address, amount); 28 | 29 | const balanceMember1 = await nxm.balanceOf(member1.address); 30 | 31 | expect(balanceMember1).to.equal(initialBalanceMember1.sub(amount)); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /test/unit/TokenController/changeOperator.js: -------------------------------------------------------------------------------- 1 | const { expect } = require('chai'); 2 | const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); 3 | const setup = require('./setup'); 4 | 5 | describe('changeOperator', function () { 6 | it('reverts if governance is not the caller', async function () { 7 | const fixture = await loadFixture(setup); 8 | const { tokenController } = fixture.contracts; 9 | const [member] = fixture.accounts.members; 10 | 11 | await expect(tokenController.connect(member).changeOperator(member.address)).to.be.revertedWith( 12 | 'Caller is not authorized to govern', 13 | ); 14 | }); 15 | 16 | it('updates operator in the token contract', async function () { 17 | const fixture = await loadFixture(setup); 18 | const { tokenController, nxm } = fixture.contracts; 19 | const [governance] = fixture.accounts.governanceContracts; 20 | const [member] = fixture.accounts.members; 21 | 22 | const initialOperator = await nxm.operator(); 23 | 24 | const newOperator = member.address; 25 | await tokenController.connect(governance).changeOperator(member.address); 26 | 27 | const operator = await nxm.operator(); 28 | 29 | expect(operator).not.equal(initialOperator); 30 | expect(operator).equal(newOperator); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /test/unit/utils.js: -------------------------------------------------------------------------------- 1 | module.exports = require('../utils'); 2 | -------------------------------------------------------------------------------- /test/utils/accounts.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat'); 2 | 3 | const assignRoles = accounts => ({ 4 | defaultSender: accounts[0], 5 | nonMembers: accounts.slice(1, 5), 6 | members: accounts.slice(5, 10), 7 | advisoryBoardMembers: accounts.slice(10, 15), 8 | internalContracts: accounts.slice(15, 20), 9 | nonInternalContracts: accounts.slice(20, 25), 10 | governanceContracts: accounts.slice(25, 30), 11 | stakingPoolManagers: accounts.slice(30, 40), 12 | emergencyAdmin: accounts[40], 13 | generalPurpose: accounts.slice(41), 14 | }); 15 | 16 | const getAccounts = async () => { 17 | const accounts = await ethers.getSigners(); 18 | return assignRoles(accounts); 19 | }; 20 | 21 | module.exports = { 22 | getAccounts, 23 | }; 24 | -------------------------------------------------------------------------------- /test/utils/addresses.js: -------------------------------------------------------------------------------- 1 | const { ethers, artifacts } = require('hardhat'); 2 | const { bytesToHex, hexToBytes } = require('ethereum-cryptography/utils'); 3 | const { keccak256 } = require('ethereum-cryptography/keccak'); 4 | 5 | async function stakingPoolAddressAt(poolFactoryAddress, poolId) { 6 | const { bytecode: proxyBytecode } = await artifacts.readArtifact('MinimalBeaconProxy'); 7 | const initCodeHash = bytesToHex(keccak256(hexToBytes(proxyBytecode.replace(/^0x/i, '')))); 8 | 9 | const salt = Buffer.from(poolId.toString(16).padStart(64, '0'), 'hex'); 10 | const initCodeHashHex = Buffer.from(initCodeHash, 'hex'); 11 | const stakingPoolAddress = ethers.utils.getCreate2Address(poolFactoryAddress, salt, initCodeHashHex); 12 | return stakingPoolAddress; 13 | } 14 | 15 | module.exports = { stakingPoolAddressAt }; 16 | -------------------------------------------------------------------------------- /test/utils/bnMath.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat'); 2 | 3 | const { BigNumber } = ethers; 4 | 5 | function divCeil(a, b) { 6 | a = BigNumber.from(a); 7 | let result = a.div(b); 8 | if (!a.mod(b).isZero()) { 9 | result = result.add(1); 10 | } 11 | return result; 12 | } 13 | 14 | function max(a, b) { 15 | a = BigNumber.from(a); 16 | return a.gte(b) ? a : b; 17 | } 18 | 19 | function min(a, b) { 20 | a = BigNumber.from(a); 21 | return a.lte(b) ? a : b; 22 | } 23 | 24 | module.exports = { 25 | divCeil, 26 | max, 27 | min, 28 | }; 29 | -------------------------------------------------------------------------------- /test/utils/errors.js: -------------------------------------------------------------------------------- 1 | // Used for generic compiler inserted panics. 2 | const COMPILER = 0x00; 3 | 4 | // If you call assert with an argument that evaluates to false. 5 | const FALSE_ASSERT = 0x01; 6 | 7 | // If an arithmetic operation results in underflow 8 | // or overflow outside of an unchecked { ... } block. 9 | const UNDER_OR_OVERFLOW = 0x11; 10 | 11 | // If you divide or modulo by zero (e.g. 5 / 0 or 23 % 0). 12 | const DIVIDE_BY_ZERO = 0x12; 13 | 14 | // If you convert a value that is too big or negative into an enum type. 15 | const INVALID_CONVERSION = 0x21; 16 | 17 | // If you access a storage byte array that is incorrectly encoded. 18 | const INCORRECT_STORAGE_ENCODING = 0x22; 19 | 20 | // If you call .pop() on an empty array. 21 | const POP_EMPTY_ARRAY = 0x31; 22 | 23 | // If you access an array, bytesN or an array slice 24 | // at an out-of-bounds or negative index 25 | // (i.e. x[i] where i >= x.length or i < 0). 26 | const INVALID_ARRAY_ACCESS = 0x32; 27 | 28 | // If you allocate too much memory or create an array that is too large. 29 | const MEMORY_TOO_LARGE = 0x41; 30 | 31 | // If you call a zero-initialized variable of internal function type. 32 | const ZERO_INITIALIZED_VARIABLE = 0x51; 33 | 34 | module.exports = { 35 | COMPILER, 36 | FALSE_ASSERT, 37 | UNDER_OR_OVERFLOW, 38 | DIVIDE_BY_ZERO, 39 | INVALID_CONVERSION, 40 | INCORRECT_STORAGE_ENCODING, 41 | POP_EMPTY_ARRAY, 42 | INVALID_ARRAY_ACCESS, 43 | MEMORY_TOO_LARGE, 44 | ZERO_INITIALIZED_VARIABLE, 45 | }; 46 | -------------------------------------------------------------------------------- /test/utils/events.js: -------------------------------------------------------------------------------- 1 | const getEventsFromTxReceipt = (txReceipt, filterContract, filterName = null, filterArgs = null) => { 2 | let events = txReceipt.events 3 | .filter(e => e.address === filterContract.address) 4 | .map(e => filterContract.interface.parseLog(e)); 5 | 6 | if (filterName) { 7 | events = events.filter(e => e.name === filterName); 8 | } 9 | 10 | if (filterArgs) { 11 | events = events.filter(e => Object.entries(filterArgs).every(([key, value]) => e.args[key] === value)); 12 | } 13 | 14 | return events; 15 | }; 16 | 17 | module.exports = { getEventsFromTxReceipt }; 18 | -------------------------------------------------------------------------------- /test/utils/index.js: -------------------------------------------------------------------------------- 1 | const { constants, helpers } = require('../../lib'); 2 | const proposalCategories = require('../../lib/proposal-categories'); 3 | 4 | const addresses = require('./addresses'); 5 | const accounts = require('./accounts'); 6 | const evm = require('./evm'); 7 | const buyCover = require('./buyCover'); 8 | const governance = require('./governance'); 9 | const membership = require('./membership'); 10 | const results = require('./results'); 11 | const errors = require('./errors'); 12 | const rammCalculations = require('./rammCalculations'); 13 | const bnMath = require('./bnMath'); 14 | const stakingPool = require('./stakingPool'); 15 | const events = require('./events'); 16 | 17 | module.exports = { 18 | addresses, 19 | accounts, 20 | constants, 21 | evm, 22 | helpers, 23 | proposalCategories, 24 | buyCover, 25 | governance, 26 | membership, 27 | results, 28 | errors, 29 | rammCalculations, 30 | bnMath, 31 | stakingPool, 32 | events, 33 | }; 34 | -------------------------------------------------------------------------------- /test/utils/membership.js: -------------------------------------------------------------------------------- 1 | const { ethers, network } = require('hardhat'); 2 | const { arrayify, formatBytes32String, defaultAbiCoder, keccak256 } = ethers.utils; 3 | 4 | const MEMBERSHIP_APPROVAL = formatBytes32String('MEMBERSHIP_APPROVAL'); 5 | 6 | const signMembershipApproval = async ({ address, nonce, chainId, kycAuthSigner }) => { 7 | const message = defaultAbiCoder.encode( 8 | ['bytes32', 'uint256', 'address', 'uint256'], 9 | [MEMBERSHIP_APPROVAL, nonce, address, chainId || network.config.chainId || 1], 10 | ); 11 | const hash = keccak256(message); 12 | const signature = await kycAuthSigner.signMessage(arrayify(hash)); 13 | return signature; 14 | }; 15 | 16 | module.exports = { signMembershipApproval }; 17 | -------------------------------------------------------------------------------- /test/utils/results.js: -------------------------------------------------------------------------------- 1 | const isNumeric = k => k === (+k).toString(); 2 | 3 | const resultAsObject = result => { 4 | const entries = Object.entries(result).filter(([k]) => !isNumeric(k)); 5 | return Object.fromEntries(entries); 6 | }; 7 | 8 | module.exports = { resultAsObject }; 9 | -------------------------------------------------------------------------------- /test/utils/stakingPool.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat'); 2 | 3 | async function calculateCurrentTrancheId() { 4 | const lastBlock = await ethers.provider.getBlock('latest'); 5 | return Math.floor(lastBlock.timestamp / (91 * 24 * 3600)); 6 | } 7 | 8 | module.exports = { 9 | calculateCurrentTrancheId, 10 | }; 11 | --------------------------------------------------------------------------------