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

39 audit controllersol needs to implement tvl cant be zero #64

119 changes: 73 additions & 46 deletions src/Controller.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ contract Controller {
error EpochExpired();
error OraclePriceZero();
error RoundIDOutdated();
error TimestampZero();
error EpochNotExist();
error EpochNotExpired();

Expand Down Expand Up @@ -62,43 +61,6 @@ contract Controller {
}
/* solhint-enable var-name-mixedcase */

/*//////////////////////////////////////////////////////////////
MODIFIERS
//////////////////////////////////////////////////////////////*/

/** @notice Modifier to ensure market exists, current market epoch time and price are valid
* @param marketIndex Target market index
* @param epochEnd End of epoch set for market
*/
modifier isDisaster(uint256 marketIndex, uint256 epochEnd) {
address[] memory vaultsAddress = vaultFactory.getVaults(marketIndex);
if(
vaultsAddress.length != VAULTS_LENGTH
)
revert MarketDoesNotExist(marketIndex);

address vaultAddress = vaultsAddress[0];
Vault vault = Vault(vaultAddress);

if(vault.idExists(epochEnd) == false)
revert EpochNotExist();

if(
vault.strikePrice() < getLatestPrice(vault.tokenInsured())
)
revert PriceNotAtStrikePrice(getLatestPrice(vault.tokenInsured()));

if(
vault.idEpochBegin(epochEnd) > block.timestamp)
revert EpochNotStarted();

if(
block.timestamp > epochEnd
)
revert EpochExpired();
_;
}

/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
Expand Down Expand Up @@ -131,12 +93,33 @@ contract Controller {
*/
function triggerDepeg(uint256 marketIndex, uint256 epochEnd)
public
isDisaster(marketIndex, epochEnd)
{
address[] memory vaultsAddress = vaultFactory.getVaults(marketIndex);
Vault insrVault = Vault(vaultsAddress[0]);
Vault riskVault = Vault(vaultsAddress[1]);

if(
vaultsAddress[0] == address(0) || vaultsAddress[1] == address(0)
)
revert MarketDoesNotExist(marketIndex);

if(insrVault.idExists(epochEnd) == false)
revert EpochNotExist();

if(
insrVault.strikePrice() < getLatestPrice(insrVault.tokenInsured())
)
revert PriceNotAtStrikePrice(getLatestPrice(insrVault.tokenInsured()));

if(
insrVault.idEpochBegin(epochEnd) > block.timestamp)
revert EpochNotStarted();

if(
block.timestamp > epochEnd
)
revert EpochExpired();

//require this function cannot be called twice in the same epoch for the same vault
if(insrVault.idFinalTVL(epochEnd) != 0)
revert NotZeroTVL();
Expand Down Expand Up @@ -180,9 +163,6 @@ contract Controller {
* @param epochEnd End of epoch set for market
*/
function triggerEndEpoch(uint256 marketIndex, uint256 epochEnd) public {
if(
vaultFactory.getVaults(marketIndex).length != VAULTS_LENGTH)
revert MarketDoesNotExist(marketIndex);
if(
block.timestamp <= epochEnd)
revert EpochNotExpired();
Expand All @@ -191,6 +171,11 @@ contract Controller {

Vault insrVault = Vault(vaultsAddress[0]);
Vault riskVault = Vault(vaultsAddress[1]);

if(
vaultsAddress[0] == address(0) || vaultsAddress[1] == address(0)
)
revert MarketDoesNotExist(marketIndex);

if(insrVault.idExists(epochEnd) == false || riskVault.idExists(epochEnd) == false)
revert EpochNotExist();
Expand Down Expand Up @@ -230,6 +215,51 @@ contract Controller {
getLatestPrice(insrVault.tokenInsured())
);
}
/** @notice Trigger epoch invalid when one vault has 0 TVL
* @param marketIndex Target market index
* @param epochEnd End of epoch set for market
*/
function triggerNullEpoch(uint256 marketIndex, uint256 epochEnd) public {
if(
vaultFactory.getVaults(marketIndex).length != VAULTS_LENGTH)
revert MarketDoesNotExist(marketIndex);
if(
block.timestamp >= epochEnd)
revert EpochExpired();

address[] memory vaultsAddress = vaultFactory.getVaults(marketIndex);

Vault insrVault = Vault(vaultsAddress[0]);
Vault riskVault = Vault(vaultsAddress[1]);

if(block.timestamp <= insrVault.idEpochBegin(epochEnd))
revert EpochNotStarted();

if(insrVault.idExists(epochEnd) == false || riskVault.idExists(epochEnd) == false)
revert EpochNotExist();

//require this function cannot be called twice in the same epoch for the same vault
if(insrVault.idFinalTVL(epochEnd) != 0)
revert NotZeroTVL();
if(riskVault.idFinalTVL(epochEnd) != 0)
revert NotZeroTVL();

//set claim TVL to 0 if total assets are 0
if(insrVault.totalAssets(epochEnd) == 0){
insrVault.endEpoch(epochEnd);
riskVault.endEpoch(epochEnd);

insrVault.setClaimTVL(epochEnd, 0);
riskVault.setClaimTVL(epochEnd, riskVault.idFinalTVL(epochEnd));
}
if(riskVault.totalAssets(epochEnd) == 0){
insrVault.endEpoch(epochEnd);
riskVault.endEpoch(epochEnd);

insrVault.setClaimTVL(epochEnd, insrVault.idFinalTVL(epochEnd) );
riskVault.setClaimTVL(epochEnd, 0);
}
}

/*//////////////////////////////////////////////////////////////
GETTERS
Expand Down Expand Up @@ -290,10 +320,7 @@ contract Controller {

if(answeredInRound < roundID)
revert RoundIDOutdated();

if(timeStamp == 0)
revert TimestampZero();


return price;
}

Expand Down
4 changes: 3 additions & 1 deletion src/SemiFungibleVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,9 @@ abstract contract SemiFungibleVault is ERC1155Supply {
/**@notice Returns total assets for token
* @param _id uint256 token id of token
*/
function totalAssets(uint256 _id) public view virtual returns (uint256);
function totalAssets(uint256 _id) public view virtual returns (uint256){
return totalSupply(_id);
}

/**
@notice Shows assets conversion output from withdrawing assets
Expand Down
24 changes: 17 additions & 7 deletions src/Vault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ contract Vault is SemiFungibleVault, ReentrancyGuard {
// @audit id can be uint32
mapping(uint256 => bool) public idExists;
mapping(uint256 => uint256) public epochFee;
mapping(uint256 => bool) public epochNull;

/*//////////////////////////////////////////////////////////////
MODIFIERS
Expand Down Expand Up @@ -188,7 +189,7 @@ contract Vault is SemiFungibleVault, ReentrancyGuard {
}

/**
@notice Withdraw entitled deposited assets, checking if a depeg event //TODO add GOV token rewards
@notice Withdraw entitled deposited assets, checking if a depeg event
@param id uint256 in UNIX timestamp, representing the end date of the epoch. Example: Epoch ends in 30th June 2022 at 00h 00min 00sec: 1654038000;
@param assets uint256 of how many assets you want to withdraw, this value will be used to calculate how many assets you are entitle to according to the events;
@param receiver Address of the receiver of the assets provided by this function, that represent the ownership of the transfered asset;
Expand All @@ -212,14 +213,19 @@ contract Vault is SemiFungibleVault, ReentrancyGuard {
isApprovedForAll(owner, msg.sender) == false)
revert OwnerDidNotAuthorize(msg.sender, owner);

uint256 entitledShares = previewWithdraw(id, assets);
uint256 entitledShares;
_burn(owner, id, assets);

//Taking fee from the amount
uint256 feeValue = calculateWithdrawalFeeValue(entitledShares, id);
entitledShares = entitledShares - feeValue;
asset.transfer(treasury, feeValue);

if(epochNull[id] == false) {
//Taking fee from the amount
entitledShares = previewWithdraw(id, assets);
uint256 feeValue = calculateWithdrawalFeeValue(entitledShares, id);
entitledShares = entitledShares - feeValue;
asset.transfer(treasury, feeValue);
}
else{
entitledShares = assets;
}
emit Withdraw(msg.sender, receiver, owner, id, assets, entitledShares);
asset.transfer(receiver, entitledShares);

Expand Down Expand Up @@ -357,6 +363,10 @@ contract Vault is SemiFungibleVault, ReentrancyGuard {
asset.transfer(_counterparty, idFinalTVL[id]);
}

function setEpochNull(uint256 id) public onlyController {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MiguelBits this is never set in triggerNullEpoch.

epochNull[id] = true;
}

/*///////////////////////////////////////////////////////////////
INTERNAL HOOKS LOGIC
//////////////////////////////////////////////////////////////*/
Expand Down