文件 1 的 15:Address.sol
pragma solidity >=0.6.2 <0.8.0;
library Address {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly { size := extcodesize(account) }
return size > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{ value: value }(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 15:AddressUpgradeable.sol
pragma solidity >=0.6.2 <0.8.0;
library AddressUpgradeable {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly { size := extcodesize(account) }
return size > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{ value: value }(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 3 的 15:Context.sol
pragma solidity >=0.6.0 <0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this;
return msg.data;
}
}
文件 4 的 15:EnumerableSet.sol
pragma solidity >=0.6.0 <0.8.0;
library EnumerableSet {
struct Set {
bytes32[] _values;
mapping (bytes32 => uint256) _indexes;
}
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
function _remove(Set storage set, bytes32 value) private returns (bool) {
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
bytes32 lastvalue = set._values[lastIndex];
set._values[toDeleteIndex] = lastvalue;
set._indexes[lastvalue] = toDeleteIndex + 1;
set._values.pop();
delete set._indexes[value];
return true;
} else {
return false;
}
}
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
function _at(Set storage set, uint256 index) private view returns (bytes32) {
require(set._values.length > index, "EnumerableSet: index out of bounds");
return set._values[index];
}
struct Bytes32Set {
Set _inner;
}
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
struct AddressSet {
Set _inner;
}
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
struct UintSet {
Set _inner;
}
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
}
文件 5 的 15:IERC20.sol
pragma solidity >=0.6.0 <0.8.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 6 的 15:ISwapper.sol
pragma solidity >=0.6.0 <0.8.0;
interface ISwapper {
function swapToken(
address _from,
address _to,
uint256 _amount,
uint256 _minAmountOut,
address _beneficiary
) external;
}
文件 7 的 15:Initializable.sol
pragma solidity >=0.4.24 <0.8.0;
import "../utils/AddressUpgradeable.sol";
abstract contract Initializable {
bool private _initialized;
bool private _initializing;
modifier initializer() {
require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized");
bool isTopLevelCall = !_initializing;
if (isTopLevelCall) {
_initializing = true;
_initialized = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
}
}
function _isConstructor() private view returns (bool) {
return !AddressUpgradeable.isContract(address(this));
}
}
文件 8 的 15:Operation.sol
pragma solidity >=0.6.0 <0.8.0;
pragma experimental ABIEncoderV2;
import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import {Context} from "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts-upgradeable/proxy/Initializable.sol";
import {WrappedAsset} from "../assets/WrappedAsset.sol";
import {Operator} from "../utils/Operator.sol";
import {OperationACL} from "./OperationACL.sol";
import {ISwapper} from "../swapper/ISwapper.sol";
interface IOperation {
event AutoFinishEnabled(address indexed operation);
event InitDeposit(address indexed operator, uint256 amount, bytes32 to);
event FinishDeposit(address indexed operator, uint256 amount);
event InitRedemption(address indexed operator, uint256 amount, bytes32 to);
event FinishRedemption(address indexed operator, uint256 amount);
event EmergencyWithdrawActivated(address token, uint256 amount);
enum Status {IDLE, RUNNING, STOPPED}
enum Type {NEUTRAL, DEPOSIT, REDEEM}
struct Info {
Status status;
Type typ;
address operator;
uint256 amount;
address input;
address output;
address swapper;
address swapDest;
}
function terraAddress() external view returns (bytes32);
function getCurrentStatus() external view returns (Info memory);
function initDepositStable(
address _operator,
uint256 _amount,
address _swapper,
address _swapDest,
bool _autoFinish
) external;
function initRedeemStable(
address _operator,
uint256 _amount,
address _swapper,
address _swapDest,
bool _autoFinish
) external;
function finish() external;
function finish(uint256 _minAmountOut) external;
function finishDepositStable() external;
function finishRedeemStable() external;
function halt() external;
function recover() external;
function emergencyWithdraw(address _token, address _to) external;
function emergencyWithdraw(address payable _to) external;
}
contract Operation is Context, OperationACL, IOperation, Initializable {
using SafeMath for uint256;
using SafeERC20 for IERC20;
using SafeERC20 for WrappedAsset;
Info public DEFAULT_STATUS =
Info({
status: Status.IDLE,
typ: Type.NEUTRAL,
operator: address(0x0),
amount: 0,
input: address(0x0),
output: address(0x0),
swapper: address(0x0),
swapDest: address(0x0)
});
Info public currentStatus;
WrappedAsset public wUST;
WrappedAsset public aUST;
bytes32 public override terraAddress;
function initialize(bytes memory args) public initializer {
(
address _router,
address _controller,
bytes32 _terraAddress,
address _wUST,
address _aUST
) = abi.decode(args, (address, address, bytes32, address, address));
currentStatus = DEFAULT_STATUS;
terraAddress = _terraAddress;
wUST = WrappedAsset(_wUST);
aUST = WrappedAsset(_aUST);
router = _router;
controller = _controller;
}
function initPayload(
address _router,
address _controller,
bytes32 _terraAddress
) public view returns (bytes memory) {
return abi.encode(_router, _controller, _terraAddress, wUST, aUST);
}
modifier checkStopped {
require(currentStatus.status != Status.STOPPED, "Operation: stopped");
_;
}
function getCurrentStatus() public view override returns (Info memory) {
return currentStatus;
}
function _init(
Type _typ,
address _operator,
uint256 _amount,
address _swapper,
address _swapDest,
bool _autoFinish
) private onlyRouter checkStopped {
require(currentStatus.status == Status.IDLE, "Operation: running");
require(_amount >= 10 ether, "Operation: amount must be more than 10");
currentStatus = Info({
status: Status.RUNNING,
typ: _typ,
operator: _operator,
amount: _amount,
input: address(0x0),
output: address(0x0),
swapper: _swapper,
swapDest: _swapDest
});
if (_typ == Type.DEPOSIT) {
currentStatus.input = address(wUST);
currentStatus.output = address(aUST);
wUST.safeTransferFrom(_msgSender(), address(this), _amount);
wUST.burn(_amount, terraAddress);
emit InitDeposit(_operator, _amount, terraAddress);
} else if (_typ == Type.REDEEM) {
currentStatus.input = address(aUST);
currentStatus.output = address(wUST);
aUST.safeTransferFrom(_msgSender(), address(this), _amount);
aUST.burn(_amount, terraAddress);
emit InitRedemption(_operator, _amount, terraAddress);
} else {
revert("Operation: invalid operation type");
}
if (_autoFinish) {
emit AutoFinishEnabled(address(this));
}
}
function initDepositStable(
address _operator,
uint256 _amount,
address _swapper,
address _swapDest,
bool _autoFinish
) public override {
_init(
Type.DEPOSIT,
_operator,
_amount,
_swapper,
_swapDest,
_autoFinish
);
}
function initRedeemStable(
address _operator,
uint256 _amount,
address _swapper,
address _swapDest,
bool _autoFinish
) public override {
_init(
Type.REDEEM,
_operator,
_amount,
_swapper,
_swapDest,
_autoFinish
);
}
function _finish(uint256 _minAmountOut)
private
onlyGranted
checkStopped
returns (address, uint256)
{
require(currentStatus.status == Status.RUNNING, "Operation: idle");
WrappedAsset output = WrappedAsset(currentStatus.output);
uint256 amount = output.balanceOf(address(this));
address operator = currentStatus.operator;
address swapper = currentStatus.swapper;
require(amount > 0, "Operation: not enough token");
if (swapper != address(0x0)) {
output.safeIncreaseAllowance(swapper, amount);
try
ISwapper(swapper).swapToken(
address(output),
currentStatus.swapDest,
amount,
_minAmountOut,
operator
)
{} catch {
output.safeDecreaseAllowance(swapper, amount);
output.safeTransfer(operator, amount);
}
} else {
output.safeTransfer(operator, amount);
}
Type typ = currentStatus.typ;
if (typ == Type.DEPOSIT) {
emit FinishDeposit(operator, amount);
} else if (typ == Type.REDEEM) {
emit FinishRedemption(operator, amount);
}
currentStatus = DEFAULT_STATUS;
return (address(output), amount);
}
function finish() public override {
_finish(0);
}
function finish(uint256 _minAmountOut) public override {
_finish(_minAmountOut);
}
function finishDepositStable() public override {
_finish(0);
}
function finishRedeemStable() public override {
_finish(0);
}
function halt() public override onlyController {
currentStatus.status = Status.STOPPED;
}
function recover() public override onlyController {
if (currentStatus.operator == address(0x0)) {
currentStatus.status = Status.IDLE;
} else {
currentStatus.status = Status.RUNNING;
}
}
function emergencyWithdraw(address _token, address _to)
public
override
onlyController
{
require(
currentStatus.status == Status.STOPPED,
"Operation: not an emergency"
);
if (currentStatus.operator != address(0x0)) {
require(
currentStatus.output != _token,
"Operation: withdrawal rejected"
);
}
IERC20(_token).safeTransfer(
_to,
IERC20(_token).balanceOf(address(this))
);
}
function emergencyWithdraw(address payable _to)
public
override
onlyController
{
require(
currentStatus.status == Status.STOPPED,
"Operation: not an emergency"
);
_to.transfer(address(this).balance);
}
}
文件 9 的 15:OperationACL.sol
pragma solidity >=0.6.0 <0.8.0;
pragma experimental ABIEncoderV2;
import {Context} from "@openzeppelin/contracts/utils/Context.sol";
abstract contract OperationACL is Context {
address public owner;
address public router;
address public controller;
constructor() {
owner = _msgSender();
router = _msgSender();
controller = _msgSender();
}
modifier onlyOwner {
require(_msgSender() == owner, "OperationACL: owner access denied");
_;
}
modifier onlyRouter {
require(_msgSender() == router, "OperationACL: router access denied");
_;
}
modifier onlyController {
require(
_msgSender() == controller,
"OperationACL: controller access denied"
);
_;
}
modifier onlyGranted {
address sender = _msgSender();
require(
sender == owner || sender == router || sender == controller,
"OperationACL: denied"
);
_;
}
function transferOwnership(address _owner) public onlyOwner {
owner = _owner;
}
function transferRouter(address _router) public onlyOwner {
router = _router;
}
function transferController(address _controller) public onlyOwner {
controller = _controller;
}
}
文件 10 的 15:OperationStore.sol
pragma solidity >=0.6.0 <0.8.0;
pragma experimental ABIEncoderV2;
import {EnumerableSet} from "@openzeppelin/contracts/utils/EnumerableSet.sol";
import {StdQueue} from "../utils/Queue.sol";
import {IOperation} from "./Operation.sol";
import {OperationACL} from "./OperationACL.sol";
interface IOperationStore {
event OperationAllocated(
address indexed controller,
address indexed operation
);
event OperationInitialized(
address indexed controller,
address indexed operation,
bool autoFinish
);
event OperationFinished(
address indexed controller,
address indexed operation
);
event OperationStopped(
address indexed controller,
address indexed operation
);
event OperationRecovered(
address indexed controller,
address indexed operation
);
event OperationDeallocated(
address indexed controller,
address indexed operation
);
event OperationFlushed(
address indexed controller,
address indexed operation,
Queue from,
Queue to
);
enum Status {
IDLE,
RUNNING_AUTO,
RUNNING_MANUAL,
FINISHED,
STOPPED,
RECOVERED,
DEALLOCATED
}
enum Queue {IDLE, RUNNING, STOPPED, NULL}
function getAvailableOperation() external view returns (address);
function getQueuedOperationAt(Queue _queue, uint256 _index)
external
view
returns (address);
function getQueueSizeOf(Queue _queue) external view returns (uint256);
function getStatusOf(address _opt) external view returns (Status);
function allocate(address _opt) external;
function init(bool _autoFinish) external returns (address);
function finish(address _opt) external;
function halt(address _opt) external;
function recover(address _opt) external;
function deallocate(address _opt) external;
function flush(Queue queue, uint256 _amount) external;
function flushAll(uint256 _amount) external;
}
contract OperationStore is IOperationStore, OperationACL {
using StdQueue for StdQueue.AddressQueue;
using EnumerableSet for EnumerableSet.AddressSet;
mapping(address => Status) public optStat;
EnumerableSet.AddressSet internal optIdle;
StdQueue.AddressQueue internal optStopped;
StdQueue.AddressQueue internal optRunning;
function getAvailableOperation() public view override returns (address) {
if (optIdle.length() == 0) {
return address(0x0);
}
return optIdle.at(0);
}
function getQueuedOperationAt(Queue _queue, uint256 _index)
public
view
override
returns (address)
{
if (_queue == Queue.IDLE) {
return optIdle.at(_index);
} else if (_queue == Queue.RUNNING) {
return optRunning.getItemAt(_index);
} else if (_queue == Queue.STOPPED) {
return optStopped.getItemAt(_index);
} else {
revert("OperationStore: invalid queue type");
}
}
function getQueueSizeOf(Queue _queue)
public
view
override
returns (uint256)
{
if (_queue == Queue.IDLE) {
return optIdle.length();
} else if (_queue == Queue.RUNNING) {
return optRunning.length();
} else if (_queue == Queue.STOPPED) {
return optStopped.length();
} else {
revert("OperationStore: invalid queue type");
}
}
function getStatusOf(address _opt) public view override returns (Status) {
return optStat[_opt];
}
function allocate(address _opt) public override onlyGranted {
optIdle.add(_opt);
optStat[_opt] = Status.IDLE;
emit OperationAllocated(msg.sender, _opt);
}
function init(bool _autoFinish)
public
override
onlyRouter
returns (address)
{
address opt = optIdle.at(0);
optIdle.remove(opt);
if (_autoFinish) {
optRunning.produce(opt);
optStat[opt] = Status.RUNNING_AUTO;
} else {
optStat[opt] = Status.RUNNING_MANUAL;
}
emit OperationInitialized(msg.sender, opt, _autoFinish);
return opt;
}
function finish(address _opt) public override onlyGranted {
Status status = optStat[_opt];
if (status == Status.RUNNING_MANUAL) {
allocate(_opt);
} else if (status == Status.RUNNING_AUTO) {
optStat[_opt] = Status.FINISHED;
} else {
revert("Router: invalid condition for finish operation");
}
emit OperationFinished(msg.sender, _opt);
}
function halt(address _opt) public override onlyController {
Status stat = optStat[_opt];
if (stat == Status.IDLE) {
optIdle.remove(_opt);
optStopped.produce(_opt);
}
optStat[_opt] = Status.STOPPED;
emit OperationStopped(msg.sender, _opt);
}
function flushRunningQueue(StdQueue.AddressQueue storage _queue)
internal
returns (bool)
{
address opt = _queue.getItemAt(0);
Status stat = optStat[opt];
if (stat == Status.FINISHED) {
optIdle.add(_queue.consume());
optStat[opt] = Status.IDLE;
emit OperationFlushed(msg.sender, opt, Queue.RUNNING, Queue.IDLE);
} else if (stat == Status.STOPPED) {
optStopped.produce(_queue.consume());
emit OperationFlushed(
msg.sender,
opt,
Queue.RUNNING,
Queue.STOPPED
);
} else {
return false;
}
return true;
}
function recover(address _opt) public override onlyController {
optStat[_opt] = Status.RECOVERED;
emit OperationRecovered(msg.sender, _opt);
}
function deallocate(address _opt) public override onlyController {
optStat[_opt] = Status.DEALLOCATED;
emit OperationDeallocated(msg.sender, _opt);
}
function flushStoppedQueue(StdQueue.AddressQueue storage _queue)
internal
returns (bool)
{
address opt = _queue.getItemAt(0);
Status stat = optStat[opt];
if (stat == Status.RECOVERED) {
optIdle.add(_queue.consume());
optStat[opt] = Status.IDLE;
emit OperationFlushed(msg.sender, opt, Queue.STOPPED, Queue.IDLE);
} else if (stat == Status.DEALLOCATED) {
_queue.consume();
emit OperationFlushed(msg.sender, opt, Queue.STOPPED, Queue.NULL);
} else {
return false;
}
return true;
}
function _flush(
StdQueue.AddressQueue storage _queue,
uint256 _amount,
function(StdQueue.AddressQueue storage) returns (bool) _handler
) internal {
for (uint256 i = 0; i < _amount; i++) {
if (_queue.isEmpty()) {
return;
}
if (!_handler(_queue)) {
return;
}
}
}
function flush(Queue _queue, uint256 _amount)
public
override
onlyController
{
if (_queue == Queue.RUNNING) {
_flush(optRunning, _amount, flushRunningQueue);
} else if (_queue == Queue.STOPPED) {
_flush(optStopped, _amount, flushStoppedQueue);
} else {
revert("OperationStore: invalid queue type");
}
}
function flushAll(uint256 _amount) public override onlyController {
flush(Queue.RUNNING, _amount);
flush(Queue.STOPPED, _amount);
}
}
文件 11 的 15:Operator.sol
pragma solidity >=0.6.0 <0.8.0;
pragma experimental ABIEncoderV2;
import {Context} from "@openzeppelin/contracts/utils/Context.sol";
contract Operator is Context {
address public owner;
address public operator;
constructor() {
owner = _msgSender();
operator = _msgSender();
}
function setRole(address _owner, address _operator) internal virtual {
owner = _owner;
operator = _operator;
}
modifier onlyOwner {
require(checkOwner(), "Operator: owner access denied");
_;
}
function checkOwner() public view returns (bool) {
return _msgSender() == owner;
}
modifier onlyOperator {
require(checkOperator(), "Operator: operator access denied");
_;
}
function checkOperator() public view returns (bool) {
return _msgSender() == operator;
}
modifier onlyGranted {
require(checkGranted(), "Operator: access denied");
_;
}
function checkGranted() public view returns (bool) {
return checkOwner() || checkOperator();
}
function transferOwnership(address _owner) public onlyOwner {
owner = _owner;
}
function transferOperator(address _operator) public onlyOwner {
operator = _operator;
}
}
文件 12 的 15:Queue.sol
pragma solidity >=0.6.0 <0.8.0;
library StdQueue {
struct Queue {
uint256 index;
uint256 size;
mapping(uint256 => bytes32) store;
}
function _length(Queue storage q) internal view returns (uint256) {
return q.size;
}
function _isEmpty(Queue storage q) internal view returns (bool) {
return q.size == 0;
}
function _getItemAt(Queue storage q, uint256 index)
internal
view
returns (bytes32)
{
return q.store[q.index + index];
}
function _produce(Queue storage q, bytes32 data) internal {
q.store[q.index + q.size] = data;
q.size += 1;
}
function _consume(Queue storage q) internal returns (bytes32) {
require(!_isEmpty(q), "StdQueue: empty queue");
bytes32 data = _getItemAt(q, 0);
q.index += 1;
q.size -= 1;
return data;
}
struct Bytes32Queue {
Queue _inner;
}
function length(Bytes32Queue storage queue)
internal
view
returns (uint256)
{
return _length(queue._inner);
}
function isEmpty(Bytes32Queue storage queue) internal view returns (bool) {
return _isEmpty(queue._inner);
}
function getItemAt(Bytes32Queue storage queue, uint256 _index)
internal
view
returns (bytes32)
{
return _getItemAt(queue._inner, _index);
}
function produce(Bytes32Queue storage queue, bytes32 _value) internal {
_produce(queue._inner, _value);
}
function consume(Bytes32Queue storage queue) internal returns (bytes32) {
return _consume(queue._inner);
}
struct AddressQueue {
Queue _inner;
}
function length(AddressQueue storage queue)
internal
view
returns (uint256)
{
return _length(queue._inner);
}
function isEmpty(AddressQueue storage queue) internal view returns (bool) {
return _isEmpty(queue._inner);
}
function getItemAt(AddressQueue storage queue, uint256 _index)
internal
view
returns (address)
{
return address(uint160(uint256(_getItemAt(queue._inner, _index))));
}
function produce(AddressQueue storage queue, address _value) internal {
_produce(queue._inner, bytes32(uint256(uint160(_value))));
}
function consume(AddressQueue storage queue) internal returns (address) {
return address(uint256(bytes32(_consume(queue._inner))));
}
}
文件 13 的 15:SafeERC20.sol
pragma solidity >=0.6.0 <0.8.0;
import "./IERC20.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";
library SafeERC20 {
using SafeMath for uint256;
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
require((value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).add(value);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 14 的 15:SafeMath.sol
pragma solidity >=0.6.0 <0.8.0;
library SafeMath {
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b > a) return (false, 0);
return (true, a - b);
}
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a / b);
}
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a % b);
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
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;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: division by zero");
return a / b;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: modulo by zero");
return a % b;
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
return a - b;
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a / b;
}
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a % b;
}
}
文件 15 的 15:WrappedAsset.sol
pragma solidity >=0.6.0 <0.8.0;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface WrappedAsset is IERC20 {
event Burn(address indexed _sender, bytes32 indexed _to, uint256 amount);
function burn(uint256 amount, bytes32 to) external;
}
{
"compilationTarget": {
"contracts/operations/OperationStore.sol": "OperationStore"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"controller","type":"address"},{"indexed":true,"internalType":"address","name":"operation","type":"address"}],"name":"OperationAllocated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"controller","type":"address"},{"indexed":true,"internalType":"address","name":"operation","type":"address"}],"name":"OperationDeallocated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"controller","type":"address"},{"indexed":true,"internalType":"address","name":"operation","type":"address"}],"name":"OperationFinished","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"controller","type":"address"},{"indexed":true,"internalType":"address","name":"operation","type":"address"},{"indexed":false,"internalType":"enum IOperationStore.Queue","name":"from","type":"uint8"},{"indexed":false,"internalType":"enum IOperationStore.Queue","name":"to","type":"uint8"}],"name":"OperationFlushed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"controller","type":"address"},{"indexed":true,"internalType":"address","name":"operation","type":"address"},{"indexed":false,"internalType":"bool","name":"autoFinish","type":"bool"}],"name":"OperationInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"controller","type":"address"},{"indexed":true,"internalType":"address","name":"operation","type":"address"}],"name":"OperationRecovered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"controller","type":"address"},{"indexed":true,"internalType":"address","name":"operation","type":"address"}],"name":"OperationStopped","type":"event"},{"inputs":[{"internalType":"address","name":"_opt","type":"address"}],"name":"allocate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"controller","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_opt","type":"address"}],"name":"deallocate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_opt","type":"address"}],"name":"finish","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum IOperationStore.Queue","name":"_queue","type":"uint8"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"flush","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"flushAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAvailableOperation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum IOperationStore.Queue","name":"_queue","type":"uint8"}],"name":"getQueueSizeOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum IOperationStore.Queue","name":"_queue","type":"uint8"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getQueuedOperationAt","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_opt","type":"address"}],"name":"getStatusOf","outputs":[{"internalType":"enum IOperationStore.Status","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_opt","type":"address"}],"name":"halt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_autoFinish","type":"bool"}],"name":"init","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"optStat","outputs":[{"internalType":"enum IOperationStore.Status","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_opt","type":"address"}],"name":"recover","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"router","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_controller","type":"address"}],"name":"transferController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_router","type":"address"}],"name":"transferRouter","outputs":[],"stateMutability":"nonpayable","type":"function"}]