Skip to content

Commit

Permalink
chore: Fix review (#907)
Browse files Browse the repository at this point in the history
* fix: deprecate incentive on dollar token

* chore: update

* chore: update

* Fix set role admin (#880)

* feat: add setRoleAdmin to AccessControlFacet

The setRoleAdmin can be only accessed by the admin.

* feat: add setRoleAdmin to AccessControl interface

* test: add testSetRoleAdmin_ShouldSetAdminRoleForGivenRole test

* feat: update access control for setRoleAdmin

* test: fix ShouldSetAdminRoleForGivenRole and add test for revert

* feat: add getRedeemCollateralBalance() method

* fix: remove balanced reserves check (#883)

* fix: limit AMO minter borrow amount (#882)

* fix: limit AMO minter borrow amount

* test: assert free collateral amount

* fix: do not allow to mint dollar with zero collateral

Resolves: sherlock-audit/2023-12-ubiquity-judging#207

* test: add testMintDollar_ShouldRevert_IfZeroCollateralAvailable

* test: update comment in zero collateral mint test

* Update block count in a week (#891)

* feat: implement BlocksInWeek script task

The BlocksInWeek task provides a very close approximate of number of
blocks mined during one week.

Supported networks: mainnnet, sepolia.

Example usage:

npx tsx scripts/task/task.ts BlocksInWeek --network=mainnet
npx tsx scripts/task/task.ts BlocksInWeek --network=sepolia

Resolves: sherlock-audit/2023-12-ubiquity-judging#230

* feat: update weekly block count to 49930

Set weekly block count to 49930 as measured in February 2024

npx tsx scripts/task/task.ts BlocksInWeek --network=mainnet
...
Calculating number of blocks in the last week...
Recent average block time: 12 seconds
Estimated blocks in a week best case 50400
Produced 49930 blocks, 470 worst than the best case

Resolves: sherlock-audit/2023-12-ubiquity-judging#230

* feat: rename task function to funcBlocksInAWeek

As proposed during pull request review.

* feat: use CurveStableSwapMetaNG contract

* refactor: update migrations to use latest metapool

* refactor: deprecate IMetaPool

* refactor: remove MockTWAPOracleDollar3pool

* refactor: remove TWAPOracleDollar3poolFacet

* refactor: remove MockMetaPool

* refactor: remove LibTWAPOracle

* fix(dapp): remove TWAP oracle ABI import

* refactor(frontend): use ICurveStableSwapMetaNG for TWAP

* feat: check if collateral is enabled in collectRedemption (#894)

Also add a unit test that verifies the check.

Resolves: sherlock-audit/2023-12-ubiquity-judging#29

---------

Co-authored-by: molecula451 <[email protected]>
Co-authored-by: korrrba <[email protected]>
Co-authored-by: Korrrba <[email protected]>
  • Loading branch information
4 people committed Mar 1, 2024
1 parent 9f88242 commit acc5800
Show file tree
Hide file tree
Showing 52 changed files with 663 additions and 1,003 deletions.
1 change: 1 addition & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@
"rpcutil",
"rustup",
"Sablier",
"sepolia",
"setu",
"Shouldset",
"Sighash",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,18 @@ import {DiamondCutFacet} from "../../src/dollar/facets/DiamondCutFacet.sol";
import {DiamondLoupeFacet} from "../../src/dollar/facets/DiamondLoupeFacet.sol";
import {ManagerFacet} from "../../src/dollar/facets/ManagerFacet.sol";
import {OwnershipFacet} from "../../src/dollar/facets/OwnershipFacet.sol";
import {TWAPOracleDollar3poolFacet} from "../../src/dollar/facets/TWAPOracleDollar3poolFacet.sol";
import {UbiquityPoolFacet} from "../../src/dollar/facets/UbiquityPoolFacet.sol";
import {ICurveStableSwapMetaNG} from "../../src/dollar/interfaces/ICurveStableSwapMetaNG.sol";
import {IDiamondCut} from "../../src/dollar/interfaces/IDiamondCut.sol";
import {IDiamondLoupe} from "../../src/dollar/interfaces/IDiamondLoupe.sol";
import {IERC173} from "../../src/dollar/interfaces/IERC173.sol";
import {IMetaPool} from "../../src/dollar/interfaces/IMetaPool.sol";
import {DEFAULT_ADMIN_ROLE, DOLLAR_TOKEN_MINTER_ROLE, DOLLAR_TOKEN_BURNER_ROLE, PAUSER_ROLE} from "../../src/dollar/libraries/Constants.sol";
import {LibAccessControl} from "../../src/dollar/libraries/LibAccessControl.sol";
import {AppStorage, LibAppStorage, Modifiers} from "../../src/dollar/libraries/LibAppStorage.sol";
import {LibDiamond} from "../../src/dollar/libraries/LibDiamond.sol";
import {MockChainLinkFeed} from "../../src/dollar/mocks/MockChainLinkFeed.sol";
import {MockCurveStableSwapMetaNG} from "../../src/dollar/mocks/MockCurveStableSwapMetaNG.sol";
import {MockERC20} from "../../src/dollar/mocks/MockERC20.sol";
import {MockMetaPool} from "../../src/dollar/mocks/MockMetaPool.sol";
import {DiamondTestHelper} from "../../test/helpers/DiamondTestHelper.sol";

/**
Expand Down Expand Up @@ -117,21 +116,19 @@ contract Deploy001_Diamond_Dollar is Script, DiamondTestHelper {
DiamondLoupeFacet diamondLoupeFacetImplementation;
ManagerFacet managerFacetImplementation;
OwnershipFacet ownershipFacetImplementation;
TWAPOracleDollar3poolFacet twapOracleDollar3PoolFacetImplementation;
UbiquityPoolFacet ubiquityPoolFacetImplementation;

// oracle related contracts
AggregatorV3Interface chainLinkPriceFeedLusd; // chainlink LUSD/USD price feed
IERC20 curveTriPoolLpToken; // Curve's 3CRV-LP token
IMetaPool curveDollarMetaPool; // Curve's Dollar-3CRVLP metapool
ICurveStableSwapMetaNG curveDollarMetaPool; // Curve's Dollar-3CRVLP metapool

// selectors for all of the facets
bytes4[] selectorsOfAccessControlFacet;
bytes4[] selectorsOfDiamondCutFacet;
bytes4[] selectorsOfDiamondLoupeFacet;
bytes4[] selectorsOfManagerFacet;
bytes4[] selectorsOfOwnershipFacet;
bytes4[] selectorsOfTWAPOracleDollar3poolFacet;
bytes4[] selectorsOfUbiquityPoolFacet;

function run() public virtual {
Expand Down Expand Up @@ -166,9 +163,6 @@ contract Deploy001_Diamond_Dollar is Script, DiamondTestHelper {
selectorsOfOwnershipFacet = getSelectorsFromAbi(
"/out/OwnershipFacet.sol/OwnershipFacet.json"
);
selectorsOfTWAPOracleDollar3poolFacet = getSelectorsFromAbi(
"/out/TWAPOracleDollar3poolFacet.sol/TWAPOracleDollar3poolFacet.json"
);
selectorsOfUbiquityPoolFacet = getSelectorsFromAbi(
"/out/UbiquityPoolFacet.sol/UbiquityPoolFacet.json"
);
Expand All @@ -179,7 +173,6 @@ contract Deploy001_Diamond_Dollar is Script, DiamondTestHelper {
diamondLoupeFacetImplementation = new DiamondLoupeFacet();
managerFacetImplementation = new ManagerFacet();
ownershipFacetImplementation = new OwnershipFacet();
twapOracleDollar3PoolFacetImplementation = new TWAPOracleDollar3poolFacet();
ubiquityPoolFacetImplementation = new UbiquityPoolFacet();

// prepare DiamondInit args
Expand All @@ -198,7 +191,7 @@ contract Deploy001_Diamond_Dollar is Script, DiamondTestHelper {
});

// prepare facet cuts
FacetCut[] memory cuts = new FacetCut[](7);
FacetCut[] memory cuts = new FacetCut[](6);
cuts[0] = (
FacetCut({
facetAddress: address(accessControlFacetImplementation),
Expand Down Expand Up @@ -235,13 +228,6 @@ contract Deploy001_Diamond_Dollar is Script, DiamondTestHelper {
})
);
cuts[5] = (
FacetCut({
facetAddress: address(twapOracleDollar3PoolFacetImplementation),
action: FacetCutAction.Add,
functionSelectors: selectorsOfTWAPOracleDollar3poolFacet
})
);
cuts[6] = (
FacetCut({
facetAddress: address(ubiquityPoolFacetImplementation),
action: FacetCutAction.Add,
Expand Down Expand Up @@ -438,7 +424,7 @@ contract Deploy001_Diamond_Dollar is Script, DiamondTestHelper {
);

// deploy mock Curve's Dollar-3CRVLP metapool
curveDollarMetaPool = new MockMetaPool(
curveDollarMetaPool = new MockCurveStableSwapMetaNG(
address(dollarToken),
address(curveTriPoolLpToken)
);
Expand All @@ -450,23 +436,15 @@ contract Deploy001_Diamond_Dollar is Script, DiamondTestHelper {
// Curve's Dollar-3CRVLP metapool setup
//========================================

// start sending owner transactions
vm.startBroadcast(ownerPrivateKey);

TWAPOracleDollar3poolFacet twapOracleDollar3PoolFacet = TWAPOracleDollar3poolFacet(
address(diamond)
);
// start sending admin transactions
vm.startBroadcast(adminPrivateKey);

// set Curve Dollar-3CRVLP pool in the diamond storage
twapOracleDollar3PoolFacet.setPool(
address(curveDollarMetaPool),
address(curveTriPoolLpToken)
);
ManagerFacet managerFacet = ManagerFacet(address(diamond));

// fetch latest Dollar price from Curve's Dollar-3CRVLP metapool
twapOracleDollar3PoolFacet.update();
// set curve's metapool in manager facet
managerFacet.setStableSwapMetaPoolAddress(address(curveDollarMetaPool));

// stop sending owner transactions
// stop sending admin transactions
vm.stopBroadcast();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ pragma solidity 0.8.19;
import {AggregatorV3Interface} from "@chainlink/interfaces/AggregatorV3Interface.sol";
import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol";
import {Deploy001_Diamond_Dollar as Deploy001_Diamond_Dollar_Development} from "../development/Deploy001_Diamond_Dollar.s.sol";
import {TWAPOracleDollar3poolFacet} from "../../src/dollar/facets/TWAPOracleDollar3poolFacet.sol";
import {ManagerFacet} from "../../src/dollar/facets/ManagerFacet.sol";
import {UbiquityPoolFacet} from "../../src/dollar/facets/UbiquityPoolFacet.sol";
import {IMetaPool} from "../../src/dollar/interfaces/IMetaPool.sol";
import {ICurveStableSwapMetaNG} from "../../src/dollar/interfaces/ICurveStableSwapMetaNG.sol";

/// @notice Migration contract
contract Deploy001_Diamond_Dollar is Deploy001_Diamond_Dollar_Development {
Expand Down Expand Up @@ -82,31 +82,22 @@ contract Deploy001_Diamond_Dollar is Deploy001_Diamond_Dollar_Development {
// Curve's Dollar-3CRVLP metapool setup
//========================================

// start sending owner transactions
vm.startBroadcast(ownerPrivateKey);
// start sending admin transactions
vm.startBroadcast(adminPrivateKey);

// init 3CRV token
curveTriPoolLpToken = IERC20(token3CrvAddress);

// init Dollar-3CRVLP Curve metapool
curveDollarMetaPool = IMetaPool(curveDollarMetapoolAddress);

/*
TODO: uncomment when we redeploy Curve's Dollar-3CRV metapool with the new Dollar token
TWAPOracleDollar3poolFacet twapOracleDollar3PoolFacet = TWAPOracleDollar3poolFacet(address(diamond));
// set Curve Dollar-3CRVLP pool in the diamond storage
twapOracleDollar3PoolFacet.setPool(
address(curveDollarMetaPool),
address(curveTriPoolLpToken)
curveDollarMetaPool = ICurveStableSwapMetaNG(
curveDollarMetapoolAddress
);

// fetch latest Dollar price from Curve's Dollar-3CRVLP metapool
twapOracleDollar3PoolFacet.update();
*/
// set curve's metapool in manager facet
ManagerFacet managerFacet = ManagerFacet(address(diamond));
managerFacet.setStableSwapMetaPoolAddress(address(curveDollarMetaPool));

// stop sending owner transactions
// stop sending admin transactions
vm.stopBroadcast();
}
}
1 change: 1 addition & 0 deletions packages/contracts/scripts/shared/constants/networks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export const Networks: Record<string, number> = {
mainnet: 1,
optimism: 10,
goerli: 5,
sepolia: 11155111,
};

export const FALLBACK_RPC = "https://eth.ubq.fi/v1/mainnet";
23 changes: 23 additions & 0 deletions packages/contracts/scripts/task/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Dollar task scripts

## BlocksInWeek

BlocksInWeek task provides a close approximate of number of blocks mined in one week.

Usage:

Ethereum mainnet:

```
npx tsx scripts/task/task.ts BlocksInWeek --network=mainnet
```

Sepolia:

Ethereum mainnet:

```
npx tsx scripts/task/task.ts BlocksInWeek --network=sepolia
```

Prerequisite: set ETHERSCAN_API_KEY in .env
51 changes: 51 additions & 0 deletions packages/contracts/scripts/task/dollar/blocks-in-week.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { OptionDefinition } from "command-line-args";

import { Networks, TaskFuncParam } from "../../shared";
import { EtherscanProvider } from "ethers";

export const optionDefinitions: OptionDefinition[] = [
{ name: "task", defaultOption: true },
{ name: "network", alias: "n", type: String },
];

const funcBlocksInAWeek = async (params: TaskFuncParam) => {
const { args, env } = params;
const { network } = args;

const chainId = Networks[network] ?? undefined;
if (!chainId) {
throw new Error(`Unsupported network: ${network} Please configure it out first`);
}

const provider = new EtherscanProvider(chainId, env.etherscanApiKey);

console.log(`Calculating number of blocks in the last week...`);
const secondsInAWeek = 604800; // 24 * 7 * 60 * 60 seconds is one week
const currentBlockNumber = await provider.getBlockNumber();
const currentBlockTimestamp = (await provider.getBlock(currentBlockNumber))?.timestamp;
const blockTimestampTwoBlocksAgo = (await provider.getBlock(currentBlockNumber - 2))?.timestamp;

if (currentBlockTimestamp && blockTimestampTwoBlocksAgo) {
const avgBlockTime = (currentBlockTimestamp - blockTimestampTwoBlocksAgo) / 2;
console.log(`Recent average block time: ${avgBlockTime} seconds`);

const oneWeekAgo = currentBlockTimestamp - secondsInAWeek;
const estimatedBlocksInAWeek = secondsInAWeek / avgBlockTime;
console.log(`Estimated blocks in a week best case ${estimatedBlocksInAWeek}`);

let estimatedBlockNumber = currentBlockNumber - estimatedBlocksInAWeek;
let estimatedBlockTimestamp = (await provider.getBlock(estimatedBlockNumber))?.timestamp;

if (estimatedBlockTimestamp) {
let deltaBlockTime = oneWeekAgo - estimatedBlockTimestamp;
estimatedBlockNumber += Math.trunc(deltaBlockTime / avgBlockTime);
estimatedBlockTimestamp = (await provider.getBlock(estimatedBlockNumber))?.timestamp || estimatedBlockTimestamp;
deltaBlockTime -= estimatedBlockTimestamp - oneWeekAgo;

console.log(`Produced ${estimatedBlocksInAWeek - deltaBlockTime / avgBlockTime} blocks, ${deltaBlockTime / avgBlockTime} worst than the best case`);
}
}

return "succeeded";
};
export default funcBlocksInAWeek;
7 changes: 6 additions & 1 deletion packages/contracts/scripts/task/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@ import { OptionDefinition } from "command-line-args";

import { TaskFuncCallBack } from "../shared";

import PriceResetHandler, { optionDefinitions as priceResetOptions } from "./dollar/priceReset";
import PriceResetHandler, { optionDefinitions, optionDefinitions as priceResetOptions } from "./dollar/price-reset";
import BlocksInWeekHandler from "./dollar/blocks-in-week";

export const TASK_FUNCS: Record<string, { handler: TaskFuncCallBack; options: OptionDefinition[] }> = {
PriceReset: {
handler: PriceResetHandler,
options: priceResetOptions,
},
BlocksInWeek: {
handler: BlocksInWeekHandler,
options: optionDefinitions,
},
};
3 changes: 2 additions & 1 deletion packages/contracts/scripts/task/task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const main = async () => {
throw new Error("You MUST put the task name in command arguments at least");
}

const envPath = path.join(__dirname, "../.env");
const envPath = path.join(__dirname, "../../.env");
if (!fs.existsSync(envPath)) {
throw new Error("Env file not found");
}
Expand All @@ -26,6 +26,7 @@ const main = async () => {
let args;
try {
args = CommandLineArgs(commandLineParseOptions);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
console.error(`Argument parse failed!, error: ${error}`);
return;
Expand Down
2 changes: 1 addition & 1 deletion packages/contracts/src/deprecated/TWAPOracle.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.3;

import "../dollar/interfaces/IMetaPool.sol";
import "./interfaces/IMetaPool.sol";

contract TWAPOracle {
address public immutable pool;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

import "./interfaces/IMetaPool.sol";
import "./interfaces/IUbiquityAlgorithmicDollar.sol";
import "../dollar/interfaces/ICurveFactory.sol";
import "../dollar/interfaces/IMetaPool.sol";

import "./TWAPOracle.sol";

Expand Down
12 changes: 12 additions & 0 deletions packages/contracts/src/dollar/access/AccessControlInternal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,18 @@ abstract contract AccessControlInternal {
return LibAccessControl.accessControlStorage().roles[role].adminRole;
}

/**
* @notice Set admin role for a given role
* @param role Role to set
* @param adminRole role for the provided role
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
LibAccessControl
.accessControlStorage()
.roles[role]
.adminRole = adminRole;
}

/**
* @notice Assigns role to a given account
* @param role Role to assign
Expand Down
Loading

0 comments on commit acc5800

Please sign in to comment.