Contract Name:
MasterMinter
Contract Source Code:
/**
* Copyright 2023 Circle Internet Financial, LTD. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.6.12;
import { MintController } from "./MintController.sol";
/**
* @title MasterMinter
* @notice MasterMinter uses multiple controllers to manage minters for a
* contract that implements the MinterManagerInterface.
* @dev MasterMinter inherits all its functionality from MintController.
*/
contract MasterMinter is MintController {
constructor(address _minterManager) public MintController(_minterManager) {}
}
/**
* Copyright 2023 Circle Internet Financial, LTD. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.6.12;
import { Controller } from "./Controller.sol";
import { MinterManagementInterface } from "./MinterManagementInterface.sol";
import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";
// solhint-disable func-name-mixedcase
/**
* @title MintController
* @dev The MintController contract manages minters for a contract that
* implements the MinterManagerInterface. It lets the owner designate certain
* addresses as controllers, and these controllers then manage the
* minters by adding and removing minters, as well as modifying their minting
* allowance. A controller may manage exactly one minter, but the same minter
* address may be managed by multiple controllers.
* MintController inherits from the Controller contract. It treats the
* Controller workers as minters.
*/
contract MintController is Controller {
using SafeMath for uint256;
/**
* @dev MintController calls the minterManager to execute/record minter
* management tasks, as well as to query the status of a minter address.
*/
MinterManagementInterface internal minterManager;
event MinterManagerSet(
address indexed _oldMinterManager,
address indexed _newMinterManager
);
event MinterConfigured(
address indexed _msgSender,
address indexed _minter,
uint256 _allowance
);
event MinterRemoved(address indexed _msgSender, address indexed _minter);
event MinterAllowanceIncremented(
address indexed _msgSender,
address indexed _minter,
uint256 _increment,
uint256 _newAllowance
);
event MinterAllowanceDecremented(
address indexed msgSender,
address indexed minter,
uint256 decrement,
uint256 newAllowance
);
/**
* @notice Initializes the minterManager.
* @param _minterManager The address of the minterManager contract.
*/
constructor(address _minterManager) public {
minterManager = MinterManagementInterface(_minterManager);
}
/**
* @notice gets the minterManager
*/
function getMinterManager()
external
view
returns (MinterManagementInterface)
{
return minterManager;
}
// onlyOwner functions
/**
* @notice Sets the minterManager.
* @param _newMinterManager The address of the new minterManager contract.
*/
function setMinterManager(address _newMinterManager) public onlyOwner {
emit MinterManagerSet(address(minterManager), _newMinterManager);
minterManager = MinterManagementInterface(_newMinterManager);
}
// onlyController functions
/**
* @notice Removes the controller's own minter.
*/
function removeMinter() public onlyController returns (bool) {
address minter = controllers[msg.sender];
emit MinterRemoved(msg.sender, minter);
return minterManager.removeMinter(minter);
}
/**
* @notice Enables the minter and sets its allowance.
* @param _newAllowance New allowance to be set for minter.
*/
function configureMinter(uint256 _newAllowance)
public
onlyController
returns (bool)
{
address minter = controllers[msg.sender];
emit MinterConfigured(msg.sender, minter, _newAllowance);
return internal_setMinterAllowance(minter, _newAllowance);
}
/**
* @notice Increases the minter's allowance if and only if the minter is an
* active minter.
* @dev An minter is considered active if minterManager.isMinter(minter)
* returns true.
*/
function incrementMinterAllowance(uint256 _allowanceIncrement)
public
onlyController
returns (bool)
{
require(
_allowanceIncrement > 0,
"Allowance increment must be greater than 0"
);
address minter = controllers[msg.sender];
require(
minterManager.isMinter(minter),
"Can only increment allowance for minters in minterManager"
);
uint256 currentAllowance = minterManager.minterAllowance(minter);
uint256 newAllowance = currentAllowance.add(_allowanceIncrement);
emit MinterAllowanceIncremented(
msg.sender,
minter,
_allowanceIncrement,
newAllowance
);
return internal_setMinterAllowance(minter, newAllowance);
}
/**
* @notice decreases the minter allowance if and only if the minter is
* currently active. The controller can safely send a signed
* decrementMinterAllowance() transaction to a minter and not worry
* about it being used to undo a removeMinter() transaction.
*/
function decrementMinterAllowance(uint256 _allowanceDecrement)
public
onlyController
returns (bool)
{
require(
_allowanceDecrement > 0,
"Allowance decrement must be greater than 0"
);
address minter = controllers[msg.sender];
require(
minterManager.isMinter(minter),
"Can only decrement allowance for minters in minterManager"
);
uint256 currentAllowance = minterManager.minterAllowance(minter);
uint256 actualAllowanceDecrement = (
currentAllowance > _allowanceDecrement
? _allowanceDecrement
: currentAllowance
);
uint256 newAllowance = currentAllowance.sub(actualAllowanceDecrement);
emit MinterAllowanceDecremented(
msg.sender,
minter,
actualAllowanceDecrement,
newAllowance
);
return internal_setMinterAllowance(minter, newAllowance);
}
// Internal functions
/**
* @notice Uses the MinterManagementInterface to enable the minter and
* set its allowance.
* @param _minter Minter to set new allowance of.
* @param _newAllowance New allowance to be set for minter.
*/
function internal_setMinterAllowance(address _minter, uint256 _newAllowance)
internal
returns (bool)
{
return minterManager.configureMinter(_minter, _newAllowance);
}
}
/**
* Copyright 2023 Circle Internet Financial, LTD. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.6.12;
import { Ownable } from "../v1/Ownable.sol";
/**
* @title Controller
* @notice Generic implementation of the owner-controller-worker model.
* One owner manages many controllers. Each controller manages one worker.
* Workers may be reused across different controllers.
*/
contract Controller is Ownable {
/**
* @dev A controller manages a single worker address.
* controllers[controller] = worker
*/
mapping(address => address) internal controllers;
event ControllerConfigured(
address indexed _controller,
address indexed _worker
);
event ControllerRemoved(address indexed _controller);
/**
* @notice Ensures that caller is the controller of a non-zero worker
* address.
*/
modifier onlyController() {
require(
controllers[msg.sender] != address(0),
"The value of controllers[msg.sender] must be non-zero"
);
_;
}
/**
* @notice Gets the worker at address _controller.
*/
function getWorker(address _controller) external view returns (address) {
return controllers[_controller];
}
// onlyOwner functions
/**
* @notice Configure a controller with the given worker.
* @param _controller The controller to be configured with a worker.
* @param _worker The worker to be set for the newly configured controller.
* _worker must not be a non-zero address. To disable a worker,
* use removeController instead.
*/
function configureController(address _controller, address _worker)
public
onlyOwner
{
require(
_controller != address(0),
"Controller must be a non-zero address"
);
require(_worker != address(0), "Worker must be a non-zero address");
controllers[_controller] = _worker;
emit ControllerConfigured(_controller, _worker);
}
/**
* @notice disables a controller by setting its worker to address(0).
* @param _controller The controller to disable.
*/
function removeController(address _controller) public onlyOwner {
require(
_controller != address(0),
"Controller must be a non-zero address"
);
require(
controllers[_controller] != address(0),
"Worker must be a non-zero address"
);
controllers[_controller] = address(0);
emit ControllerRemoved(_controller);
}
}
/**
* Copyright 2023 Circle Internet Financial, LTD. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.6.12;
/**
* @dev A contract that implements the MinterManagementInterface has external
* functions for adding and removing minters and modifying their allowances.
* An example is the FiatTokenV1 contract.
*/
interface MinterManagementInterface {
function isMinter(address _account) external view returns (bool);
function minterAllowance(address _minter) external view returns (uint256);
function configureMinter(address _minter, uint256 _minterAllowedAmount)
external
returns (bool);
function removeMinter(address _minter) external returns (bool);
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
/**
* @dev Returns the substraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b > a) return (false, 0);
return (true, a - b);
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a / b);
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a % b);
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) return 0;
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: division by zero");
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: modulo by zero");
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
return a - b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryDiv}.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a % b;
}
}
/**
* SPDX-License-Identifier: MIT
*
* Copyright (c) 2018 zOS Global Limited.
* Copyright (c) 2018-2020 CENTRE SECZ
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
pragma solidity 0.6.12;
/**
* @notice The Ownable contract has an owner address, and provides basic
* authorization control functions
* @dev Forked from https://github.com/OpenZeppelin/openzeppelin-labs/blob/3887ab77b8adafba4a26ace002f3a684c1a3388b/upgradeability_ownership/contracts/ownership/Ownable.sol
* Modifications:
* 1. Consolidate OwnableStorage into this contract (7/13/18)
* 2. Reformat, conform to Solidity 0.6 syntax, and add error messages (5/13/20)
* 3. Make public functions external (5/27/20)
*/
contract Ownable {
// Owner of the contract
address private _owner;
/**
* @dev Event to show ownership has been transferred
* @param previousOwner representing the address of the previous owner
* @param newOwner representing the address of the new owner
*/
event OwnershipTransferred(address previousOwner, address newOwner);
/**
* @dev The constructor sets the original owner of the contract to the sender account.
*/
constructor() public {
setOwner(msg.sender);
}
/**
* @dev Tells the address of the owner
* @return the address of the owner
*/
function owner() external view returns (address) {
return _owner;
}
/**
* @dev Sets a new owner address
*/
function setOwner(address newOwner) internal {
_owner = newOwner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(msg.sender == _owner, "Ownable: caller is not the owner");
_;
}
/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
*/
function transferOwnership(address newOwner) external onlyOwner {
require(
newOwner != address(0),
"Ownable: new owner is the zero address"
);
emit OwnershipTransferred(_owner, newOwner);
setOwner(newOwner);
}
}