├── .env.sample ├── .github ├── CONTRIBUTING └── workflows │ └── test.yml ├── .gitignore ├── .gitmodules ├── .prettierrc ├── .solcover.js ├── .solhint.json ├── .solhintignore ├── .vscode └── settings.json ├── LICENSE ├── abis ├── IAaveV2LendingPoolLike.json ├── IBondPool.json ├── IClaimsProcessor.json ├── ICompoundERC20DelegatorLike.json ├── ICover.json ├── ICoverReassurance.json ├── ICoverStake.json ├── ICxToken.json ├── ICxTokenFactory.json ├── IERC20.json ├── IERC20Detailed.json ├── IFinalization.json ├── IGovernance.json ├── ILendingStrategy.json ├── ILiquidityEngine.json ├── IMember.json ├── IPausable.json ├── IPolicy.json ├── IPolicyAdmin.json ├── IPriceOracle.json ├── IProtocol.json ├── IRecoverable.json ├── IReporter.json ├── IResolution.json ├── IResolvable.json ├── IStakingPools.json ├── IStore.json ├── IUniswapV2FactoryLike.json ├── IUniswapV2PairLike.json ├── IUniswapV2RouterLike.json ├── IUnstakable.json ├── IVault.json ├── IVaultDelegate.json ├── IVaultFactory.json └── IWitness.json ├── audits ├── 001-blocksec.pdf └── 002-open-zeppelin.pdf ├── contracts ├── core │ ├── ProtoBase.sol │ ├── Protocol.sol │ ├── Recoverable.sol │ ├── claims │ │ └── Processor.sol │ ├── cxToken │ │ ├── cxToken.sol │ │ └── cxTokenFactory.sol │ ├── delegates │ │ ├── VaultDelegate.sol │ │ ├── VaultDelegateBase.sol │ │ └── VaultDelegateWithFlashLoan.sol │ ├── governance │ │ ├── Governance.sol │ │ ├── Reporter.sol │ │ ├── Witness.sol │ │ └── resolution │ │ │ ├── Finalization.sol │ │ │ ├── Resolution.sol │ │ │ ├── Resolvable.sol │ │ │ └── Unstakable.sol │ ├── lifecycle │ │ ├── Cover.sol │ │ ├── CoverBase.sol │ │ ├── CoverReassurance.sol │ │ └── CoverStake.sol │ ├── liquidity │ │ ├── LiquidityEngine.sol │ │ ├── Vault.sol │ │ ├── VaultBase.sol │ │ ├── VaultFactory.sol │ │ ├── VaultLiquidity.sol │ │ ├── VaultStrategy.sol │ │ ├── WithFlashLoan.sol │ │ └── strategies │ │ │ ├── AaveStrategy.sol │ │ │ └── CompoundStrategy.sol │ ├── policy │ │ ├── Policy.sol │ │ └── PolicyAdmin.sol │ ├── store │ │ ├── Store.sol │ │ └── StoreBase.sol │ └── token │ │ ├── Delayable.sol │ │ ├── NPM.sol │ │ ├── POT.sol │ │ ├── Treasury.sol │ │ ├── WithPausability.sol │ │ └── WithRecovery.sol ├── dependencies │ ├── BokkyPooBahsDateTimeLibrary.sol │ ├── aave │ │ └── IAaveV2LendingPoolLike.sol │ ├── compound │ │ └── ICompoundERC20DelegatorLike.sol │ └── uniswap-v2 │ │ ├── IUniswapV2FactoryLike.sol │ │ ├── IUniswapV2PairLike.sol │ │ └── IUniswapV2RouterLike.sol ├── examples │ └── NpmDistributor.sol ├── fakes │ ├── Destroyable.sol │ ├── FakeAaveLendingPool.sol │ ├── FakeCompoundStablecoinDelegator.sol │ ├── FakePriceOracle.sol │ ├── FakeRecoverable.sol │ ├── FakeStore.sol │ ├── FakeToken.sol │ ├── FakeUniswapPair.sol │ ├── FakeUniswapV2FactoryLike.sol │ ├── FakeUniswapV2PairLike.sol │ ├── FakeUniswapV2RouterLike.sol │ ├── FaultyAaveLendingPool.sol │ ├── FaultyCompoundStablecoinDelegator.sol │ ├── ForceEther.sol │ ├── InvalidStrategy.sol │ ├── MaliciousToken.sol │ ├── NTransferUtilV2Intermediate.sol │ └── PoorMansERC20.sol ├── interfaces │ ├── IBondPool.sol │ ├── IClaimsProcessor.sol │ ├── ICover.sol │ ├── ICoverReassurance.sol │ ├── ICoverStake.sol │ ├── ICxToken.sol │ ├── ICxTokenFactory.sol │ ├── IERC20Detailed.sol │ ├── IFinalization.sol │ ├── IGovernance.sol │ ├── ILendingStrategy.sol │ ├── ILiquidityEngine.sol │ ├── IMember.sol │ ├── IPausable.sol │ ├── IPolicy.sol │ ├── IPolicyAdmin.sol │ ├── IPriceOracle.sol │ ├── IProtocol.sol │ ├── IRecoverable.sol │ ├── IReporter.sol │ ├── IResolution.sol │ ├── IResolvable.sol │ ├── IStakingPools.sol │ ├── IStore.sol │ ├── IUnstakable.sol │ ├── IVault.sol │ ├── IVaultDelegate.sol │ ├── IVaultFactory.sol │ └── IWitness.sol ├── libraries │ ├── AccessControlLibV1.sol │ ├── BaseLibV1.sol │ ├── BondPoolLibV1.sol │ ├── CoverLibV1.sol │ ├── CoverUtilV1.sol │ ├── GovernanceUtilV1.sol │ ├── NTransferUtilV2.sol │ ├── PolicyHelperV1.sol │ ├── PriceLibV1.sol │ ├── ProtoUtilV1.sol │ ├── RegistryLibV1.sol │ ├── RoutineInvokerLibV1.sol │ ├── StakingPoolCoreLibV1.sol │ ├── StakingPoolLibV1.sol │ ├── StoreKeyUtil.sol │ ├── StrategyLibV1.sol │ ├── ValidationLibV1.sol │ ├── VaultFactoryLibV1.sol │ ├── VaultLibV1.sol │ └── cxTokenFactoryLibV1.sol ├── mock │ ├── MockFlashBorrower.sol │ ├── MockRegistryClient.sol │ ├── base │ │ ├── MockCxToken.sol │ │ ├── MockProtocol.sol │ │ └── MockStore.sol │ ├── claims-processor │ │ ├── MockProcessorStore.sol │ │ └── MockVault.sol │ ├── cx-token │ │ ├── MockCxTokenPolicy.sol │ │ └── MockCxTokenStore.sol │ └── lib-user │ │ ├── MockAccessControlUser.sol │ │ ├── MockCoverUtil.sol │ │ ├── MockLiquidityEngineUser.sol │ │ ├── MockStoreKeyUtilUser.sol │ │ ├── MockValidationLibUser.sol │ │ └── MockVaultLibUser.sol └── pool │ ├── Bond │ ├── BondPool.sol │ └── BondPoolBase.sol │ └── Staking │ ├── StakingPoolBase.sol │ ├── StakingPoolInfo.sol │ ├── StakingPoolReward.sol │ └── StakingPools.sol ├── docs ├── AaveStrategy.md ├── AccessControl.md ├── AccessControlLibV1.md ├── Address.md ├── BaseLibV1.md ├── BokkyPooBahsDateTimeLibrary.md ├── BondPool.md ├── BondPoolBase.md ├── BondPoolLibV1.md ├── CompoundStrategy.md ├── Context.md ├── Cover.md ├── CoverBase.md ├── CoverLibV1.md ├── CoverReassurance.md ├── CoverStake.md ├── CoverUtilV1.md ├── Delayable.md ├── Destroyable.md ├── ERC165.md ├── ERC20.md ├── FakeAaveLendingPool.md ├── FakeCompoundStablecoinDelegator.md ├── FakePriceOracle.md ├── FakeRecoverable.md ├── FakeStore.md ├── FakeToken.md ├── FakeUniswapPair.md ├── FakeUniswapV2FactoryLike.md ├── FakeUniswapV2PairLike.md ├── FakeUniswapV2RouterLike.md ├── FaultyAaveLendingPool.md ├── FaultyCompoundStablecoinDelegator.md ├── Finalization.md ├── ForceEther.md ├── Governance.md ├── GovernanceUtilV1.md ├── IAaveV2LendingPoolLike.md ├── IAccessControl.md ├── IBondPool.md ├── IClaimsProcessor.md ├── ICompoundERC20DelegatorLike.md ├── ICover.md ├── ICoverReassurance.md ├── ICoverStake.md ├── ICxToken.md ├── ICxTokenFactory.md ├── IERC165.md ├── IERC20.md ├── IERC20Detailed.md ├── IERC20Metadata.md ├── IERC3156FlashBorrower.md ├── IERC3156FlashLender.md ├── IFinalization.md ├── IGovernance.md ├── ILendingStrategy.md ├── ILiquidityEngine.md ├── IMember.md ├── INeptuneRouterV1.md ├── IPausable.md ├── IPolicy.md ├── IPolicyAdmin.md ├── IPriceOracle.md ├── IProtocol.md ├── IRecoverable.md ├── IReporter.md ├── IResolution.md ├── IResolvable.md ├── IStakingPools.md ├── IStore.md ├── IStoreLike.md ├── IUniswapV2FactoryLike.md ├── IUniswapV2PairLike.md ├── IUniswapV2RouterLike.md ├── IUnstakable.md ├── IVault.md ├── IVaultDelegate.md ├── IVaultFactory.md ├── IWitness.md ├── InvalidStrategy.md ├── LiquidityEngine.md ├── MaliciousToken.md ├── MockAccessControlUser.md ├── MockCoverUtilUser.md ├── MockCxToken.md ├── MockCxTokenPolicy.md ├── MockCxTokenStore.md ├── MockFlashBorrower.md ├── MockLiquidityEngineUser.md ├── MockProcessorStore.md ├── MockProcessorStoreLib.md ├── MockProtocol.md ├── MockRegistryClient.md ├── MockStore.md ├── MockStoreKeyUtilUser.md ├── MockValidationLibUser.md ├── MockVault.md ├── MockVaultLibUser.md ├── NPM.md ├── NTransferUtilV2.md ├── NTransferUtilV2Intermediate.md ├── NeptuneRouterV1.md ├── NpmDistributor.md ├── Ownable.md ├── POT.md ├── Pausable.md ├── Policy.md ├── PolicyAdmin.md ├── PolicyHelperV1.md ├── PoorMansERC20.md ├── PriceLibV1.md ├── Processor.md ├── ProtoBase.md ├── ProtoUtilV1.md ├── Protocol.md ├── Recoverable.md ├── ReentrancyGuard.md ├── RegistryLibV1.md ├── Reporter.md ├── Resolution.md ├── Resolvable.md ├── RoutineInvokerLibV1.md ├── SafeERC20.md ├── StakingPoolBase.md ├── StakingPoolCoreLibV1.md ├── StakingPoolInfo.md ├── StakingPoolLibV1.md ├── StakingPoolReward.md ├── StakingPools.md ├── Store.md ├── StoreBase.md ├── StoreKeyUtil.md ├── StrategyLibV1.md ├── Strings.md ├── TimelockController.md ├── Unstakable.md ├── ValidationLibV1.md ├── Vault.md ├── VaultBase.md ├── VaultDelegate.md ├── VaultDelegateBase.md ├── VaultDelegateWithFlashLoan.md ├── VaultFactory.md ├── VaultFactoryLibV1.md ├── VaultLibV1.md ├── VaultLiquidity.md ├── VaultStrategy.md ├── WithFlashLoan.md ├── WithPausability.md ├── WithRecovery.md ├── Witness.md ├── cxToken.md ├── cxTokenFactory.md └── cxTokenFactoryLibV1.md ├── events.md ├── examples ├── dedicated │ ├── exchanges │ │ ├── binance.js │ │ ├── coinbase.js │ │ ├── huobi.js │ │ ├── index.js │ │ └── okx.js │ └── index.js ├── diversified │ ├── animoca │ │ ├── cover.js │ │ └── products │ │ │ └── index.js │ ├── defi │ │ ├── cover.js │ │ ├── index.js │ │ └── products │ │ │ ├── 1inch.js │ │ │ ├── compound.js │ │ │ ├── convex.js │ │ │ ├── index.js │ │ │ ├── kyberswap.js │ │ │ ├── lido.js │ │ │ ├── loopring.js │ │ │ ├── nexus-mutual.js │ │ │ ├── rocket-pool.js │ │ │ ├── sushi.js │ │ │ └── uniswap.js │ ├── index.js │ └── prime │ │ ├── cover.js │ │ ├── index.js │ │ └── products │ │ ├── aave.js │ │ ├── balancer.js │ │ ├── curve.js │ │ ├── gnosis-safe.js │ │ ├── index.js │ │ ├── maker.js │ │ ├── synthetix.js │ │ └── uniswap.js └── index.js ├── files └── protocol.png ├── foundry.toml ├── fuzzing ├── CoverSpec.sol └── core │ ├── StoreTest.sol │ └── VaultTest.sol ├── hardhat.config.js ├── oracle ├── contracts │ ├── IPriceOracle.sol │ └── NpmPriceOracle.sol ├── hardhat.config.js ├── package.json ├── scripts │ └── deploy.js └── yarn.lock ├── package.json ├── readme.md ├── remappings.txt ├── scripts ├── config │ ├── deployments │ │ ├── arbitrum.json │ │ ├── basegoerli.json │ │ ├── bsc.json │ │ └── ethereum.json │ ├── index.js │ └── network │ │ ├── arbitrum.js │ │ ├── base-goerli.js │ │ ├── bsc.js │ │ ├── hardhat.js │ │ ├── index.js │ │ ├── local.js │ │ └── mainnet.js ├── covers │ ├── dedicated │ │ ├── binance.js │ │ └── okx.js │ ├── deployments │ │ ├── binance.js │ │ ├── okx.js │ │ ├── popular-defi-apps-bnb.js │ │ ├── popular-defi-apps.js │ │ └── prime-dapps.js │ └── diversified │ │ ├── popular-defi-apps-bnb │ │ ├── cover.js │ │ ├── index.js │ │ └── products │ │ │ ├── alpaca.js │ │ │ ├── dodo.js │ │ │ ├── index.js │ │ │ ├── one-inch.js │ │ │ ├── pancakeswap.js │ │ │ └── uniswap.js │ │ ├── popular-defi-apps │ │ ├── cover.js │ │ ├── index.js │ │ └── products │ │ │ ├── aave.js │ │ │ ├── bancor.js │ │ │ ├── compound.js │ │ │ ├── convex.js │ │ │ ├── dydx.js │ │ │ ├── gmx.js │ │ │ ├── index.js │ │ │ ├── one-inch.js │ │ │ ├── sushi.js │ │ │ └── uniswap.js │ │ └── prime │ │ ├── cover.js │ │ ├── index.js │ │ └── products │ │ ├── aave.js │ │ ├── balancer.js │ │ ├── curve.js │ │ ├── gnosis-safe.js │ │ ├── index.js │ │ ├── maker.js │ │ ├── synthetix.js │ │ └── uniswap.js ├── deploy-covers.js ├── deploy-npm.js ├── deploy-pot.js ├── deploy-treasury.js ├── deploy.js ├── update-oracle.js ├── upgrade │ ├── bond-pool.js │ ├── resolution.js │ └── vault-delegate.js └── verify.js ├── security.md ├── slither.config.json ├── solidoc.json ├── sonar-project.properties ├── test ├── bdd │ └── fractionalization.js ├── examples │ └── distributor │ │ ├── add-liquidity.spec.js │ │ ├── ctor.spec.js │ │ ├── deps.js │ │ ├── drain.spec.js │ │ ├── get-premium.spec.js │ │ ├── purchase-policy.spec.js │ │ └── remove-liquidity.spec.js ├── specs │ ├── claims-processor │ │ ├── claim.spec.js │ │ ├── ctor-vfns.spec.js │ │ ├── deps.js │ │ ├── set-claim-period.spec.js │ │ └── validate.spec.js │ ├── cx-token-factory │ │ ├── ctor.spec.js │ │ ├── deploy.spec.js │ │ └── deps.js │ ├── cx-token │ │ ├── before-token-transfer.spec.js │ │ ├── burn.spec.js │ │ ├── ctor-vfns.spec.js │ │ ├── deps.js │ │ ├── get-claimable-policy-of.spec.js │ │ ├── get-coverage-starts-from.spec.js │ │ └── mint.spec.js │ ├── governance │ │ ├── attest.spec.js │ │ ├── close-report.spec.js │ │ ├── ctor.spec.js │ │ ├── deps.js │ │ ├── dispute.spec.js │ │ ├── emergency-resolve.spec.js │ │ ├── finalize.spec.js │ │ ├── get-resolution-date.spec.js │ │ ├── refute.spec.js │ │ ├── report.spec.js │ │ ├── resolution │ │ │ ├── configure-cool-down-period.spec.js │ │ │ ├── ctor.spec.js │ │ │ ├── deps.js │ │ │ ├── get-cool-down-period.spec.js │ │ │ ├── get-resolution-deadline.spec.js │ │ │ ├── get-unstake-info-for.spec.js │ │ │ ├── unstake-with-claim.spec.js │ │ │ └── unstake.spec.js │ │ ├── resolve.spec.js │ │ ├── set-first-reporting-stake.spec.js │ │ ├── set-reporter-burn-rate.spec.js │ │ └── set-reporter-commission.spec.js │ ├── libraries │ │ ├── access-control.spec.js │ │ ├── cover-util.spec.js │ │ ├── deps.js │ │ ├── routine-invoker.spec.js │ │ ├── store-key-util.spec.js │ │ ├── validation.spec.js │ │ └── vault.spec.js │ ├── lifecycle │ │ ├── cover-reassurance │ │ │ ├── add-reassurance.spec.js │ │ │ ├── capitalize-pool.spec.js │ │ │ ├── ctor-vfns.spec.js │ │ │ ├── deps.js │ │ │ ├── get-reassurance.spec.js │ │ │ └── set-weight.spec.js │ │ ├── cover-stake │ │ │ ├── ctor-vfns.spec.js │ │ │ ├── decrease-stake.spec.js │ │ │ ├── deps.js │ │ │ ├── increase-stake.spec.js │ │ │ └── stake-of.spec.js │ │ └── cover │ │ │ ├── add-cover.spec.js │ │ │ ├── add-product.spec.js │ │ │ ├── ctor-vfns.spec.js │ │ │ ├── deps.js │ │ │ ├── disable-policy.spec.js │ │ │ ├── initialize.spec.js │ │ │ ├── set-cover-creation-fee.spec.js │ │ │ ├── set-min-cover-creation-stake.spec.js │ │ │ ├── set-min-stake-to-add-liquidity.spec.js │ │ │ ├── update-cover-creator-whitelist.spec.js │ │ │ ├── update-cover-users-whitelist.spec.js │ │ │ ├── update-cover.spec.js │ │ │ └── update-product.spec.js │ ├── liquidity │ │ ├── delegates │ │ │ ├── ctor-vfns.spec.js │ │ │ └── deps.js │ │ ├── engine │ │ │ ├── add-strategies.spec.js │ │ │ ├── ctor.spec.js │ │ │ ├── delete-strategy.spec.js │ │ │ ├── deps.js │ │ │ ├── disable-strategy.spec.js │ │ │ ├── set-liquidity-state-update-interval.spec.js │ │ │ ├── set-max-lending-ratio.spec.js │ │ │ └── set-risk-pooling-periods.spec.js │ │ ├── strategy │ │ │ ├── aave │ │ │ │ ├── ctor.spec.js │ │ │ │ ├── deposit.spec.js │ │ │ │ ├── drain.spec.js │ │ │ │ └── withdraw.spec.js │ │ │ ├── compound │ │ │ │ ├── ctor.spec.js │ │ │ │ ├── deposit.spec.js │ │ │ │ ├── drain.spec.js │ │ │ │ └── withdraw.spec.js │ │ │ └── deps.js │ │ ├── vault-factory │ │ │ ├── ctor.spec.js │ │ │ └── deps.js │ │ └── vault │ │ │ ├── add-liquidity.spec.js │ │ │ ├── calculate-liquidity.spec.js │ │ │ ├── calculate-pods.spec.js │ │ │ ├── ctor.spec.js │ │ │ ├── deps.js │ │ │ ├── flash-fee.spec.js │ │ │ ├── flashloan.spec.js │ │ │ ├── get-info.spec.js │ │ │ ├── max-flash-loan.spec.js │ │ │ ├── receive-from-strategy.spec.js │ │ │ ├── remove-liquidity.spec.js │ │ │ ├── transfer-governance.spec.js │ │ │ └── transfer-to-strategy.spec.js │ ├── policy-admin │ │ ├── ctor.spec.js │ │ ├── deps.js │ │ ├── set-coverage-lag.spec.js │ │ └── set-policy-rates-by-key.spec.js │ ├── policy │ │ ├── ctor.spec.js │ │ ├── deps.js │ │ ├── get-cover-fee-info.spec.js │ │ ├── get-cxtoken-by-expiry-date.spec.js │ │ ├── purchase-cover.spec.js │ │ └── util │ │ │ ├── calculator.js │ │ │ └── calculator.spec.js │ ├── pool │ │ ├── bond │ │ │ ├── calculate-tokens-for-lp.spec.js │ │ │ ├── claim-bond.spec.js │ │ │ ├── create-bond.spec.js │ │ │ ├── ctor.spec.js │ │ │ ├── deps.js │ │ │ ├── get-info.spec.js │ │ │ ├── npm-token-price.spec.js │ │ │ └── setup.spec.js │ │ └── staking │ │ │ ├── add-or-edit-pool.spec.js │ │ │ ├── close-pool.spec.js │ │ │ ├── ctor-vfns.spec.js │ │ │ ├── deposit.spec.js │ │ │ ├── deposit.target.achieved.spec.js │ │ │ ├── deps.js │ │ │ ├── withdraw-rewards.spec.js │ │ │ ├── withdrawal.spec.js │ │ │ └── zero-reward.spec.js │ ├── protocol │ │ ├── add-contract.spec.js │ │ ├── add-member.spec.js │ │ ├── ctor-vfns.spec.js │ │ ├── deps.js │ │ ├── grant-role.spec.js │ │ ├── pause.spec.js │ │ ├── remove-member.spec.js │ │ ├── setup-role.spec.js │ │ ├── unpause.spec.js │ │ └── upgrade-contract.spec.js │ ├── recoverable │ │ ├── ctor.spec.js │ │ ├── deps.js │ │ ├── ethers.spec.js │ │ └── token.spec.js │ ├── store │ │ ├── add-uint.spec.js │ │ ├── count-address-array-items.spec.js │ │ ├── delete-address-array-item-by-index.spec.js │ │ ├── delete-address-array-item.spec.js │ │ ├── delete-bool.spec.js │ │ ├── delete-bytes.spec.js │ │ ├── delete-bytes32.spec.js │ │ ├── delete-int.spec.js │ │ ├── delete-string.spec.js │ │ ├── delete-uint.spec.js │ │ ├── delete-uints.spec.js │ │ ├── get-address-array-item-by-index.spec.js │ │ ├── get-address-values.spec.js │ │ ├── get-uint-values.spec.js │ │ ├── pausable.spec.js │ │ ├── recoverable.spec.js │ │ ├── set-address-array-item.spec.js │ │ ├── set-address-boolean.spec.js │ │ ├── set-address.spec.js │ │ ├── set-bool.spec.js │ │ ├── set-bytes.spec.js │ │ ├── set-bytes32-array-item.spec.js │ │ ├── set-bytes32.spec.js │ │ ├── set-int.spec.js │ │ ├── set-string.spec.js │ │ ├── set-uint.spec.js │ │ ├── set-uints.spec.js │ │ └── subtract-uint.spec.js │ └── token │ │ ├── delayable.spec.js │ │ ├── npm.spec.js │ │ ├── recoverable.spec.js │ │ └── treasury.spec.js └── stories │ ├── 0. setup.spec.js │ ├── 1. policy.spec.js │ ├── 2. governance.spec.js │ ├── 3.staking.pool.spec.js │ ├── 4.liquidity.spec.js │ └── 5.coverage.claim.spec.js ├── truffle-config.js ├── util ├── analyzers │ ├── chain-state.js │ └── validators │ │ ├── access-control.js │ │ ├── accidental-zero.js │ │ ├── address.js │ │ ├── erc-20.js │ │ ├── fraction.js │ │ ├── index.js │ │ ├── initialization.js │ │ ├── lib.js │ │ ├── mock.js │ │ ├── non-reentrancy.js │ │ ├── not-implemented.js │ │ ├── pausable.js │ │ ├── revert.js │ │ ├── subtraction.js │ │ ├── todo.js │ │ └── zero-value.js ├── attach │ ├── attach.js │ ├── index.js │ └── protocol.js ├── block-time.js ├── block.js ├── composer │ ├── add-pools.js │ ├── covers.js │ ├── external-protocols.js │ ├── fakes.js │ ├── grant-roles.js │ ├── index.js │ ├── initializer.js │ ├── libs.js │ ├── pod-staking.js │ ├── store.js │ ├── testnet │ │ └── staking-pools.js │ ├── token.js │ ├── uniswap-pair.js │ └── vault.js ├── contract-helper │ ├── erc20.js │ ├── faucet.js │ └── uniswap.js ├── count-lines │ └── index.js ├── cxToken.js ├── demo-data │ ├── add-liquidity.js │ ├── add-reassurance.js │ ├── index.js │ └── purchase-policy.js ├── deployer.js ├── events │ ├── all.js │ ├── index.js │ └── table.js ├── extract │ ├── abis │ │ └── index.js │ ├── genabi.js │ └── keys │ │ ├── code-generator-as.js │ │ ├── code-generator.js │ │ ├── index.js │ │ ├── processor.js │ │ ├── requirement.js │ │ ├── template-as.js │ │ ├── template-js.js │ │ ├── template-ts.js │ │ └── template.js ├── file-cache │ ├── addresses.js │ ├── contract.js │ ├── data.js │ ├── index.js │ └── upgrade.js ├── helper.js ├── index.js ├── intermediate.js ├── io.js ├── ipfs.js ├── key.js ├── net │ └── ipfs-client.js ├── network.js ├── sample.js ├── store-util.js ├── typedefs.js └── wallet.js └── yarn.lock /.env.sample: -------------------------------------------------------------------------------- 1 | PRIVATE_KEY= 2 | POLYGONSCAN_API_KEY= 3 | ETHERSCAN_API_KEY= 4 | ALCHEMY_API_URL= 5 | ROPSTEN_RPC_URL= 6 | KOVAN_RPC_URL= 7 | ETHEREUM_RPC_URL= 8 | ARBITRUM_RPC_URL= 9 | BSC_RPC_URL= 10 | NPM_IPFS_API_URL= -------------------------------------------------------------------------------- /.github/CONTRIBUTING: -------------------------------------------------------------------------------- 1 | ## Installation 2 | 3 | ### Checklist 4 | 5 | - [ ] Install [foundry](https://book.getfoundry.sh/getting-started/installation) 6 | - [ ] Install [lcov](https://formulae.brew.sh/formula/lcov) on Mac OS or [genhtml](https://manpages.ubuntu.com/manpages/xenial/man1/genhtml.1.html) on Linux 7 | 8 | ``` 9 | git submodule update --init --recursive 10 | forge install 11 | yarn install 12 | ``` 13 | 14 | ### Commands 15 | 16 | **Build** 17 | 18 | ``` 19 | yarn build 20 | ``` 21 | 22 | **Test** 23 | 24 | ``` 25 | yarn test 26 | ``` 27 | 28 | **Coverage** 29 | 30 | ``` 31 | yarn coverage 32 | 33 | open ./coverage/index.html 34 | ``` -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: workflow_dispatch 4 | 5 | env: 6 | FOUNDRY_PROFILE: ci 7 | 8 | jobs: 9 | check: 10 | strategy: 11 | fail-fast: true 12 | 13 | name: Foundry project 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v3 17 | with: 18 | submodules: recursive 19 | 20 | - name: Install Foundry 21 | uses: foundry-rs/foundry-toolchain@v1 22 | with: 23 | version: nightly 24 | 25 | - name: Run Forge build 26 | run: | 27 | forge --version 28 | forge build --sizes 29 | id: build 30 | 31 | - name: Run Forge tests 32 | run: | 33 | forge test -vvv 34 | id: test 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .* 2 | node_modules 3 | yarn-error.log 4 | artifacts 5 | build 6 | _*.sol* 7 | cache* 8 | coverage 9 | coverage.json 10 | walk 11 | !.github 12 | out/ 13 | 14 | 15 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/forge-std"] 2 | path = lib/forge-std 3 | url = https://github.com/foundry-rs/forge-std 4 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "overrides": [ 3 | { 4 | "files": "*.sol", 5 | "options": { 6 | "printWidth": 200, 7 | "tabWidth": 2, 8 | "useTabs": false, 9 | "singleQuote": false, 10 | "bracketSpacing": false, 11 | "explicitTypes": "always", 12 | "format": "" 13 | } 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /.solcover.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | peephole: false, 3 | inliner: false, 4 | jumpdestRemover: false, 5 | orderLiterals: true, 6 | deduplicate: false, 7 | cse: false, 8 | constantOptimizer: false, 9 | yul: false, 10 | configureYulOptimizer: true, 11 | skipFiles: ['fakes', 'mock', 'dependencies'] 12 | } -------------------------------------------------------------------------------- /.solhint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "solhint:all", 3 | "rules": { 4 | "avoid-throw": "off", 5 | "avoid-suicide": "error", 6 | "avoid-sha3": "warn", 7 | "compiler-version": [ 8 | "error", 9 | "0.8.0" 10 | ], 11 | "comprehensive-interface": "off", 12 | "max-line-length": "off", 13 | "ordering": "off", 14 | "func-visibility": [ 15 | "error", 16 | { 17 | "ignoreConstructors": true 18 | } 19 | ], 20 | "reason-string": "error", 21 | "quotes": [ 22 | "error", 23 | "double" 24 | ], 25 | "private-vars-leading-underscore": "error" 26 | } 27 | } -------------------------------------------------------------------------------- /.solhintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .todo -------------------------------------------------------------------------------- /abis/IAaveV2LendingPoolLike.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "address", 6 | "name": "asset", 7 | "type": "address" 8 | }, 9 | { 10 | "internalType": "uint256", 11 | "name": "amount", 12 | "type": "uint256" 13 | }, 14 | { 15 | "internalType": "address", 16 | "name": "onBehalfOf", 17 | "type": "address" 18 | }, 19 | { 20 | "internalType": "uint16", 21 | "name": "referralCode", 22 | "type": "uint16" 23 | } 24 | ], 25 | "name": "deposit", 26 | "outputs": [], 27 | "stateMutability": "nonpayable", 28 | "type": "function" 29 | }, 30 | { 31 | "inputs": [ 32 | { 33 | "internalType": "address", 34 | "name": "asset", 35 | "type": "address" 36 | }, 37 | { 38 | "internalType": "uint256", 39 | "name": "amount", 40 | "type": "uint256" 41 | }, 42 | { 43 | "internalType": "address", 44 | "name": "to", 45 | "type": "address" 46 | } 47 | ], 48 | "name": "withdraw", 49 | "outputs": [ 50 | { 51 | "internalType": "uint256", 52 | "name": "", 53 | "type": "uint256" 54 | } 55 | ], 56 | "stateMutability": "nonpayable", 57 | "type": "function" 58 | } 59 | ] -------------------------------------------------------------------------------- /abis/ICompoundERC20DelegatorLike.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "uint256", 6 | "name": "mintAmount", 7 | "type": "uint256" 8 | } 9 | ], 10 | "name": "mint", 11 | "outputs": [ 12 | { 13 | "internalType": "uint256", 14 | "name": "", 15 | "type": "uint256" 16 | } 17 | ], 18 | "stateMutability": "nonpayable", 19 | "type": "function" 20 | }, 21 | { 22 | "inputs": [ 23 | { 24 | "internalType": "uint256", 25 | "name": "redeemTokens", 26 | "type": "uint256" 27 | } 28 | ], 29 | "name": "redeem", 30 | "outputs": [ 31 | { 32 | "internalType": "uint256", 33 | "name": "", 34 | "type": "uint256" 35 | } 36 | ], 37 | "stateMutability": "nonpayable", 38 | "type": "function" 39 | } 40 | ] -------------------------------------------------------------------------------- /abis/IFinalization.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": true, 7 | "internalType": "bytes32", 8 | "name": "coverKey", 9 | "type": "bytes32" 10 | }, 11 | { 12 | "indexed": true, 13 | "internalType": "bytes32", 14 | "name": "productKey", 15 | "type": "bytes32" 16 | }, 17 | { 18 | "indexed": false, 19 | "internalType": "address", 20 | "name": "finalizer", 21 | "type": "address" 22 | }, 23 | { 24 | "indexed": true, 25 | "internalType": "uint256", 26 | "name": "incidentDate", 27 | "type": "uint256" 28 | } 29 | ], 30 | "name": "Finalized", 31 | "type": "event" 32 | }, 33 | { 34 | "inputs": [ 35 | { 36 | "internalType": "bytes32", 37 | "name": "coverKey", 38 | "type": "bytes32" 39 | }, 40 | { 41 | "internalType": "bytes32", 42 | "name": "productKey", 43 | "type": "bytes32" 44 | }, 45 | { 46 | "internalType": "uint256", 47 | "name": "incidentDate", 48 | "type": "uint256" 49 | } 50 | ], 51 | "name": "finalize", 52 | "outputs": [], 53 | "stateMutability": "nonpayable", 54 | "type": "function" 55 | } 56 | ] -------------------------------------------------------------------------------- /abis/IMember.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [], 4 | "name": "getName", 5 | "outputs": [ 6 | { 7 | "internalType": "bytes32", 8 | "name": "", 9 | "type": "bytes32" 10 | } 11 | ], 12 | "stateMutability": "pure", 13 | "type": "function" 14 | }, 15 | { 16 | "inputs": [], 17 | "name": "version", 18 | "outputs": [ 19 | { 20 | "internalType": "bytes32", 21 | "name": "", 22 | "type": "bytes32" 23 | } 24 | ], 25 | "stateMutability": "pure", 26 | "type": "function" 27 | } 28 | ] -------------------------------------------------------------------------------- /abis/IPausable.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [], 4 | "name": "paused", 5 | "outputs": [ 6 | { 7 | "internalType": "bool", 8 | "name": "", 9 | "type": "bool" 10 | } 11 | ], 12 | "stateMutability": "view", 13 | "type": "function" 14 | } 15 | ] -------------------------------------------------------------------------------- /abis/IPriceOracle.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "address", 6 | "name": "token", 7 | "type": "address" 8 | }, 9 | { 10 | "internalType": "uint256", 11 | "name": "amountIn", 12 | "type": "uint256" 13 | } 14 | ], 15 | "name": "consult", 16 | "outputs": [ 17 | { 18 | "internalType": "uint256", 19 | "name": "amountOut", 20 | "type": "uint256" 21 | } 22 | ], 23 | "stateMutability": "view", 24 | "type": "function" 25 | }, 26 | { 27 | "inputs": [ 28 | { 29 | "internalType": "uint256", 30 | "name": "amountIn", 31 | "type": "uint256" 32 | } 33 | ], 34 | "name": "consultPair", 35 | "outputs": [ 36 | { 37 | "internalType": "uint256", 38 | "name": "", 39 | "type": "uint256" 40 | } 41 | ], 42 | "stateMutability": "view", 43 | "type": "function" 44 | }, 45 | { 46 | "inputs": [], 47 | "name": "update", 48 | "outputs": [], 49 | "stateMutability": "nonpayable", 50 | "type": "function" 51 | } 52 | ] -------------------------------------------------------------------------------- /abis/IRecoverable.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "address", 6 | "name": "sendTo", 7 | "type": "address" 8 | } 9 | ], 10 | "name": "recoverEther", 11 | "outputs": [], 12 | "stateMutability": "nonpayable", 13 | "type": "function" 14 | }, 15 | { 16 | "inputs": [ 17 | { 18 | "internalType": "address", 19 | "name": "token", 20 | "type": "address" 21 | }, 22 | { 23 | "internalType": "address", 24 | "name": "sendTo", 25 | "type": "address" 26 | } 27 | ], 28 | "name": "recoverToken", 29 | "outputs": [], 30 | "stateMutability": "nonpayable", 31 | "type": "function" 32 | }, 33 | { 34 | "inputs": [], 35 | "name": "s", 36 | "outputs": [ 37 | { 38 | "internalType": "contract IStore", 39 | "name": "", 40 | "type": "address" 41 | } 42 | ], 43 | "stateMutability": "view", 44 | "type": "function" 45 | } 46 | ] -------------------------------------------------------------------------------- /abis/IUniswapV2FactoryLike.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": true, 7 | "internalType": "address", 8 | "name": "token0", 9 | "type": "address" 10 | }, 11 | { 12 | "indexed": true, 13 | "internalType": "address", 14 | "name": "token1", 15 | "type": "address" 16 | }, 17 | { 18 | "indexed": false, 19 | "internalType": "address", 20 | "name": "pair", 21 | "type": "address" 22 | }, 23 | { 24 | "indexed": false, 25 | "internalType": "uint256", 26 | "name": "", 27 | "type": "uint256" 28 | } 29 | ], 30 | "name": "PairCreated", 31 | "type": "event" 32 | }, 33 | { 34 | "inputs": [ 35 | { 36 | "internalType": "address", 37 | "name": "tokenA", 38 | "type": "address" 39 | }, 40 | { 41 | "internalType": "address", 42 | "name": "tokenB", 43 | "type": "address" 44 | } 45 | ], 46 | "name": "getPair", 47 | "outputs": [ 48 | { 49 | "internalType": "address", 50 | "name": "pair", 51 | "type": "address" 52 | } 53 | ], 54 | "stateMutability": "view", 55 | "type": "function" 56 | } 57 | ] -------------------------------------------------------------------------------- /abis/IUniswapV2PairLike.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [], 4 | "name": "getReserves", 5 | "outputs": [ 6 | { 7 | "internalType": "uint112", 8 | "name": "reserve0", 9 | "type": "uint112" 10 | }, 11 | { 12 | "internalType": "uint112", 13 | "name": "reserve1", 14 | "type": "uint112" 15 | }, 16 | { 17 | "internalType": "uint32", 18 | "name": "blockTimestampLast", 19 | "type": "uint32" 20 | } 21 | ], 22 | "stateMutability": "view", 23 | "type": "function" 24 | }, 25 | { 26 | "inputs": [], 27 | "name": "token0", 28 | "outputs": [ 29 | { 30 | "internalType": "address", 31 | "name": "", 32 | "type": "address" 33 | } 34 | ], 35 | "stateMutability": "view", 36 | "type": "function" 37 | }, 38 | { 39 | "inputs": [], 40 | "name": "token1", 41 | "outputs": [ 42 | { 43 | "internalType": "address", 44 | "name": "", 45 | "type": "address" 46 | } 47 | ], 48 | "stateMutability": "view", 49 | "type": "function" 50 | }, 51 | { 52 | "inputs": [], 53 | "name": "totalSupply", 54 | "outputs": [ 55 | { 56 | "internalType": "uint256", 57 | "name": "", 58 | "type": "uint256" 59 | } 60 | ], 61 | "stateMutability": "view", 62 | "type": "function" 63 | } 64 | ] -------------------------------------------------------------------------------- /audits/001-blocksec.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neptune-mutual-blue/protocol/1256dfc57bd727bdba171d34eabd4176db89f999/audits/001-blocksec.pdf -------------------------------------------------------------------------------- /audits/002-open-zeppelin.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neptune-mutual-blue/protocol/1256dfc57bd727bdba171d34eabd4176db89f999/audits/002-open-zeppelin.pdf -------------------------------------------------------------------------------- /contracts/core/delegates/VaultDelegate.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | 5 | import "./VaultDelegateWithFlashLoan.sol"; 6 | 7 | /** 8 | * @title Vault Delegate 9 | * 10 | * @dev Because vaults cannot be upgraded individually, all vaults delegate some logic to this contract. 11 | * 12 | * @notice Liquidity providers can earn fees by adding stablecoin liquidity 13 | * to any cover contract. The cover pool is collectively owned by liquidity providers 14 | * where fees automatically get accumulated and compounded. 15 | * 16 | *

17 | * 18 | * **Fees:** 19 | * 20 | * - Cover fees paid in stablecoin get added to the liquidity pool. 21 | * - The protocol supplies a small portion of idle assets to third-party lending protocols. 22 | * - Flash loan interest also gets added back to the pool. 23 | * - Cover creators can donate a small portion of their revenue as a reassurance fund 24 | * to protect liquidity providers. This assists liquidity providers in the event of an exploit 25 | * by preventing pool depletion. 26 | * 27 | */ 28 | contract VaultDelegate is VaultDelegateWithFlashLoan { 29 | constructor(IStore store) VaultDelegateBase(store) {} // solhint-disable-line 30 | } 31 | -------------------------------------------------------------------------------- /contracts/core/governance/resolution/Resolution.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "./Unstakable.sol"; 5 | import "../../../interfaces/IResolution.sol"; 6 | 7 | /** 8 | * 9 | * @title Resolution Contract 10 | * @dev This contract enables governance agents or admins to resolve 11 | * actively-reporting cover products. Once a resolution occurs, the 12 | * NPM token holders who voted for the valid camp can unstake 13 | * their stakes after resolution and before finalization 14 | * with additional rewards. 15 | * 16 | */ 17 | contract Resolution is IResolution, Unstakable { 18 | constructor(IStore store) Recoverable(store) {} // solhint-disable-line 19 | 20 | /** 21 | * @dev Version number of this contract 22 | */ 23 | function version() external pure override returns (bytes32) { 24 | return "v0.1"; 25 | } 26 | 27 | /** 28 | * @dev Name of this contract 29 | */ 30 | function getName() external pure override returns (bytes32) { 31 | return ProtoUtilV1.CNAME_RESOLUTION; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /contracts/core/liquidity/VaultBase.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; 4 | import "../Recoverable.sol"; 5 | import "../../interfaces/IVaultDelegate.sol"; 6 | import "../../interfaces/IVault.sol"; 7 | import "../../libraries/NTransferUtilV2.sol"; 8 | 9 | pragma solidity ^0.8.0; 10 | 11 | /** 12 | * @title Vault Base Contract 13 | */ 14 | abstract contract VaultBase is ERC20, Recoverable, IVault { 15 | using ProtoUtilV1 for IStore; 16 | using RegistryLibV1 for IStore; 17 | using NTransferUtilV2 for IERC20; 18 | 19 | bytes32 public override key; 20 | address public override sc; 21 | 22 | /** 23 | * @dev Constructs this contract 24 | * 25 | * @param store Provide store instance 26 | * @param coverKey Provide a cover key that doesn't have a vault deployed 27 | * @param tokenName Enter the token name of the POD. Example: `Uniswap nDAI` or `Uniswap nUSDC` 28 | * @param tokenSymbol Enter the token symbol of the POD. Example: UNI-NDAI or `UNI-NUSDC`. 29 | * @param stablecoin Provide an instance of the stablecoin this vault supports. 30 | * 31 | */ 32 | constructor( 33 | IStore store, 34 | bytes32 coverKey, 35 | string memory tokenName, 36 | string memory tokenSymbol, 37 | IERC20 stablecoin 38 | ) ERC20(tokenName, tokenSymbol) Recoverable(store) { 39 | key = coverKey; 40 | sc = address(stablecoin); 41 | } 42 | 43 | /** 44 | * @dev Returns the delegate contract instance 45 | */ 46 | function delegate() public view returns (IVaultDelegate) { 47 | return IVaultDelegate(s.getVaultDelegate()); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /contracts/core/token/Delayable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.0; 3 | 4 | import "openzeppelin-solidity/contracts/governance/TimelockController.sol"; 5 | import "./WithRecovery.sol"; 6 | 7 | contract Delayable is TimelockController, WithRecovery { 8 | constructor( 9 | uint256 minDelay, 10 | address[] memory proposers, 11 | address[] memory executors 12 | ) TimelockController(minDelay, proposers, executors) {} // solhint-disable-line 13 | } 14 | -------------------------------------------------------------------------------- /contracts/core/token/Treasury.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | 5 | import {IERC20} from "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol"; 6 | import {WithRecovery} from "./WithRecovery.sol"; 7 | import {WithPausability} from "./WithPausability.sol"; 8 | import {SafeERC20} from "openzeppelin-solidity/contracts/token/ERC20/utils/SafeERC20.sol"; 9 | 10 | contract Treasury is WithPausability, WithRecovery { 11 | using SafeERC20 for IERC20; 12 | 13 | constructor(address timelockOrOwner) { 14 | require(timelockOrOwner != address(0), "Invalid owner"); 15 | super._transferOwnership(timelockOrOwner); 16 | } 17 | 18 | function transferMany(IERC20 token, address[] calldata receivers, uint256[] calldata amounts) external onlyOwner whenNotPaused { 19 | require(receivers.length > 0, "No receiver"); 20 | require(receivers.length == amounts.length, "Invalid args"); 21 | require(token.balanceOf(address(this)) >= _sumOf(amounts), "Insufficient Balance"); 22 | 23 | for (uint256 i = 0; i < receivers.length; i++) { 24 | token.safeTransfer(receivers[i], amounts[i]); 25 | } 26 | } 27 | 28 | function _sumOf(uint256[] calldata amounts) private pure returns (uint256 total) { 29 | for (uint256 i = 0; i < amounts.length; i++) { 30 | total += amounts[i]; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /contracts/core/token/WithPausability.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | 5 | import "openzeppelin-solidity/contracts/security/Pausable.sol"; 6 | import "openzeppelin-solidity/contracts/access/Ownable.sol"; 7 | 8 | abstract contract WithPausability is Pausable, Ownable { 9 | mapping(address => bool) public pausers; 10 | 11 | event PausersSet(address indexed addedBy, address[] accounts, bool[] statuses); 12 | 13 | /** 14 | * 15 | * @dev Accepts a list of accounts and their respective statuses for addition or removal as pausers. 16 | * 17 | * @custom:suppress-reentrancy Risk tolerable. Can only be called by the owner. 18 | * @custom:suppress-address-trust-issue Risk tolerable. 19 | */ 20 | function setPausers(address[] calldata accounts, bool[] calldata statuses) external onlyOwner whenNotPaused { 21 | require(accounts.length > 0, "No pauser specified"); 22 | require(accounts.length == statuses.length, "Invalid args"); 23 | 24 | for (uint256 i = 0; i < accounts.length; i++) { 25 | pausers[accounts[i]] = statuses[i]; 26 | } 27 | 28 | emit PausersSet(msg.sender, accounts, statuses); 29 | } 30 | 31 | /** 32 | * @dev Pauses the token 33 | * 34 | * @custom:suppress-reentrancy Risk tolerable. Can only be called by a pauser. 35 | * 36 | */ 37 | function pause() external { 38 | require(pausers[msg.sender], "Forbidden"); 39 | super._pause(); 40 | } 41 | 42 | /** 43 | * @dev Unpauses the token 44 | * 45 | * @custom:suppress-reentrancy Risk tolerable. Can only be called by the owner. 46 | * 47 | */ 48 | function unpause() external onlyOwner { 49 | super._unpause(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /contracts/core/token/WithRecovery.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | 5 | import "openzeppelin-solidity/contracts/token/ERC20/utils/SafeERC20.sol"; 6 | import "openzeppelin-solidity/contracts/access/Ownable.sol"; 7 | 8 | abstract contract WithRecovery is Ownable { 9 | using SafeERC20 for IERC20; 10 | 11 | /** 12 | * @dev Recover all Ether held by the contract. 13 | * 14 | * @custom:suppress-pausable Risk tolerable because of the ACL 15 | * 16 | */ 17 | function recoverEther(address sendTo) external onlyOwner { 18 | // slither-disable-next-line low-level-calls 19 | (bool success, ) = payable(sendTo).call{value: address(this).balance}(""); // solhint-disable-line avoid-low-level-calls 20 | require(success, "Recipient may have reverted"); 21 | } 22 | 23 | /** 24 | * @dev Recover an ERC-20 compatible token sent to this contract. 25 | * @param malicious ERC-20 The address of the token contract 26 | * @param sendTo The address that receives the recovered tokens 27 | * 28 | * @custom:suppress-pausable Risk tolerable because of the ACL 29 | * 30 | */ 31 | function recoverToken(IERC20 malicious, address sendTo) external onlyOwner { 32 | malicious.safeTransfer(sendTo, malicious.balanceOf(address(this))); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /contracts/dependencies/compound/ICompoundERC20DelegatorLike.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: agpl-3.0 2 | pragma solidity ^0.8.0; 3 | 4 | // https://github.com/compound-finance/compound-protocol/blob/master/contracts/CErc20Delegator.sol 5 | interface ICompoundERC20DelegatorLike { 6 | /** 7 | * @notice Sender supplies assets into the market and receives cTokens in exchange 8 | * @dev Accrues interest whether or not the operation succeeds, unless reverted 9 | * @param mintAmount The amount of the underlying asset to supply 10 | * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) 11 | */ 12 | function mint(uint256 mintAmount) external returns (uint256); 13 | 14 | /** 15 | * @notice Sender redeems cTokens in exchange for the underlying asset 16 | * @dev Accrues interest whether or not the operation succeeds, unless reverted 17 | * @param redeemTokens The number of cTokens to redeem into underlying 18 | * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) 19 | */ 20 | function redeem(uint256 redeemTokens) external returns (uint256); 21 | } 22 | -------------------------------------------------------------------------------- /contracts/dependencies/uniswap-v2/IUniswapV2FactoryLike.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | 5 | interface IUniswapV2FactoryLike { 6 | event PairCreated(address indexed token0, address indexed token1, address pair, uint256); 7 | 8 | function getPair(address tokenA, address tokenB) external view returns (address pair); 9 | } 10 | -------------------------------------------------------------------------------- /contracts/dependencies/uniswap-v2/IUniswapV2PairLike.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | 5 | interface IUniswapV2PairLike { 6 | function token0() external view returns (address); 7 | 8 | function token1() external view returns (address); 9 | 10 | function totalSupply() external view returns (uint256); 11 | 12 | function getReserves() 13 | external 14 | view 15 | returns ( 16 | uint112 reserve0, 17 | uint112 reserve1, 18 | uint32 blockTimestampLast 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /contracts/dependencies/uniswap-v2/IUniswapV2RouterLike.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | 5 | interface IUniswapV2RouterLike { 6 | function factory() external view returns (address); 7 | 8 | function getAmountOut( 9 | uint256 amountIn, 10 | uint256 reserveIn, 11 | uint256 reserveOut 12 | ) external pure returns (uint256 amountOut); 13 | 14 | function getAmountIn( 15 | uint256 amountOut, 16 | uint256 reserveIn, 17 | uint256 reserveOut 18 | ) external pure returns (uint256 amountIn); 19 | 20 | function getAmountsOut(uint256 amountIn, address[] calldata path) external view returns (uint256[] memory amounts); 21 | 22 | function getAmountsIn(uint256 amountOut, address[] calldata path) external view returns (uint256[] memory amounts); 23 | 24 | function quote( 25 | uint256 amountA, 26 | uint256 reserveA, 27 | uint256 reserveB 28 | ) external pure returns (uint256 amountB); 29 | 30 | function addLiquidity( 31 | address tokenA, 32 | address tokenB, 33 | uint256 amountADesired, 34 | uint256 amountBDesired, 35 | uint256 amountAMin, 36 | uint256 amountBMin, 37 | address to, 38 | uint256 deadline 39 | ) 40 | external 41 | returns ( 42 | uint256 amountA, 43 | uint256 amountB, 44 | uint256 liquidity 45 | ); 46 | } 47 | -------------------------------------------------------------------------------- /contracts/fakes/Destroyable.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | 5 | contract Destroyable { 6 | constructor() payable {} // solhint-disable-line 7 | 8 | // slither-disable-next-line suicidal 9 | function destroy(address payable _recipient) public { 10 | selfdestruct(_recipient); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /contracts/fakes/FakeAaveLendingPool.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "../dependencies/aave/IAaveV2LendingPoolLike.sol"; 5 | import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; 6 | import "./FakeToken.sol"; 7 | 8 | contract FakeAaveLendingPool is IAaveV2LendingPoolLike, ERC20 { 9 | FakeToken public aToken; 10 | 11 | constructor(FakeToken _aToken) ERC20("aStablecoin", "aStablecoin") { 12 | aToken = _aToken; 13 | } 14 | 15 | function deposit( 16 | address asset, 17 | uint256 amount, 18 | address, 19 | uint16 20 | ) external override { 21 | IERC20(asset).transferFrom(msg.sender, address(this), amount); 22 | aToken.mint(amount); 23 | aToken.transfer(msg.sender, amount); 24 | } 25 | 26 | function withdraw( 27 | address asset, 28 | uint256 amount, 29 | address to 30 | ) external override returns (uint256) { 31 | aToken.transferFrom(msg.sender, address(this), amount); 32 | 33 | FakeToken stablecoin = FakeToken(asset); 34 | 35 | uint256 interest = (amount * 10) / 100; 36 | stablecoin.mint(interest); 37 | 38 | stablecoin.transfer(to, amount + interest); 39 | 40 | return amount; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /contracts/fakes/FakePriceOracle.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "../interfaces/IPriceOracle.sol"; 5 | 6 | contract FakePriceOracle is IPriceOracle { 7 | uint256 private _counter = 0; 8 | 9 | function update() external override { 10 | _counter++; 11 | } 12 | 13 | function consult(address, uint256 amountIn) external pure override returns (uint256) { 14 | return amountIn * 2; 15 | } 16 | 17 | function consultPair(uint256 amountIn) external pure override returns (uint256) { 18 | return amountIn; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /contracts/fakes/FakeRecoverable.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "../core/Recoverable.sol"; 5 | 6 | contract FakeRecoverable is Recoverable { 7 | constructor(IStore s) Recoverable(s) {} // solhint-disable-line 8 | } 9 | -------------------------------------------------------------------------------- /contracts/fakes/FakeToken.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; 5 | 6 | contract FakeToken is ERC20 { 7 | address public immutable deployer; 8 | mapping(address => bool) public minters; 9 | uint8 private immutable _decimals; 10 | 11 | function addMinter(address account, bool flag) public onlyDeployer { 12 | minters[account] = flag; 13 | } 14 | 15 | modifier onlyDeployer() { 16 | require(msg.sender == deployer, "Forbidden"); 17 | _; 18 | } 19 | 20 | constructor( 21 | string memory name, 22 | string memory symbol, 23 | uint256 supply, 24 | uint8 decimalPlaces 25 | ) ERC20(name, symbol) { 26 | require(decimalPlaces > 0, "Invalid decimal places value"); 27 | 28 | super._mint(msg.sender, supply); 29 | deployer = msg.sender; 30 | minters[msg.sender] = true; 31 | _decimals = decimalPlaces; 32 | } 33 | 34 | function decimals() public view virtual override returns (uint8) { 35 | return _decimals; 36 | } 37 | 38 | function mint(uint256 amount) external { 39 | if (amount > 2000 * (10**_decimals)) { 40 | require(minters[msg.sender], "Please specify a smaller value"); 41 | } 42 | 43 | super._mint(msg.sender, amount); 44 | } 45 | 46 | function burn(uint256 amount) external { 47 | super._burn(msg.sender, amount); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /contracts/fakes/FakeUniswapPair.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "../dependencies/uniswap-v2/IUniswapV2PairLike.sol"; 5 | import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; 6 | 7 | contract FakeUniswapPair is IUniswapV2PairLike, ERC20 { 8 | address public override token0; 9 | address public override token1; 10 | 11 | constructor(address _token0, address _token1) ERC20("PAIR", "PAIR") { 12 | token0 = _token0; 13 | token1 = _token1; 14 | 15 | super._mint(msg.sender, 100000 ether); 16 | } 17 | 18 | function totalSupply() public view override(ERC20, IUniswapV2PairLike) returns (uint256) { 19 | return super.totalSupply(); 20 | } 21 | 22 | function getReserves() 23 | external 24 | view 25 | override 26 | returns ( 27 | uint112 reserve0, 28 | uint112 reserve1, 29 | uint32 blockTimestampLast 30 | ) 31 | { 32 | reserve0 = 100000 ether; 33 | reserve1 = 50000 ether; 34 | blockTimestampLast = uint32(block.timestamp - 1 hours); // solhint-disable-line 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /contracts/fakes/FakeUniswapV2FactoryLike.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "../dependencies/uniswap-v2/IUniswapV2FactoryLike.sol"; 5 | 6 | contract FakeUniswapV2FactoryLike is IUniswapV2FactoryLike { 7 | address public pair; 8 | 9 | constructor(address _pair) { 10 | pair = _pair; 11 | } 12 | 13 | function getPair(address, address) external view override returns (address) { 14 | return pair; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /contracts/fakes/FakeUniswapV2PairLike.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "../dependencies/uniswap-v2/IUniswapV2PairLike.sol"; 5 | 6 | contract FakeUniswapV2PairLike is IUniswapV2PairLike { 7 | address public override token0; 8 | address public override token1; 9 | 10 | constructor(address _token0, address _token1) { 11 | token0 = _token0; 12 | token1 = _token1; 13 | } 14 | 15 | function totalSupply() external pure override returns (uint256) { 16 | return 100 ether; 17 | } 18 | 19 | function getReserves() 20 | external 21 | view 22 | override 23 | returns ( 24 | uint112 reserve0, 25 | uint112 reserve1, 26 | uint32 blockTimestampLast 27 | ) 28 | { 29 | reserve0 = 200 ether; 30 | reserve1 = 100 ether; 31 | blockTimestampLast = uint32(block.timestamp); // solhint-disable-line 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /contracts/fakes/FaultyAaveLendingPool.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "../dependencies/aave/IAaveV2LendingPoolLike.sol"; 5 | import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; 6 | import "./FakeToken.sol"; 7 | 8 | contract FaultyAaveLendingPool is IAaveV2LendingPoolLike, ERC20 { 9 | FakeToken public aToken; 10 | 11 | constructor(FakeToken _aToken) ERC20("aStablecoin", "aStablecoin") { 12 | aToken = _aToken; 13 | } 14 | 15 | function deposit( 16 | address asset, 17 | uint256 amount, 18 | address, 19 | uint16 20 | ) external override { 21 | IERC20(asset).transferFrom(msg.sender, address(this), amount); 22 | } 23 | 24 | function withdraw( 25 | address, /*asset*/ 26 | uint256 amount, 27 | address /*to*/ 28 | ) external override returns (uint256) { 29 | aToken.transferFrom(msg.sender, address(this), amount); 30 | return amount; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /contracts/fakes/ForceEther.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: BUSL-1.1 2 | pragma solidity ^0.8.0; 3 | 4 | contract ForceEther { 5 | event Received(address indexed account, uint256 amount); 6 | 7 | receive() external payable { 8 | emit Received(msg.sender, msg.value); 9 | } 10 | 11 | function destruct(address payable to) external { 12 | selfdestruct(to); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /contracts/fakes/InvalidStrategy.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | 5 | import "../core/liquidity/strategies/AaveStrategy.sol"; 6 | 7 | contract InvalidStrategy is AaveStrategy { 8 | constructor( 9 | IStore _s, 10 | IAaveV2LendingPoolLike _lendingPool, 11 | address _aToken 12 | ) AaveStrategy(_s, _lendingPool, _aToken) {} // solhint-disable-line 13 | 14 | function getWeight() external pure override returns (uint256) { 15 | return 20_000; // 100% 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /contracts/fakes/MaliciousToken.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; 5 | 6 | contract MaliciousToken is ERC20 { 7 | address public constant BAD = 0x0000000000000000000000000000000000000010; 8 | 9 | constructor() ERC20("Malicious Token", "MAL") {} // solhint-disable-line 10 | 11 | function mint(address account, uint256 amount) external { 12 | super._mint(account, amount); 13 | } 14 | 15 | function transfer(address recipient, uint256 amount) public override returns (bool) { 16 | _transfer(msg.sender, BAD, (amount * 10) / 100); 17 | _transfer(msg.sender, recipient, (amount * 90) / 100); 18 | 19 | return true; 20 | } 21 | 22 | function transferFrom( 23 | address sender, 24 | address recipient, 25 | uint256 amount 26 | ) public override returns (bool) { 27 | super.transferFrom(sender, BAD, (amount * 10) / 100); 28 | super.transferFrom(sender, recipient, (amount * 90) / 100); 29 | 30 | return true; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /contracts/fakes/NTransferUtilV2Intermediate.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol"; 5 | import "../libraries/NTransferUtilV2.sol"; 6 | 7 | contract NTransferUtilV2Intermediate { 8 | using NTransferUtilV2 for IERC20; 9 | 10 | function iTransfer( 11 | IERC20 token, 12 | address recipient, 13 | uint256 amount 14 | ) external { 15 | token.ensureTransfer(recipient, amount); 16 | } 17 | 18 | function iTransferFrom( 19 | IERC20 token, 20 | address sender, 21 | address recipient, 22 | uint256 amount 23 | ) external { 24 | token.ensureTransferFrom(sender, recipient, amount); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /contracts/interfaces/IBondPool.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "./IMember.sol"; 5 | 6 | interface IBondPool is IMember { 7 | struct BondPoolInfoType { 8 | address lpToken; 9 | uint256 marketPrice; 10 | uint256 discountRate; 11 | uint256 vestingTerm; 12 | uint256 maxBond; 13 | uint256 totalNpmAllocated; 14 | uint256 totalNpmDistributed; 15 | uint256 npmAvailable; 16 | uint256 bondContribution; 17 | uint256 claimable; 18 | uint256 unlockDate; 19 | } 20 | 21 | struct SetupBondPoolArgs { 22 | address lpToken; 23 | address treasury; 24 | uint256 bondDiscountRate; 25 | uint256 maxBondAmount; 26 | uint256 vestingTerm; 27 | uint256 npmToTopUpNow; 28 | } 29 | 30 | event BondPoolSetup(SetupBondPoolArgs args); 31 | event BondCreated(address indexed account, uint256 lpTokens, uint256 npmToVest, uint256 unlockDate); 32 | event BondClaimed(address indexed account, uint256 amount); 33 | 34 | function setup(SetupBondPoolArgs calldata args) external; 35 | 36 | function createBond(uint256 lpTokens, uint256 minNpmDesired) external; 37 | 38 | function claimBond() external; 39 | 40 | function getNpmMarketPrice() external view returns (uint256); 41 | 42 | function calculateTokensForLp(uint256 lpTokens) external view returns (uint256); 43 | 44 | function getInfo(address forAccount) external view returns (BondPoolInfoType memory info); 45 | } 46 | -------------------------------------------------------------------------------- /contracts/interfaces/IClaimsProcessor.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "./IMember.sol"; 5 | 6 | interface IClaimsProcessor is IMember { 7 | event Claimed( 8 | address cxToken, 9 | bytes32 indexed coverKey, 10 | bytes32 indexed productKey, 11 | uint256 incidentDate, 12 | address indexed account, 13 | address reporter, 14 | uint256 amount, 15 | uint256 reporterFee, 16 | uint256 platformFee, 17 | uint256 claimed 18 | ); 19 | event ClaimPeriodSet(bytes32 indexed coverKey, uint256 previous, uint256 current); 20 | event BlacklistSet(bytes32 indexed coverKey, bytes32 indexed productKey, uint256 indexed incidentDate, address account, bool status); 21 | 22 | function claim( 23 | address cxToken, 24 | bytes32 coverKey, 25 | bytes32 productKey, 26 | uint256 incidentDate, 27 | uint256 amount 28 | ) external; 29 | 30 | function validate( 31 | address cxToken, 32 | bytes32 coverKey, 33 | bytes32 productKey, 34 | uint256 incidentDate, 35 | uint256 amount 36 | ) external view returns (bool); 37 | 38 | function setClaimPeriod(bytes32 coverKey, uint256 value) external; 39 | 40 | function getClaimExpiryDate(bytes32 coverKey, bytes32 productKey) external view returns (uint256); 41 | 42 | function setBlacklist( 43 | bytes32 coverKey, 44 | bytes32 productKey, 45 | uint256 incidentDate, 46 | address[] calldata accounts, 47 | bool[] calldata statuses 48 | ) external; 49 | 50 | function isBlacklisted( 51 | bytes32 coverKey, 52 | bytes32 productKey, 53 | uint256 incidentDate, 54 | address account 55 | ) external view returns (bool); 56 | } 57 | -------------------------------------------------------------------------------- /contracts/interfaces/ICoverReassurance.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "./IMember.sol"; 5 | 6 | interface ICoverReassurance is IMember { 7 | event ReassuranceAdded(bytes32 indexed coverKey, address indexed onBehalfOf, uint256 amount); 8 | event WeightSet(bytes32 indexed coverKey, uint256 weight); 9 | event PoolCapitalized(bytes32 indexed coverKey, bytes32 indexed productKey, uint256 indexed incidentDate, uint256 amount); 10 | 11 | /** 12 | * @dev Adds reassurance to the specified cover contract 13 | * @param coverKey Enter the cover key 14 | * @param onBehalfOf Enter the account on behalf of which you are adding reassurance. 15 | * @param amount Enter the amount you would like to supply 16 | */ 17 | function addReassurance( 18 | bytes32 coverKey, 19 | address onBehalfOf, 20 | uint256 amount 21 | ) external; 22 | 23 | function setWeight(bytes32 coverKey, uint256 weight) external; 24 | 25 | function capitalizePool( 26 | bytes32 coverKey, 27 | bytes32 productKey, 28 | uint256 incidentDate 29 | ) external; 30 | 31 | /** 32 | * @dev Gets the reassurance amount of the specified cover contract 33 | * @param coverKey Enter the cover key 34 | */ 35 | function getReassurance(bytes32 coverKey) external view returns (uint256); 36 | } 37 | -------------------------------------------------------------------------------- /contracts/interfaces/ICoverStake.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "./IMember.sol"; 5 | 6 | interface ICoverStake is IMember { 7 | event StakeAdded(bytes32 indexed coverKey, address indexed account, uint256 amount); 8 | event StakeRemoved(bytes32 indexed coverKey, address indexed account, uint256 amount); 9 | event FeeBurned(bytes32 indexed coverKey, uint256 amount); 10 | 11 | /** 12 | * @dev Increase the stake of the given cover pool 13 | * @param coverKey Enter the cover key 14 | * @param account Enter the account from where the NPM tokens will be transferred 15 | * @param amount Enter the amount of stake 16 | * @param fee Enter the fee amount. Note: do not enter the fee if you are directly calling this function. 17 | */ 18 | function increaseStake( 19 | bytes32 coverKey, 20 | address account, 21 | uint256 amount, 22 | uint256 fee 23 | ) external; 24 | 25 | /** 26 | * @dev Decreases the stake from the given cover pool 27 | * @param coverKey Enter the cover key 28 | * @param amount Enter the amount of stake to decrease 29 | */ 30 | function decreaseStake(bytes32 coverKey, uint256 amount) external; 31 | 32 | /** 33 | * @dev Gets the stake of an account for the given cover key 34 | * @param coverKey Enter the cover key 35 | * @param account Specify the account to obtain the stake of 36 | * @return Returns the total stake of the specified account on the given cover key 37 | */ 38 | function stakeOf(bytes32 coverKey, address account) external view returns (uint256); 39 | } 40 | -------------------------------------------------------------------------------- /contracts/interfaces/ICxToken.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol"; 4 | 5 | pragma solidity ^0.8.0; 6 | 7 | interface ICxToken is IERC20 { 8 | event CoverageStartSet(uint256 policyId, bytes32 coverKey, bytes32 productKey, address account, uint256 effectiveFrom, uint256 amount); 9 | 10 | function mint( 11 | uint256 policyId, 12 | bytes32 coverKey, 13 | bytes32 productKey, 14 | address to, 15 | uint256 amount 16 | ) external; 17 | 18 | function burn(uint256 amount) external; 19 | 20 | function createdOn() external view returns (uint256); 21 | 22 | function expiresOn() external view returns (uint256); 23 | 24 | // slither-disable-next-line naming-convention 25 | function COVER_KEY() external view returns (bytes32); // solhint-disable 26 | 27 | // slither-disable-next-line naming-convention 28 | function PRODUCT_KEY() external view returns (bytes32); // solhint-disable 29 | 30 | function getCoverageStartsFrom(address account, uint256 date) external view returns (uint256); 31 | 32 | function getClaimablePolicyOf(address account) external view returns (uint256); 33 | } 34 | -------------------------------------------------------------------------------- /contracts/interfaces/ICxTokenFactory.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "./IStore.sol"; 5 | import "./IMember.sol"; 6 | 7 | interface ICxTokenFactory is IMember { 8 | event CxTokenDeployed(address cxToken, IStore store, bytes32 indexed coverKey, bytes32 indexed productKey, string tokenName, uint256 indexed expiryDate); 9 | 10 | function deploy( 11 | bytes32 coverKey, 12 | bytes32 productKey, 13 | string calldata tokenName, 14 | uint256 expiryDate 15 | ) external returns (address); 16 | } 17 | -------------------------------------------------------------------------------- /contracts/interfaces/IERC20Detailed.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol"; 4 | 5 | pragma solidity ^0.8.0; 6 | 7 | interface IERC20Detailed is IERC20 { 8 | function name() external view returns (string memory); 9 | 10 | function symbol() external view returns (string memory); 11 | 12 | function decimals() external view returns (uint8); 13 | 14 | function mint(uint256 amount) external; 15 | } 16 | -------------------------------------------------------------------------------- /contracts/interfaces/IFinalization.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | 5 | interface IFinalization { 6 | event Finalized(bytes32 indexed coverKey, bytes32 indexed productKey, address finalizer, uint256 indexed incidentDate); 7 | 8 | function finalize( 9 | bytes32 coverKey, 10 | bytes32 productKey, 11 | uint256 incidentDate 12 | ) external; 13 | } 14 | -------------------------------------------------------------------------------- /contracts/interfaces/IGovernance.sol: -------------------------------------------------------------------------------- 1 | /* solhint-disable function-max-lines */ 2 | // Neptune Mutual Protocol (https://neptunemutual.com) 3 | // SPDX-License-Identifier: BUSL-1.1 4 | pragma solidity ^0.8.0; 5 | import "./IReporter.sol"; 6 | import "./IWitness.sol"; 7 | import "./IMember.sol"; 8 | 9 | // solhint-disable-next-line 10 | interface IGovernance is IMember, IReporter, IWitness { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /contracts/interfaces/ILendingStrategy.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol"; 4 | import "./IMember.sol"; 5 | 6 | pragma solidity ^0.8.0; 7 | 8 | interface ILendingStrategy is IMember { 9 | struct LendingStrategyInfoType { 10 | uint256 deposits; 11 | uint256 withdrawals; 12 | } 13 | 14 | event LogDeposit(bytes32 indexed name, uint256 counter, uint256 amount, uint256 certificateReceived, uint256 depositTotal, uint256 withdrawalTotal); 15 | event Deposited(bytes32 indexed key, address indexed onBehalfOf, uint256 stablecoinDeposited, uint256 certificateTokenIssued); 16 | event LogWithdrawal(bytes32 indexed name, uint256 counter, uint256 stablecoinWithdrawn, uint256 certificateRedeemed, uint256 depositTotal, uint256 withdrawalTotal); 17 | event Withdrawn(bytes32 indexed key, address indexed sendTo, uint256 stablecoinWithdrawn, uint256 certificateTokenRedeemed); 18 | event Drained(IERC20 indexed asset, uint256 amount); 19 | 20 | function getKey() external pure returns (bytes32); 21 | 22 | function getWeight() external pure returns (uint256); 23 | 24 | function getDepositAsset() external view returns (IERC20); 25 | 26 | function getDepositCertificate() external view returns (IERC20); 27 | 28 | /** 29 | * @dev Gets info of this strategy by cover key 30 | * @param coverKey Enter the cover key 31 | */ 32 | function getInfo(bytes32 coverKey) external view returns (LendingStrategyInfoType memory info); 33 | 34 | function deposit(bytes32 coverKey, uint256 amount) external returns (uint256 certificateReceived); 35 | 36 | function withdraw(bytes32 coverKey) external returns (uint256 stablecoinWithdrawn); 37 | } 38 | -------------------------------------------------------------------------------- /contracts/interfaces/ILiquidityEngine.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol"; 4 | import "./IMember.sol"; 5 | import "./IVault.sol"; 6 | 7 | pragma solidity ^0.8.0; 8 | 9 | interface ILiquidityEngine is IMember { 10 | event StrategyAdded(address indexed strategy); 11 | event StrategyDisabled(address indexed strategy); 12 | event StrategyDeleted(address indexed strategy); 13 | event RiskPoolingPeriodSet(bytes32 indexed coverKey, uint256 lendingPeriod, uint256 withdrawalWindow); 14 | event LiquidityStateUpdateIntervalSet(uint256 duration); 15 | event MaxLendingRatioSet(uint256 ratio); 16 | 17 | function addStrategies(address[] calldata strategies) external; 18 | 19 | function disableStrategy(address strategy) external; 20 | 21 | function deleteStrategy(address strategy) external; 22 | 23 | function setRiskPoolingPeriods( 24 | bytes32 coverKey, 25 | uint256 lendingPeriod, 26 | uint256 withdrawalWindow 27 | ) external; 28 | 29 | function getRiskPoolingPeriods(bytes32 coverKey) external view returns (uint256 lendingPeriod, uint256 withdrawalWindow); 30 | 31 | function setLiquidityStateUpdateInterval(uint256 value) external; 32 | 33 | function setMaxLendingRatio(uint256 ratio) external; 34 | 35 | function getMaxLendingRatio() external view returns (uint256 ratio); 36 | 37 | function getDisabledStrategies() external view returns (address[] memory strategies); 38 | 39 | function getActiveStrategies() external view returns (address[] memory strategies); 40 | 41 | function addBulkLiquidity(IVault.AddLiquidityArgs[] calldata args) external; 42 | } 43 | -------------------------------------------------------------------------------- /contracts/interfaces/IMember.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | 5 | interface IMember { 6 | /** 7 | * @dev Version number of this contract 8 | */ 9 | function version() external pure returns (bytes32); 10 | 11 | /** 12 | * @dev Name of this contract 13 | */ 14 | function getName() external pure returns (bytes32); 15 | } 16 | -------------------------------------------------------------------------------- /contracts/interfaces/IPausable.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | 5 | interface IPausable { 6 | function paused() external view returns (bool); 7 | } 8 | -------------------------------------------------------------------------------- /contracts/interfaces/IPolicyAdmin.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "./IMember.sol"; 5 | 6 | interface IPolicyAdmin is IMember { 7 | event CoverPolicyRateSet(bytes32 indexed coverKey, uint256 floor, uint256 ceiling); 8 | event CoverageLagSet(bytes32 indexed coverKey, uint256 window); 9 | 10 | /** 11 | * @dev Sets policy rates for the given cover key. This feature is only accessible by owner or protocol owner. 12 | * @param floor The lowest cover fee rate for this cover 13 | * @param ceiling The highest cover fee rate for this cover 14 | */ 15 | function setPolicyRatesByKey( 16 | bytes32 coverKey, 17 | uint256 floor, 18 | uint256 ceiling 19 | ) external; 20 | 21 | /** 22 | * @dev Gets the cover policy rates for the given cover key 23 | */ 24 | function getPolicyRates(bytes32 coverKey) external view returns (uint256 floor, uint256 ceiling); 25 | 26 | function setCoverageLag(bytes32 coverKey, uint256 window) external; 27 | 28 | function getCoverageLag(bytes32 coverKey) external view returns (uint256); 29 | } 30 | -------------------------------------------------------------------------------- /contracts/interfaces/IPriceOracle.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | 5 | interface IPriceOracle { 6 | function update() external; 7 | 8 | function consult(address token, uint256 amountIn) external view returns (uint256 amountOut); 9 | 10 | function consultPair(uint256 amountIn) external view returns (uint256); 11 | } 12 | -------------------------------------------------------------------------------- /contracts/interfaces/IRecoverable.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "./IStore.sol"; 5 | 6 | interface IRecoverable { 7 | function s() external view returns (IStore); 8 | 9 | function recoverEther(address sendTo) external; 10 | 11 | function recoverToken(address token, address sendTo) external; 12 | } 13 | -------------------------------------------------------------------------------- /contracts/interfaces/IResolution.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "./IFinalization.sol"; 5 | import "./IResolvable.sol"; 6 | import "./IUnstakable.sol"; 7 | import "./IMember.sol"; 8 | 9 | //solhint-disable-next-line 10 | interface IResolution is IFinalization, IResolvable, IUnstakable, IMember { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /contracts/interfaces/IResolvable.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | 5 | interface IResolvable { 6 | event Resolved( 7 | bytes32 indexed coverKey, 8 | bytes32 indexed productKey, 9 | uint256 incidentDate, 10 | uint256 resolutionDeadline, 11 | bool decision, 12 | bool emergency, 13 | uint256 claimBeginsFrom, 14 | uint256 claimExpiresAt 15 | ); 16 | event CooldownPeriodConfigured(bytes32 indexed coverKey, uint256 period); 17 | event ReportClosed(bytes32 indexed coverKey, bytes32 indexed productKey, address indexed closedBy, uint256 incidentDate); 18 | 19 | function resolve( 20 | bytes32 coverKey, 21 | bytes32 productKey, 22 | uint256 incidentDate 23 | ) external; 24 | 25 | function emergencyResolve( 26 | bytes32 coverKey, 27 | bytes32 productKey, 28 | uint256 incidentDate, 29 | bool decision 30 | ) external; 31 | 32 | function closeReport( 33 | bytes32 coverKey, 34 | bytes32 productKey, 35 | uint256 incidentDate 36 | ) external; 37 | 38 | function configureCoolDownPeriod(bytes32 coverKey, uint256 period) external; 39 | 40 | function getCoolDownPeriod(bytes32 coverKey) external view returns (uint256); 41 | 42 | function getResolutionDeadline(bytes32 coverKey, bytes32 productKey) external view returns (uint256); 43 | } 44 | -------------------------------------------------------------------------------- /contracts/interfaces/IUnstakable.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "./IStore.sol"; 5 | 6 | interface IUnstakable { 7 | struct UnstakeInfoType { 8 | uint256 totalStakeInWinningCamp; 9 | uint256 totalStakeInLosingCamp; 10 | uint256 myStakeInWinningCamp; 11 | uint256 toBurn; 12 | uint256 toReporter; 13 | uint256 myReward; 14 | uint256 unstaken; 15 | } 16 | 17 | event Unstaken(bytes32 indexed coverKey, bytes32 indexed productKey, address indexed caller, uint256 originalStake, uint256 reward); 18 | event ReporterRewardDistributed(bytes32 indexed coverKey, bytes32 indexed productKey, address caller, address indexed reporter, uint256 originalReward, uint256 reporterReward); 19 | event GovernanceBurned(bytes32 indexed coverKey, bytes32 indexed productKey, address caller, address indexed burner, uint256 originalReward, uint256 burnedAmount); 20 | 21 | function unstake( 22 | bytes32 coverKey, 23 | bytes32 productKey, 24 | uint256 incidentDate 25 | ) external; 26 | 27 | function unstakeWithClaim( 28 | bytes32 coverKey, 29 | bytes32 productKey, 30 | uint256 incidentDate 31 | ) external; 32 | 33 | function getUnstakeInfoFor( 34 | address account, 35 | bytes32 coverKey, 36 | bytes32 productKey, 37 | uint256 incidentDate 38 | ) external view returns (UnstakeInfoType memory); 39 | } 40 | -------------------------------------------------------------------------------- /contracts/interfaces/IVaultFactory.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "./IStore.sol"; 5 | import "./IMember.sol"; 6 | 7 | interface IVaultFactory is IMember { 8 | event VaultDeployed(address vault, bytes32 indexed coverKey, string name, string symbol); 9 | 10 | function deploy( 11 | bytes32 coverKey, 12 | string calldata name, 13 | string calldata symbol 14 | ) external returns (address); 15 | } 16 | -------------------------------------------------------------------------------- /contracts/interfaces/IWitness.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | 5 | interface IWitness { 6 | event Attested(bytes32 indexed coverKey, bytes32 indexed productKey, address witness, uint256 indexed incidentDate, uint256 stake); 7 | event Refuted(bytes32 indexed coverKey, bytes32 indexed productKey, address witness, uint256 indexed incidentDate, uint256 stake); 8 | 9 | function attest( 10 | bytes32 coverKey, 11 | bytes32 productKey, 12 | uint256 incidentDate, 13 | uint256 stake 14 | ) external; 15 | 16 | function refute( 17 | bytes32 coverKey, 18 | bytes32 productKey, 19 | uint256 incidentDate, 20 | uint256 stake 21 | ) external; 22 | 23 | function getStatus(bytes32 coverKey, bytes32 productKey) external view returns (uint256); 24 | 25 | function isCoverNormal(bytes32 coverKey) external view returns (bool); 26 | 27 | function getStakes( 28 | bytes32 coverKey, 29 | bytes32 productKey, 30 | uint256 incidentDate 31 | ) external view returns (uint256, uint256); 32 | 33 | function getStakesOf( 34 | bytes32 coverKey, 35 | bytes32 productKey, 36 | uint256 incidentDate, 37 | address account 38 | ) external view returns (uint256, uint256); 39 | } 40 | -------------------------------------------------------------------------------- /contracts/libraries/VaultFactoryLibV1.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | 5 | import "../core/liquidity/Vault.sol"; 6 | 7 | library VaultFactoryLibV1 { 8 | /** 9 | * @dev Gets the bytecode of the `Vault` contract 10 | * @param s Provide the store instance 11 | * @param coverKey Provide the cover key 12 | * @param stablecoin Specify the liquidity token for this Vault 13 | */ 14 | function getByteCodeInternal( 15 | IStore s, 16 | bytes32 coverKey, 17 | string calldata tokenName, 18 | string calldata tokenSymbol, 19 | address stablecoin 20 | ) external pure returns (bytes memory bytecode, bytes32 salt) { 21 | salt = keccak256(abi.encodePacked(ProtoUtilV1.NS_CONTRACTS, ProtoUtilV1.CNS_COVER_VAULT, coverKey)); 22 | 23 | //slither-disable-next-line too-many-digits 24 | bytecode = abi.encodePacked(type(Vault).creationCode, abi.encode(s, coverKey, tokenName, tokenSymbol, stablecoin)); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /contracts/libraries/cxTokenFactoryLibV1.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | 5 | import "../core/cxToken/cxToken.sol"; 6 | 7 | // slither-disable-next-line naming-convention 8 | library cxTokenFactoryLibV1 { 9 | // solhint-disable-previous-line 10 | /** 11 | * @dev Gets the bytecode of the `cxToken` contract 12 | * 13 | * Warning: this function does not validate the input arguments. 14 | * 15 | * @param s Provide the store instance 16 | * @param coverKey Provide the cover key 17 | * @param expiryDate Specify the expiry date of this cxToken instance 18 | * 19 | */ 20 | function getByteCodeInternal( 21 | IStore s, 22 | bytes32 coverKey, 23 | bytes32 productKey, 24 | string memory tokenName, 25 | uint256 expiryDate 26 | ) external pure returns (bytes memory bytecode, bytes32 salt) { 27 | salt = keccak256(abi.encodePacked(ProtoUtilV1.NS_COVER_CXTOKEN, coverKey, productKey, expiryDate)); 28 | 29 | //slither-disable-next-line too-many-digits 30 | bytecode = abi.encodePacked(type(cxToken).creationCode, abi.encode(s, coverKey, productKey, tokenName, expiryDate)); 31 | require(bytecode.length > 0, "Invalid bytecode"); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /contracts/mock/MockRegistryClient.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "../libraries/RegistryLibV1.sol"; 5 | 6 | contract MockRegistryClient { 7 | using RegistryLibV1 for IStore; 8 | IStore public s; 9 | 10 | constructor(IStore store) { 11 | s = store; 12 | } 13 | 14 | function getGovernanceContract() external view returns (IGovernance) { 15 | return s.getGovernanceContract(); 16 | } 17 | 18 | function getPolicyContract() external view returns (IPolicy) { 19 | return s.getPolicyContract(); 20 | } 21 | 22 | function getBondPoolContract() external view returns (IBondPool) { 23 | return s.getBondPoolContract(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /contracts/mock/base/MockCxToken.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; 5 | 6 | contract MockCxToken is ERC20 { 7 | constructor() ERC20("Test", "Test") { 8 | super._mint(msg.sender, 1 ether); 9 | } 10 | 11 | function burn(uint256 amount) external { 12 | super._burn(msg.sender, amount); 13 | } 14 | 15 | function expiresOn() external view returns (uint256) { 16 | return block.timestamp + 30 days; // solhint-disable-line 17 | } 18 | 19 | function getClaimablePolicyOf(address) external pure returns (uint256) { 20 | return 1000 ether; 21 | } 22 | 23 | // slither-disable-next-line naming-convention 24 | function COVER_KEY() external pure returns (bytes32) { 25 | // solhint-disable-previous-line 26 | return "test"; 27 | } 28 | 29 | // slither-disable-next-line naming-convention 30 | function PRODUCT_KEY() external pure returns (bytes32) { 31 | // solhint-disable-previous-line 32 | return ""; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /contracts/mock/base/MockProtocol.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "openzeppelin-solidity/contracts/access/AccessControl.sol"; 5 | 6 | // slither-disable-next-line missing-inheritance 7 | contract MockProtocol is AccessControl { 8 | bool public state = false; 9 | 10 | function setPaused(bool s) external { 11 | state = s; 12 | } 13 | 14 | function paused() external view returns (bool) { 15 | return state; 16 | } 17 | 18 | function setupRole( 19 | bytes32 role, 20 | bytes32 adminRole, 21 | address account 22 | ) external { 23 | _setRoleAdmin(role, adminRole); 24 | 25 | if (account != address(0)) { 26 | _setupRole(role, account); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /contracts/mock/base/MockStore.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "../../fakes/FakeStore.sol"; 5 | 6 | contract MockStore is FakeStore { 7 | function setBool(bytes32 prefix, address a) external { 8 | bytes32 k = keccak256(abi.encodePacked(prefix, a)); 9 | this.setBool(k, true); 10 | } 11 | 12 | function unsetBool(bytes32 prefix, address a) external { 13 | bytes32 k = keccak256(abi.encodePacked(prefix, a)); 14 | this.deleteBool(k); 15 | } 16 | 17 | function setAddress( 18 | bytes32 k1, 19 | bytes32 k2, 20 | address v 21 | ) public { 22 | this.setAddress(keccak256(abi.encodePacked(k1, k2)), v); 23 | } 24 | 25 | function setAddress( 26 | bytes32 k1, 27 | bytes32 k2, 28 | bytes32 k3, 29 | address v 30 | ) external { 31 | this.setAddress(keccak256(abi.encodePacked(k1, k2, k3)), v); 32 | } 33 | 34 | function setUint( 35 | bytes32 k1, 36 | bytes32 k2, 37 | uint256 v 38 | ) external { 39 | this.setUint(keccak256(abi.encodePacked(k1, k2)), v); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /contracts/mock/claims-processor/MockVault.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; 5 | 6 | contract MockVault is ERC20 { 7 | constructor() ERC20("POD", "POD") { 8 | super._mint(msg.sender, 100_000 ether); 9 | } 10 | 11 | function transferGovernance( 12 | bytes32, 13 | address sender, 14 | uint256 amount 15 | ) external { 16 | if (sender != address(0)) { 17 | super._mint(sender, amount); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /contracts/mock/cx-token/MockCxTokenPolicy.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "../../interfaces/ICxToken.sol"; 5 | 6 | contract MockCxTokenPolicy { 7 | ICxToken public cxToken; 8 | 9 | constructor(ICxToken _cxToken) { 10 | cxToken = _cxToken; 11 | } 12 | 13 | function callMint( 14 | bytes32 key, 15 | bytes32 productKey, 16 | address to, 17 | uint256 amount 18 | ) external { 19 | cxToken.mint(1, key, productKey, to, amount); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /contracts/mock/cx-token/MockCxTokenStore.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "../base/MockStore.sol"; 5 | import "../base/MockProtocol.sol"; 6 | import "../../libraries/ProtoUtilV1.sol"; 7 | import "../../fakes/FakePriceOracle.sol"; 8 | 9 | contract MockCxTokenStore is MockStore { 10 | function initialize() external returns (address) { 11 | MockProtocol protocol = new MockProtocol(); 12 | FakePriceOracle oracle = new FakePriceOracle(); 13 | 14 | this.setAddress(ProtoUtilV1.CNS_CORE, address(protocol)); 15 | this.setAddress(ProtoUtilV1.CNS_NPM_PRICE_ORACLE, address(oracle)); 16 | 17 | return address(protocol); 18 | } 19 | 20 | function registerPolicyContract(address policy) external { 21 | super.setAddress(ProtoUtilV1.NS_CONTRACTS, ProtoUtilV1.CNS_COVER_POLICY, policy); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /contracts/mock/lib-user/MockAccessControlUser.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "../../libraries/AccessControlLibV1.sol"; 5 | import "../../libraries/ProtoUtilV1.sol"; 6 | 7 | contract MockAccessControlUser { 8 | using AccessControlLibV1 for IStore; 9 | using ProtoUtilV1 for IStore; 10 | using StoreKeyUtil for IStore; 11 | 12 | IStore public s; 13 | 14 | constructor(IStore store) { 15 | s = store; 16 | } 17 | 18 | function callerMustBeAdmin(address caller) external view { 19 | s.callerMustBeAdmin(caller); 20 | } 21 | 22 | function callerMustBeCoverManager(address caller) external view { 23 | s.callerMustBeCoverManager(caller); 24 | } 25 | 26 | function callerMustBeGovernanceAgent(address caller) external view { 27 | s.callerMustBeGovernanceAgent(caller); 28 | } 29 | 30 | function callerMustBeGovernanceAdmin(address caller) external view { 31 | s.callerMustBeGovernanceAdmin(caller); 32 | } 33 | 34 | function callerMustBeRecoveryAgent(address caller) external view { 35 | s.callerMustBeRecoveryAgent(caller); 36 | } 37 | 38 | function callerMustBePauseAgent(address caller) external view { 39 | s.callerMustBePauseAgent(caller); 40 | } 41 | 42 | function callerMustBeUnpauseAgent(address caller) external view { 43 | s.callerMustBeUnpauseAgent(caller); 44 | } 45 | 46 | function hasAccess(bytes32 role, address user) external view returns (bool) { 47 | return s.hasAccessInternal(role, user); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /contracts/mock/lib-user/MockCoverUtil.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "../../libraries/StoreKeyUtil.sol"; 5 | import "../../libraries/ProtoUtilV1.sol"; 6 | import "../../libraries/CoverUtilV1.sol"; 7 | import "../../libraries/StrategyLibV1.sol"; 8 | 9 | contract MockCoverUtilUser { 10 | using ProtoUtilV1 for IStore; 11 | using StoreKeyUtil for IStore; 12 | using StrategyLibV1 for IStore; 13 | using CoverUtilV1 for IStore; 14 | 15 | IStore public s; 16 | 17 | constructor(IStore store) { 18 | s = store; 19 | } 20 | 21 | function getActiveLiquidityUnderProtection(bytes32 coverKey, bytes32 productKey) external view returns (uint256) { 22 | uint256 precision = s.getStablecoinPrecisionInternal(); 23 | return s.getActiveLiquidityUnderProtectionInternal(coverKey, productKey, precision); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /contracts/mock/lib-user/MockLiquidityEngineUser.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "../../libraries/StoreKeyUtil.sol"; 5 | import "../../libraries/ProtoUtilV1.sol"; 6 | import "../../libraries/CoverUtilV1.sol"; 7 | import "../../libraries/StrategyLibV1.sol"; 8 | 9 | contract MockLiquidityEngineUser { 10 | using ProtoUtilV1 for IStore; 11 | using StoreKeyUtil for IStore; 12 | using StrategyLibV1 for IStore; 13 | using CoverUtilV1 for IStore; 14 | 15 | IStore public s; 16 | 17 | constructor(IStore store) { 18 | s = store; 19 | } 20 | 21 | function setMaxLendingRatioInternal(uint256 ratio) external { 22 | s.setMaxLendingRatioInternal(ratio); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /contracts/mock/lib-user/MockValidationLibUser.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | pragma solidity ^0.8.0; 4 | import "../../libraries/ValidationLibV1.sol"; 5 | 6 | contract MockValidationLibUser { 7 | using ValidationLibV1 for IStore; 8 | IStore public s; 9 | 10 | constructor(IStore store) { 11 | s = store; 12 | } 13 | 14 | function senderMustBePolicyManagerContract() external view { 15 | s.senderMustBePolicyManagerContract(); 16 | } 17 | 18 | function senderMustBeGovernanceContract() external view { 19 | s.senderMustBeGovernanceContract(); 20 | } 21 | 22 | function senderMustBeClaimsProcessorContract() external view { 23 | s.senderMustBeClaimsProcessorContract(); 24 | } 25 | 26 | function senderMustBeStrategyContract() external view { 27 | s.senderMustBeStrategyContract(); 28 | } 29 | 30 | function mustBeDisputed(bytes32 coverKey, bytes32 productKey) external view { 31 | s.mustBeDisputed(coverKey, productKey); 32 | } 33 | 34 | function mustHaveNormalProductStatus(bytes32 coverKey, bytes32 productKey) external view { 35 | s.mustHaveNormalProductStatus(coverKey, productKey); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /contracts/pool/Bond/BondPool.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | import "./BondPoolBase.sol"; 4 | 5 | contract BondPool is BondPoolBase { 6 | using BondPoolLibV1 for IStore; 7 | using ValidationLibV1 for IStore; 8 | 9 | constructor(IStore s) BondPoolBase(s) {} //solhint-disable-line 10 | 11 | /** 12 | * @dev Create a new bond contract by supplying your LP tokens 13 | * 14 | * @custom:suppress-acl This is a publicly accessible feature 15 | * 16 | */ 17 | function createBond(uint256 lpTokens, uint256 minNpmDesired) external override nonReentrant { 18 | s.mustNotBePaused(); 19 | 20 | require(lpTokens > 0, "Please specify `lpTokens`"); 21 | require(minNpmDesired > 0, "Please enter `minNpmDesired`"); 22 | 23 | (uint256 npmToVest, uint256 unlockDate) = s.createBondInternal(lpTokens, minNpmDesired); 24 | emit BondCreated(msg.sender, lpTokens, npmToVest, unlockDate); 25 | } 26 | 27 | /** 28 | * @dev Claim your bond and receive your NPM tokens after waiting period 29 | * 30 | * @custom:suppress-acl This is a publicly accessible feature 31 | * 32 | */ 33 | function claimBond() external override nonReentrant { 34 | s.mustNotBePaused(); 35 | 36 | // @suppress-zero-value-check The uint values are validated in the function `claimBondInternal` 37 | uint256 npmTransferred = s.claimBondInternal(); 38 | emit BondClaimed(msg.sender, npmTransferred); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /contracts/pool/Staking/StakingPoolInfo.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | import "./StakingPoolReward.sol"; 4 | 5 | abstract contract StakingPoolInfo is StakingPoolReward { 6 | using StakingPoolLibV1 for IStore; 7 | 8 | constructor(IStore s) StakingPoolReward(s) {} //solhint-disable-line 9 | 10 | /** 11 | * @dev Gets the info of a given staking pool by key 12 | * @param key Provide the staking pool key to fetch info for 13 | * @param you Specify the address to customize the info for 14 | * 15 | */ 16 | function getInfo(bytes32 key, address you) external view override returns (StakingPoolInfoType memory) { 17 | return s.getInfoInternal(key, you); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /contracts/pool/Staking/StakingPoolReward.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | import "./StakingPoolBase.sol"; 4 | 5 | abstract contract StakingPoolReward is StakingPoolBase { 6 | using ValidationLibV1 for IStore; 7 | using StakingPoolCoreLibV1 for IStore; 8 | using StakingPoolLibV1 for IStore; 9 | 10 | constructor(IStore s) StakingPoolBase(s) {} //solhint-disable-line 11 | 12 | function calculateRewards(bytes32 key, address account) external view override returns (uint256) { 13 | return s.calculateRewardsInternal(key, account); 14 | } 15 | 16 | /** 17 | * @dev Withdraw your staking reward. Ensure that you preiodically call this function 18 | * or else you risk receiving no rewards as a result of token depletion in the reward pool. 19 | * 20 | * @custom:suppress-acl This is a publicly accessible feature 21 | * 22 | */ 23 | function withdrawRewards(bytes32 key) external override nonReentrant { 24 | s.mustNotBePaused(); 25 | s.ensureValidStakingPoolInternal(key); 26 | 27 | (address rewardToken, uint256 rewards, uint256 platformFee) = s.withdrawRewardsInternal(key, msg.sender); 28 | 29 | if (rewards > 0) { 30 | emit RewardsWithdrawn(key, msg.sender, rewardToken, rewards, platformFee); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /examples/dedicated/exchanges/index.js: -------------------------------------------------------------------------------- 1 | const binance = require('./binance') 2 | const coinbase = require('./coinbase') 3 | const huobi = require('./huobi') 4 | const okx = require('./okx') 5 | 6 | module.exports = [binance, coinbase, huobi, okx] 7 | -------------------------------------------------------------------------------- /examples/dedicated/index.js: -------------------------------------------------------------------------------- 1 | const exchanges = require('./exchanges') 2 | 3 | module.exports = [...exchanges] 4 | -------------------------------------------------------------------------------- /examples/diversified/animoca/cover.js: -------------------------------------------------------------------------------- 1 | const { key, helper } = require('../../../util') 2 | const { ether, percentage, STABLECOIN_DECIMALS } = helper 3 | 4 | const MINUTES = 60 5 | const PRECISION = STABLECOIN_DECIMALS 6 | 7 | module.exports = { 8 | coverKey: key.toBytes32('animoca'), 9 | coverName: 'Animoca Brands', 10 | projectName: null, 11 | tokenName: 'Yield Bearing USDC', 12 | tokenSymbol: 'iUSDC-AB', 13 | requiresWhitelist: false, 14 | supportsProducts: true, 15 | leverageFactor: '5', 16 | tags: ['nft', 'lending', 'flashloan', 'borrowing', 'interest', 'loan', 'staking', 'yield', 'payment'], 17 | about: '', 18 | blockchains: [{ 19 | chainId: 1, 20 | name: 'Main Ethereum Network' 21 | }], 22 | floor: percentage(2), 23 | ceiling: percentage(15), 24 | reportingPeriod: 5 * MINUTES, 25 | cooldownPeriod: 5 * MINUTES, 26 | claimPeriod: 5 * MINUTES, 27 | minStakeToReport: ether(2000), 28 | stakeWithFee: ether(25000), 29 | initialReassuranceAmount: ether(50_000, PRECISION), 30 | reassuranceRate: percentage(25) 31 | } 32 | -------------------------------------------------------------------------------- /examples/diversified/animoca/products/index.js: -------------------------------------------------------------------------------- 1 | module.exports = [] 2 | -------------------------------------------------------------------------------- /examples/diversified/defi/cover.js: -------------------------------------------------------------------------------- 1 | const { key, helper } = require('../../../util') 2 | const { ether, percentage, STABLECOIN_DECIMALS } = helper 3 | 4 | const MINUTES = 60 5 | const PRECISION = STABLECOIN_DECIMALS 6 | 7 | module.exports = { 8 | coverKey: key.toBytes32('defi'), 9 | coverName: 'Popular DeFi Apps', 10 | projectName: null, 11 | tokenName: 'Yield Bearing USDC', 12 | tokenSymbol: 'iUSDC-POP', 13 | requiresWhitelist: false, 14 | supportsProducts: true, 15 | leverageFactor: '10', 16 | tags: ['nft', 'exchange', 'dex', 'swap', 'fork', 'stablecoin', 'lending', 'flashloan', 'borrowing', 'interest', 'loan', 'staking', 'yield', 'insurance', 'payment'], 17 | about: '', 18 | blockchains: [{ 19 | chainId: 1, 20 | name: 'Main Ethereum Network' 21 | }], 22 | floor: percentage(2), 23 | ceiling: percentage(12), 24 | reportingPeriod: 5 * MINUTES, 25 | cooldownPeriod: 5 * MINUTES, 26 | claimPeriod: 5 * MINUTES, 27 | minStakeToReport: ether(2000), 28 | stakeWithFee: ether(25000), 29 | initialReassuranceAmount: ether(50_000, PRECISION), 30 | reassuranceRate: percentage(25) 31 | } 32 | -------------------------------------------------------------------------------- /examples/diversified/defi/index.js: -------------------------------------------------------------------------------- 1 | const cover = require('./cover') 2 | const products = require('./products') 3 | 4 | module.exports = { cover, products } 5 | -------------------------------------------------------------------------------- /examples/diversified/defi/products/index.js: -------------------------------------------------------------------------------- 1 | const oneInch = require('./1inch') 2 | const compound = require('./compound') 3 | const convex = require('./convex') 4 | const kyberswap = require('./kyberswap') 5 | const lido = require('./lido') 6 | const nexusMutual = require('./nexus-mutual') 7 | const rocketPool = require('./rocket-pool') 8 | const sushi = require('./sushi') 9 | const uniswap = require('./uniswap') 10 | 11 | module.exports = [ 12 | oneInch, 13 | compound, 14 | convex, 15 | kyberswap, 16 | lido, 17 | nexusMutual, 18 | rocketPool, 19 | sushi, 20 | uniswap 21 | ] 22 | -------------------------------------------------------------------------------- /examples/diversified/index.js: -------------------------------------------------------------------------------- 1 | const defi = require('./defi') 2 | const prime = require('./prime') 3 | 4 | const covers = [ 5 | defi.cover, 6 | prime.cover 7 | ] 8 | 9 | const products = [ 10 | ...defi.products, 11 | ...prime.products 12 | ] 13 | 14 | module.exports = { covers, products } 15 | -------------------------------------------------------------------------------- /examples/diversified/prime/cover.js: -------------------------------------------------------------------------------- 1 | const { key, helper } = require('../../../util') 2 | const { ether, percentage, STABLECOIN_DECIMALS } = helper 3 | 4 | const MINUTES = 60 5 | const PRECISION = STABLECOIN_DECIMALS 6 | 7 | module.exports = { 8 | coverKey: key.toBytes32('prime'), 9 | coverName: 'Prime dApps', 10 | projectName: null, 11 | tokenName: 'Yield Bearing USDC', 12 | tokenSymbol: 'iUSDC-PRI', 13 | requiresWhitelist: false, 14 | supportsProducts: true, 15 | leverageFactor: '10', 16 | tags: ['nft', 'exchange', 'dex', 'swap', 'fork', 'stablecoin', 'lending', 'flashloan', 'borrowing', 'interest', 'loan', 'staking', 'yield', 'insurance', 'payment'], 17 | about: '', 18 | blockchains: [{ 19 | chainId: 1, 20 | name: 'Main Ethereum Network' 21 | }], 22 | floor: percentage(0.5), 23 | ceiling: percentage(8), 24 | reportingPeriod: 5 * MINUTES, 25 | cooldownPeriod: 5 * MINUTES, 26 | claimPeriod: 5 * MINUTES, 27 | minStakeToReport: ether(2000), 28 | stakeWithFee: ether(25000), 29 | initialReassuranceAmount: ether(50_000, PRECISION), 30 | reassuranceRate: percentage(25) 31 | } 32 | -------------------------------------------------------------------------------- /examples/diversified/prime/index.js: -------------------------------------------------------------------------------- 1 | const cover = require('./cover') 2 | const products = require('./products') 3 | 4 | module.exports = { cover, products } 5 | -------------------------------------------------------------------------------- /examples/diversified/prime/products/index.js: -------------------------------------------------------------------------------- 1 | const aave = require('./aave') 2 | const balancer = require('./balancer') 3 | const curve = require('./curve') 4 | const gnosisSafe = require('./gnosis-safe') 5 | const maker = require('./maker') 6 | const synthetix = require('./synthetix') 7 | const uniswap = require('./uniswap') 8 | 9 | module.exports = [aave, balancer, curve, gnosisSafe, maker, synthetix, uniswap] 10 | -------------------------------------------------------------------------------- /examples/index.js: -------------------------------------------------------------------------------- 1 | const diversified = require('./diversified') 2 | const dedicated = require('./dedicated') 3 | 4 | const covers = [ 5 | ...diversified.covers, 6 | ...dedicated 7 | ] 8 | 9 | const { products } = diversified 10 | 11 | module.exports = { covers, diversified, dedicated, products } 12 | -------------------------------------------------------------------------------- /files/protocol.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neptune-mutual-blue/protocol/1256dfc57bd727bdba171d34eabd4176db89f999/files/protocol.png -------------------------------------------------------------------------------- /fuzzing/core/StoreTest.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | import "forge-std/Test.sol"; 7 | import "forge-std/Vm.sol"; 8 | import "../../contracts/core/store/Store.sol"; 9 | 10 | contract StoreTest is Test { 11 | Store public store; 12 | using stdStorage for StdStorage; 13 | 14 | function setUp() public { 15 | store = new Store(); 16 | } 17 | 18 | function testSetUint(bytes32 key, uint256 value) public { 19 | store.setUint(key, value); 20 | assertEq(store.getUint(key), value); 21 | } 22 | 23 | function testSetUintAsNonMember(bytes32 key, uint256 value) public { 24 | vm.expectRevert("Forbidden"); 25 | vm.prank(address(2)); 26 | store.setUint(key, value); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /oracle/contracts/IPriceOracle.sol: -------------------------------------------------------------------------------- 1 | // Neptune Mutual Protocol (https://neptunemutual.com) 2 | // SPDX-License-Identifier: BUSL-1.1 3 | // solhint-disable compiler-version 4 | pragma solidity 0.6.6; 5 | 6 | interface IPriceOracle { 7 | event PriceUpdated(address indexed updater, uint32 timeElapsed, uint256 price0Cumulative, uint256 price1Cumulative); 8 | 9 | function update() external; 10 | 11 | function consult(address token, uint256 amountIn) external view returns (uint256); 12 | 13 | function consultPair(uint256 amountIn) external view returns (uint256); 14 | } 15 | -------------------------------------------------------------------------------- /oracle/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "npm-price-oracle", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "compile": "cp ../.env .env && hardhat compile", 8 | "build": "cp ../.env .env && hardhat compile", 9 | "clean": "hardhat clean", 10 | "compile:clean": "cp ../.env .env && hardhat clean && hardhat compile", 11 | "build:clean": "npm run compile:clean", 12 | "deploy": "hardhat run scripts/deploy.js --network hardhat", 13 | "deploy:mumbai": "hardhat run scripts/deploy.js --network mumbai", 14 | "deploy:fuji": "hardhat run scripts/deploy.js --network fuji", 15 | "slither": "slither .", 16 | "fix": "standard --fix" 17 | }, 18 | "author": "", 19 | "license": "SEE LICENSE IN ", 20 | "bugs": { 21 | "url": "https://github.com/neptune-mutual/protocol/issues" 22 | }, 23 | "homepage": "https://github.com/neptune-mutual/protocol#readme", 24 | "standard": { 25 | "env": [ 26 | "mocha" 27 | ], 28 | "global": [ 29 | "ethers", 30 | "task", 31 | "contract", 32 | "artifacts", 33 | "web3" 34 | ] 35 | }, 36 | "devDependencies": { 37 | "@nomiclabs/hardhat-ethers": "^2.0.3", 38 | "@nomiclabs/hardhat-etherscan": "^3.1.7", 39 | "@nomiclabs/hardhat-waffle": "^2.0.1", 40 | "@uniswap/lib": "^4.0.1-alpha", 41 | "@uniswap/v2-core": "1.0.0", 42 | "@uniswap/v2-periphery": "^1.1.0-beta.0", 43 | "dotenv": "^10.0.0", 44 | "ethereum-waffle": "^3.4.0", 45 | "ethers": "^5.5.2", 46 | "hardhat": "2.19.3", 47 | "hardhat-contract-sizer": "2.1.1", 48 | "hardhat-gas-reporter": "1.0.6", 49 | "openzeppelin-solidity": "3.4.0", 50 | "solidity-coverage": "^0.8.7", 51 | "standard": "^16.0.4" 52 | }, 53 | "volta": { 54 | "node": "18.12.0", 55 | "yarn": "1.22.19" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /oracle/scripts/deploy.js: -------------------------------------------------------------------------------- 1 | const { network } = require('hardhat') 2 | const { ethers } = require('hardhat') 3 | const config = require('../../scripts/config/network') 4 | 5 | const main = async () => { 6 | const [deployer] = await ethers.getSigners() 7 | const chainId = network.config.chainId 8 | 9 | console.log('Deployer: %s. Balance: %s', deployer.address, await deployer.getBalance()) 10 | 11 | const ContractFactory = await ethers.getContractFactory('NpmPriceOracle') 12 | 13 | const oracle = await ContractFactory.deploy(config[chainId].stablecoinPairs.NPM_STABLECOIN, config[chainId].deployedTokens.NPM) 14 | await oracle.deployed() 15 | 16 | console.log('Deployed: %s/address/%s', network.config.explorer, oracle.address) 17 | } 18 | 19 | main() 20 | .then(() => process.exit(0)) 21 | .catch((error) => { 22 | console.error(error) 23 | process.exit(1) 24 | }) 25 | -------------------------------------------------------------------------------- /remappings.txt: -------------------------------------------------------------------------------- 1 | ds-test/=lib/forge-std/lib/ds-test/src/ 2 | forge-std/=lib/forge-std/src/ 3 | @ensdomains/=node_modules/@ensdomains/ 4 | eth-gas-reporter/=node_modules/eth-gas-reporter/ 5 | hardhat/=node_modules/hardhat/ 6 | openzeppelin-solidity/=node_modules/openzeppelin-solidity/ 7 | -------------------------------------------------------------------------------- /scripts/config/index.js: -------------------------------------------------------------------------------- 1 | module.exports = {} 2 | -------------------------------------------------------------------------------- /scripts/config/network/hardhat.js: -------------------------------------------------------------------------------- 1 | const { ACCESS_CONTROL } = require('../../../util/key') 2 | const wallet = require('../../../util/wallet') 3 | 4 | const DAYS = 86400 5 | const HOURS = 3600 6 | 7 | const config = { 8 | 31338: { 9 | network: 'Hardhat', 10 | name: 'hardhat', 11 | chainId: 31338, 12 | mainnet: false, 13 | pool: { 14 | bond: { 15 | period: 7 * DAYS 16 | } 17 | }, 18 | cover: { 19 | lendingPeriod: 180 * DAYS, 20 | withdrawalWindow: 7 * DAYS, 21 | claimPeriod: 7 * DAYS, 22 | cooldownPeriod: 1 * DAYS, 23 | reportingPeriod: 7 * DAYS, 24 | stateUpdateInterval: 1 * HOURS 25 | }, 26 | // knownAccounts, 27 | // uniswapV2Like, 28 | knownAccounts: [ 29 | { 30 | account: '0xA96813969437F3bad7B59335934aa75933670615', 31 | roles: [ 32 | ACCESS_CONTROL.ADMIN, 33 | ACCESS_CONTROL.COVER_MANAGER, 34 | ACCESS_CONTROL.LIQUIDITY_MANAGER, 35 | ACCESS_CONTROL.GOVERNANCE_ADMIN, 36 | ACCESS_CONTROL.RECOVERY_AGENT, 37 | ACCESS_CONTROL.UNPAUSE_AGENT, 38 | ACCESS_CONTROL.UPGRADE_AGENT 39 | ] 40 | }, { 41 | account: wallet.toWalletAddress(process.env.PRIVATE_KEY), 42 | roles: [ 43 | ACCESS_CONTROL.ADMIN, 44 | ACCESS_CONTROL.COVER_MANAGER, 45 | ACCESS_CONTROL.LIQUIDITY_MANAGER, 46 | ACCESS_CONTROL.GOVERNANCE_ADMIN, 47 | ACCESS_CONTROL.RECOVERY_AGENT, 48 | ACCESS_CONTROL.UNPAUSE_AGENT, 49 | ACCESS_CONTROL.UPGRADE_AGENT 50 | ] 51 | } 52 | ], 53 | uniswapV2Like: null, 54 | protocol: { 55 | burner: '0x0000000000000000000000000000000000000001', 56 | treasury: '0x0000000000000000000000000000000000000001' 57 | } 58 | } 59 | } 60 | 61 | module.exports = config 62 | -------------------------------------------------------------------------------- /scripts/config/network/index.js: -------------------------------------------------------------------------------- 1 | const hardhat = require('./hardhat') 2 | const mainnet = require('./mainnet') 3 | const arbitrum = require('./arbitrum') 4 | const bsc = require('./bsc') 5 | const baseGoerli = require('./base-goerli') 6 | const local = require('./local') 7 | 8 | module.exports = { 9 | ...hardhat, 10 | ...baseGoerli, 11 | ...mainnet, 12 | ...arbitrum, 13 | ...bsc, 14 | ...local 15 | } 16 | -------------------------------------------------------------------------------- /scripts/config/network/local.js: -------------------------------------------------------------------------------- 1 | const mainnet = require('./bsc') 2 | 3 | const config = {} 4 | config[31337] = { ...mainnet[56] } 5 | config[31337].network = 'Hardhat Forked BNB Chain Network' 6 | config[31337].mainnet = true 7 | config[31337].chainId = 31337 8 | 9 | module.exports = config 10 | -------------------------------------------------------------------------------- /scripts/covers/diversified/popular-defi-apps-bnb/cover.js: -------------------------------------------------------------------------------- 1 | const { key, helper } = require('../../../../util') 2 | const { ether, percentage } = helper 3 | 4 | const DAYS = 86400 5 | 6 | module.exports = { 7 | coverKey: key.toBytes32('popular-defi-apps'), 8 | coverName: 'Popular DeFi Apps', 9 | projectName: null, 10 | tokenName: 'Yield Bearing USDC', 11 | tokenSymbol: 'iUSDC-POP', 12 | requiresWhitelist: false, 13 | supportsProducts: true, 14 | leverageFactor: '6', 15 | tags: ['nft', 'exchange', 'dex', 'swap', 'fork', 'stablecoin', 'lending', 'flashloan', 'borrowing', 'interest', 'loan', 'staking', 'yield', 'insurance', 'payment'], 16 | about: '', 17 | blockchains: [ 18 | { 19 | chainId: 56, 20 | name: 'BNB Chain' 21 | } 22 | ], 23 | floor: percentage(2), 24 | ceiling: percentage(12), 25 | reportingPeriod: 7 * DAYS, 26 | cooldownPeriod: 1 * DAYS, 27 | claimPeriod: 7 * DAYS, 28 | minStakeToReport: ether(10_000), 29 | stakeWithFee: ether(12_500), 30 | initialReassuranceAmount: '0', 31 | reassuranceRate: percentage(25) 32 | } 33 | -------------------------------------------------------------------------------- /scripts/covers/diversified/popular-defi-apps-bnb/index.js: -------------------------------------------------------------------------------- 1 | const cover = require('./cover') 2 | const products = require('./products') 3 | 4 | module.exports = { cover, products } 5 | -------------------------------------------------------------------------------- /scripts/covers/diversified/popular-defi-apps-bnb/products/index.js: -------------------------------------------------------------------------------- 1 | const alpaca = require('./alpaca') 2 | const dodo = require('./dodo') 3 | const oneInch = require('./one-inch') 4 | const pancakeswap = require('./pancakeswap') 5 | const uniswap = require('./uniswap') 6 | 7 | module.exports = [alpaca, dodo, oneInch, pancakeswap, uniswap] 8 | -------------------------------------------------------------------------------- /scripts/covers/diversified/popular-defi-apps/cover.js: -------------------------------------------------------------------------------- 1 | const { key, helper } = require('../../../../util') 2 | const { ether, percentage } = helper 3 | 4 | const DAYS = 86400 5 | 6 | module.exports = { 7 | coverKey: key.toBytes32('popular-defi-apps'), 8 | coverName: 'Popular DeFi Apps', 9 | projectName: null, 10 | tokenName: 'Yield Bearing USDC', 11 | tokenSymbol: 'iUSDC-POP', 12 | requiresWhitelist: false, 13 | supportsProducts: true, 14 | leverageFactor: '6', 15 | tags: ['nft', 'exchange', 'dex', 'swap', 'fork', 'stablecoin', 'lending', 'flashloan', 'borrowing', 'interest', 'loan', 'staking', 'yield', 'insurance', 'payment'], 16 | about: '', 17 | blockchains: [{ 18 | chainId: 1, 19 | name: 'Main Ethereum Network' 20 | }, 21 | { 22 | chainId: 42161, 23 | name: 'Arbitrum' 24 | }], 25 | floor: percentage(2), 26 | ceiling: percentage(12), 27 | reportingPeriod: 7 * DAYS, 28 | cooldownPeriod: 1 * DAYS, 29 | claimPeriod: 7 * DAYS, 30 | minStakeToReport: ether(10_000), 31 | stakeWithFee: ether(30_000), 32 | initialReassuranceAmount: '0', 33 | reassuranceRate: percentage(25) 34 | } 35 | -------------------------------------------------------------------------------- /scripts/covers/diversified/popular-defi-apps/index.js: -------------------------------------------------------------------------------- 1 | const cover = require('./cover') 2 | const products = require('./products') 3 | 4 | module.exports = { cover, products } 5 | -------------------------------------------------------------------------------- /scripts/covers/diversified/popular-defi-apps/products/index.js: -------------------------------------------------------------------------------- 1 | const aave = require('./aave') 2 | const bancor = require('./bancor') 3 | const compound = require('./compound') 4 | const convex = require('./convex') 5 | const dydx = require('./dydx') 6 | const gmx = require('./gmx') 7 | const oneInch = require('./one-inch') 8 | const sushi = require('./sushi') 9 | const uniswap = require('./uniswap') 10 | 11 | module.exports = [aave, bancor, compound, convex, dydx, gmx, oneInch, sushi, uniswap] 12 | -------------------------------------------------------------------------------- /scripts/covers/diversified/prime/cover.js: -------------------------------------------------------------------------------- 1 | const { key, helper } = require('../../../../util') 2 | const { ether, percentage } = helper 3 | 4 | const DAYS = 86400 5 | 6 | module.exports = { 7 | coverKey: key.toBytes32('prime'), 8 | coverName: 'Prime dApps', 9 | projectName: null, 10 | tokenName: 'Yield Bearing USDC', 11 | tokenSymbol: 'iUSDC-PRI', 12 | requiresWhitelist: false, 13 | supportsProducts: true, 14 | leverageFactor: '6', 15 | tags: ['nft', 'exchange', 'dex', 'swap', 'fork', 'stablecoin', 'lending', 'flashloan', 'borrowing', 'interest', 'loan', 'staking', 'yield', 'insurance', 'payment'], 16 | about: '', 17 | blockchains: [{ 18 | chainId: 1, 19 | name: 'Main Ethereum Network' 20 | }], 21 | floor: percentage(0.5), 22 | ceiling: percentage(8), 23 | reportingPeriod: 7 * DAYS, 24 | cooldownPeriod: 1 * DAYS, 25 | claimPeriod: 7 * DAYS, 26 | minStakeToReport: ether(10_000), 27 | stakeWithFee: ether(30_000), 28 | initialReassuranceAmount: '0', 29 | reassuranceRate: percentage(25) 30 | } 31 | -------------------------------------------------------------------------------- /scripts/covers/diversified/prime/index.js: -------------------------------------------------------------------------------- 1 | const cover = require('./cover') 2 | const products = require('./products') 3 | 4 | module.exports = { cover, products } 5 | -------------------------------------------------------------------------------- /scripts/covers/diversified/prime/products/index.js: -------------------------------------------------------------------------------- 1 | const aave = require('./aave') 2 | const balancer = require('./balancer') 3 | const curve = require('./curve') 4 | const gnosisSafe = require('./gnosis-safe') 5 | const maker = require('./maker') 6 | const synthetix = require('./synthetix') 7 | const uniswap = require('./uniswap') 8 | 9 | module.exports = [aave, balancer, curve, gnosisSafe, maker, synthetix, uniswap] 10 | -------------------------------------------------------------------------------- /scripts/deploy-covers.js: -------------------------------------------------------------------------------- 1 | const { deploy } = require('./covers/deployments/popular-defi-apps-bnb') 2 | 3 | deploy() 4 | .then(() => process.exit(0)) 5 | .catch(error => { 6 | console.error(error) 7 | process.exit(1) 8 | }) 9 | -------------------------------------------------------------------------------- /scripts/deploy-npm.js: -------------------------------------------------------------------------------- 1 | const { formatEther } = require('ethers/lib/utils') 2 | const { network } = require('hardhat') 3 | const { ethers } = require('hardhat') 4 | 5 | const deploy = async (contractName, ...args) => { 6 | const ContractFactory = await ethers.getContractFactory(contractName) 7 | const instance = await ContractFactory.deploy(...args) 8 | await instance.deployed() 9 | 10 | const { explorer } = network.config 11 | 12 | if (explorer) { 13 | console.log('%s Deployed: %s/address/%s', contractName, network.config.explorer, instance.address) 14 | } else { 15 | console.log('%s Deployed: %s', contractName, instance.address) 16 | } 17 | 18 | return instance 19 | } 20 | 21 | const main = async () => { 22 | const [deployer] = await ethers.getSigners() 23 | 24 | const previousBalance = await deployer.getBalance() 25 | 26 | console.log('Deployer: %s. Balance: %s ETH', deployer.address, formatEther(previousBalance)) 27 | 28 | await deploy('NPM', '0xAc6CD41F7E434DCf2Da45bb3ff385706DC2A2b9C', 'Neptune Mutual', 'NPM') 29 | 30 | const balance = await deployer.getBalance() 31 | const cost = previousBalance.sub(balance) 32 | console.log('Cost: %s ETH. Balance: %s ETH', formatEther(cost), formatEther(balance)) 33 | } 34 | 35 | main() 36 | .then(() => process.exit(0)) 37 | .catch((error) => { 38 | console.error(error) 39 | process.exit(1) 40 | }) 41 | -------------------------------------------------------------------------------- /scripts/deploy-pot.js: -------------------------------------------------------------------------------- 1 | const { formatEther } = require('ethers/lib/utils') 2 | const { network } = require('hardhat') 3 | const { ethers } = require('hardhat') 4 | 5 | const deploy = async (contractName, ...args) => { 6 | const ContractFactory = await ethers.getContractFactory(contractName) 7 | const instance = await ContractFactory.deploy(...args) 8 | await instance.deployed() 9 | 10 | const { explorer } = network.config 11 | 12 | if (explorer) { 13 | console.log('%s Deployed: %s/address/%s', contractName, network.config.explorer, instance.address) 14 | } else { 15 | console.log('%s Deployed: %s', contractName, instance.address) 16 | } 17 | 18 | return instance 19 | } 20 | 21 | const main = async () => { 22 | const [deployer] = await ethers.getSigners() 23 | 24 | const previousBalance = await deployer.getBalance() 25 | 26 | console.log('Deployer: %s. Balance: %s ETH', deployer.address, formatEther(previousBalance)) 27 | 28 | await deploy('POT', deployer.address) 29 | 30 | const balance = await deployer.getBalance() 31 | const cost = previousBalance.sub(balance) 32 | console.log('Cost: %s ETH. Balance: %s ETH', formatEther(cost), formatEther(balance)) 33 | } 34 | 35 | main() 36 | .then(() => process.exit(0)) 37 | .catch((error) => { 38 | console.error(error) 39 | process.exit(1) 40 | }) 41 | -------------------------------------------------------------------------------- /scripts/deploy-treasury.js: -------------------------------------------------------------------------------- 1 | const { formatEther } = require('ethers/lib/utils') 2 | const { network } = require('hardhat') 3 | const { ethers } = require('hardhat') 4 | 5 | const OWNER = '0xAc6CD41F7E434DCf2Da45bb3ff385706DC2A2b9C' 6 | 7 | const deploy = async (contractName, ...args) => { 8 | const ContractFactory = await ethers.getContractFactory(contractName) 9 | const instance = await ContractFactory.deploy(...args) 10 | await instance.deployed() 11 | 12 | const { explorer } = network.config 13 | 14 | if (explorer) { 15 | console.log('%s Deployed: %s/address/%s', contractName, network.config.explorer, instance.address) 16 | } else { 17 | console.log('%s Deployed: %s', contractName, instance.address) 18 | } 19 | 20 | return instance 21 | } 22 | 23 | const main = async () => { 24 | const [deployer] = await ethers.getSigners() 25 | 26 | const previousBalance = await deployer.getBalance() 27 | 28 | console.log('Deployer: %s. Balance: %s ETH', deployer.address, formatEther(previousBalance)) 29 | 30 | await deploy('Treasury', OWNER) 31 | 32 | const balance = await deployer.getBalance() 33 | const cost = previousBalance.sub(balance) 34 | console.log('Cost: %s ETH. Balance: %s ETH', formatEther(cost), formatEther(balance)) 35 | } 36 | 37 | main() 38 | .then(() => process.exit(0)) 39 | .catch((error) => { 40 | console.error(error) 41 | process.exit(1) 42 | }) 43 | -------------------------------------------------------------------------------- /slither.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "compile_force_framework": false, 3 | "hardhat_ignore_compile": false, 4 | "detectors_to_exclude": "assembly-usage,boolean-equality,solc-version,similar-names", 5 | "exclude_informational": false, 6 | "exclude_low": true, 7 | "exclude_medium": true, 8 | "exclude_high": false, 9 | "disable_color": false, 10 | "legacy_ast": false, 11 | "filter_paths": "./contracts/fakes|BokkyPooBahsDateTimeLibrary.sol|openzeppelin|Migrations.sol|lib" 12 | } -------------------------------------------------------------------------------- /solidoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "pathToRoot": "./", 3 | "outputPath": "./docs", 4 | "noCompilation": true, 5 | "compiler": "truffle compile", 6 | "language": "en", 7 | "rootContract": "Cover", 8 | "readMe": "./readme.md" 9 | } -------------------------------------------------------------------------------- /sonar-project.properties: -------------------------------------------------------------------------------- 1 | sonar.projectKey=neptune-mutual_protocol 2 | sonar.projectName=Neptune Mutual Protocol 3 | sonar.sources=. 4 | sonar.sourceEncoding=UTF-8 5 | #sonar.cpd.exclusions= 6 | sonar.exclusions=stories/**/*.js,test/**/*.js 7 | sonar.test.exclusions=stories/**/*.js,test/**/*.js 8 | -------------------------------------------------------------------------------- /test/examples/distributor/drain.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { deployer, helper, key } = require('../../../util') 4 | const { deployDependencies } = require('./deps') 5 | const cache = null 6 | const PRECISION = helper.STABLECOIN_DECIMALS 7 | 8 | require('chai') 9 | .use(require('chai-as-promised')) 10 | .use(require('chai-bignumber')(BigNumber)) 11 | .should() 12 | 13 | describe('Distributor: `drain` function', () => { 14 | let deployed, treasury, feePercentage, distributor 15 | 16 | before(async () => { 17 | deployed = await deployDependencies() 18 | 19 | treasury = helper.randomAddress() 20 | feePercentage = helper.percentage(20) 21 | 22 | distributor = await deployer.deploy(cache, 'NpmDistributor', deployed.store.address, treasury, feePercentage) 23 | }) 24 | 25 | it('must correctly drain the entire token balance', async () => { 26 | const coverKey = deployed.coverKey 27 | const amount = helper.ether(5000, PRECISION) 28 | const npmStakeToAdd = helper.ether(1000) 29 | const referralCode = key.toBytes32('referral-code') 30 | 31 | await deployed.npm.approve(distributor.address, npmStakeToAdd) 32 | await deployed.stablecoin.approve(distributor.address, amount) 33 | 34 | await deployed.npm.transfer(distributor.address, helper.ether(3333)) 35 | 36 | const tx = await distributor.addLiquidity({ 37 | coverKey, 38 | amount, 39 | npmStakeToAdd, 40 | referralCode 41 | }) 42 | 43 | const { events } = await tx.wait() 44 | const event = events.find(x => x.event === 'Drained') 45 | 46 | event.args.token.should.equal(deployed.npm.address) 47 | event.args.to.should.equal(treasury) 48 | event.args.amount.should.equal(helper.ether(3333)) 49 | }) 50 | }) 51 | -------------------------------------------------------------------------------- /test/specs/claims-processor/deps.js: -------------------------------------------------------------------------------- 1 | const composer = require('../../../util/composer') 2 | const cache = null 3 | 4 | /** 5 | * Deploys all libraries 6 | * @return {Promise<{dependencies: Object, all: Libraries}>} 7 | */ 8 | const deployDependencies = async () => { 9 | const all = await composer.libs.deployAll(cache) 10 | 11 | return { 12 | dependencies: { 13 | AccessControlLibV1: all.accessControlLibV1.address, 14 | BaseLibV1: all.baseLibV1.address, 15 | CoverUtilV1: all.coverUtilV1.address, 16 | GovernanceUtilV1: all.governanceUtilV1.address, 17 | RoutineInvokerLibV1: all.routineInvokerLibV1.address, 18 | NTransferUtilV2: all.transferLib.address, 19 | ProtoUtilV1: all.protoUtilV1.address, 20 | RegistryLibV1: all.registryLibV1.address, 21 | StoreKeyUtil: all.storeKeyUtil.address, 22 | ValidationLibV1: all.validationLibV1.address 23 | }, 24 | all 25 | } 26 | } 27 | 28 | module.exports = { deployDependencies } 29 | -------------------------------------------------------------------------------- /test/specs/cx-token-factory/ctor.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { deployer, key } = require('../../../util') 4 | const { deployDependencies } = require('./deps') 5 | const cache = null 6 | 7 | require('chai') 8 | .use(require('chai-as-promised')) 9 | .use(require('chai-bignumber')(BigNumber)) 10 | .should() 11 | 12 | describe('cxTokenFactory: Constructor and Views', () => { 13 | let store, deployed 14 | 15 | before(async () => { 16 | deployed = await deployDependencies() 17 | 18 | store = deployed.store 19 | }) 20 | 21 | it('correctly deploys', async () => { 22 | const factory = await deployer.deployWithLibraries(cache, 'cxTokenFactory', { 23 | AccessControlLibV1: deployed.accessControlLibV1.address, 24 | BaseLibV1: deployed.baseLibV1.address, 25 | StoreKeyUtil: deployed.storeKeyUtil.address, 26 | ValidationLibV1: deployed.validationLibV1.address, 27 | cxTokenFactoryLibV1: deployed.cxTokenFactoryLib.address 28 | }, store.address) 29 | 30 | const _store = await factory.s() 31 | _store.should.equal(store.address) 32 | 33 | const version = await factory.version() 34 | version.should.equal(key.toBytes32('v0.1')) 35 | 36 | const name = await factory.getName() 37 | name.should.equal(key.PROTOCOL.CNAME.CXTOKEN_FACTORY) 38 | }) 39 | }) 40 | -------------------------------------------------------------------------------- /test/specs/governance/resolution/ctor.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { deployer, key } = require('../../../../util') 4 | const { deployDependencies } = require('./deps') 5 | const cache = null 6 | 7 | require('chai') 8 | .use(require('chai-as-promised')) 9 | .use(require('chai-bignumber')(BigNumber)) 10 | .should() 11 | 12 | describe('Resolution Constructor', () => { 13 | let deployed 14 | 15 | before(async () => { 16 | deployed = await deployDependencies() 17 | }) 18 | 19 | it('correctly deploys', async () => { 20 | const resolution = await deployer.deployWithLibraries(cache, 'Resolution', 21 | { 22 | AccessControlLibV1: deployed.accessControlLibV1.address, 23 | BaseLibV1: deployed.baseLibV1.address, 24 | RoutineInvokerLibV1: deployed.routineInvokerLibV1.address, 25 | StoreKeyUtil: deployed.storeKeyUtil.address, 26 | ProtoUtilV1: deployed.protoUtilV1.address, 27 | CoverUtilV1: deployed.coverUtilV1.address, 28 | NTransferUtilV2: deployed.transferLib.address, 29 | ValidationLibV1: deployed.validationLibV1.address, 30 | GovernanceUtilV1: deployed.governanceUtilV1.address 31 | }, 32 | deployed.store.address 33 | ) 34 | 35 | const version = await resolution.version() 36 | const name = await resolution.getName() 37 | 38 | version.should.equal(key.toBytes32('v0.1')) 39 | name.should.equal(key.PROTOCOL.CNAME.RESOLUTION) 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /test/specs/governance/set-reporter-burn-rate.spec.js: -------------------------------------------------------------------------------- 1 | const BigNumber = require('bignumber.js') 2 | const { deployDependencies } = require('./deps') 3 | 4 | require('chai') 5 | .use(require('chai-as-promised')) 6 | .use(require('chai-bignumber')(BigNumber)) 7 | .should() 8 | 9 | describe('Governance: `setReportingBurnRate` function', () => { 10 | const burnRate = '1' 11 | let deployed 12 | 13 | before(async () => { 14 | deployed = await deployDependencies() 15 | }) 16 | 17 | it('must correctly set reporter commission', async () => { 18 | const tx = await deployed.governance.setReportingBurnRate(burnRate) 19 | const { events } = await tx.wait() 20 | const event = events.find(x => x.event === 'ReportingBurnRateSet') 21 | 22 | event.args.current.should.equal(burnRate) 23 | }) 24 | 25 | it('reverts when protocol is paused', async () => { 26 | await deployed.protocol.pause() 27 | await deployed.governance.setReportingBurnRate(burnRate).should.be.rejectedWith('Protocol is paused') 28 | await deployed.protocol.unpause() 29 | }) 30 | 31 | it('reverts when zero is specified as burn rate', async () => { 32 | await deployed.governance.setReportingBurnRate('0').should.be.rejectedWith('Please specify value') 33 | }) 34 | 35 | it('reverts when not accessed by CoverManager', async () => { 36 | const [, bob] = await ethers.getSigners() 37 | 38 | await deployed.governance.connect(bob).setReportingBurnRate(burnRate).should.be.rejectedWith('Forbidden') 39 | }) 40 | }) 41 | -------------------------------------------------------------------------------- /test/specs/governance/set-reporter-commission.spec.js: -------------------------------------------------------------------------------- 1 | const BigNumber = require('bignumber.js') 2 | const { deployDependencies } = require('./deps') 3 | 4 | require('chai') 5 | .use(require('chai-as-promised')) 6 | .use(require('chai-bignumber')(BigNumber)) 7 | .should() 8 | 9 | describe('Governance: `setReporterCommission` function', () => { 10 | const commission = '1' 11 | let deployed 12 | 13 | before(async () => { 14 | deployed = await deployDependencies() 15 | }) 16 | 17 | it('must correctly set reporter commission', async () => { 18 | await deployed.governance.setReporterCommission(commission) 19 | }) 20 | 21 | it('reverts when not accessed by CoverManager', async () => { 22 | const [, bob] = await ethers.getSigners() 23 | 24 | await deployed.governance.connect(bob).setReporterCommission(commission).should.be.rejectedWith('Forbidden') 25 | }) 26 | 27 | it('reverts when protocol is paused', async () => { 28 | await deployed.protocol.pause() 29 | await deployed.governance.setReporterCommission(commission).should.be.rejectedWith('Protocol is paused') 30 | await deployed.protocol.unpause() 31 | }) 32 | 33 | it('reverts when zero is specified as commision', async () => { 34 | await deployed.governance.setReporterCommission('0').should.be.rejectedWith('Please specify value') 35 | }) 36 | }) 37 | -------------------------------------------------------------------------------- /test/specs/lifecycle/cover/set-cover-creation-fee.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { deployDependencies } = require('./deps') 4 | 5 | require('chai') 6 | .use(require('chai-as-promised')) 7 | .use(require('chai-bignumber')(BigNumber)) 8 | .should() 9 | 10 | describe('Cover: setCoverCreationFee', () => { 11 | let deployed 12 | 13 | beforeEach(async () => { 14 | deployed = await deployDependencies() 15 | }) 16 | 17 | it('correctly sets cover fees', async () => { 18 | const fees = '1' 19 | 20 | const tx = await deployed.cover.setCoverCreationFee(fees) 21 | const { events } = await tx.wait() 22 | 23 | const event = events.find(x => x.event === 'CoverCreationFeeSet') 24 | event.args.previous.should.equal('0') 25 | event.args.current.should.equal(fees) 26 | }) 27 | 28 | it('reverts when invalid value is passed as cover fees', async () => { 29 | const fees = '0' 30 | 31 | await deployed.cover.setCoverCreationFee(fees) 32 | .should.be.rejectedWith('Please specify value') 33 | }) 34 | 35 | it('reverts when protocol is paused', async () => { 36 | const fees = '1' 37 | 38 | await deployed.protocol.pause() 39 | await deployed.cover.setCoverCreationFee(fees) 40 | .should.be.rejectedWith('Protocol is paused') 41 | await deployed.protocol.unpause() 42 | }) 43 | 44 | it('reverts when not accessed by cover manager', async () => { 45 | const [, bob] = await ethers.getSigners() 46 | const fees = '1' 47 | 48 | await deployed.cover.connect(bob).setCoverCreationFee(fees) 49 | .should.be.rejectedWith('Forbidden') 50 | }) 51 | }) 52 | -------------------------------------------------------------------------------- /test/specs/lifecycle/cover/set-min-cover-creation-stake.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { helper } = require('../../../../util') 4 | const { deployDependencies } = require('./deps') 5 | 6 | require('chai') 7 | .use(require('chai-as-promised')) 8 | .use(require('chai-bignumber')(BigNumber)) 9 | .should() 10 | 11 | describe('Cover: setMinCoverCreationStake', () => { 12 | let deployed 13 | 14 | beforeEach(async () => { 15 | deployed = await deployDependencies() 16 | }) 17 | 18 | it('correctly sets min cover creation stake', async () => { 19 | const minStake = '1' 20 | 21 | const tx = await deployed.cover.setMinCoverCreationStake(minStake) 22 | const { events } = await tx.wait() 23 | 24 | const event = events.find(x => x.event === 'MinCoverCreationStakeSet') 25 | event.args.previous.should.equal(helper.ether(2)) 26 | event.args.current.should.equal(minStake) 27 | }) 28 | 29 | it('reverts when invalid value is passed as min stake', async () => { 30 | const minStake = '0' 31 | 32 | await deployed.cover.setMinCoverCreationStake(minStake) 33 | .should.be.rejectedWith('Please specify value') 34 | }) 35 | 36 | it('reverts when protocol is paused', async () => { 37 | const minStake = '1' 38 | 39 | await deployed.protocol.pause() 40 | await deployed.cover.setMinCoverCreationStake(minStake) 41 | .should.be.rejectedWith('Protocol is paused') 42 | await deployed.protocol.unpause() 43 | }) 44 | 45 | it('reverts when not accessed by cover manager', async () => { 46 | const [, bob] = await ethers.getSigners() 47 | const minStake = '1' 48 | 49 | await deployed.cover.connect(bob).setMinCoverCreationStake(minStake) 50 | .should.be.rejectedWith('Forbidden') 51 | }) 52 | }) 53 | -------------------------------------------------------------------------------- /test/specs/lifecycle/cover/set-min-stake-to-add-liquidity.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { helper } = require('../../../../util') 4 | const { deployDependencies } = require('./deps') 5 | 6 | require('chai') 7 | .use(require('chai-as-promised')) 8 | .use(require('chai-bignumber')(BigNumber)) 9 | .should() 10 | 11 | describe('Cover: setMinStakeToAddLiquidity', () => { 12 | let deployed 13 | 14 | beforeEach(async () => { 15 | deployed = await deployDependencies() 16 | }) 17 | 18 | it('correctly sets min stake to add liquidity', async () => { 19 | const minStake = '1' 20 | 21 | const tx = await deployed.cover.setMinStakeToAddLiquidity(minStake) 22 | const { events } = await tx.wait() 23 | 24 | const event = events.find(x => x.event === 'MinStakeToAddLiquiditySet') 25 | event.args.previous.should.equal(helper.ether(0)) 26 | event.args.current.should.equal(minStake) 27 | }) 28 | 29 | it('reverts when protocol is paused', async () => { 30 | const minStake = '1' 31 | 32 | await deployed.protocol.pause() 33 | await deployed.cover.setMinStakeToAddLiquidity(minStake) 34 | .should.be.rejectedWith('Protocol is paused') 35 | await deployed.protocol.unpause() 36 | }) 37 | 38 | it('reverts when not accessed by cover manager', async () => { 39 | const [, bob] = await ethers.getSigners() 40 | const minStake = '1' 41 | 42 | await deployed.cover.connect(bob).setMinStakeToAddLiquidity(minStake) 43 | .should.be.rejectedWith('Forbidden') 44 | }) 45 | }) 46 | -------------------------------------------------------------------------------- /test/specs/lifecycle/cover/update-cover-creator-whitelist.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const { ethers } = require('hardhat') 3 | const BigNumber = require('bignumber.js') 4 | const { deployDependencies } = require('./deps') 5 | 6 | require('chai') 7 | .use(require('chai-as-promised')) 8 | .use(require('chai-bignumber')(BigNumber)) 9 | .should() 10 | 11 | describe('Cover: updateCoverCreatorWhitelist', () => { 12 | let deployed 13 | 14 | before(async () => { 15 | deployed = await deployDependencies() 16 | }) 17 | 18 | it('correctly whitelists cover creator', async () => { 19 | const [owner, bob] = await ethers.getSigners() 20 | 21 | await deployed.cover.updateCoverCreatorWhitelist([owner.address], [true]) 22 | 23 | const isWhitelistedOwner = await deployed.cover.checkIfWhitelistedCoverCreator(owner.address) 24 | isWhitelistedOwner.should.equal(true) 25 | 26 | const isWhitelistedBob = await deployed.cover.checkIfWhitelistedCoverCreator(bob.address) 27 | isWhitelistedBob.should.equal(false) 28 | }) 29 | 30 | it('reverts when protocol is paused', async () => { 31 | await deployed.protocol.pause() 32 | 33 | const [owner] = await ethers.getSigners() 34 | await deployed.cover.updateCoverCreatorWhitelist([owner.address], [true]) 35 | .should.be.rejectedWith('Protocol is paused') 36 | 37 | await deployed.protocol.unpause() 38 | }) 39 | 40 | it('reverts when not accessed by CoverManager', async () => { 41 | const [owner, bob] = await ethers.getSigners() 42 | 43 | await deployed.cover.connect(bob).updateCoverCreatorWhitelist([owner.address], [true]) 44 | .should.be.rejectedWith('Forbidden') 45 | }) 46 | }) 47 | -------------------------------------------------------------------------------- /test/specs/liquidity/delegates/ctor-vfns.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { deployer, key } = require('../../../../util') 4 | const { deployDependencies } = require('./deps') 5 | const cache = null 6 | 7 | require('chai') 8 | .use(require('chai-as-promised')) 9 | .use(require('chai-bignumber')(BigNumber)) 10 | .should() 11 | 12 | describe('VaultDelegate Constructor and Views', () => { 13 | let deployed 14 | 15 | before(async () => { 16 | deployed = await deployDependencies() 17 | }) 18 | 19 | it('correctly deploys', async () => { 20 | const vaultDelegate = await deployer.deployWithLibraries(cache, 'VaultDelegate', 21 | { 22 | AccessControlLibV1: deployed.accessControlLibV1.address, 23 | BaseLibV1: deployed.baseLibV1.address, 24 | GovernanceUtilV1: deployed.governanceUtilV1.address, 25 | ProtoUtilV1: deployed.protoUtilV1.address, 26 | RoutineInvokerLibV1: deployed.routineInvokerLibV1.address, 27 | StoreKeyUtil: deployed.storeKeyUtil.address, 28 | StrategyLibV1: deployed.strategyLibV1.address, 29 | ValidationLibV1: deployed.validationLibV1.address, 30 | VaultLibV1: deployed.vaultLib.address 31 | } 32 | , deployed.store.address 33 | ) 34 | 35 | const _store = await vaultDelegate.s() 36 | _store.should.equal(deployed.store.address) 37 | 38 | const version = await vaultDelegate.version() 39 | version.should.equal(key.toBytes32('v0.1')) 40 | 41 | const name = await vaultDelegate.getName() 42 | name.should.equal(key.PROTOCOL.CNAME.VAULT_DELEGATE) 43 | }) 44 | }) 45 | -------------------------------------------------------------------------------- /test/specs/liquidity/engine/ctor.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { deployer, key } = require('../../../../util') 4 | const { deployDependencies } = require('./deps') 5 | const cache = null 6 | 7 | require('chai') 8 | .use(require('chai-as-promised')) 9 | .use(require('chai-bignumber')(BigNumber)) 10 | .should() 11 | 12 | describe('Liquidity Engine Constructor and Views', () => { 13 | let store, deployed 14 | 15 | beforeEach(async () => { 16 | deployed = await deployDependencies() 17 | store = deployed.store 18 | }) 19 | 20 | it('correctly deploys', async () => { 21 | const liquidityEngine = await deployer.deployWithLibraries(cache, 'LiquidityEngine', { 22 | AccessControlLibV1: deployed.accessControlLibV1.address, 23 | BaseLibV1: deployed.baseLibV1.address, 24 | NTransferUtilV2: deployed.transferLib.address, 25 | ProtoUtilV1: deployed.protoUtilV1.address, 26 | RegistryLibV1: deployed.registryLibV1.address, 27 | StoreKeyUtil: deployed.storeKeyUtil.address, 28 | StrategyLibV1: deployed.strategyLibV1.address, 29 | ValidationLibV1: deployed.validationLibV1.address 30 | }, store.address) 31 | 32 | const _store = await liquidityEngine.s() 33 | 34 | _store.should.equal(store.address) 35 | 36 | const version = await liquidityEngine.version() 37 | version.should.equal(key.toBytes32('v0.1')) 38 | 39 | const name = await liquidityEngine.getName() 40 | name.should.equal(key.PROTOCOL.CNAME.LIQUIDITY_ENGINE) 41 | }) 42 | }) 43 | -------------------------------------------------------------------------------- /test/specs/liquidity/strategy/aave/ctor.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { deployer, key, helper } = require('../../../../../util') 4 | const { deployDependencies } = require('../deps') 5 | const cache = null 6 | const CNAME_STRATEGY_AAVE = key.toBytes32('Aave Strategy') 7 | 8 | require('chai') 9 | .use(require('chai-as-promised')) 10 | .use(require('chai-bignumber')(BigNumber)) 11 | .should() 12 | 13 | describe('Aave Strategy Constructor', () => { 14 | let deployed, aaveLendingPool, aToken 15 | 16 | beforeEach(async () => { 17 | deployed = await deployDependencies() 18 | 19 | aToken = await deployer.deploy(cache, 'FakeToken', 'aToken', 'aToken', helper.ether(100_000_000), 18) 20 | aaveLendingPool = await deployer.deploy(cache, 'FakeAaveLendingPool', aToken.address) 21 | }) 22 | 23 | it('correctly deploys', async () => { 24 | const aaveStrategy = await deployer.deployWithLibraries(cache, 'AaveStrategy', { 25 | AccessControlLibV1: deployed.accessControlLibV1.address, 26 | BaseLibV1: deployed.baseLibV1.address, 27 | NTransferUtilV2: deployed.transferLib.address, 28 | ProtoUtilV1: deployed.protoUtilV1.address, 29 | RegistryLibV1: deployed.registryLibV1.address, 30 | StoreKeyUtil: deployed.storeKeyUtil.address, 31 | ValidationLibV1: deployed.validationLibV1.address 32 | }, deployed.store.address, aaveLendingPool.address, aToken.address) 33 | 34 | ; (await aaveStrategy.getKey()).should.equal(ethers.utils.solidityKeccak256(['string', 'string', 'string', 'string'], ['lending', 'strategy', 'aave', 'v2'])) 35 | ; (await aaveStrategy.version()).should.equal(key.toBytes32('v0.1')) 36 | ; (await aaveStrategy.getName()).should.equal(CNAME_STRATEGY_AAVE) 37 | }) 38 | }) 39 | -------------------------------------------------------------------------------- /test/specs/liquidity/vault-factory/ctor.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { deployer, key } = require('../../../../util') 4 | const { deployDependencies } = require('./deps') 5 | const cache = null 6 | 7 | require('chai') 8 | .use(require('chai-as-promised')) 9 | .use(require('chai-bignumber')(BigNumber)) 10 | .should() 11 | 12 | describe('VaultFactory Constructor and Views', () => { 13 | let store, deployed 14 | 15 | before(async () => { 16 | deployed = await deployDependencies() 17 | 18 | store = deployed.store 19 | }) 20 | 21 | it('correctly deploys', async () => { 22 | const vault = await deployer.deployWithLibraries(cache, 'VaultFactory', { 23 | AccessControlLibV1: deployed.accessControlLibV1.address, 24 | BaseLibV1: deployed.baseLibV1.address, 25 | ProtoUtilV1: deployed.protoUtilV1.address, 26 | ValidationLibV1: deployed.validationLibV1.address, 27 | VaultFactoryLibV1: deployed.vaultFactoryLibV1.address 28 | }, store.address) 29 | 30 | const _store = await vault.s() 31 | _store.should.equal(store.address) 32 | 33 | const version = await vault.version() 34 | version.should.equal(key.toBytes32('v0.1')) 35 | 36 | const name = await vault.getName() 37 | name.should.equal(key.PROTOCOL.CNAME.VAULT_FACTORY) 38 | }) 39 | }) 40 | -------------------------------------------------------------------------------- /test/specs/liquidity/vault/calculate-liquidity.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { helper } = require('../../../../util') 4 | const { deployDependencies } = require('./deps') 5 | const PRECISION = helper.STABLECOIN_DECIMALS 6 | 7 | require('chai') 8 | .use(require('chai-as-promised')) 9 | .use(require('chai-bignumber')(BigNumber)) 10 | .should() 11 | 12 | describe('Vault: calculateLiquidity', () => { 13 | let deployed 14 | 15 | before(async () => { 16 | deployed = await deployDependencies() 17 | }) 18 | 19 | it('correctly calculates the liquidity', async () => { 20 | const result = await deployed.vault.calculateLiquidity(helper.ether(1_000)) 21 | result.should.equal(helper.ether(1_000, PRECISION)) 22 | }) 23 | }) 24 | -------------------------------------------------------------------------------- /test/specs/liquidity/vault/calculate-pods.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { helper } = require('../../../../util') 4 | const { deployDependencies } = require('./deps') 5 | const PRECISION = helper.STABLECOIN_DECIMALS 6 | 7 | require('chai') 8 | .use(require('chai-as-promised')) 9 | .use(require('chai-bignumber')(BigNumber)) 10 | .should() 11 | 12 | describe('Vault: calculatePods', () => { 13 | let deployed 14 | 15 | before(async () => { 16 | deployed = await deployDependencies() 17 | }) 18 | 19 | it('correctly calculates amount of pods', async () => { 20 | const result = await deployed.vault.calculatePods(helper.ether(1_000, PRECISION)) 21 | result.should.equal(helper.ether(1_000)) 22 | }) 23 | }) 24 | -------------------------------------------------------------------------------- /test/specs/liquidity/vault/ctor.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { deployer, key, helper } = require('../../../../util') 4 | const { deployDependencies } = require('./deps') 5 | const PRECISION = helper.STABLECOIN_DECIMALS 6 | const cache = null 7 | 8 | require('chai') 9 | .use(require('chai-as-promised')) 10 | .use(require('chai-bignumber')(BigNumber)) 11 | .should() 12 | 13 | describe('Vault Constructor and Views', () => { 14 | let store, deployed 15 | 16 | beforeEach(async () => { 17 | deployed = await deployDependencies() 18 | 19 | store = deployed.store 20 | }) 21 | 22 | it('correctly deploys', async () => { 23 | const coverKey = key.toBytes32('test') 24 | const liquidityToken = await deployer.deploy(cache, 'FakeToken', 'USDC Token', 'USDC', helper.ether(100_000_000, PRECISION), PRECISION) 25 | 26 | const vault = await deployer.deployWithLibraries(cache, 'Vault', { 27 | AccessControlLibV1: deployed.accessControlLibV1.address, 28 | BaseLibV1: deployed.baseLibV1.address, 29 | NTransferUtilV2: deployed.transferLib.address, 30 | ProtoUtilV1: deployed.protoUtilV1.address, 31 | RegistryLibV1: deployed.registryLibV1.address, 32 | ValidationLibV1: deployed.validationLibV1.address 33 | }, store.address, coverKey, 'Vault', 'VAULT', liquidityToken.address) 34 | 35 | const _store = await vault.s() 36 | _store.should.equal(store.address) 37 | 38 | const version = await vault.version() 39 | version.should.equal(key.toBytes32('v0.1')) 40 | 41 | const name = await vault.getName() 42 | name.should.equal(key.PROTOCOL.CNAME.LIQUIDITY_VAULT) 43 | }) 44 | }) 45 | -------------------------------------------------------------------------------- /test/specs/liquidity/vault/flash-fee.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { deployDependencies } = require('./deps') 4 | 5 | require('chai') 6 | .use(require('chai-as-promised')) 7 | .use(require('chai-bignumber')(BigNumber)) 8 | .should() 9 | 10 | describe('Flashloan: flashFee', () => { 11 | let deployed 12 | 13 | before(async () => { 14 | deployed = await deployDependencies() 15 | }) 16 | 17 | it('must get flashloan fee', async () => { 18 | const amount = 200 19 | const fee = 1 // Flash Loan Fee: 0.5% 20 | 21 | const result = await deployed.vault.flashFee(deployed.stablecoin.address, amount) 22 | result.should.equal(fee) 23 | }) 24 | }) 25 | -------------------------------------------------------------------------------- /test/specs/liquidity/vault/get-info.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { helper } = require('../../../../util') 4 | const { deployDependencies } = require('./deps') 5 | const PRECISION = helper.STABLECOIN_DECIMALS 6 | 7 | require('chai') 8 | .use(require('chai-as-promised')) 9 | .use(require('chai-bignumber')(BigNumber)) 10 | .should() 11 | 12 | describe('Vault: getInfo', () => { 13 | let deployed 14 | 15 | before(async () => { 16 | deployed = await deployDependencies() 17 | }) 18 | 19 | it('correctly gets vault info', async () => { 20 | const [owner] = await ethers.getSigners() 21 | 22 | const result = await deployed.vault.getInfo(owner.address) 23 | result[0].should.equal(helper.ether(4_000_000)) 24 | result[1].should.equal(helper.ether(4_000_000, PRECISION)) 25 | }) 26 | }) 27 | -------------------------------------------------------------------------------- /test/specs/liquidity/vault/max-flash-loan.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { helper } = require('../../../../util') 4 | const { deployDependencies } = require('./deps') 5 | const PRECISION = helper.STABLECOIN_DECIMALS 6 | 7 | require('chai') 8 | .use(require('chai-as-promised')) 9 | .use(require('chai-bignumber')(BigNumber)) 10 | .should() 11 | 12 | describe('Flashloan: max flash loan', () => { 13 | let deployed 14 | 15 | before(async () => { 16 | deployed = await deployDependencies() 17 | }) 18 | 19 | it('must get max flashloan amount', async () => { 20 | const result = await deployed.vault.maxFlashLoan(deployed.stablecoin.address) 21 | 22 | result.should.equal(helper.ether(4_000_000, PRECISION)) 23 | }) 24 | }) 25 | -------------------------------------------------------------------------------- /test/specs/liquidity/vault/transfer-governance.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { helper, key } = require('../../../../util') 4 | const { deployDependencies } = require('./deps') 5 | const PRECISION = helper.STABLECOIN_DECIMALS 6 | 7 | require('chai') 8 | .use(require('chai-as-promised')) 9 | .use(require('chai-bignumber')(BigNumber)) 10 | .should() 11 | 12 | describe('Vault: transferGovernance', () => { 13 | let deployed 14 | 15 | before(async () => { 16 | deployed = await deployDependencies() 17 | }) 18 | 19 | it('reverts when coverKey is invalid', async () => { 20 | const coverKey = key.toBytes32('foo-bar2') 21 | const amount = helper.ether(1_000, PRECISION) 22 | const address = helper.zero1 23 | 24 | await deployed.vault.transferGovernance(coverKey, address, amount) 25 | .should.be.rejectedWith('Forbidden') 26 | }) 27 | 28 | it('reverts when invalid amount is supplied', async () => { 29 | const coverKey = key.toBytes32('foo-bar') 30 | const amount = helper.ether(0) 31 | const address = helper.zero1 32 | 33 | await deployed.vault.transferGovernance(coverKey, address, amount) 34 | .should.be.rejectedWith('Please specify amount') 35 | }) 36 | }) 37 | -------------------------------------------------------------------------------- /test/specs/policy-admin/ctor.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { deployer, key } = require('../../../util') 4 | const { deployDependencies } = require('./deps') 5 | const cache = null 6 | 7 | require('chai') 8 | .use(require('chai-as-promised')) 9 | .use(require('chai-bignumber')(BigNumber)) 10 | .should() 11 | 12 | describe('Policy Admin Constructor and Views', () => { 13 | let deployed 14 | 15 | before(async () => { 16 | deployed = await deployDependencies() 17 | }) 18 | 19 | it('correctly deploys', async () => { 20 | const policyAdminContract = await deployer.deployWithLibraries(cache, 'PolicyAdmin', { 21 | AccessControlLibV1: deployed.accessControlLibV1.address, 22 | BaseLibV1: deployed.baseLibV1.address, 23 | PolicyHelperV1: deployed.policyHelperV1.address, 24 | RoutineInvokerLibV1: deployed.routineInvokerLibV1.address, 25 | StoreKeyUtil: deployed.storeKeyUtil.address, 26 | ValidationLibV1: deployed.validationLibV1.address 27 | }, deployed.store.address) 28 | 29 | const version = await policyAdminContract.version() 30 | const name = await policyAdminContract.getName() 31 | 32 | version.should.equal(key.toBytes32('v0.1')) 33 | name.should.equal(key.PROTOCOL.CNAME.POLICY_ADMIN) 34 | }) 35 | }) 36 | -------------------------------------------------------------------------------- /test/specs/policy/ctor.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { deployer, key } = require('../../../util') 4 | const { deployDependencies } = require('./deps') 5 | const cache = null 6 | 7 | require('chai') 8 | .use(require('chai-as-promised')) 9 | .use(require('chai-bignumber')(BigNumber)) 10 | .should() 11 | 12 | describe('Policy Constructor', () => { 13 | let deployed, registry, policy 14 | 15 | before(async () => { 16 | deployed = await deployDependencies() 17 | 18 | registry = await deployer.deployWithLibraries(cache, 'MockRegistryClient', { 19 | RegistryLibV1: deployed.registryLibV1.address 20 | }, deployed.store.address) 21 | }) 22 | 23 | it('correctly deploys', async () => { 24 | policy = await deployer.deployWithLibraries(cache, 'Policy', { 25 | AccessControlLibV1: deployed.accessControlLibV1.address, 26 | BaseLibV1: deployed.baseLibV1.address, 27 | CoverUtilV1: deployed.coverUtilV1.address, 28 | PolicyHelperV1: deployed.policyHelperV1.address, 29 | ProtoUtilV1: deployed.protoUtilV1.address, 30 | StrategyLibV1: deployed.strategyLibV1.address, 31 | ValidationLibV1: deployed.validationLibV1.address 32 | }, deployed.store.address) 33 | 34 | await deployed.protocol.addContract(key.PROTOCOL.CNS.COVER_POLICY, policy.address) 35 | 36 | const version = await policy.version() 37 | const name = await policy.getName() 38 | 39 | version.should.equal(key.toBytes32('v0.1')) 40 | name.should.equal(key.PROTOCOL.CNAME.POLICY) 41 | }) 42 | 43 | it('must correctly return policy contract address from the registry', async () => { 44 | (await registry.getPolicyContract()).should.equal(policy.address) 45 | }) 46 | }) 47 | -------------------------------------------------------------------------------- /test/specs/pool/bond/calculate-tokens-for-lp.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { helper, deployer, key } = require('../../../../util') 4 | const { deployDependencies } = require('./deps') 5 | const { ethers } = require('hardhat') 6 | const MINUTES = 60 7 | const cache = null 8 | 9 | require('chai') 10 | .use(require('chai-as-promised')) 11 | .use(require('chai-bignumber')(BigNumber)) 12 | .should() 13 | 14 | describe('Bond: Calculate Tokens for LP', () => { 15 | let deployed, store, pool, payload 16 | 17 | before(async () => { 18 | deployed = await deployDependencies() 19 | 20 | store = deployed.store 21 | 22 | pool = await deployer.deployWithLibraries(cache, 'BondPool', { 23 | AccessControlLibV1: deployed.accessControlLibV1.address, 24 | BondPoolLibV1: deployed.bondPoolLibV1.address, 25 | BaseLibV1: deployed.baseLibV1.address, 26 | PriceLibV1: deployed.priceLibV1.address, 27 | ValidationLibV1: deployed.validationLibV1.address 28 | }, store.address) 29 | 30 | await deployed.protocol.addContract(key.PROTOCOL.CNS.BOND_POOL, pool.address) 31 | 32 | payload = { 33 | lpToken: deployed.npmStablecoinPair.address, 34 | treasury: helper.randomAddress(), 35 | bondDiscountRate: helper.percentage(1), 36 | maxBondAmount: helper.ether(100_000), 37 | vestingTerm: (5 * MINUTES).toString(), 38 | npmToTopUpNow: helper.ether(10_000_000) 39 | } 40 | 41 | await deployed.npm.approve(pool.address, ethers.constants.MaxUint256) 42 | 43 | await pool.setup(payload) 44 | }) 45 | 46 | it('correctly calculates NPM tokens for specified LP tokens', async () => { 47 | const npmTokens = await pool.calculateTokensForLp(helper.ether(200)) 48 | npmTokens.should.equal('101010101010101010101') 49 | }) 50 | }) 51 | -------------------------------------------------------------------------------- /test/specs/pool/bond/ctor.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { helper, deployer, key } = require('../../../../util') 4 | const { deployDependencies } = require('./deps') 5 | const cache = null 6 | 7 | require('chai') 8 | .use(require('chai-as-promised')) 9 | .use(require('chai-bignumber')(BigNumber)) 10 | .should() 11 | 12 | describe('Bond Pool Constructor and Views', () => { 13 | let deployed, registry, bondPool 14 | 15 | before(async () => { 16 | deployed = await deployDependencies() 17 | 18 | registry = await deployer.deployWithLibraries(cache, 'MockRegistryClient', { 19 | RegistryLibV1: deployed.registryLibV1.address 20 | }, deployed.store.address) 21 | }) 22 | 23 | it('correctly deploys', async () => { 24 | bondPool = await deployer.deployWithLibraries(cache, 'BondPool', { 25 | AccessControlLibV1: deployed.accessControlLibV1.address, 26 | BondPoolLibV1: deployed.bondPoolLibV1.address, 27 | BaseLibV1: deployed.baseLibV1.address, 28 | PriceLibV1: deployed.priceLibV1.address, 29 | ValidationLibV1: deployed.validationLibV1.address 30 | }, deployed.store.address) 31 | 32 | await deployed.protocol.addContract(key.PROTOCOL.CNS.BOND_POOL, bondPool.address) 33 | 34 | bondPool.address.should.not.be.empty 35 | bondPool.address.should.not.equal(helper.zerox) 36 | ; (await bondPool.version()).should.equal(key.toBytes32('v0.1')) 37 | ; (await bondPool.getName()).should.equal(key.PROTOCOL.CNAME.BOND_POOL) 38 | }) 39 | 40 | it('must correctly return bond pool contract address from the registry', async () => { 41 | (await registry.getBondPoolContract()).should.equal(bondPool.address) 42 | }) 43 | }) 44 | -------------------------------------------------------------------------------- /test/specs/pool/bond/npm-token-price.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { helper, deployer, key } = require('../../../../util') 4 | const { deployDependencies } = require('./deps') 5 | const { ethers } = require('hardhat') 6 | const MINUTES = 60 7 | const cache = null 8 | 9 | require('chai') 10 | .use(require('chai-as-promised')) 11 | .use(require('chai-bignumber')(BigNumber)) 12 | .should() 13 | 14 | describe('Bond: NPM Token Price', () => { 15 | let deployed, store, pool, payload 16 | 17 | before(async () => { 18 | deployed = await deployDependencies() 19 | 20 | store = deployed.store 21 | 22 | pool = await deployer.deployWithLibraries(cache, 'BondPool', { 23 | AccessControlLibV1: deployed.accessControlLibV1.address, 24 | BondPoolLibV1: deployed.bondPoolLibV1.address, 25 | BaseLibV1: deployed.baseLibV1.address, 26 | PriceLibV1: deployed.priceLibV1.address, 27 | ValidationLibV1: deployed.validationLibV1.address 28 | }, store.address) 29 | 30 | await deployed.protocol.addContract(key.PROTOCOL.CNS.BOND_POOL, pool.address) 31 | 32 | payload = { 33 | lpToken: deployed.npmStablecoinPair.address, 34 | treasury: helper.randomAddress(), 35 | bondDiscountRate: helper.percentage(1), 36 | maxBondAmount: helper.ether(100_000), 37 | vestingTerm: (5 * MINUTES).toString(), 38 | npmToTopUpNow: helper.ether(10_000_000) 39 | } 40 | 41 | await deployed.npm.approve(pool.address, ethers.constants.MaxUint256) 42 | 43 | await pool.setup(payload) 44 | }) 45 | 46 | it('correctly returns the NPM token price', async () => { 47 | const price = await pool.getNpmMarketPrice() 48 | price.should.equal(helper.ether(2)) 49 | }) 50 | }) 51 | -------------------------------------------------------------------------------- /test/specs/pool/staking/ctor-vfns.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { helper, deployer, key } = require('../../../../util') 4 | const { deployDependencies } = require('./deps') 5 | const cache = null 6 | 7 | require('chai') 8 | .use(require('chai-as-promised')) 9 | .use(require('chai-bignumber')(BigNumber)) 10 | .should() 11 | 12 | describe('Staking Pool Constructor and Views', () => { 13 | let store, deployed 14 | 15 | before(async () => { 16 | deployed = await deployDependencies() 17 | 18 | store = deployed.store 19 | }) 20 | 21 | it('correctly deploys', async () => { 22 | const stakingPoolContract = await deployer.deployWithLibraries(cache, 'StakingPools', { 23 | AccessControlLibV1: deployed.accessControlLibV1.address, 24 | BaseLibV1: deployed.baseLibV1.address, 25 | StakingPoolCoreLibV1: deployed.stakingPoolCoreLibV1.address, 26 | StakingPoolLibV1: deployed.stakingPoolLibV1.address, 27 | StoreKeyUtil: deployed.storeKeyUtil.address, 28 | ValidationLibV1: deployed.validationLibV1.address 29 | }, store.address) 30 | 31 | stakingPoolContract.address.should.not.be.empty 32 | stakingPoolContract.address.should.not.equal(helper.zerox) 33 | ; (await stakingPoolContract.version()).should.equal(key.toBytes32('v0.1')) 34 | ; (await stakingPoolContract.getName()).should.equal(key.PROTOCOL.CNAME.STAKING_POOL) 35 | }) 36 | }) 37 | -------------------------------------------------------------------------------- /test/specs/store/count-address-array-items.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { deployer, key, helper } = require('../../../util') 4 | const cache = null 5 | 6 | require('chai') 7 | .use(require('chai-as-promised')) 8 | .use(require('chai-bignumber')(BigNumber)) 9 | .should() 10 | 11 | describe('Store: count address array items', () => { 12 | let store, items, k 13 | 14 | before(async () => { 15 | items = [helper.randomAddress(), helper.randomAddress(), helper.randomAddress(), helper.randomAddress()] 16 | 17 | store = await deployer.deploy(cache, 'Store') 18 | 19 | k = key.toBytes32('test:address:array:item') 20 | 21 | for (const item of items) { 22 | await store.setAddressArrayItem(k, item) 23 | await store.setAddressArrayItem(k, item) // same item added multiple times should not increase the count 24 | } 25 | }) 26 | 27 | it('must correctly count address array items', async () => { 28 | const result = await store.countAddressArrayItems(k) 29 | result.should.equal(items.length.toString()) 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /test/specs/store/delete-address-array-item-by-index.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { deployer, key, helper } = require('../../../util') 4 | const cache = null 5 | 6 | require('chai') 7 | .use(require('chai-as-promised')) 8 | .use(require('chai-bignumber')(BigNumber)) 9 | .should() 10 | 11 | describe('Store: delete address array item by index', () => { 12 | let store, items, k 13 | 14 | before(async () => { 15 | items = [helper.randomAddress(), helper.randomAddress(), helper.randomAddress(), helper.randomAddress(), helper.randomAddress()] 16 | store = await deployer.deploy(cache, 'Store') 17 | 18 | k = key.toBytes32('test:address:array:item') 19 | 20 | for (const item of items) { 21 | await store.setAddressArrayItem(k, item) 22 | } 23 | }) 24 | 25 | it('must correctly delete address array items by indices', async () => { 26 | const index = 1 27 | await store.deleteAddressArrayItemByIndex(k, index) 28 | items.splice(index, 1) 29 | 30 | const result = await store.getAddressArray(k) 31 | ; [...result].sort().should.deep.equal([...items].sort()) 32 | }) 33 | 34 | it('must revert with an error if an invalid index is specified', async () => { 35 | await store.deleteAddressArrayItemByIndex(k, 10) 36 | .should.be.rejectedWith('Invalid index') 37 | }) 38 | }) 39 | -------------------------------------------------------------------------------- /test/specs/store/delete-address-array-item.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { deployer, key, helper } = require('../../../util') 4 | const cache = null 5 | 6 | require('chai') 7 | .use(require('chai-as-promised')) 8 | .use(require('chai-bignumber')(BigNumber)) 9 | .should() 10 | 11 | describe('Store: delete address array item', () => { 12 | let store, items, k, toDelete 13 | 14 | before(async () => { 15 | items = [helper.randomAddress(), helper.randomAddress(), helper.randomAddress(), helper.randomAddress(), helper.randomAddress()] 16 | toDelete = items[2] 17 | 18 | store = await deployer.deploy(cache, 'Store') 19 | 20 | k = key.toBytes32('test:address:array:item') 21 | 22 | for (const item of items) { 23 | await store.setAddressArrayItem(k, item) 24 | } 25 | }) 26 | 27 | it('must correctly delete an address array item', async () => { 28 | await store.deleteAddressArrayItem(k, toDelete) 29 | 30 | const result = await store.getAddressArray(k) 31 | ; [...result].sort().should.deep.equal(items.filter(x => x !== toDelete).sort()) 32 | }) 33 | 34 | it('must revert with an error if an invalid address is specified', async () => { 35 | await store.deleteAddressArrayItem(k, helper.randomAddress()) 36 | .should.be.rejectedWith('Not found') 37 | }) 38 | }) 39 | -------------------------------------------------------------------------------- /test/specs/store/get-address-array-item-by-index.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { deployer, key, helper } = require('../../../util') 4 | const cache = null 5 | 6 | require('chai') 7 | .use(require('chai-as-promised')) 8 | .use(require('chai-bignumber')(BigNumber)) 9 | .should() 10 | 11 | describe('Store: get address array item by index', () => { 12 | let store, items, k 13 | 14 | before(async () => { 15 | items = [helper.randomAddress(), helper.randomAddress(), helper.randomAddress()] 16 | store = await deployer.deploy(cache, 'Store') 17 | 18 | k = key.toBytes32('test:address:array:item') 19 | 20 | for (const item of items) { 21 | await store.setAddressArrayItem(k, item) 22 | } 23 | }) 24 | 25 | it('must correctly get address array items by indices', async () => { 26 | for (const i in items) { 27 | const item = items[i] 28 | const result = await store.getAddressArrayItemByIndex(k, i) 29 | 30 | result.should.equal(item) 31 | } 32 | }) 33 | 34 | it('must revert with an error if an invalid index is specified', async () => { 35 | await store.getAddressArrayItemByIndex(k, 10) 36 | .should.be.rejectedWith('Invalid index') 37 | }) 38 | }) 39 | -------------------------------------------------------------------------------- /test/specs/store/get-address-values.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { helper, deployer, key } = require('../../../util') 4 | const cache = null 5 | 6 | require('chai') 7 | .use(require('chai-as-promised')) 8 | .use(require('chai-bignumber')(BigNumber)) 9 | .should() 10 | 11 | describe('Store: get address values', () => { 12 | let store 13 | 14 | before(async () => { 15 | store = await deployer.deploy(cache, 'Store') 16 | }) 17 | 18 | it('must correctly get the stored address values', async () => { 19 | const keys = [key.toBytes32('test:address1'), key.toBytes32('test:address2')] 20 | 21 | const values = [ 22 | helper.randomAddress(), 23 | helper.randomAddress() 24 | ] 25 | 26 | for (const i in keys) { 27 | await store.setAddress(keys[i], values[i]) 28 | } 29 | 30 | const result = await store.getAddressValues(keys) 31 | result.should.deep.equal(values) 32 | }) 33 | }) 34 | -------------------------------------------------------------------------------- /test/specs/store/get-uint-values.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { ethers } = require('hardhat') 4 | const { helper, deployer, key } = require('../../../util') 5 | const cache = null 6 | 7 | require('chai') 8 | .use(require('chai-as-promised')) 9 | .use(require('chai-bignumber')(BigNumber)) 10 | .should() 11 | 12 | describe('Store: get uint values', () => { 13 | let store 14 | 15 | before(async () => { 16 | store = await deployer.deploy(cache, 'Store') 17 | }) 18 | 19 | it('must correctly get the stored uint values', async () => { 20 | const keys = [key.toBytes32('test:uint1'), key.toBytes32('test:uint2')] 21 | 22 | const values = [ 23 | ethers.BigNumber.from(helper.getRandomNumber(10000000, 100000000).toString()), 24 | ethers.BigNumber.from(helper.getRandomNumber(10000000, 100000000).toString()) 25 | ] 26 | 27 | for (const i in keys) { 28 | await store.setUint(keys[i], values[i]) 29 | } 30 | 31 | const result = await store.getUintValues(keys) 32 | 33 | for (const i in result) { 34 | result[i].should.equal(values[i]) 35 | } 36 | }) 37 | }) 38 | -------------------------------------------------------------------------------- /test/specs/store/pausable.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { deployer, key } = require('../../../util') 4 | const cache = null 5 | 6 | require('chai') 7 | .use(require('chai-as-promised')) 8 | .use(require('chai-bignumber')(BigNumber)) 9 | .should() 10 | 11 | describe('Store: Pausable', () => { 12 | let store 13 | 14 | before(async () => { 15 | store = await deployer.deploy(cache, 'Store') 16 | }) 17 | 18 | it('must allow a pauser to pause the store', async () => { 19 | const [owner] = await ethers.getSigners() 20 | await store.setPausers([owner.address], [true]) 21 | await store.pause() 22 | 23 | const state = await store.paused() 24 | 25 | state.should.be.true 26 | }) 27 | 28 | it('must throw if the store is paused', async () => { 29 | await store.setUint(key.toBytes32('test'), '1') 30 | .should.be.rejectedWith('Pausable: paused') 31 | }) 32 | 33 | it('must allow the owner to unpause the store', async () => { 34 | await store.unpause() 35 | 36 | const state = await store.paused() 37 | state.should.be.false 38 | }) 39 | 40 | it('must allow store member to update the store', async () => { 41 | await store.setUint(key.toBytes32('test'), '1') 42 | .should.not.be.rejected 43 | }) 44 | }) 45 | -------------------------------------------------------------------------------- /test/specs/store/set-address.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { ethers } = require('hardhat') 4 | const { deployer, key, helper } = require('../../../util') 5 | const cache = null 6 | 7 | require('chai') 8 | .use(require('chai-as-promised')) 9 | .use(require('chai-bignumber')(BigNumber)) 10 | .should() 11 | 12 | describe('Store: set address', () => { 13 | let store 14 | 15 | before(async () => { 16 | store = await deployer.deploy(cache, 'Store') 17 | }) 18 | 19 | it('must correctly set address', async () => { 20 | const k = key.toBytes32('test:address') 21 | const value = helper.randomAddress() 22 | await store.setAddress(k, value) 23 | 24 | const result = await store.getAddress(k) 25 | result.should.equal(value) 26 | }) 27 | 28 | it('must revert if the store is paused', async () => { 29 | const [owner] = await ethers.getSigners() 30 | await store.setPausers([owner.address], [true]) 31 | await store.pause() 32 | 33 | const k = key.toBytes32('test:address') 34 | const value = helper.randomAddress() 35 | 36 | await store.setAddress(k, value) 37 | .should.be.rejectedWith('Pausable: paused') 38 | 39 | await store.unpause() 40 | 41 | await store.setAddress(k, value) 42 | .should.not.be.rejected 43 | }) 44 | 45 | it('must revert if the sender is not a store or protocol member', async () => { 46 | const [, bob] = await ethers.getSigners() 47 | 48 | const k = key.toBytes32('test:address') 49 | const value = helper.randomAddress() 50 | 51 | await store.connect(bob).setAddress(k, value) 52 | .should.be.rejectedWith('Forbidden') 53 | }) 54 | }) 55 | -------------------------------------------------------------------------------- /test/specs/store/set-bool.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { ethers } = require('hardhat') 4 | const { deployer, key } = require('../../../util') 5 | const cache = null 6 | 7 | require('chai') 8 | .use(require('chai-as-promised')) 9 | .use(require('chai-bignumber')(BigNumber)) 10 | .should() 11 | 12 | describe('Store: set bool', () => { 13 | let store 14 | 15 | before(async () => { 16 | store = await deployer.deploy(cache, 'Store') 17 | }) 18 | 19 | it('must correctly set bool', async () => { 20 | const k = key.toBytes32('test:bool') 21 | const value = Math.random() < 0.5 22 | await store.setBool(k, value) 23 | 24 | const result = await store.getBool(k) 25 | result.should.equal(value) 26 | }) 27 | 28 | it('must revert if the store is paused', async () => { 29 | const [owner] = await ethers.getSigners() 30 | await store.setPausers([owner.address], [true]) 31 | await store.pause() 32 | 33 | const k = key.toBytes32('test:bool') 34 | const value = Math.random() < 0.5 35 | 36 | await store.setBool(k, value) 37 | .should.be.rejectedWith('Pausable: paused') 38 | 39 | await store.unpause() 40 | 41 | await store.setBool(k, value) 42 | .should.not.be.rejected 43 | }) 44 | 45 | it('must revert if the sender is not a store or protocol member', async () => { 46 | const [, bob] = await ethers.getSigners() 47 | 48 | const k = key.toBytes32('test:bool') 49 | const value = Math.random() < 0.5 50 | 51 | await store.connect(bob).setBool(k, value) 52 | .should.be.rejectedWith('Forbidden') 53 | }) 54 | }) 55 | -------------------------------------------------------------------------------- /test/specs/store/set-bytes.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { ethers } = require('hardhat') 4 | const uuid = require('uuid') 5 | const { helper, deployer, key } = require('../../../util') 6 | const cache = null 7 | 8 | require('chai') 9 | .use(require('chai-as-promised')) 10 | .use(require('chai-bignumber')(BigNumber)) 11 | .should() 12 | 13 | describe('Store: set bytes', () => { 14 | let store 15 | 16 | before(async () => { 17 | store = await deployer.deploy(cache, 'Store') 18 | }) 19 | 20 | it('must correctly set bytes', async () => { 21 | const k = key.toBytes32('test:bytes') 22 | const value = helper.stringToHex(uuid.v4()) 23 | await store.setBytes(k, value) 24 | 25 | const result = await store.getBytes(k) 26 | result.should.equal(value) 27 | }) 28 | 29 | it('must revert if the store is paused', async () => { 30 | const [owner] = await ethers.getSigners() 31 | await store.setPausers([owner.address], [true]) 32 | await store.pause() 33 | 34 | const k = key.toBytes32('test:bytes') 35 | const value = helper.stringToHex(uuid.v4()) 36 | 37 | await store.setBytes(k, value) 38 | .should.be.rejectedWith('Pausable: paused') 39 | 40 | await store.unpause() 41 | 42 | await store.setBytes(k, value) 43 | .should.not.be.rejected 44 | }) 45 | 46 | it('must revert if the sender is not a store or protocol member', async () => { 47 | const [, bob] = await ethers.getSigners() 48 | 49 | const k = key.toBytes32('test:bytes') 50 | const value = helper.stringToHex(uuid.v4()) 51 | 52 | await store.connect(bob).setBytes(k, value) 53 | .should.be.rejectedWith('Forbidden') 54 | }) 55 | }) 56 | -------------------------------------------------------------------------------- /test/specs/store/set-bytes32.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { ethers } = require('hardhat') 4 | const uuid = require('uuid') 5 | const { deployer, key } = require('../../../util') 6 | const cache = null 7 | 8 | require('chai') 9 | .use(require('chai-as-promised')) 10 | .use(require('chai-bignumber')(BigNumber)) 11 | .should() 12 | 13 | describe('Store: set bytes32', () => { 14 | let store 15 | 16 | before(async () => { 17 | store = await deployer.deploy(cache, 'Store') 18 | }) 19 | 20 | it('must correctly set bytes32', async () => { 21 | const k = key.toBytes32('test:bytes32') 22 | const value = key.toBytes32(uuid.v4().substring(0, 30)) 23 | await store.setBytes32(k, value) 24 | 25 | const result = await store.getBytes32(k) 26 | result.should.equal(value) 27 | }) 28 | 29 | it('must revert if the store is paused', async () => { 30 | const [owner] = await ethers.getSigners() 31 | await store.setPausers([owner.address], [true]) 32 | await store.pause() 33 | 34 | const k = key.toBytes32('test:bytes32') 35 | const value = key.toBytes32(uuid.v4().substring(0, 30)) 36 | 37 | await store.setBytes32(k, value) 38 | .should.be.rejectedWith('Pausable: paused') 39 | 40 | await store.unpause() 41 | 42 | await store.setBytes32(k, value) 43 | .should.not.be.rejected 44 | }) 45 | 46 | it('must revert if the sender is not a store or protocol member', async () => { 47 | const [, bob] = await ethers.getSigners() 48 | 49 | const k = key.toBytes32('test:bytes32') 50 | const value = key.toBytes32(uuid.v4().substring(0, 30)) 51 | 52 | await store.connect(bob).setBytes32(k, value) 53 | .should.be.rejectedWith('Forbidden') 54 | }) 55 | }) 56 | -------------------------------------------------------------------------------- /test/specs/store/set-int.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { ethers } = require('hardhat') 4 | const { helper, deployer, key } = require('../../../util') 5 | const cache = null 6 | 7 | require('chai') 8 | .use(require('chai-as-promised')) 9 | .use(require('chai-bignumber')(BigNumber)) 10 | .should() 11 | 12 | describe('Store: set int', () => { 13 | let store 14 | 15 | before(async () => { 16 | store = await deployer.deploy(cache, 'Store') 17 | }) 18 | 19 | it('must correctly set int', async () => { 20 | const k = key.toBytes32('test:int') 21 | const value = helper.getRandomNumber(-100000000, 100000000).toString() 22 | await store.setInt(k, value) 23 | 24 | const result = await store.getInt(k) 25 | result.should.equal(value) 26 | }) 27 | 28 | it('must revert if the store is paused', async () => { 29 | const [owner] = await ethers.getSigners() 30 | await store.setPausers([owner.address], [true]) 31 | await store.pause() 32 | 33 | const k = key.toBytes32('test:int') 34 | const value = helper.getRandomNumber(-100000000, 100000000).toString() 35 | 36 | await store.setInt(k, value) 37 | .should.be.rejectedWith('Pausable: paused') 38 | 39 | await store.unpause() 40 | 41 | await store.setInt(k, value) 42 | .should.not.be.rejected 43 | }) 44 | 45 | it('must revert if the sender is not a store or protocol member', async () => { 46 | const [, bob] = await ethers.getSigners() 47 | 48 | const k = key.toBytes32('test:int') 49 | const value = helper.getRandomNumber(-10000000, 100000000).toString() 50 | 51 | await store.connect(bob).setInt(k, value) 52 | .should.be.rejectedWith('Forbidden') 53 | }) 54 | }) 55 | -------------------------------------------------------------------------------- /test/specs/store/set-string.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { ethers } = require('hardhat') 4 | const uuid = require('uuid') 5 | const { deployer, key } = require('../../../util') 6 | const cache = null 7 | 8 | require('chai') 9 | .use(require('chai-as-promised')) 10 | .use(require('chai-bignumber')(BigNumber)) 11 | .should() 12 | 13 | describe('Store: set string', () => { 14 | let store 15 | 16 | before(async () => { 17 | store = await deployer.deploy(cache, 'Store') 18 | }) 19 | 20 | it('must correctly set string', async () => { 21 | const k = key.toBytes32('test:string') 22 | const value = uuid.v4() 23 | await store.setString(k, value) 24 | 25 | const result = await store.getString(k) 26 | result.should.equal(value) 27 | }) 28 | 29 | it('must revert if the store is paused', async () => { 30 | const [owner] = await ethers.getSigners() 31 | await store.setPausers([owner.address], [true]) 32 | await store.pause() 33 | 34 | const k = key.toBytes32('test:string') 35 | const value = uuid.v4() 36 | 37 | await store.setString(k, value) 38 | .should.be.rejectedWith('Pausable: paused') 39 | 40 | await store.unpause() 41 | 42 | await store.setString(k, value) 43 | .should.not.be.rejected 44 | }) 45 | 46 | it('must revert if the sender is not a store or protocol member', async () => { 47 | const [, bob] = await ethers.getSigners() 48 | 49 | const k = key.toBytes32('test:string') 50 | const value = uuid.v4() 51 | 52 | await store.connect(bob).setString(k, value) 53 | .should.be.rejectedWith('Forbidden') 54 | }) 55 | }) 56 | -------------------------------------------------------------------------------- /test/specs/store/set-uint.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { ethers } = require('hardhat') 4 | const { helper, deployer, key } = require('../../../util') 5 | const cache = null 6 | 7 | require('chai') 8 | .use(require('chai-as-promised')) 9 | .use(require('chai-bignumber')(BigNumber)) 10 | .should() 11 | 12 | describe('Store: set uint', () => { 13 | let store 14 | 15 | before(async () => { 16 | store = await deployer.deploy(cache, 'Store') 17 | }) 18 | 19 | it('must correctly set uint', async () => { 20 | const k = key.toBytes32('test:uint') 21 | const value = helper.getRandomNumber(10000000, 100000000).toString() 22 | await store.setUint(k, value) 23 | 24 | const result = await store.getUint(k) 25 | result.should.equal(value) 26 | }) 27 | 28 | it('must revert if the store is paused', async () => { 29 | const [owner] = await ethers.getSigners() 30 | await store.setPausers([owner.address], [true]) 31 | await store.pause() 32 | 33 | const k = key.toBytes32('test:uint') 34 | const value = helper.getRandomNumber(10000000, 100000000).toString() 35 | 36 | await store.setUint(k, value) 37 | .should.be.rejectedWith('Pausable: paused') 38 | 39 | await store.unpause() 40 | 41 | await store.setUint(k, value) 42 | .should.not.be.rejected 43 | }) 44 | 45 | it('must revert if the sender is not a store or protocol member', async () => { 46 | const [, bob] = await ethers.getSigners() 47 | 48 | const k = key.toBytes32('test:uint') 49 | const value = helper.getRandomNumber(10000000, 100000000).toString() 50 | 51 | await store.connect(bob).setUint(k, value) 52 | .should.be.rejectedWith('Forbidden') 53 | }) 54 | }) 55 | -------------------------------------------------------------------------------- /test/specs/token/delayable.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | const BigNumber = require('bignumber.js') 3 | const { helper, deployer } = require('../../../util') 4 | const DAYS = 86400 5 | const cache = null 6 | 7 | require('chai') 8 | .use(require('chai-as-promised')) 9 | .use(require('chai-bignumber')(BigNumber)) 10 | .should() 11 | 12 | describe('Delayable', () => { 13 | it('should deploy correctly', async () => { 14 | const minDelay = 1 * DAYS 15 | const proposers = [helper.randomAddress()] 16 | const executors = [helper.randomAddress()] 17 | 18 | const delayable = await deployer.deploy(cache, 'Delayable', minDelay, proposers, executors) 19 | const { events } = await delayable.deployTransaction.wait() 20 | const event = events.find(x => x.event === 'MinDelayChange') 21 | 22 | event.args.oldDuration.should.equal('0') 23 | event.args.newDuration.should.equal(minDelay.toString()) 24 | }) 25 | }) 26 | -------------------------------------------------------------------------------- /truffle-config.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | mocha: { 3 | timeout: 250000 4 | }, 5 | compilers: { 6 | solc: { 7 | version: '0.8.17', 8 | docker: false, 9 | settings: { 10 | optimizer: { 11 | enabled: true, 12 | runs: 200 13 | }, 14 | evmVersion: 'istanbul' 15 | } 16 | } 17 | }, 18 | db: { 19 | enabled: false 20 | } 21 | } 22 | 23 | module.exports = config 24 | -------------------------------------------------------------------------------- /util/analyzers/validators/access-control.js: -------------------------------------------------------------------------------- 1 | const { isMock } = require('./mock') 2 | 3 | const validate = async (code, _, name) => { 4 | if (isMock(name)) { 5 | return null 6 | } 7 | 8 | const hasAcl = code.indexOf('AccessControl') > -1 9 | const hasCallerCheck = code.indexOf('callerMustBe') > -1 10 | const hasOwnerCheck = code.indexOf('onlyOwner') > -1 11 | const isLibrary = (name || '').split('/').indexOf('libraries') > -1 12 | const suppressionMissing = code.toLowerCase().indexOf('@suppress-acl') === -1 && code.toLowerCase().indexOf('@custom:suppress-acl') === -1 13 | 14 | if (!(hasAcl || hasCallerCheck || hasOwnerCheck || isLibrary) && suppressionMissing) { 15 | return '\x1b[31m' + '* Access control logic not found. Are you sure this function should be publicly accessible?' + '\x1b[0m' 16 | } 17 | 18 | return null 19 | } 20 | 21 | module.exports = validate 22 | -------------------------------------------------------------------------------- /util/analyzers/validators/accidental-zero.js: -------------------------------------------------------------------------------- 1 | const { isLib } = require('./lib') 2 | const { isMock } = require('./mock') 3 | 4 | const validate = async (code, _, name) => { 5 | if (isLib(name) || isMock(name)) { 6 | return null 7 | } 8 | 9 | const supressionMissing = code.toLowerCase().indexOf('@suppress-accidental-zero') === -1 && code.toLowerCase().indexOf('@custom:suppress-accidental-zero') === -1 10 | const hasLogic = code.toLowerCase().indexOf('> ') > -1 || code.toLowerCase().indexOf('>= ') > -1 || code.toLowerCase().indexOf('< ') > -1 || code.toLowerCase().indexOf('<= ') > -1 11 | 12 | if (supressionMissing && hasLogic) { 13 | return '\x1b[31m' + '* Warning: Ensure that either of these values are not unassigned or accidentally zero' + '\x1b[0m' 14 | } 15 | 16 | return null 17 | } 18 | 19 | module.exports = validate 20 | -------------------------------------------------------------------------------- /util/analyzers/validators/address.js: -------------------------------------------------------------------------------- 1 | const { isMock } = require('./mock') 2 | 3 | const validate = async (code, selector, name) => { 4 | if (isMock(name)) { 5 | return null 6 | } 7 | 8 | const addressArgs = selector.parameters 9 | .parameters.filter(x => x.typeName.name === 'address' && 10 | ['account', 'to', 'from', 'v', 'sendTo'].indexOf(x.name) === -1) 11 | 12 | const suppressionMissing = code.toLowerCase().indexOf('@suppress-address-trust-issue') === -1 && code.toLowerCase().indexOf('@custom:suppress-address-trust-issue') === -1 13 | 14 | if (addressArgs.length && suppressionMissing) { 15 | return '\x1b[31m' + `* Ensure [${addressArgs.map(x => x.name).join(',')}] can be trusted. Ensure this function has AccessControl logic. Ensure you validate address before using.` + '\x1b[0m' 16 | } 17 | 18 | return null 19 | } 20 | 21 | module.exports = validate 22 | -------------------------------------------------------------------------------- /util/analyzers/validators/erc-20.js: -------------------------------------------------------------------------------- 1 | const { isMock } = require('./mock') 2 | 3 | const validate = async (code, _, name) => { 4 | if (isMock(name)) { 5 | return null 6 | } 7 | const suppressionMissing = code.toLowerCase().indexOf('@suppress-malicious-erc20') === -1 && code.toLowerCase().indexOf('@custom:suppress-malicious-erc') === -1 8 | 9 | if (code.toLowerCase().indexOf('erc20') > -1 && suppressionMissing) { 10 | return '\x1b[31m' + '* Ensure that you validate this ERC-20 token instance if the address came from user input' + '\x1b[0m' 11 | } 12 | 13 | return null 14 | } 15 | 16 | module.exports = validate 17 | -------------------------------------------------------------------------------- /util/analyzers/validators/fraction.js: -------------------------------------------------------------------------------- 1 | const { isMock } = require('./mock') 2 | 3 | const validate = async (code, _, name) => { 4 | if (isMock(name)) { 5 | return null 6 | } 7 | 8 | const suppressionMissing = code.toLowerCase().indexOf('@suppress-division') === -1 && code.toLowerCase().indexOf('@custom:suppress-division') === -1 9 | 10 | if (code.toLowerCase().indexOf('div(') > -1 && suppressionMissing) { 11 | return '\x1b[31m' + '* Warning: Please ensure the division(s) here does not end up producing zero values.' + '\x1b[0m' 12 | } 13 | 14 | if (code.toLowerCase().indexOf(' / ') > -1 && suppressionMissing) { 15 | return '\x1b[31m' + '* Warning: Please ensure the division(s) here does not end up producing zero values.' + '\x1b[0m' 16 | } 17 | 18 | return null 19 | } 20 | 21 | module.exports = validate 22 | -------------------------------------------------------------------------------- /util/analyzers/validators/index.js: -------------------------------------------------------------------------------- 1 | const acl = require('./access-control') 2 | const address = require('./address') 3 | const erc20 = require('./erc-20') 4 | const fraction = require('./fraction') 5 | const initialization = require('./initialization') 6 | const nonReentrancy = require('./non-reentrancy') 7 | const notImplemented = require('./not-implemented') 8 | const pausable = require('./pausable') 9 | const revert = require('./revert') 10 | const subtraction = require('./subtraction') 11 | const todo = require('./todo') 12 | const zero = require('./zero-value') 13 | const accidentalZero = require('./accidental-zero') 14 | 15 | module.exports = [acl, address, erc20, fraction, initialization, nonReentrancy, notImplemented, pausable, revert, subtraction, todo, zero, accidentalZero] 16 | -------------------------------------------------------------------------------- /util/analyzers/validators/initialization.js: -------------------------------------------------------------------------------- 1 | const { isMock } = require('./mock') 2 | 3 | const validate = async (code, _, name) => { 4 | if (isMock(name)) { 5 | return null 6 | } 7 | const suppressionMissing = code.toLowerCase().indexOf('@suppress-initialization') === -1 && code.toLowerCase().indexOf('@custom:suppress-initialization') === -1 8 | 9 | if (code.toLowerCase().indexOf('function initia') > -1 && suppressionMissing) { 10 | return '\x1b[31m' + '* Ensure that there is access control for this initializer' + '\x1b[0m' 11 | } 12 | 13 | return null 14 | } 15 | 16 | module.exports = validate 17 | -------------------------------------------------------------------------------- /util/analyzers/validators/lib.js: -------------------------------------------------------------------------------- 1 | const isLib = (name) => { 2 | const contract = (name || '').toLowerCase().split('/').pop() 3 | 4 | if (contract.indexOf('lib') > -1 || contract.indexOf('util') > -1 || contract.indexOf('helper') > -1) { 5 | return true 6 | } 7 | 8 | return false 9 | } 10 | 11 | module.exports = { isLib } 12 | -------------------------------------------------------------------------------- /util/analyzers/validators/mock.js: -------------------------------------------------------------------------------- 1 | const isMock = (name) => { 2 | if ((name || '').toLowerCase().split('/').indexOf('mock') > -1) { 3 | return true 4 | } 5 | 6 | if ((name || '').toLowerCase().split('/').indexOf('fake') > -1) { 7 | return true 8 | } 9 | 10 | return false 11 | } 12 | 13 | module.exports = { isMock } 14 | -------------------------------------------------------------------------------- /util/analyzers/validators/non-reentrancy.js: -------------------------------------------------------------------------------- 1 | const { isMock } = require('./mock') 2 | 3 | const validate = async (code, _, name) => { 4 | if (isMock(name)) { 5 | return null 6 | } 7 | 8 | if ((name || '').split('/').indexOf('libraries') > -1) { 9 | return null 10 | } 11 | 12 | const suppressionMissing = code.toLowerCase().indexOf('@suppress-reentrancy') === -1 && code.toLowerCase().indexOf('@custom:suppress-reentrancy') === -1 13 | 14 | if (code.indexOf('nonReentrant') === -1 && suppressionMissing) { 15 | return '\x1b[31m' + '* Non Reentrancy logic not found. Are you sure this function should be publicly accessible?' + '\x1b[0m' 16 | } 17 | 18 | return null 19 | } 20 | 21 | module.exports = validate 22 | -------------------------------------------------------------------------------- /util/analyzers/validators/not-implemented.js: -------------------------------------------------------------------------------- 1 | const { isMock } = require('./mock') 2 | 3 | const validate = async (code, _, name) => { 4 | if (isMock(name)) { 5 | return null 6 | } 7 | 8 | if (code.toLowerCase().indexOf('not implemented') > -1 || code.toLowerCase().indexOf('to-do') > -1) { 9 | return '\x1b[31m' + '* Error: implement the missing functionalities' + '\x1b[0m' 10 | } 11 | 12 | return null 13 | } 14 | 15 | module.exports = validate 16 | -------------------------------------------------------------------------------- /util/analyzers/validators/pausable.js: -------------------------------------------------------------------------------- 1 | const { isMock } = require('./mock') 2 | 3 | const validate = async (code, _, name) => { 4 | if (isMock(name)) { 5 | return null 6 | } 7 | 8 | const hasPausable = code.toLowerCase().indexOf('pause') > -1 9 | const isLibrary = (name || '').split('/').indexOf('libraries') > -1 10 | const suppressionMissing = code.toLowerCase().indexOf('@suppress-pausable') === -1 && code.toLowerCase().indexOf('@custom:suppress-pausable') === -1 11 | 12 | if (!(hasPausable || isLibrary) && suppressionMissing) { 13 | return '\x1b[31m' + '* Pausable logic not found' + '\x1b[0m' 14 | } 15 | 16 | return null 17 | } 18 | 19 | module.exports = validate 20 | -------------------------------------------------------------------------------- /util/analyzers/validators/revert.js: -------------------------------------------------------------------------------- 1 | const { isMock } = require('./mock') 2 | 3 | const validate = async (code, _, name) => { 4 | if (isMock(name)) { 5 | return null 6 | } 7 | 8 | const suppressionMissing = code.toLowerCase().indexOf('@suppress-revert') === -1 && code.toLowerCase().indexOf('@custom:suppress-revert') === -1 9 | 10 | if (code.toLowerCase().indexOf('revert') > -1 && suppressionMissing) { 11 | return '\x1b[31m' + '* Ensure that the usage of revert is correct' + '\x1b[0m' 12 | } 13 | 14 | return null 15 | } 16 | 17 | module.exports = validate 18 | -------------------------------------------------------------------------------- /util/analyzers/validators/subtraction.js: -------------------------------------------------------------------------------- 1 | const { isMock } = require('./mock') 2 | 3 | const validate = async (code, _, name) => { 4 | if (isMock(name)) { 5 | return null 6 | } 7 | 8 | const suppressionMissing = code.toLowerCase().indexOf('@suppress-subtraction') === -1 && code.toLowerCase().indexOf('@custom:suppress-subtraction') === -1 9 | 10 | if (code.toLowerCase().indexOf('subtract') > -1 && suppressionMissing) { 11 | return '\x1b[31m' + '* Warning: Please ensure this subtraction does not result in an underflow.' + '\x1b[0m' 12 | } 13 | 14 | if (code.toLowerCase().indexOf(' - ') > -1 && suppressionMissing) { 15 | return '\x1b[31m' + '* Warning: Please ensure this subtraction does not result in an underflow.' + '\x1b[0m' 16 | } 17 | 18 | return null 19 | } 20 | 21 | module.exports = validate 22 | -------------------------------------------------------------------------------- /util/analyzers/validators/todo.js: -------------------------------------------------------------------------------- 1 | const { isMock } = require('./mock') 2 | 3 | const validate = async (code, _, name) => { 4 | if (isMock(name)) { 5 | return null 6 | } 7 | 8 | if (code.toLowerCase().indexOf('todo') > -1 || code.toLowerCase().indexOf('to-do') > -1) { 9 | return '\x1b[31m' + '* Warning: complete the todo list' + '\x1b[0m' 10 | } 11 | 12 | return null 13 | } 14 | 15 | module.exports = validate 16 | -------------------------------------------------------------------------------- /util/analyzers/validators/zero-value.js: -------------------------------------------------------------------------------- 1 | const { isLib } = require('./lib') 2 | const { isMock } = require('./mock') 3 | 4 | const validate = async (code, _, name) => { 5 | if (isLib(name) || isMock(name)) { 6 | return null 7 | } 8 | 9 | const hasUint = code.toLowerCase().indexOf('uint') > -1 10 | const supressionMissing = code.toLowerCase().indexOf('@suppress-zero-value-check') === -1 && code.toLowerCase().indexOf('@custom:suppress-zero-value-check') === -1 11 | const hasCheck = code.toLowerCase().indexOf('> ') > -1 || code.toLowerCase().indexOf('>= ') > -1 12 | 13 | if (hasUint && supressionMissing && !hasCheck) { 14 | return '\x1b[31m' + '* Warning: Ensure that the uint value is not zero' + '\x1b[0m' 15 | } 16 | 17 | return null 18 | } 19 | 20 | module.exports = validate 21 | -------------------------------------------------------------------------------- /util/attach/attach.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat') 2 | 3 | const attach = async (contractName, address, libraries) => { 4 | const contract = libraries ? await ethers.getContractFactory(contractName, libraries) : await ethers.getContractFactory(contractName) 5 | return contract.attach(address) 6 | } 7 | 8 | module.exports = { attach } 9 | -------------------------------------------------------------------------------- /util/attach/index.js: -------------------------------------------------------------------------------- 1 | const attach = require('./attach') 2 | const protocol = require('./protocol') 3 | 4 | module.exports = { attach, protocol } 5 | -------------------------------------------------------------------------------- /util/attach/protocol.js: -------------------------------------------------------------------------------- 1 | const { attach } = require('./attach') 2 | 3 | /** 4 | * Attaches protocol instance to a given address 5 | * @param {string} address 6 | * @param {Libraries} libraries 7 | * @returns {ethers.Contract} 8 | */ 9 | const attacher = async (address, libraries) => { 10 | return attach('MockProtocol', address, { 11 | AccessControlLibV1: libraries.accessControlLibV1.address, 12 | BaseLibV1: libraries.baseLibV1.address, 13 | ProtoUtilV1: libraries.protoUtilV1.address, 14 | StoreKeyUtil: libraries.storeKeyUtil.address, 15 | ValidationLibV1: libraries.validationLibV1.address 16 | }) 17 | } 18 | 19 | module.exports = { attach: attacher } 20 | -------------------------------------------------------------------------------- /util/block-time.js: -------------------------------------------------------------------------------- 1 | const networks = { 2 | 1: { 3 | approximateBlockTime: 15 4 | }, 5 | 3: { 6 | approximateBlockTime: 12 7 | }, 8 | 42: { 9 | approximateBlockTime: 4 10 | }, 11 | 97: { 12 | approximateBlockTime: 3 13 | }, 14 | 80001: { 15 | approximateBlockTime: 3 16 | }, 17 | 43113: { 18 | approximateBlockTime: 2 19 | }, 20 | 84531: { 21 | approximateBlockTime: 2 22 | }, 23 | 31337: { 24 | approximateBlockTime: 1 25 | }, 26 | 31338: { 27 | approximateBlockTime: 1 28 | } 29 | } 30 | 31 | const minutesToBlocks = (chainId, minutes) => { 32 | try { 33 | const seconds = minutes * 60 34 | const { approximateBlockTime } = networks[chainId] 35 | 36 | return seconds / approximateBlockTime 37 | } catch (error) { 38 | console.error(error) 39 | } 40 | 41 | return networks[1] 42 | } 43 | 44 | const hoursToBlocks = (chainId, hours) => { 45 | const minutes = hours * 60 46 | return minutesToBlocks(chainId, minutes) 47 | } 48 | 49 | const daysToBlocks = (chainId, days) => { 50 | const hours = days * 24 51 | return hoursToBlocks(chainId, hours) 52 | } 53 | 54 | module.exports = { minutesToBlocks, hoursToBlocks, daysToBlocks } 55 | -------------------------------------------------------------------------------- /util/block.js: -------------------------------------------------------------------------------- 1 | const hre = require('hardhat') 2 | const moment = require('moment') 3 | 4 | const getTimestamp = async () => { 5 | const { timestamp } = await hre.ethers.provider.getBlock('latest') 6 | return moment.unix(timestamp) 7 | } 8 | 9 | const mineBlocks = async (totalBlocks) => { 10 | while (totalBlocks > 0) { 11 | totalBlocks-- 12 | await hre.network.provider.request({ 13 | method: 'evm_mine', 14 | params: [] 15 | }) 16 | } 17 | } 18 | 19 | module.exports = { getTimestamp, mineBlocks } 20 | -------------------------------------------------------------------------------- /util/composer/add-pools.js: -------------------------------------------------------------------------------- 1 | const { approve } = require('../contract-helper/erc20') 2 | 3 | const addPodStaking = async (intermediate, cache, info, contracts, provider) => { 4 | const { rewardToken } = info 5 | 6 | const { stakingPoolContract } = contracts 7 | await approve(rewardToken, stakingPoolContract.address, provider) 8 | 9 | await intermediate(cache, stakingPoolContract, 'addOrEditPool', info) 10 | } 11 | 12 | const addPools = async (intermediate, cache, pools, contracts, provider) => { 13 | console.log('Wait') 14 | 15 | for (const i in pools) { 16 | const pool = pools[i] 17 | console.log('Task %s:%s | %s', parseInt(i) + 1, pools.length, pool.name) 18 | 19 | await addPodStaking(intermediate, cache, pool, contracts, provider) 20 | } 21 | } 22 | 23 | module.exports = { addPools } 24 | -------------------------------------------------------------------------------- /util/composer/external-protocols.js: -------------------------------------------------------------------------------- 1 | const hre = require('hardhat') 2 | const fakesComposer = require('./fakes') 3 | const { getNetworkInfo } = require('../network') 4 | const { zerox } = require('../helper') 5 | 6 | /** 7 | * Initializes all contracts 8 | * @return {Promise} 9 | */ 10 | const getExternalProtocols = async (cache, tokens) => { 11 | const network = await getNetworkInfo() 12 | 13 | let router = network?.uniswapV2Like?.addresses?.router 14 | let factory = network?.uniswapV2Like?.addresses?.factory 15 | let priceOracle = network?.uniswapV2Like?.addresses?.npmPriceOracle 16 | let aaveLendingPool = network?.aave?.addresses?.lendingPool 17 | let compoundStablecoinDelegator = network?.compound?.stablecoin?.delegator 18 | 19 | if (hre.network.name === 'hardhat') { 20 | const fakes = await fakesComposer.deployAll(cache, tokens) 21 | 22 | if (!router) { 23 | router = fakes.router.address 24 | } 25 | 26 | if (!factory) { 27 | factory = fakes.factory.address 28 | } 29 | 30 | if (!aaveLendingPool) { 31 | aaveLendingPool = fakes.aave.lendingPool.address 32 | } 33 | 34 | if (!compoundStablecoinDelegator) { 35 | compoundStablecoinDelegator = fakes.compound.stablecoinDelegator.address 36 | } 37 | } 38 | 39 | if (!priceOracle) { 40 | priceOracle = zerox 41 | } 42 | 43 | return { 44 | router, 45 | factory, 46 | priceOracle, 47 | aaveLendingPool, 48 | compoundStablecoinDelegator 49 | } 50 | } 51 | 52 | module.exports = { getExternalProtocols } 53 | -------------------------------------------------------------------------------- /util/composer/fakes.js: -------------------------------------------------------------------------------- 1 | const { deployer } = require('..') 2 | 3 | const deployAll = async (cache, tokens) => { 4 | const { stablecoin, cStablecoin, aToken } = tokens 5 | 6 | const router = await deployer.deploy(cache, 'FakeUniswapV2RouterLike') 7 | const pair = await deployer.deploy(cache, 'FakeUniswapV2PairLike', '0x0000000000000000000000000000000000000001', '0x0000000000000000000000000000000000000002') 8 | const factory = await deployer.deploy(cache, 'FakeUniswapV2FactoryLike', pair.address) 9 | const lendingPool = await deployer.deploy(cache, 'FakeAaveLendingPool', aToken.address) 10 | const stablecoinDelegator = await deployer.deploy(cache, 'FakeCompoundStablecoinDelegator', stablecoin.address, cStablecoin.address) 11 | const priceOracle = await deployer.deploy(cache, 'FakePriceOracle') 12 | 13 | await stablecoin.addMinter(lendingPool.address, true) 14 | await aToken.addMinter(lendingPool.address, true) 15 | 16 | await stablecoin.addMinter(stablecoinDelegator.address, true) 17 | await cStablecoin.addMinter(stablecoinDelegator.address, true) 18 | 19 | return { router, pair, factory, priceOracle, aave: { lendingPool }, compound: { stablecoinDelegator } } 20 | } 21 | 22 | module.exports = { deployAll } 23 | -------------------------------------------------------------------------------- /util/composer/grant-roles.js: -------------------------------------------------------------------------------- 1 | const hre = require('hardhat') 2 | const { getNetworkInfo } = require('../network') 3 | const { ACCESS_CONTROL } = require('../../util/key') 4 | const { key } = require('..') 5 | 6 | const grantRoles = async (intermediate, cache, { protocol, cover, policy }) => { 7 | const [owner] = await hre.ethers.getSigners() 8 | const network = await getNetworkInfo() 9 | 10 | const payload = [{ 11 | account: owner.address, 12 | roles: [ 13 | ACCESS_CONTROL.COVER_MANAGER, 14 | ACCESS_CONTROL.UPGRADE_AGENT, 15 | ACCESS_CONTROL.GOVERNANCE_ADMIN 16 | ] 17 | }] 18 | 19 | if (network.mainnet === false) { 20 | payload[payload.length - 1].roles.push(ACCESS_CONTROL.LIQUIDITY_MANAGER) 21 | } 22 | 23 | if (network?.knownAccounts) { 24 | payload.push(...network.knownAccounts) 25 | } 26 | 27 | payload.push({ 28 | account: cover.address, 29 | roles: [key.ACCESS_CONTROL.UPGRADE_AGENT] 30 | }, 31 | { 32 | account: policy.address, 33 | roles: [key.ACCESS_CONTROL.UPGRADE_AGENT] 34 | }, 35 | { 36 | account: protocol.address, 37 | roles: [key.ACCESS_CONTROL.UPGRADE_AGENT] 38 | }) 39 | 40 | await intermediate(cache, protocol, 'grantRoles', payload) 41 | } 42 | 43 | module.exports = { grantRoles } 44 | -------------------------------------------------------------------------------- /util/composer/index.js: -------------------------------------------------------------------------------- 1 | const store = require('./store') 2 | const libs = require('./libs') 3 | const token = require('./token') 4 | const vault = require('./vault') 5 | const initializer = require('./initializer') 6 | 7 | module.exports = { initializer, store, libs, token, vault } 8 | -------------------------------------------------------------------------------- /util/composer/store.js: -------------------------------------------------------------------------------- 1 | const { deployer } = require('..') 2 | 3 | const deploy = async (cache) => { 4 | return deployer.deploy(cache, 'Store') 5 | } 6 | 7 | module.exports = { deploy } 8 | -------------------------------------------------------------------------------- /util/composer/vault.js: -------------------------------------------------------------------------------- 1 | const { storeUtil } = require('../../util') 2 | 3 | /** 4 | * Gets the vault from store 5 | * @param {Contracts} contracts All contracts 6 | * @param {string} coverKey The cover Key 7 | * @returns {any} Returns the vault contract 8 | */ 9 | const getVault = async (contracts, coverKey) => { 10 | const vaultAddress = await storeUtil.getVaultAddress(contracts.store, coverKey) 11 | 12 | const Vault = await ethers.getContractFactory('Vault', { 13 | libraries: { 14 | AccessControlLibV1: contracts.libs.accessControlLibV1.address, 15 | BaseLibV1: contracts.libs.baseLibV1.address, 16 | NTransferUtilV2: contracts.libs.transferLib.address, 17 | ProtoUtilV1: contracts.libs.protoUtilV1.address, 18 | RegistryLibV1: contracts.libs.registryLibV1.address, 19 | ValidationLibV1: contracts.libs.validationLibV1.address 20 | } 21 | }) 22 | 23 | return Vault.attach(vaultAddress) 24 | } 25 | 26 | module.exports = { getVault } 27 | -------------------------------------------------------------------------------- /util/contract-helper/erc20.js: -------------------------------------------------------------------------------- 1 | const { ethers, network } = require('hardhat') 2 | const erc20abi = require('../../abis/IERC20Detailed.json') 3 | 4 | const getInstance = async (at, signer) => { 5 | const [owner] = await ethers.getSigners() 6 | return new ethers.Contract(at, erc20abi, signer || owner) 7 | } 8 | 9 | const approve = async (tokenAddress, spender, account, amount = ethers.constants.MaxUint256) => { 10 | const erc20 = await getInstance(tokenAddress, account) 11 | 12 | if (network.name !== 'hardhat') { 13 | const allowance = await erc20.allowance(account.address, spender) 14 | const symbol = await erc20.symbol() 15 | 16 | if (allowance.gte(amount)) { 17 | console.info('Spender %s already approved to spend %s from account %s', spender, symbol, account.address) 18 | return 19 | } 20 | } 21 | 22 | const tx = await erc20.connect(account).approve(spender, amount) 23 | await tx.wait() 24 | } 25 | 26 | module.exports = { getInstance, approve } 27 | -------------------------------------------------------------------------------- /util/contract-helper/faucet.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat') 2 | const { ether } = require('../helper') 3 | 4 | const request = async (token, amount) => { 5 | const [owner] = await ethers.getSigners() 6 | 7 | const balance = await token.balanceOf(owner.address) 8 | 9 | if (balance.gte(amount || '0')) { 10 | return 11 | } 12 | 13 | const contract = await new ethers.Contract(token.address, ['function mint(uint256) external'], owner) 14 | console.info('Requesting tokens') 15 | 16 | const tx = await contract.connect(owner).mint(amount || ether(1_000_000)) 17 | await tx.wait() 18 | } 19 | 20 | module.exports = { request } 21 | -------------------------------------------------------------------------------- /util/contract-helper/uniswap.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat') 2 | const routerAbi = require('../../abis/IUniswapV2RouterLike.json') 3 | const factoryAbi = require('../../abis/IUniswapV2FactoryLike.json') 4 | const pairAbi = require('../../abis/IUniswapV2PairLike.json') 5 | const { helper } = require('..') 6 | 7 | const getRouter = async (routerAt, signer) => { 8 | const [owner] = await ethers.getSigners() 9 | return new ethers.Contract(routerAt, routerAbi, signer || owner) 10 | } 11 | 12 | const getFactory = async (factoryAt, signer) => { 13 | const [owner] = await ethers.getSigners() 14 | return new ethers.Contract(factoryAt, factoryAbi, signer || owner) 15 | } 16 | 17 | const getPair = async (pairAt, signer) => { 18 | if (pairAbi === helper.zerox) { 19 | return helper.zerox 20 | } 21 | 22 | const [owner] = await ethers.getSigners() 23 | return new ethers.Contract(pairAt, pairAbi, signer || owner) 24 | } 25 | 26 | module.exports = { getRouter, getFactory, getPair } 27 | -------------------------------------------------------------------------------- /util/cxToken.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Gets cxToken from an address 3 | * @param {string} at Address where your cxToken is deployed 4 | * @param {Libraries} libraries The deployed libraries 5 | */ 6 | const atAddress = async (at, libraries) => { 7 | const cxToken = await ethers.getContractFactory('cxToken', { 8 | libraries: { 9 | AccessControlLibV1: libraries.accessControlLibV1.address, 10 | BaseLibV1: libraries.baseLibV1.address, 11 | CoverUtilV1: libraries.coverUtilV1.address, 12 | GovernanceUtilV1: libraries.governanceUtilV1.address, 13 | PolicyHelperV1: libraries.policyHelperV1.address, 14 | ProtoUtilV1: libraries.protoUtilV1.address, 15 | StoreKeyUtil: libraries.storeKeyUtil.address, 16 | ValidationLibV1: libraries.validationLibV1.address 17 | 18 | } 19 | }) 20 | 21 | return cxToken.attach(at) 22 | } 23 | 24 | module.exports = { atAddress } 25 | -------------------------------------------------------------------------------- /util/demo-data/add-liquidity.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat') 2 | const { covers } = require('../../examples') 3 | const composer = require('../composer') 4 | const { ether, getRandomNumber, weiAsToken, STABLECOIN_DECIMALS } = require('../helper') 5 | const { approve } = require('../contract-helper/erc20') 6 | const { key } = require('..') 7 | const PRECISION = STABLECOIN_DECIMALS 8 | 9 | const add = async (coverKey, payload) => { 10 | const [lp] = await ethers.getSigners() // eslint-disable-line 11 | const amount = ether(getRandomNumber(1_250_000, 5_000_000), PRECISION) 12 | const npmStakeToAdd = ether(getRandomNumber(1000, 125_000)) 13 | 14 | const { tokens } = payload 15 | const vault = await composer.vault.getVault(payload, coverKey) 16 | 17 | console.info('%s %s %s', vault.address, tokens.stablecoin.address, tokens.npm.address) 18 | 19 | await approve(tokens.stablecoin.address, vault.address, lp, ethers.constants.MaxUint256) 20 | await approve(tokens.npm.address, vault.address, lp, ethers.constants.MaxUint256) 21 | 22 | console.info('Adding %s to the vault. Stake: %s. From: %s', weiAsToken(amount, 'USDC', PRECISION), weiAsToken(npmStakeToAdd, 'NPM'), lp.address) 23 | 24 | await vault.addLiquidity({ 25 | coverKey, 26 | amount, 27 | npmStakeToAdd, 28 | referralCode: key.toBytes32('') 29 | }) 30 | 31 | console.info('Added %s to the vault. Stake: %s', weiAsToken(amount, 'USDC', PRECISION), weiAsToken(npmStakeToAdd, 'NPM')) 32 | } 33 | 34 | const addLiquidity = async (payload) => { 35 | for (const i in covers) { 36 | const { coverKey, coverName } = covers[i] 37 | 38 | console.info('Adding liquidity to %s', coverName) 39 | await add(coverKey, payload) 40 | } 41 | } 42 | 43 | module.exports = { addLiquidity } 44 | -------------------------------------------------------------------------------- /util/demo-data/add-reassurance.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('hardhat') 2 | const { covers } = require('../../examples') 3 | const { ether, getRandomNumber, weiAsToken, STABLECOIN_DECIMALS } = require('../helper') 4 | const { approve } = require('../contract-helper/erc20') 5 | const faucet = require('../contract-helper/faucet') 6 | const PRECISION = STABLECOIN_DECIMALS 7 | 8 | const add = async (coverKey, payload) => { 9 | const [owner] = await ethers.getSigners() 10 | const amount = ether(getRandomNumber(250_000, 5_000_000), PRECISION) 11 | 12 | const { tokens, reassuranceContract } = payload 13 | 14 | await faucet.request(tokens.stablecoin, amount) 15 | 16 | await approve(tokens.stablecoin.address, reassuranceContract.address, owner, ethers.constants.MaxUint256) 17 | 18 | await reassuranceContract.connect(owner).addReassurance(coverKey, owner.address, amount) 19 | 20 | console.info('Added %s to the reassurance vault.', weiAsToken(amount, 'USDC', PRECISION)) 21 | } 22 | 23 | const addReassurance = async (payload) => { 24 | for (const i in covers) { 25 | const { coverKey, coverName } = covers[i] 26 | 27 | console.info('Adding reassurance to %s', coverName) 28 | await add(coverKey, payload) 29 | } 30 | } 31 | 32 | module.exports = { addReassurance } 33 | -------------------------------------------------------------------------------- /util/demo-data/index.js: -------------------------------------------------------------------------------- 1 | const { addLiquidity } = require('./add-liquidity') 2 | const { addReassurance } = require('./add-reassurance') 3 | 4 | const create = async (payload) => { 5 | console.info('Creating demo data') 6 | await addLiquidity(payload) 7 | await addReassurance(payload) 8 | } 9 | 10 | module.exports = { create } 11 | -------------------------------------------------------------------------------- /util/demo-data/purchase-policy.js: -------------------------------------------------------------------------------- 1 | const { covers } = require('../../examples') 2 | const composer = require('../composer') 3 | const { ether, getRandomNumber, weiAsToken, STABLECOIN_DECIMALS } = require('../helper') 4 | const { toBytes32 } = require('../key') 5 | const { approve } = require('../contract-helper/erc20') 6 | const PRECISION = STABLECOIN_DECIMALS 7 | 8 | const add = async (coverKey, payload) => { 9 | const [lp] = await ethers.getSigners() // eslint-disable-line 10 | const amount = ether(getRandomNumber(250_000, 5_000_000), PRECISION) 11 | const stake = ether(getRandomNumber(1000, 125_000)) 12 | 13 | const { stablecoin, npm } = payload 14 | const vault = await composer.vault.getVault(payload, coverKey) 15 | 16 | await stablecoin.mint(amount) 17 | await npm.mint(stake) 18 | 19 | await approve(stablecoin.address, vault.address, lp, amount) 20 | await approve(npm.address, vault.address, lp, stake) 21 | 22 | await vault.connect(lp).addLiquidity({ 23 | coverKey, 24 | amount, 25 | npmStakeToAdd: stake, 26 | referralCode: toBytes32('') 27 | }) 28 | 29 | console.info('Added %s to the vault. Stake: %s', weiAsToken(amount, 'USDC'), weiAsToken(stake, 'NPM')) 30 | } 31 | 32 | const addLiquidity = async (payload) => { 33 | for (const i in covers) { 34 | const { key, coverName } = covers[i] 35 | 36 | console.info('Adding liquidity to %s', coverName) 37 | await add(key, payload) 38 | } 39 | } 40 | 41 | module.exports = { addLiquidity } 42 | -------------------------------------------------------------------------------- /util/events/all.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const io = require('../io') 3 | 4 | const getFileList = async () => io.findFiles('json', path.join(process.cwd(), 'abis')) 5 | const ignored = ['Approval', 'Transfer'] 6 | const divider = '-'.repeat(128) 7 | 8 | const getEvents = async (file) => { 9 | const contents = await io.readFile(file) 10 | const parsed = JSON.parse(contents) 11 | const events = parsed.filter(x => x.type === 'event') 12 | 13 | const result = [`${file}`, divider] 14 | 15 | const candidates = [] 16 | 17 | for (const event of events) { 18 | if (ignored.indexOf(event.name) > -1) { 19 | continue 20 | } 21 | 22 | const args = event.inputs 23 | .filter(x => ['Approval', 'Transfer'].indexOf(x.name) === -1) 24 | .map(x => { 25 | const { indexed, type, name } = x 26 | 27 | return `${type}${indexed ? ' indexed' : ''} ${name}` 28 | }).join(', ') 29 | 30 | candidates.push(`event ${event.name}(${args});`) 31 | } 32 | 33 | if (candidates.length === 0) { 34 | return '' 35 | } 36 | 37 | result.push('```\n' + candidates.join('\n') + '\n```') 38 | 39 | result.push('') 40 | return result.join('\n') 41 | } 42 | 43 | const start = async () => { 44 | const events = [] 45 | const abis = await getFileList() 46 | 47 | if (!abis.length) { 48 | console.error(new Error('Please first export the ABIs')) 49 | return 50 | } 51 | 52 | for (const abi of abis) { 53 | events.push(await getEvents(abi)) 54 | } 55 | 56 | console.info(events.filter(x => !!x).join('\n')) 57 | } 58 | 59 | start() 60 | -------------------------------------------------------------------------------- /util/events/index.js: -------------------------------------------------------------------------------- 1 | const all = require('./all') 2 | 3 | module.exports = { 4 | all 5 | } 6 | -------------------------------------------------------------------------------- /util/events/table.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const io = require('../io') 3 | 4 | const getFileList = async () => io.findFiles('json', path.join(process.cwd(), 'abis')) 5 | const ignored = ['Approval', 'Transfer'] 6 | 7 | const getEvents = async (file) => { 8 | const contents = await io.readFile(file) 9 | const parsed = JSON.parse(contents) 10 | const events = parsed.filter(x => x.type === 'event') 11 | 12 | const candidates = [] 13 | 14 | for (const event of events) { 15 | const { name } = event 16 | if (ignored.indexOf(name) > -1) { 17 | continue 18 | } 19 | 20 | candidates.push(`${file.split('/').pop()} | ${name} | |`) 21 | } 22 | 23 | if (candidates.length === 0) { 24 | return 25 | } 26 | 27 | console.log(candidates.join('\n')) 28 | } 29 | 30 | const start = async () => { 31 | const abis = await getFileList() 32 | 33 | if (!abis.length) { 34 | console.error(new Error('Please first export the ABIs')) 35 | return 36 | } 37 | 38 | console.log('| Contract | Events | Roles |') 39 | console.log('| -------- | ------ | ------- |') 40 | 41 | for (const abi of abis) { 42 | await getEvents(abi) 43 | } 44 | } 45 | 46 | start() 47 | -------------------------------------------------------------------------------- /util/extract/abis/index.js: -------------------------------------------------------------------------------- 1 | const io = require('../../io') 2 | const path = require('path') 3 | const root = path.join('artifacts', 'contracts', 'interfaces') 4 | 5 | const getFiles = async () => { 6 | const hasFiles = await io.exists(root) 7 | 8 | if (!hasFiles) { 9 | const command = '\x1b[36m' + 'npx hardhat compile' + '\x1b[0m' 10 | console.log(`Please generate artifacts using: ${command}`) 11 | return 12 | } 13 | 14 | const files = await io.findFiles('json', root) 15 | const all = files.map(x => `${x.replace('.dbg', '')}`) 16 | 17 | all.push('./artifacts/openzeppelin-solidity/contracts/token/ERC20/IERC20.sol/IERC20.json') 18 | all.push('./artifacts/contracts/dependencies/aave/IAaveV2LendingPoolLike.sol/IAaveV2LendingPoolLike.json') 19 | all.push('./artifacts/contracts/dependencies/compound/ICompoundERC20DelegatorLike.sol/ICompoundERC20DelegatorLike.json') 20 | all.push('./artifacts/contracts/dependencies/uniswap-v2/IUniswapV2FactoryLike.sol/IUniswapV2FactoryLike.json') 21 | all.push('./artifacts/contracts/dependencies/uniswap-v2/IUniswapV2PairLike.sol/IUniswapV2PairLike.json') 22 | all.push('./artifacts/contracts/dependencies/uniswap-v2/IUniswapV2RouterLike.sol/IUniswapV2RouterLike.json') 23 | 24 | return [...new Set(all)] 25 | } 26 | 27 | const createAbi = async (file) => { 28 | const destination = path.join(process.cwd(), 'abis', file.split('/').pop()) 29 | 30 | if (!(await io.exists(file))) { 31 | return 32 | } 33 | 34 | const contents = await io.readFile(file) 35 | const artifact = JSON.parse(contents) 36 | 37 | await io.ensureFile(destination, JSON.stringify(artifact.abi, null, 2)) 38 | } 39 | 40 | const extract = async () => { 41 | const files = await getFiles() 42 | 43 | for (const i in files) { 44 | await createAbi(files[i]) 45 | } 46 | } 47 | 48 | extract() 49 | -------------------------------------------------------------------------------- /util/extract/genabi.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const fs = require('fs').promises 3 | const { 4 | FormatTypes, 5 | Interface 6 | } = require('@ethersproject/abi') 7 | 8 | const { exists, findFiles, writeFile, ensureFile } = require('../io') 9 | 10 | const srcAbiFolder = path.resolve('.', process.argv[2]) 11 | const targetFile = path.resolve('.', process.argv[3]) 12 | 13 | if (!exists(srcAbiFolder)) { 14 | throw Error('Invalid ABI directory') 15 | } 16 | 17 | const generateFileContents = async () => { 18 | const files = await findFiles('json', srcAbiFolder) 19 | 20 | if (files.length === 0) { 21 | throw Error('No ABIs found') 22 | } 23 | 24 | const contents = [] 25 | const exportedVariables = [] 26 | 27 | for (let i = 0; i < files.length; i++) { 28 | const file = files[i] 29 | 30 | const variable = path.parse(file).name 31 | const abi = await fs.readFile(file) 32 | try { 33 | const iface = new Interface(abi.toString()) 34 | 35 | // abi constant declaration 36 | contents.push( 37 | `const ${variable} = ${JSON.stringify(iface.format(FormatTypes.full), null, 2)}` 38 | ) 39 | } catch (error) { 40 | console.error('Invalid ABI %s', file, error) 41 | } 42 | 43 | exportedVariables.push(variable) 44 | } 45 | 46 | // export statement 47 | contents.push(`export {\n ${exportedVariables.join(',\n ')}\n}`) 48 | 49 | return contents.join('\n\n') 50 | } 51 | 52 | async function main () { 53 | console.log('Generating abi:js from %s', srcAbiFolder) 54 | const contents = await generateFileContents() 55 | 56 | await ensureFile(targetFile) 57 | await writeFile(targetFile, contents) 58 | console.log('Generated: %s', targetFile) 59 | } 60 | 61 | main() 62 | -------------------------------------------------------------------------------- /util/extract/keys/code-generator-as.js: -------------------------------------------------------------------------------- 1 | const Enumerable = require('node-enumerable') 2 | 3 | const generate = async (all) => { 4 | Enumerable.from(all) 5 | .orderBy(x => x.prefix) 6 | .thenBy(x => x.key) 7 | .each(c => { 8 | const comment = c.comment ? ` // ${c.comment}` : '' 9 | const value = c.value === '0x00' ? 'toBytes32("")' : `toBytes32("${c.value}")` 10 | console.info(`export const ${c.prefix}${c.key} = ${value};${comment}`) 11 | }) 12 | } 13 | 14 | module.exports = { generate } 15 | -------------------------------------------------------------------------------- /util/extract/keys/code-generator.js: -------------------------------------------------------------------------------- 1 | const Enumerable = require('node-enumerable') 2 | 3 | const generate = async (groupKey, group) => { 4 | const prefixes = Enumerable.from(group).select(x => x.prefix).distinct().toArray() 5 | 6 | const builder = [] 7 | builder.push(`const ${groupKey} = {`) 8 | 9 | Enumerable.from(group).groupBy(x => x.prefix).each(item => { 10 | const candidates = item.toArray() 11 | 12 | if (prefixes.length === 1) { 13 | const code = candidates.map(x => ` ${x.key}: toBytes32('${x.value === '0x00' ? '' : x.value}'),`) 14 | builder.push(...code) 15 | } else { 16 | builder.push(` ${item.key.slice(0, -1)}: {`) 17 | const code = candidates.map(x => ` ${x.key}: toBytes32('${x.value === '0x00' ? '' : x.value}'),`) 18 | builder.push(...code) 19 | builder.push(' },') 20 | } 21 | }) 22 | 23 | builder.push('}\n\n') 24 | console.log(builder.join('\n')) 25 | } 26 | 27 | module.exports = { generate } 28 | -------------------------------------------------------------------------------- /util/extract/keys/index.js: -------------------------------------------------------------------------------- 1 | const Enumerable = require('node-enumerable') 2 | const files = require('./requirement') 3 | const codegen = require('./code-generator') 4 | const codegenAs = require('./code-generator-as') 5 | const processor = require('./processor') 6 | const template = require('./template') 7 | const [, , type] = process.argv 8 | 9 | const start = async () => { 10 | const candidates = [] 11 | const mode = type && type.replace('--', '') 12 | const { pre, post } = template.get(mode) 13 | 14 | console.log(pre) 15 | console.log('\n') 16 | 17 | for (const i in files) { 18 | const result = await processor.process(files[i]) 19 | candidates.push(...result) 20 | } 21 | 22 | if (mode === 'as') { 23 | await codegenAs.generate(candidates) 24 | return 25 | } 26 | 27 | Enumerable.from(candidates) 28 | .groupBy(x => x.scope) 29 | .each(async (scope) => codegen.generate(scope.key, scope.toArray())) 30 | 31 | const scopes = Enumerable.from(candidates).select(x => x.scope).distinct().toArray().join(', ') 32 | 33 | console.log(post.replace('{{scopes}}', scopes)) 34 | } 35 | 36 | start() 37 | -------------------------------------------------------------------------------- /util/extract/keys/processor.js: -------------------------------------------------------------------------------- 1 | const io = require('../../io') 2 | 3 | const extractPair = (match, scope, prefix, type) => { 4 | const parts = match.replace('bytes32 public constant ', '').split('=') 5 | let [key, contents] = parts 6 | 7 | let [value, comment] = contents.trim().split(';') 8 | 9 | key = key.trim().replace(prefix, '') 10 | value = value.replace(/"/g, '').trim() 11 | comment = (comment || '').replace('//', '').trim() 12 | 13 | return { scope, prefix, key, value, comment, type } 14 | } 15 | 16 | const process = async (file) => { 17 | const { type, scope, prefix, expression, src } = file 18 | const contents = await io.readFile(src) 19 | const matches = contents.match(expression) 20 | 21 | return matches.map(x => extractPair(x.trim(), scope, prefix, type)) 22 | } 23 | 24 | module.exports = { process } 25 | -------------------------------------------------------------------------------- /util/extract/keys/requirement.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { 3 | scope: 'ACCESS_CONTROL', 4 | type: 'role', 5 | prefix: 'NS_ROLES_', 6 | expression: /.*constant NS_ROLES_.*\n/g, 7 | src: './contracts/Libraries/AccessControlLibV1.sol' 8 | }, 9 | { 10 | scope: 'BOND', 11 | type: 'bond', 12 | prefix: 'NS_BOND_', 13 | expression: /.*constant NS_BOND_.*\n/g, 14 | src: './contracts/Libraries/BondPoolLibV1.sol' 15 | }, 16 | { 17 | scope: 'PROTOCOL', 18 | type: 'cns', 19 | prefix: 'CNS_', 20 | expression: /.*constant CNS_.*\n/g, 21 | src: './contracts/Libraries/ProtoUtilV1.sol' 22 | }, 23 | { 24 | scope: 'PROTOCOL', 25 | type: 'ns', 26 | prefix: 'NS_', 27 | expression: /.*constant NS_.*\n/g, 28 | src: './contracts/Libraries/ProtoUtilV1.sol' 29 | }, 30 | { 31 | scope: 'PROTOCOL', 32 | type: 'cname', 33 | prefix: 'CNAME_', 34 | expression: /.*constant CNAME_.*\n/g, 35 | src: './contracts/Libraries/ProtoUtilV1.sol' 36 | }, 37 | { 38 | scope: 'STAKING', 39 | type: 'staking:pool', 40 | prefix: 'NS_POOL_', 41 | expression: /.*constant NS_POOL_.*\n/g, 42 | src: './contracts/Libraries/StakingPoolCoreLibV1.sol' 43 | } 44 | ] 45 | -------------------------------------------------------------------------------- /util/extract/keys/template-as.js: -------------------------------------------------------------------------------- 1 | const pre = `import { ByteArray } from "@graphprotocol/graph-ts"; 2 | 3 | const toBytes32 = (x: string): ByteArray => ByteArray.fromUTF8(x);` 4 | 5 | const post = '' 6 | 7 | module.exports = { pre, post } 8 | -------------------------------------------------------------------------------- /util/extract/keys/template-js.js: -------------------------------------------------------------------------------- 1 | const pre = `const ethers = require('ethers') 2 | 3 | const encodeKey = (x) => ethers.utils.solidityKeccak256(['bytes32'], [toBytes32(x)]) 4 | const encodeKeys = (x, y) => ethers.utils.solidityKeccak256(x, y) 5 | const toBytes32 = (x) => ethers.utils.formatBytes32String(x) 6 | const getCoverContractKey = (namespace, coverKey) => encodeKeys(['bytes32', 'bytes32'], [toBytes32(namespace), coverKey]) 7 | const qualifyBytes32 = (k) => encodeKeys(['bytes32', 'bytes32'], [PROTOCOL.NS.CONTRACTS, k]) 8 | const qualify = (k) => encodeKeys(['bytes32', 'address'], [PROTOCOL.NS.CONTRACTS, k]) 9 | const qualifyMember = (k) => encodeKeys(['bytes32', 'address'], [PROTOCOL.NS.MEMBERS, k])` 10 | 11 | const post = `module.exports = { 12 | encodeKey, 13 | encodeKeys, 14 | toBytes32, 15 | getCoverContractKey, 16 | qualify, 17 | qualifyMember, 18 | qualifyBytes32, 19 | {{scopes}} 20 | }` 21 | 22 | module.exports = { pre, post } 23 | -------------------------------------------------------------------------------- /util/extract/keys/template-ts.js: -------------------------------------------------------------------------------- 1 | const pre = `import { keccak256 as solidityKeccak256 } from '@ethersproject/solidity' 2 | import { formatBytes32String } from '@ethersproject/strings' 3 | 4 | const encodeKey = (x: string): string => solidityKeccak256(['bytes32'], [x]) 5 | const encodeKeys = (x: string[], y: string[]): string => solidityKeccak256(x, y) 6 | const toBytes32 = (x: string): string => formatBytes32String(x) 7 | const getCoverContractKey = (namespace: string, coverKey: string): string => encodeKeys(['bytes32', 'bytes32'], [namespace, coverKey]) 8 | const qualifyBytes32 = (k: string): string => encodeKeys(['bytes32', 'bytes32'], [PROTOCOL.NS.CONTRACTS, k]) 9 | const qualify = (k: string): string => encodeKeys(['bytes32', 'address'], [PROTOCOL.NS.CONTRACTS, k]) 10 | const qualifyMember = (k: string): string => encodeKeys(['bytes32', 'address'], [PROTOCOL.NS.MEMBERS, k])` 11 | 12 | const post = `export { 13 | encodeKey, 14 | encodeKeys, 15 | toBytes32, 16 | getCoverContractKey, 17 | qualify, 18 | qualifyMember, 19 | qualifyBytes32, 20 | {{scopes}} 21 | }` 22 | 23 | module.exports = { pre, post } 24 | -------------------------------------------------------------------------------- /util/extract/keys/template.js: -------------------------------------------------------------------------------- 1 | const tas = require('./template-as') 2 | const tjs = require('./template-js') 3 | const tts = require('./template-ts') 4 | 5 | const get = (type) => { 6 | if (type === 'ts') { 7 | return tts 8 | } 9 | 10 | if (type === 'as') { 11 | return tas 12 | } 13 | 14 | return tjs 15 | } 16 | 17 | module.exports = { get } 18 | -------------------------------------------------------------------------------- /util/file-cache/contract.js: -------------------------------------------------------------------------------- 1 | const { getData } = require('./data') 2 | 3 | const getContract = async (file, id, contractName) => { 4 | const data = await getData(file) 5 | const { deployments } = data[id] 6 | 7 | for (const prop in deployments) { 8 | const contract = deployments[prop] 9 | 10 | const found = contract.contractName === contractName 11 | 12 | if (found) { 13 | return contract.address 14 | } 15 | } 16 | 17 | return null 18 | } 19 | 20 | module.exports = { getContract } 21 | -------------------------------------------------------------------------------- /util/file-cache/data.js: -------------------------------------------------------------------------------- 1 | const io = require('../io') 2 | 3 | const getData = async (file) => { 4 | const contents = await io.readFile(file) 5 | return JSON.parse(contents) 6 | } 7 | 8 | module.exports = { getData } 9 | -------------------------------------------------------------------------------- /util/file-cache/index.js: -------------------------------------------------------------------------------- 1 | const hre = require('hardhat') 2 | const path = require('path') 3 | const io = require('../io') 4 | const { getData } = require('./data') 5 | const { getContract } = require('./contract') 6 | const { getContracts } = require('./addresses') 7 | const { addUpgrade } = require('./upgrade') 8 | 9 | const from = async (id) => { 10 | const network = hre.network.name 11 | 12 | const file = path.join(process.cwd(), '.deployments', `${network}.json`) 13 | 14 | await io.ensureFile(file, '{}') 15 | 16 | return { 17 | file, 18 | getData: () => getData(file), 19 | addUpgrade: (upgrade) => addUpgrade(file, id, upgrade), 20 | getContract: (contractName) => getContract(file, id, contractName), 21 | getContracts: () => getContracts(file, id), 22 | id 23 | } 24 | } 25 | 26 | module.exports = { from } 27 | -------------------------------------------------------------------------------- /util/file-cache/upgrade.js: -------------------------------------------------------------------------------- 1 | const io = require('../io') 2 | const { getData } = require('./data') 3 | 4 | const addUpgrade = async (file, id, upgrade) => { 5 | const data = await getData(file) 6 | 7 | if (!data[id].upgrades) { 8 | data[id].upgrades = [] 9 | } 10 | 11 | data[id].upgrades.push(upgrade) 12 | 13 | await io.writeFile(file, JSON.stringify(data, null, 2)) 14 | } 15 | 16 | module.exports = { addUpgrade } 17 | -------------------------------------------------------------------------------- /util/index.js: -------------------------------------------------------------------------------- 1 | const cxToken = require('./cxToken') 2 | const helper = require('./helper') 3 | const deployer = require('./deployer') 4 | const key = require('./key') 5 | const storeUtil = require('./store-util') 6 | const ipfs = require('./ipfs') 7 | const io = require('./io') 8 | const fileCache = require('./file-cache') 9 | const intermediate = require('./intermediate') 10 | const sample = require('./sample') 11 | const typedefs = require('./typedefs') 12 | 13 | module.exports = { cxToken, helper, deployer, key, storeUtil, ipfs, sample, io, intermediate, fileCache, typedefs } 14 | -------------------------------------------------------------------------------- /util/intermediate.js: -------------------------------------------------------------------------------- 1 | const io = require('./io') 2 | 3 | module.exports = async (cache, contract, action, ...args) => { 4 | const key = [action, contract.address, contract.interface.encodeFunctionData(action, [...args])].join('.') 5 | 6 | const persisted = await io.fetchValue(cache, key) 7 | 8 | if (persisted) { 9 | global.log && console.log('[skip] %s(%s) to %s was found on the tx %s', action, JSON.stringify(args), contract.address, persisted) 10 | return 11 | } 12 | 13 | global.log && console.log('[tx] %s(%s) to %s', action, JSON.stringify(args), contract.address) 14 | 15 | const tx = await contract[action](...args) 16 | await tx.wait() 17 | await io.cacheValue(cache, key, tx.hash) 18 | } 19 | -------------------------------------------------------------------------------- /util/ipfs.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios') 2 | 3 | const write = async (contents) => { 4 | const { data } = await axios.put(process.env.NPM_IPFS_API_URL, contents) 5 | const { hash } = data 6 | 7 | return hash 8 | } 9 | 10 | module.exports = { write } 11 | -------------------------------------------------------------------------------- /util/network.js: -------------------------------------------------------------------------------- 1 | const hre = require('hardhat') 2 | const network = require('../scripts/config/network') 3 | 4 | const getNetworkInfo = async () => { 5 | return network[hre.network.config.chainId] 6 | } 7 | 8 | module.exports = { getNetworkInfo } 9 | -------------------------------------------------------------------------------- /util/store-util.js: -------------------------------------------------------------------------------- 1 | const key = require('./key') 2 | 3 | const getStoreAddressCustom = async (store, namespace, coverKey) => store.getAddress(key.getCoverContractKey(namespace, coverKey)) 4 | const getVaultAddress = async (store, coverKey) => store.getAddress(key.encodeKeys(['bytes32', 'bytes32', 'bytes32'], [key.PROTOCOL.NS.CONTRACTS, key.PROTOCOL.CNS.COVER_VAULT, coverKey])) 5 | 6 | module.exports = { 7 | getStoreAddressCustom, 8 | getVaultAddress 9 | } 10 | -------------------------------------------------------------------------------- /util/wallet.js: -------------------------------------------------------------------------------- 1 | const ethers = require('ethers') 2 | 3 | const toWalletAddress = (privateKey) => { 4 | const wallet = new ethers.Wallet(privateKey) 5 | return wallet.address 6 | } 7 | 8 | module.exports = { 9 | toWalletAddress 10 | } 11 | --------------------------------------------------------------------------------