Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Fixes Issue #155 - Variable outside store #168

Merged
merged 4 commits into from
Sep 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 24 additions & 54 deletions contracts/core/policy/Policy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,12 @@ contract Policy is IPolicy, Recoverable {
using RoutineInvokerLibV1 for IStore;
using StrategyLibV1 for IStore;

uint256 public lastPolicyId;

constructor(IStore store, uint256 _lastPolicyId) Recoverable(store) {
lastPolicyId = _lastPolicyId;
}
/**
* @dev Constructs this contract
*
* @param store Provide an implementation of IStore
*/
constructor(IStore store) Recoverable(store) {} // solhint-disable-line

/**
* @dev Purchase cover for the specified amount. <br /> <br />
Expand Down Expand Up @@ -84,40 +85,28 @@ contract Policy is IPolicy, Recoverable {
*
* @custom:suppress-acl This is a publicly accessible feature
*
*
* @param onBehalfOf Enter an address you would like to send the claim tokens (cxTokens) to.
* @param coverKey Enter the cover key you wish to purchase the policy for
* @param coverDuration Enter the number of months to cover. Accepted values: 1-3.
* @param amountToCover Enter the amount of the stablecoin to cover.
*/
function purchaseCover(
address onBehalfOf,
bytes32 coverKey,
bytes32 productKey,
uint256 coverDuration,
uint256 amountToCover,
bytes32 referralCode
) external override nonReentrant returns (address, uint256) {
function purchaseCover(PurchaseCoverArgs calldata args) external override nonReentrant returns (address, uint256) {
// @todo: When the POT system is replaced with NPM tokens in the future, upgrade this contract
// and uncomment the following line
// require(IERC20(s.getNpmTokenAddress()).balanceOf(msg.sender) >= 1 ether, "No NPM balance");
require(coverKey > 0, "Invalid cover key");
require(onBehalfOf != address(0), "Invalid `onBehalfOf`");
require(amountToCover > 0, "Enter an amount");
require(coverDuration > 0 && coverDuration <= ProtoUtilV1.MAX_POLICY_DURATION, "Invalid cover duration");
require(args.coverKey > 0, "Invalid cover key");
require(args.onBehalfOf != address(0), "Invalid `onBehalfOf`");
require(args.amountToCover > 0, "Enter an amount");
require(args.coverDuration > 0 && args.coverDuration <= ProtoUtilV1.MAX_POLICY_DURATION, "Invalid cover duration");

s.mustNotBePaused();
s.mustNotExceedProposalThreshold(amountToCover);
s.mustBeSupportedProductOrEmpty(coverKey, productKey);
s.mustHaveNormalProductStatus(coverKey, productKey);
s.mustNotHavePolicyDisabled(coverKey, productKey);
s.senderMustBeWhitelistedIfRequired(coverKey, productKey, onBehalfOf);
s.mustNotExceedProposalThreshold(args.amountToCover);
s.mustBeSupportedProductOrEmpty(args.coverKey, args.productKey);
s.mustHaveNormalProductStatus(args.coverKey, args.productKey);
s.mustNotHavePolicyDisabled(args.coverKey, args.productKey);
s.senderMustBeWhitelistedIfRequired(args.coverKey, args.productKey, args.onBehalfOf);

lastPolicyId += 1;
uint256 lastPolicyId = s.incrementPolicyId();

(ICxToken cxToken, uint256 fee, uint256 platformFee) = s.purchaseCoverInternal(onBehalfOf, coverKey, productKey, coverDuration, amountToCover);
(ICxToken cxToken, uint256 fee, uint256 platformFee) = s.purchaseCoverInternal(args);

emit CoverPurchased(coverKey, productKey, onBehalfOf, address(cxToken), fee, platformFee, amountToCover, cxToken.expiresOn(), referralCode, lastPolicyId);
emit CoverPurchased(args, address(cxToken), fee, platformFee, cxToken.expiresOn(), lastPolicyId);
return (address(cxToken), lastPolicyId);
}

Expand Down Expand Up @@ -205,37 +194,18 @@ contract Policy is IPolicy, Recoverable {
bytes32 productKey,
uint256 coverDuration,
uint256 amountToCover
)
external
view
override
returns (
uint256 fee,
uint256 utilizationRatio,
uint256 totalAvailableLiquidity,
uint256 floor,
uint256 ceiling,
uint256 rate
)
{
return s.calculatePolicyFeeInternal(coverKey, productKey, coverDuration, amountToCover);
) external view override returns (CoverFeeInfoType memory) {
PolicyHelperV1.CalculatePolicyFeeArgs memory args = PolicyHelperV1.CalculatePolicyFeeArgs({coverKey: coverKey, productKey: productKey, coverDuration: coverDuration, amountToCover: amountToCover});
return s.calculatePolicyFeeInternal(args);
}

/**
* @dev Returns the values of the given cover key
* @dev Returns the pool summary of the given cover key
*
* Warning: this function does not validate the cover key supplied.
*
* @param _values[0] The total amount in the cover pool
* @param _values[1] The total commitment amount
* @param _values[2] Reassurance amount
* @param _values[3] Reassurance pool weight
* @param _values[4] Count of products under this cover
* @param _values[5] Leverage
* @param _values[6] Cover product efficiency weight
*
*/
function getCoverPoolSummary(bytes32 coverKey, bytes32 productKey) external view override returns (uint256[] memory _values) {
function getCoverPoolSummary(bytes32 coverKey, bytes32 productKey) external view override returns (IPolicy.CoverPoolSummaryType memory summary) {
return s.getCoverPoolSummaryInternal(coverKey, productKey);
}

Expand Down
29 changes: 11 additions & 18 deletions contracts/examples/NpmDistributor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ contract NpmDistributor is ReentrancyGuard {
IPolicy policy = getPolicyContract();
require(address(policy) != address(0), "Fatal: Policy missing");

(premium, , , , , ) = policy.getCoverFeeInfo(coverKey, productKey, duration, protection);
IPolicy.CoverFeeInfoType memory coverFeeInfo = policy.getCoverFeeInfo(coverKey, productKey, duration, protection);
premium = coverFeeInfo.fee;

// Add your fee in addition to the protocol premium
fee = (premium * feePercentage) / MULTIPLIER;
Expand All @@ -142,21 +143,11 @@ contract NpmDistributor is ReentrancyGuard {
* @custom:suppress-acl This is a publicly accessible feature
* @custom:suppress-pausable
*
* @param coverKey Enter the cover key for which you want to buy policy.
* @param duration Enter the period of the protection in months.
* @param protection Enter the stablecoin dollar amount you want to protect.
* @param referralCode Provide a referral code if applicable.
*/
function purchasePolicy(
bytes32 coverKey,
bytes32 productKey,
uint256 duration,
uint256 protection,
bytes32 referralCode
) external nonReentrant {
require(coverKey > 0, "Invalid key");
require(duration > 0 && duration < 4, "Invalid duration");
require(protection > 0, "Invalid protection amount");
function purchasePolicy(IPolicy.PurchaseCoverArgs memory args) external nonReentrant {
require(args.coverKey > 0, "Invalid key");
require(args.coverDuration > 0 && args.coverDuration < 4, "Invalid duration");
require(args.amountToCover > 0, "Invalid protection amount");

IPolicy policy = getPolicyContract();
require(address(policy) != address(0), "Fatal: Policy missing");
Expand All @@ -165,21 +156,23 @@ contract NpmDistributor is ReentrancyGuard {
require(address(dai) != address(0), "Fatal: DAI missing");

// Get fee info
(uint256 premium, uint256 fee) = getPremium(coverKey, productKey, duration, protection);
(uint256 premium, uint256 fee) = getPremium(args.coverKey, args.productKey, args.coverDuration, args.amountToCover);

// Transfer DAI to this contract
dai.safeTransferFrom(msg.sender, address(this), premium + fee);

// Approve protocol to pull the protocol fee
dai.safeIncreaseAllowance(address(policy), premium);

args.onBehalfOf = msg.sender;

// Purchase protection for this user
(address cxTokenAt, ) = policy.purchaseCover(msg.sender, coverKey, productKey, duration, protection, referralCode);
(address cxTokenAt, ) = policy.purchaseCover(args);

// Send your fee (+ any remaining DAI balance) to your treasury address
dai.safeTransfer(treasury, dai.balanceOf(address(this)));

emit PolicySold(coverKey, productKey, cxTokenAt, msg.sender, duration, protection, referralCode, fee, premium);
emit PolicySold(args.coverKey, args.productKey, cxTokenAt, msg.sender, args.coverDuration, args.amountToCover, args.referralCode, fee, premium);
}

function addLiquidity(
Expand Down
78 changes: 34 additions & 44 deletions contracts/interfaces/IPolicy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,45 @@ pragma solidity ^0.8.0;
import "./IMember.sol";

interface IPolicy is IMember {
event CoverPurchased(
bytes32 coverKey,
bytes32 productKey,
address onBehalfOf,
address indexed cxToken,
uint256 fee,
uint256 platformFee,
uint256 amountToCover,
uint256 expiresOn,
bytes32 indexed referralCode,
uint256 policyId
);
struct PurchaseCoverArgs {
address onBehalfOf;
bytes32 coverKey;
bytes32 productKey;
uint256 coverDuration;
uint256 amountToCover;
bytes32 referralCode;
}

struct CoverFeeInfoType {
uint256 fee;
uint256 utilizationRatio;
uint256 totalAvailableLiquidity;
uint256 floor;
uint256 ceiling;
uint256 rate;
}

struct CoverPoolSummaryType {
uint256 totalAmountInPool;
uint256 totalCommitment;
uint256 reassuranceAmount;
uint256 reassurancePoolWeight;
uint256 productCount;
uint256 leverage;
uint256 productCapitalEfficiency;
}

event CoverPurchased(PurchaseCoverArgs args, address indexed cxToken, uint256 fee, uint256 platformFee, uint256 expiresOn, uint256 policyId);

/**
* @dev Purchase cover for the specified amount. <br /> <br />
* When you purchase covers, you receive equal amount of cxTokens back.
* You need the cxTokens to claim the cover when resolution occurs.
* Each unit of cxTokens are fully redeemable at 1:1 ratio to the given
* stablecoins (like wxDai, DAI, USDC, or BUSD) based on the chain.
* @param onBehalfOf Enter an address you would like to send the claim tokens (cxTokens) to.
* @param coverKey Enter the cover key you wish to purchase the policy for
* @param coverDuration Enter the number of months to cover. Accepted values: 1-3.
* @param amountToCover Enter the amount of the stablecoin to cover.
*/
function purchaseCover(
address onBehalfOf,
bytes32 coverKey,
bytes32 productKey,
uint256 coverDuration,
uint256 amountToCover,
bytes32 referralCode
) external returns (address, uint256);

function purchaseCover(PurchaseCoverArgs calldata args) external returns (address, uint256);

/**
* @dev Gets the cover fee info for the given cover key, duration, and amount
Expand All @@ -49,29 +56,12 @@ interface IPolicy is IMember {
bytes32 productKey,
uint256 coverDuration,
uint256 amountToCover
)
external
view
returns (
uint256 fee,
uint256 utilizationRatio,
uint256 totalAvailableLiquidity,
uint256 floor,
uint256 ceiling,
uint256 rate
);
) external view returns (CoverFeeInfoType memory);

/**
* @dev Returns the values of the given cover key
* @param _values[0] The total amount in the cover pool
* @param _values[1] The total commitment amount
* @param _values[2] Reassurance amount
* @param _values[3] Reassurance pool weight
* @param _values[4] Count of products under this cover
* @param _values[5] Leverage
* @param _values[6] Cover product efficiency weight
* @dev Returns pool summary of the given cover key
*/
function getCoverPoolSummary(bytes32 coverKey, bytes32 productKey) external view returns (uint256[] memory _values);
function getCoverPoolSummary(bytes32 coverKey, bytes32 productKey) external view returns (CoverPoolSummaryType memory summary);

function getCxToken(
bytes32 coverKey,
Expand Down
25 changes: 8 additions & 17 deletions contracts/libraries/CoverUtilV1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -129,30 +129,21 @@ library CoverUtilV1 {
*
* Warning: this function does not validate the cover key supplied.
*
* @param _values[0] The total amount in the cover pool
* @param _values[1] The total commitment amount
* @param _values[2] Reassurance amount
* @param _values[3] Reassurance pool weight
* @param _values[4] Count of products under this cover
* @param _values[5] Leverage
* @param _values[6] Cover product efficiency weight
*/
function getCoverPoolSummaryInternal(
IStore s,
bytes32 coverKey,
bytes32 productKey
) external view returns (uint256[] memory _values) {
_values = new uint256[](8);

) external view returns (IPolicy.CoverPoolSummaryType memory summary) {
uint256 precision = s.getStablecoinPrecision();

_values[0] = s.getStablecoinOwnedByVaultInternal(coverKey); // precision: stablecoin
_values[1] = getActiveLiquidityUnderProtection(s, coverKey, productKey, precision); // <-- adjusted precision
_values[2] = getReassuranceAmountInternal(s, coverKey); // precision: stablecoin
_values[3] = getReassuranceWeightInternal(s, coverKey);
_values[4] = s.countBytes32ArrayByKeys(ProtoUtilV1.NS_COVER_PRODUCT, coverKey);
_values[5] = s.getUintByKeys(ProtoUtilV1.NS_COVER_LEVERAGE_FACTOR, coverKey);
_values[6] = s.getUintByKeys(ProtoUtilV1.NS_COVER_PRODUCT_EFFICIENCY, coverKey, productKey);
summary.totalAmountInPool = s.getStablecoinOwnedByVaultInternal(coverKey); // precision: stablecoin
summary.totalCommitment = getActiveLiquidityUnderProtection(s, coverKey, productKey, precision); // <-- adjusted precision
summary.reassuranceAmount = getReassuranceAmountInternal(s, coverKey); // precision: stablecoin
summary.reassurancePoolWeight = getReassuranceWeightInternal(s, coverKey);
summary.productCount = s.countBytes32ArrayByKeys(ProtoUtilV1.NS_COVER_PRODUCT, coverKey);
summary.leverage = s.getUintByKeys(ProtoUtilV1.NS_COVER_LEVERAGE_FACTOR, coverKey);
summary.productCapitalEfficiency = s.getUintByKeys(ProtoUtilV1.NS_COVER_PRODUCT_EFFICIENCY, coverKey, productKey);
}

/**
Expand Down
Loading