编译器
0.8.10+commit.fc410830
文件 1 的 8:IAllocator.sol
pragma solidity >=0.8.0;
import "./IERC20.sol";
import "./ITreasuryExtender.sol";
import "./IOlympusAuthority.sol";
enum AllocatorStatus {
OFFLINE,
ACTIVATED,
MIGRATING
}
struct AllocatorInitData {
IOlympusAuthority authority;
ITreasuryExtender extender;
IERC20[] tokens;
}
interface IAllocator {
event AllocatorDeployed(address authority, address extender);
event AllocatorActivated();
event AllocatorDeactivated(bool panic);
event LossLimitViolated(uint128 lastLoss, uint128 dloss, uint256 estimatedTotalAllocated);
event MigrationExecuted(address allocator);
event EtherReceived(uint256 amount);
function update(uint256 id) external;
function deallocate(uint256[] memory amounts) external;
function prepareMigration() external;
function migrate() external;
function activate() external;
function deactivate(bool panic) external;
function addId(uint256 id) external;
function name() external view returns (string memory);
function ids() external view returns (uint256[] memory);
function tokenIds(uint256 id) external view returns (uint256);
function version() external view returns (string memory);
function status() external view returns (AllocatorStatus);
function tokens() external view returns (IERC20[] memory);
function utilityTokens() external view returns (IERC20[] memory);
function rewardTokens() external view returns (IERC20[] memory);
function amountAllocated(uint256 id) external view returns (uint256);
}
文件 2 的 8:IERC20.sol
pragma solidity >=0.7.5;
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);
}
文件 3 的 8:IOlympusAuthority.sol
pragma solidity >=0.7.5;
interface IOlympusAuthority {
event GovernorPushed(address indexed from, address indexed to, bool _effectiveImmediately);
event GuardianPushed(address indexed from, address indexed to, bool _effectiveImmediately);
event PolicyPushed(address indexed from, address indexed to, bool _effectiveImmediately);
event VaultPushed(address indexed from, address indexed to, bool _effectiveImmediately);
event GovernorPulled(address indexed from, address indexed to);
event GuardianPulled(address indexed from, address indexed to);
event PolicyPulled(address indexed from, address indexed to);
event VaultPulled(address indexed from, address indexed to);
function governor() external view returns (address);
function guardian() external view returns (address);
function policy() external view returns (address);
function vault() external view returns (address);
}
文件 4 的 8:ITreasury.sol
pragma solidity >=0.7.5;
interface ITreasury {
function deposit(
uint256 _amount,
address _token,
uint256 _profit
) external returns (uint256);
function withdraw(uint256 _amount, address _token) external;
function tokenValue(address _token, uint256 _amount) external view returns (uint256 value_);
function mint(address _recipient, uint256 _amount) external;
function manage(address _token, uint256 _amount) external;
function incurDebt(uint256 amount_, address token_) external;
function repayDebtWithReserve(uint256 amount_, address token_) external;
function excessReserves() external view returns (uint256);
function baseSupply() external view returns (uint256);
}
文件 5 的 8:ITreasuryExtender.sol
pragma solidity ^0.8.10;
struct AllocatorPerformance {
uint128 gain;
uint128 loss;
}
struct AllocatorLimits {
uint128 allocated;
uint128 loss;
}
struct AllocatorHoldings {
uint256 allocated;
}
struct AllocatorData {
AllocatorHoldings holdings;
AllocatorLimits limits;
AllocatorPerformance performance;
}
interface ITreasuryExtender {
event NewDepositRegistered(address allocator, address token, uint256 id);
event AllocatorFunded(uint256 id, uint256 amount, uint256 value);
event AllocatorWithdrawal(uint256 id, uint256 amount, uint256 value);
event AllocatorRewardsWithdrawal(address allocator, uint256 amount, uint256 value);
event AllocatorReportedGain(uint256 id, uint128 gain);
event AllocatorReportedLoss(uint256 id, uint128 loss);
event AllocatorReportedMigration(uint256 id);
event AllocatorLimitsChanged(uint256 id, uint128 allocationLimit, uint128 lossLimit);
function registerDeposit(address newAllocator) external;
function setAllocatorLimits(uint256 id, AllocatorLimits memory limits) external;
function report(
uint256 id,
uint128 gain,
uint128 loss
) external;
function requestFundsFromTreasury(uint256 id, uint256 amount) external;
function returnFundsToTreasury(uint256 id, uint256 amount) external;
function returnRewardsToTreasury(
uint256 id,
address token,
uint256 amount
) external;
function getTotalAllocatorCount() external view returns (uint256);
function getAllocatorByID(uint256 id) external view returns (address);
function getAllocatorAllocated(uint256 id) external view returns (uint256);
function getAllocatorLimits(uint256 id) external view returns (AllocatorLimits memory);
function getAllocatorPerformance(uint256 id) external view returns (AllocatorPerformance memory);
}
文件 6 的 8:OlympusAccessControlledV2.sol
pragma solidity ^0.8.10;
import "../interfaces/IOlympusAuthority.sol";
error UNAUTHORIZED();
error AUTHORITY_INITIALIZED();
abstract contract OlympusAccessControlledV2 {
event AuthorityUpdated(IOlympusAuthority authority);
IOlympusAuthority public authority;
constructor(IOlympusAuthority _authority) {
authority = _authority;
emit AuthorityUpdated(_authority);
}
modifier onlyGovernor {
_onlyGovernor();
_;
}
modifier onlyGuardian {
_onlyGuardian();
_;
}
modifier onlyPolicy {
_onlyPolicy();
_;
}
modifier onlyVault {
_onlyVault();
_;
}
function initializeAuthority(IOlympusAuthority _newAuthority) internal {
if (authority != IOlympusAuthority(address(0))) revert AUTHORITY_INITIALIZED();
authority = _newAuthority;
emit AuthorityUpdated(_newAuthority);
}
function setAuthority(IOlympusAuthority _newAuthority) external {
_onlyGovernor();
authority = _newAuthority;
emit AuthorityUpdated(_newAuthority);
}
function _onlyGovernor() internal view {
if (msg.sender != authority.governor()) revert UNAUTHORIZED();
}
function _onlyGuardian() internal view {
if (msg.sender != authority.guardian()) revert UNAUTHORIZED();
}
function _onlyPolicy() internal view {
if (msg.sender != authority.policy()) revert UNAUTHORIZED();
}
function _onlyVault() internal view {
if (msg.sender != authority.vault()) revert UNAUTHORIZED();
}
}
文件 7 的 8:SafeERC20.sol
pragma solidity >=0.7.5;
import {IERC20} from "../interfaces/IERC20.sol";
library SafeERC20 {
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 amount
) internal {
(bool success, bytes memory data) = address(token).call(
abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, amount)
);
require(success && (data.length == 0 || abi.decode(data, (bool))), "TRANSFER_FROM_FAILED");
}
function safeTransfer(
IERC20 token,
address to,
uint256 amount
) internal {
(bool success, bytes memory data) = address(token).call(
abi.encodeWithSelector(IERC20.transfer.selector, to, amount)
);
require(success && (data.length == 0 || abi.decode(data, (bool))), "TRANSFER_FAILED");
}
function safeApprove(
IERC20 token,
address to,
uint256 amount
) internal {
(bool success, bytes memory data) = address(token).call(
abi.encodeWithSelector(IERC20.approve.selector, to, amount)
);
require(success && (data.length == 0 || abi.decode(data, (bool))), "APPROVE_FAILED");
}
function safeTransferETH(address to, uint256 amount) internal {
(bool success, ) = to.call{value: amount}(new bytes(0));
require(success, "ETH_TRANSFER_FAILED");
}
}
文件 8 的 8:TreasuryExtender.sol
pragma solidity ^0.8.10;
import "./interfaces/IERC20.sol";
import "./interfaces/ITreasury.sol";
import "./interfaces/IAllocator.sol";
import "./interfaces/ITreasuryExtender.sol";
import "./types/OlympusAccessControlledV2.sol";
import "./libraries/SafeERC20.sol";
error TreasuryExtender_AllocatorOffline();
error TreasuryExtender_AllocatorNotActivated();
error TreasuryExtender_AllocatorNotOffline();
error TreasuryExtender_AllocatorRegistered(uint256 id);
error TreasuryExtender_OnlyAllocator(uint256 id, address sender);
error TreasuryExtender_MaxAllocation(uint256 allocated, uint256 limit);
contract TreasuryExtender is OlympusAccessControlledV2, ITreasuryExtender {
using SafeERC20 for IERC20;
ITreasury public immutable treasury;
IAllocator[] public allocators;
mapping(IAllocator => mapping(uint256 => AllocatorData)) public allocatorData;
constructor(address treasuryAddress, address authorityAddress)
OlympusAccessControlledV2(IOlympusAuthority(authorityAddress))
{
treasury = ITreasury(treasuryAddress);
allocators.push(IAllocator(address(0)));
}
function _allocatorActivated(AllocatorStatus status) internal pure {
if (AllocatorStatus.ACTIVATED != status) revert TreasuryExtender_AllocatorNotActivated();
}
function _allocatorOffline(AllocatorStatus status) internal pure {
if (AllocatorStatus.OFFLINE != status) revert TreasuryExtender_AllocatorNotOffline();
}
function _onlyAllocator(
IAllocator byStatedId,
address sender,
uint256 id
) internal pure {
if (IAllocator(sender) != byStatedId) revert TreasuryExtender_OnlyAllocator(id, sender);
}
function registerDeposit(address newAllocator) external override onlyGuardian {
IAllocator allocator = IAllocator(newAllocator);
allocators.push(allocator);
uint256 id = allocators.length - 1;
allocator.addId(id);
emit NewDepositRegistered(newAllocator, address(allocator.tokens()[allocator.tokenIds(id)]), id);
}
function setAllocatorLimits(uint256 id, AllocatorLimits calldata limits) external override onlyGuardian {
IAllocator allocator = allocators[id];
_allocatorOffline(allocator.status());
allocatorData[allocator][id].limits = limits;
emit AllocatorLimitsChanged(id, limits.allocated, limits.loss);
}
function report(
uint256 id,
uint128 gain,
uint128 loss
) external override {
IAllocator allocator = allocators[id];
AllocatorData storage data = allocatorData[allocator][id];
AllocatorPerformance memory perf = data.performance;
AllocatorStatus status = allocator.status();
_onlyAllocator(allocator, msg.sender, id);
if (status == AllocatorStatus.OFFLINE) revert TreasuryExtender_AllocatorOffline();
if (gain >= loss) {
if (loss == type(uint128).max) {
AllocatorData storage newAllocatorData = allocatorData[allocators[allocators.length - 1]][id];
newAllocatorData.holdings.allocated = data.holdings.allocated;
newAllocatorData.performance.gain = data.performance.gain;
data.holdings.allocated = 0;
perf.gain = 0;
perf.loss = 0;
emit AllocatorReportedMigration(id);
} else {
perf.gain += gain;
emit AllocatorReportedGain(id, gain);
}
} else {
data.holdings.allocated -= loss;
perf.loss += loss;
emit AllocatorReportedLoss(id, loss);
}
data.performance = perf;
}
function requestFundsFromTreasury(uint256 id, uint256 amount) external override onlyGuardian {
IAllocator allocator = allocators[id];
AllocatorData memory data = allocatorData[allocator][id];
address token = address(allocator.tokens()[allocator.tokenIds(id)]);
uint256 value = treasury.tokenValue(token, amount);
_allocatorActivated(allocator.status());
_allocatorBelowLimit(data, amount);
treasury.manage(token, amount);
allocatorData[allocator][id].holdings.allocated += amount;
IERC20(token).safeTransfer(address(allocator), amount);
emit AllocatorFunded(id, amount, value);
}
function returnFundsToTreasury(uint256 id, uint256 amount) external override onlyGuardian {
IAllocator allocator = allocators[id];
uint256 allocated = allocatorData[allocator][id].holdings.allocated;
uint128 gain = allocatorData[allocator][id].performance.gain;
address token = address(allocator.tokens()[allocator.tokenIds(id)]);
if (amount > allocated) {
amount -= allocated;
if (amount > gain) {
amount = allocated + gain;
gain = 0;
} else {
gain -= uint128(amount);
amount += allocated;
}
allocated = 0;
} else {
allocated -= amount;
}
uint256 value = treasury.tokenValue(token, amount);
_allowTreasuryWithdrawal(IERC20(token));
IERC20(token).safeTransferFrom(address(allocator), address(this), amount);
allocatorData[allocator][id].holdings.allocated = allocated;
if (allocated == 0) allocatorData[allocator][id].performance.gain = gain;
assert(treasury.deposit(amount, token, value) == 0);
emit AllocatorWithdrawal(id, amount, value);
}
function returnRewardsToTreasury(
uint256 id,
address token,
uint256 amount
) external {
_returnRewardsToTreasury(allocators[id], IERC20(token), amount);
}
function returnRewardsToTreasury(
address allocatorAddress,
address token,
uint256 amount
) external {
_returnRewardsToTreasury(IAllocator(allocatorAddress), IERC20(token), amount);
}
function getAllocatorByID(uint256 id) external view override returns (address allocatorAddress) {
allocatorAddress = address(allocators[id]);
}
function getTotalAllocatorCount() external view returns (uint256) {
return allocators.length;
}
function getAllocatorLimits(uint256 id) external view override returns (AllocatorLimits memory) {
return allocatorData[allocators[id]][id].limits;
}
function getAllocatorPerformance(uint256 id) external view override returns (AllocatorPerformance memory) {
return allocatorData[allocators[id]][id].performance;
}
function getAllocatorAllocated(uint256 id) external view override returns (uint256) {
return allocatorData[allocators[id]][id].holdings.allocated;
}
function _returnRewardsToTreasury(
IAllocator allocator,
IERC20 token,
uint256 amount
) internal onlyGuardian {
uint256 balance = token.balanceOf(address(allocator));
amount = (balance < amount) ? balance : amount;
uint256 value = treasury.tokenValue(address(token), amount);
_allowTreasuryWithdrawal(token);
token.safeTransferFrom(address(allocator), address(this), amount);
assert(treasury.deposit(amount, address(token), value) == 0);
emit AllocatorRewardsWithdrawal(address(allocator), amount, value);
}
function _allowTreasuryWithdrawal(IERC20 token) internal {
if (token.allowance(address(this), address(treasury)) == 0) token.approve(address(treasury), type(uint256).max);
}
function _allocatorBelowLimit(AllocatorData memory data, uint256 amount) internal pure {
uint256 newAllocated = data.holdings.allocated + amount;
if (newAllocated > data.limits.allocated)
revert TreasuryExtender_MaxAllocation(newAllocated, data.limits.allocated);
}
}
{
"compilationTarget": {
"contracts/TreasuryExtender.sol": "TreasuryExtender"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "none",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 800
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"treasuryAddress","type":"address"},{"internalType":"address","name":"authorityAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"TreasuryExtender_AllocatorNotActivated","type":"error"},{"inputs":[],"name":"TreasuryExtender_AllocatorNotOffline","type":"error"},{"inputs":[],"name":"TreasuryExtender_AllocatorOffline","type":"error"},{"inputs":[{"internalType":"uint256","name":"allocated","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"TreasuryExtender_MaxAllocation","type":"error"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"sender","type":"address"}],"name":"TreasuryExtender_OnlyAllocator","type":"error"},{"inputs":[],"name":"UNAUTHORIZED","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"AllocatorFunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint128","name":"allocationLimit","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"lossLimit","type":"uint128"}],"name":"AllocatorLimitsChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint128","name":"gain","type":"uint128"}],"name":"AllocatorReportedGain","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint128","name":"loss","type":"uint128"}],"name":"AllocatorReportedLoss","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"}],"name":"AllocatorReportedMigration","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"allocator","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"AllocatorRewardsWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"AllocatorWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IOlympusAuthority","name":"authority","type":"address"}],"name":"AuthorityUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"allocator","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"}],"name":"NewDepositRegistered","type":"event"},{"inputs":[{"internalType":"contract IAllocator","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"allocatorData","outputs":[{"components":[{"internalType":"uint256","name":"allocated","type":"uint256"}],"internalType":"struct AllocatorHoldings","name":"holdings","type":"tuple"},{"components":[{"internalType":"uint128","name":"allocated","type":"uint128"},{"internalType":"uint128","name":"loss","type":"uint128"}],"internalType":"struct AllocatorLimits","name":"limits","type":"tuple"},{"components":[{"internalType":"uint128","name":"gain","type":"uint128"},{"internalType":"uint128","name":"loss","type":"uint128"}],"internalType":"struct AllocatorPerformance","name":"performance","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allocators","outputs":[{"internalType":"contract IAllocator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"authority","outputs":[{"internalType":"contract IOlympusAuthority","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getAllocatorAllocated","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getAllocatorByID","outputs":[{"internalType":"address","name":"allocatorAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getAllocatorLimits","outputs":[{"components":[{"internalType":"uint128","name":"allocated","type":"uint128"},{"internalType":"uint128","name":"loss","type":"uint128"}],"internalType":"struct AllocatorLimits","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getAllocatorPerformance","outputs":[{"components":[{"internalType":"uint128","name":"gain","type":"uint128"},{"internalType":"uint128","name":"loss","type":"uint128"}],"internalType":"struct AllocatorPerformance","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalAllocatorCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newAllocator","type":"address"}],"name":"registerDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint128","name":"gain","type":"uint128"},{"internalType":"uint128","name":"loss","type":"uint128"}],"name":"report","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"requestFundsFromTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"returnFundsToTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"allocatorAddress","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"returnRewardsToTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"returnRewardsToTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"uint128","name":"allocated","type":"uint128"},{"internalType":"uint128","name":"loss","type":"uint128"}],"internalType":"struct AllocatorLimits","name":"limits","type":"tuple"}],"name":"setAllocatorLimits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IOlympusAuthority","name":"_newAuthority","type":"address"}],"name":"setAuthority","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"contract ITreasury","name":"","type":"address"}],"stateMutability":"view","type":"function"}]