Skip to content
Open
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
52 changes: 52 additions & 0 deletions contracts/script/DeployConverter.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: GPL-3.0
// Docgen-SOLC: 0.8.25
pragma solidity 0.8.24;

import {Script, console} from "forge-std/Script.sol";
import {BoldConverter, Path, IWhitelist, IBoldToken, IERC20Metadata} from "src/Dependencies/BoldConverter.sol";
import {Whitelist} from "src/Dependencies/Whitelist.sol";

contract DeployConverter is Script {
function run() public returns (BoldConverter converter) {
vm.startBroadcast();
console.log("msg.sender:", msg.sender);

IERC20Metadata[] memory underlyings = new IERC20Metadata[](1);
Path[] memory paths = new Path[](1);

// Edit this
underlyings[0] = IERC20Metadata(
0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
); // usdc
paths[0] = Path(
address(0x452DC676b4E377a76B4b3048eB3b511A0F1ec057),
6,
0
);
address bvUSD = 0x9BC2F611fa2196E097496B722f1CBCDfE2303855;
address whitelist = 0x788DbB1888a50e97837b9D06Fd70db107b082A12;
address owner = 0x452DC676b4E377a76B4b3048eB3b511A0F1ec057;

converter = new BoldConverter(
underlyings,
paths,
bvUSD
);
converter.setWhitelist(IWhitelist(whitelist));
converter.nominateNewOwner(owner);

vm.stopBroadcast();
}
}

contract DeployWhitelist is Script {
function run() public returns (Whitelist whitelist) {
vm.startBroadcast();
console.log("msg.sender:", msg.sender);
address owner = address(0);

whitelist = new Whitelist(owner);

vm.stopBroadcast();
}
}
18 changes: 12 additions & 6 deletions contracts/src/BorrowerOperations.sol
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ contract BorrowerOperations is
) external override returns (uint256) {
_requireValidAnnualInterestRate(_annualInterestRate);

_checkWhitelisted(_owner, msg.sender, _receiver);
_checkWhitelisted(this.openTrove.selector, _owner, msg.sender, _receiver);

OpenTroveVars memory vars;

Expand Down Expand Up @@ -281,7 +281,12 @@ contract BorrowerOperations is
) external override returns (uint256) {
_requireValidInterestBatchManager(_params.interestBatchManager);

_checkWhitelisted(_params.owner, msg.sender, _params.receiver);
_checkWhitelisted(
this.openTroveAndJoinInterestBatchManager.selector,
_params.owner,
msg.sender,
_params.receiver
);

OpenTroveVars memory vars;
vars.troveManager = troveManager;
Expand Down Expand Up @@ -733,7 +738,7 @@ contract BorrowerOperations is
}

// _requireNonZeroAdjustment(_troveChange);
if (
if (
_troveChange.collIncrease == 0 &&
_troveChange.collDecrease == 0 &&
_troveChange.debtIncrease == 0 &&
Expand Down Expand Up @@ -2093,16 +2098,17 @@ contract BorrowerOperations is
}

function _checkWhitelisted(
bytes4 _funcSig,
address _owner,
address _sender,
address _receiver
) internal view {
IWhitelist _whitelist = whitelist;
if (address(_whitelist) != address(0)) {
_requireWhitelisted(_whitelist, _owner);
_requireWhitelisted(_whitelist, _sender);
_requireWhitelisted(_whitelist, _funcSig, _owner);
_requireWhitelisted(_whitelist, _funcSig, _sender);
if (_receiver != address(0)) {
_requireWhitelisted(whitelist, _receiver);
_requireWhitelisted(whitelist, _funcSig, _receiver);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions contracts/src/CollateralRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ contract CollateralRegistry is Owned, ICollateralRegistry {
bool redeemable
) = troveManager.getUnbackedPortionPriceAndRedeemability();
prices[index] = price;
if (redeemable && troveManager.isWhitelisted(msg.sender)) {
if (redeemable && troveManager.isWhitelisted(msg.sender, ITroveManager.redeemCollateral.selector)) {
totals.unbacked += unbackedPortion;
unbackedPortions[index] = unbackedPortion;
}
Expand All @@ -189,7 +189,7 @@ contract CollateralRegistry is Owned, ICollateralRegistry {
ITroveManager troveManager = getTroveManager(index);
(, , bool redeemable) = troveManager
.getUnbackedPortionPriceAndRedeemability();
if (redeemable && troveManager.isWhitelisted(msg.sender)) {
if (redeemable && troveManager.isWhitelisted(msg.sender, ITroveManager.redeemCollateral.selector)) {
uint256 unbackedPortion = troveManager
.getEntireBranchDebt();
totals.unbacked += unbackedPortion;
Expand Down
46 changes: 34 additions & 12 deletions contracts/src/Dependencies/AddRemoveManagers.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,11 @@ contract AddRemoveManagers is HasWhitelist, IAddRemoveManagers {

event TroveNFTAddressChanged(address _newTroveNFTAddress);
event AddManagerUpdated(uint256 indexed _troveId, address _newAddManager);
event RemoveManagerAndReceiverUpdated(uint256 indexed _troveId, address _newRemoveManager, address _newReceiver);
event RemoveManagerAndReceiverUpdated(
uint256 indexed _troveId,
address _newRemoveManager,
address _newReceiver
);

constructor(IAddressesRegistry _addressesRegistry) {
troveNFT = _addressesRegistry.troveNFT();
Expand All @@ -59,18 +63,30 @@ contract AddRemoveManagers is HasWhitelist, IAddRemoveManagers {
emit AddManagerUpdated(_troveId, _manager);
}

function setRemoveManagerWithReceiver(uint256 _troveId, address _manager, address _receiver) public {
function setRemoveManagerWithReceiver(
uint256 _troveId,
address _manager,
address _receiver
) public {
_requireCallerIsBorrower(_troveId);

IWhitelist _whitelist = whitelist;
if (address(_whitelist) != address(0)) {
_requireWhitelisted(_whitelist, _receiver);
_requireWhitelisted(
_whitelist,
this.setRemoveManagerWithReceiver.selector,
_receiver
);
}

_setRemoveManagerAndReceiver(_troveId, _manager, _receiver);
}

function _setRemoveManagerAndReceiver(uint256 _troveId, address _manager, address _receiver) internal {
function _setRemoveManagerAndReceiver(
uint256 _troveId,
address _manager,
address _receiver
) internal {
// _requireNonZeroManagerUnlessWiping(_manager, _receiver);
if (_manager == address(0) && _receiver != address(0)) {
revert EmptyManager();
Expand Down Expand Up @@ -99,18 +115,24 @@ contract AddRemoveManagers is HasWhitelist, IAddRemoveManagers {
}
}

function _requireSenderIsOwnerOrAddManager(uint256 _troveId, address _owner) internal view {
function _requireSenderIsOwnerOrAddManager(
uint256 _troveId,
address _owner
) internal view {
address addManager = addManagerOf[_troveId];
if (msg.sender != _owner && addManager != address(0) && msg.sender != addManager) {
if (
msg.sender != _owner &&
addManager != address(0) &&
msg.sender != addManager
) {
revert NotOwnerNorAddManager();
}
}

function _requireSenderIsOwnerOrRemoveManagerAndGetReceiver(uint256 _troveId, address _owner)
internal
view
returns (address)
{
function _requireSenderIsOwnerOrRemoveManagerAndGetReceiver(
uint256 _troveId,
address _owner
) internal view returns (address) {
address manager = removeManagerReceiverOf[_troveId].manager;
address receiver = removeManagerReceiverOf[_troveId].receiver;
if (msg.sender != _owner && msg.sender != manager) {
Expand Down
68 changes: 59 additions & 9 deletions contracts/src/Dependencies/BoldConverter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,23 @@ import {ReentrancyGuard} from "openzeppelin-contracts/contracts/security/Reentra
import {IERC20Metadata} from "openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {IBoldToken} from "../Interfaces/IBoldToken.sol";
import "./Owned.sol";
import "./HasWhitelist.sol";

contract BoldConverter is Owned, ReentrancyGuard {
struct Path {
address underlyingReceiver;
uint256 underlyingDecimals;
uint256 withdrawalFee;
}

contract BoldConverter is Owned, HasWhitelist, ReentrancyGuard {
uint256 public constant MAX_FEE = 10000;
bytes4 public constant DEPOSIT_SELECTOR =
bytes4(keccak256("deposit(address,uint256,address)"));
bytes4 public constant WITHDRAW_SELECTOR =
bytes4(keccak256("withdraw(address,uint256,address)"));

IBoldToken public bvUSD;

struct Path {
address underlyingReceiver;
uint256 underlyingDecimals;
uint256 withdrawalFee;
}

mapping(IERC20Metadata => Path) private _underlyingPaths;

event NewPath(IERC20Metadata indexed underlying);
Expand All @@ -33,6 +38,8 @@ contract BoldConverter is Owned, ReentrancyGuard {
bvUSD = IBoldToken(bvUSD_);
}

// --- View functions ---

function isValidPath(
IERC20Metadata underlying
) external view returns (bool) {
Expand All @@ -45,12 +52,19 @@ contract BoldConverter is Owned, ReentrancyGuard {
path = _underlyingPaths[underlying];
}

// --- Deposit functions ---

// amount in underlying token decimals
function deposit(
IERC20Metadata underlying,
uint256 amount,
address to
) public nonReentrant returns (uint256 boldAmount) {
)
public
nonReentrant
checkWhitelistedSenderAndOrigin(DEPOSIT_SELECTOR)
returns (uint256 boldAmount)
{
Path memory path = _underlyingPaths[underlying];
require(path.underlyingReceiver != address(0), "Invalid path");

Expand All @@ -77,12 +91,18 @@ contract BoldConverter is Owned, ReentrancyGuard {
return deposit(underlying, amount, msg.sender);
}

// --- Withdraw functions ---

function withdraw(
IERC20Metadata underlying,
uint256 amount,
address to
) public nonReentrant returns (uint256 underlyingOut) {
)
public
nonReentrant
checkWhitelistedSenderAndOrigin(WITHDRAW_SELECTOR)
returns (uint256 underlyingOut)
{
Path memory path = _underlyingPaths[underlying];
require(path.underlyingReceiver != address(0), "Invalid path");

Expand Down Expand Up @@ -115,6 +135,8 @@ contract BoldConverter is Owned, ReentrancyGuard {
return withdraw(underlying, amount, msg.sender);
}

// --- Path management functions ---

function deletePaths(
IERC20Metadata[] memory underlyings
) external onlyOwner {
Expand Down Expand Up @@ -158,4 +180,32 @@ contract BoldConverter is Owned, ReentrancyGuard {
emit NewPath(underlying);
}
}

// --- Whitelist management functions ---

function setWhitelist(IWhitelist _whitelist) external onlyOwner {
_setWhitelist(_whitelist);
}

modifier checkWhitelistedSenderAndOrigin(bytes4 funcSig) {
IWhitelist _whitelist = whitelist;
if (address(_whitelist) != address(0)) {
bool isWhitelisted = _whitelist.isWhitelisted(
address(this),
funcSig,
msg.sender
);
if (!isWhitelisted && msg.sender != tx.origin) {
isWhitelisted = _whitelist.isWhitelisted(
address(this),
funcSig,
tx.origin
);
}
if (!isWhitelisted) {
revert NotWhitelisted(msg.sender);
}
}
_;
}
}
18 changes: 15 additions & 3 deletions contracts/src/Dependencies/HasWhitelist.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,21 @@ abstract contract HasWhitelist {
whitelist = _whitelist;
}

function _requireWhitelisted(IWhitelist _whitelist, address _user) internal view {
if (!_whitelist.isWhitelisted(address(this), _user)) {
function _requireWhitelisted(
IWhitelist _whitelist,
bytes4 _funcSig,
address _user
) internal view {
if (!_whitelist.isWhitelisted(address(this), _funcSig, _user)) {
revert NotWhitelisted(_user);
}
}
}

modifier checkWhitelisted(bytes4 _funcSig) {
IWhitelist _whitelist = whitelist;
if (address(_whitelist) != address(0)) {
_requireWhitelisted(_whitelist, _funcSig, msg.sender);
}
_;
}
}
Loading