Address Contract Verified
Address
0x58907ad5c7eD1EaB5FdCc0Cc347F25bF5BC0e7da
Balance
0 ETH
Nonce
1
Code Size
6857 bytes
Creator
0xc1364aD8...a312 at tx 0x16675c4b...c8e7a0
Indexed Transactions
0
Contract Bytecode
6857 bytes
0x60806040526004361061013d575f3560e01c80621a55971461014857806301a4c2f81461016957806306fdde03146101885780631aac030c146101a95780631c2ca2fd146101ca5780631f660123146101f35780632e1a7d4d1461020757806333ba095714610226578063461632991461026657806352efea6e146102855780635f6550d5146102995780636c23ab4c146102b8578063715018a6146102cc5780637654f7ab146102e057806379ba5097146102f45780638da5cb5b146103085780639d80349b1461031c578063a4ba0b101461034f578063b4027ea81461036e578063ba7b67031461038d578063d0e30db0146103a2578063d4532dfd146103aa578063dd07d288146103dd578063e30c3978146103f2578063f2fde38b14610406578063f77c479114610425578063fd92bff214610207575f80fd5b3661014457005b5f80fd5b348015610153575f80fd5b505f5b6040519081526020015b60405180910390f35b348015610174575f80fd5b50610156610183366004611677565b610458565b348015610193575f80fd5b5061019c610646565b60405161016091906116b0565b3480156101b4575f80fd5b506101c86101c3366004611677565b6106d2565b005b3480156101d5575f80fd5b506101de6106df565b60408051928352602083019190915201610160565b3480156101fe575f80fd5b50610156610892565b348015610212575f80fd5b50610156610221366004611677565b610a75565b348015610231575f80fd5b506102597f000000000000000000000000a2e3356610840701bdf5611a53974510ae27e2e181565b60405161016091906116e2565b348015610271575f80fd5b506101c8610280366004611677565b610acd565b348015610290575f80fd5b50610156610b4d565b3480156102a4575f80fd5b506101566102b336600461170a565b610bcf565b3480156102c3575f80fd5b50610156610dbe565b3480156102d7575f80fd5b506101c8610dfd565b3480156102eb575f80fd5b50610156610e10565b3480156102ff575f80fd5b506101c8610e1e565b348015610313575f80fd5b50610259610e9c565b348015610327575f80fd5b506102597f00000000000000000000000079973d557cd9dd87eb61e250cc2572c990e2019681565b34801561035a575f80fd5b50610156610369366004611677565b610eaa565b348015610379575f80fd5b50610156610388366004611677565b61105a565b348015610398575f80fd5b5061015660035481565b6101c8611288565b3480156103b5575f80fd5b506102597f000000000000000000000000422f5accc812c396600010f224b320a743695f8581565b3480156103e8575f80fd5b5061015660025481565b3480156103fd575f80fd5b50610259611348565b348015610411575f80fd5b506101c8610420366004611738565b611357565b348015610430575f80fd5b506102597f000000000000000000000000396abf9ff46e21694f4ef01ca77c6d7893a017b281565b5f6104616113bd565b7f000000000000000000000000a2e3356610840701bdf5611a53974510ae27e2e15f8390036104ab5760405162461bcd60e51b81526004016104a290611753565b60405180910390fd5b6040516370a0823160e01b81526001600160a01b038216906370a08231906104d79030906004016116e2565b602060405180830381865afa1580156104f2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105169190611771565b8311156105355760405162461bcd60e51b81526004016104a290611788565b60405163a090728360e01b8152600481018490526001600160a01b0382169063a0907283906024015f604051808303815f87803b158015610574575f80fd5b505af1158015610586573d5f803e3d5ffd5b505050507f0000000000000000000000000000000000000000000000000de0b6b3a76400007f000000000000000000000000a2e3356610840701bdf5611a53974510ae27e2e16001600160a01b0316633ba0b9a96040518163ffffffff1660e01b8152600401602060405180830381865afa158015610607573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061062b9190611771565b61063590856117c4565b61063f91906117db565b9392505050565b60048054610653906117fa565b80601f016020809104026020016040519081016040528092919081815260200182805461067f906117fa565b80156106ca5780601f106106a1576101008083540402835291602001916106ca565b820191905f5260205f20905b8154815290600101906020018083116106ad57829003601f168201915b505050505081565b6106da6113bd565b600355565b60405163781364bd60e01b81525f9081907f00000000000000000000000079973d557cd9dd87eb61e250cc2572c990e201969082906001600160a01b0383169063781364bd906107339030906004016116e2565b5f60405180830381865afa15801561074d573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261077491908101906118ad565b80519091505f81900361078d57505f9485945092505050565b5f836001600160a01b0316630d6680876040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107ca573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107ee9190611771565b90505f5b82811015610889575f84828151811061080d5761080d6119a8565b6020026020010151905080608001515f146108285750610877565b82816060015161083891906119bc565b421015801561084857508060a001515b1561086357604081015161085c90896119bc565b9750610875565b604081015161087290886119bc565b96505b505b80610881816119cf565b9150506107f2565b50505050509091565b5f807f000000000000000000000000a2e3356610840701bdf5611a53974510ae27e2e16001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016108e091906116e2565b602060405180830381865afa1580156108fb573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061091f9190611771565b90505f7f000000000000000000000000422f5accc812c396600010f224b320a743695f856001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161096e91906116e2565b602060405180830381865afa158015610989573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109ad9190611771565b90507f0000000000000000000000000000000000000000000000000de0b6b3a76400007f000000000000000000000000a2e3356610840701bdf5611a53974510ae27e2e16001600160a01b0316633ba0b9a96040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a2c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a509190611771565b610a5a83856119bc565b610a6491906117c4565b610a6e91906117db565b9250505090565b5f7f000000000000000000000000396abf9ff46e21694f4ef01ca77c6d7893a017b26001600160a01b03163314610abe5760405162461bcd60e51b81526004016104a2906119e7565b610ac78261141c565b92915050565b610ad56113bd565b60405163b13acedd60e01b8152600481018290527f00000000000000000000000079973d557cd9dd87eb61e250cc2572c990e201966001600160a01b03169063b13acedd906024015f604051808303815f87803b158015610b34575f80fd5b505af1158015610b46573d5f803e3d5ffd5b5050505050565b5f7f000000000000000000000000396abf9ff46e21694f4ef01ca77c6d7893a017b26001600160a01b03163314610b965760405162461bcd60e51b81526004016104a2906119e7565b478015610bcb57610bc77f000000000000000000000000396abf9ff46e21694f4ef01ca77c6d7893a017b28261146d565b8091505b5090565b5f610bd86113bd565b825f03610bf75760405162461bcd60e51b81526004016104a290611753565b47831115610c175760405162461bcd60e51b81526004016104a290611788565b6040516370a0823160e01b81527f000000000000000000000000a2e3356610840701bdf5611a53974510ae27e2e1905f906001600160a01b038316906370a0823190610c679030906004016116e2565b602060405180830381865afa158015610c82573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ca69190611771565b9050816001600160a01b031663f340fa0186866040518363ffffffff1660e01b8152600401610cd591906116e2565b5f604051808303818588803b158015610cec575f80fd5b505af1158015610cfe573d5f803e3d5ffd5b50506040516370a0823160e01b81528493506001600160a01b03861692506370a082319150610d319030906004016116e2565b602060405180830381865afa158015610d4c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d709190611771565b610d7a9190611a0f565b60408051878152602081018390529194507f29c78d6f3bc4be22a7d3b080c2ee4dd05e0cabf415da6e105dce069930d4062b910160405180910390a1505092915050565b5f478180610dca6106df565b91509150610dd6610892565b81610de184866119bc565b610deb91906119bc565b610df591906119bc565b935050505090565b610e056113bd565b610e0e5f611511565b565b5f610e19610dbe565b905090565b3380610e28611348565b6001600160a01b031614610e905760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016104a2565b610e9981611511565b50565b5f546001600160a01b031690565b5f610eb36113bd565b815f03610ed25760405162461bcd60e51b81526004016104a290611753565b610f1d7f000000000000000000000000a2e3356610840701bdf5611a53974510ae27e2e17f000000000000000000000000422f5accc812c396600010f224b320a743695f858461152a565b6040516311f9fbc960e21b81526001600160a01b037f000000000000000000000000422f5accc812c396600010f224b320a743695f8516906347e7ef2490610f6b9030908690600401611a22565b6020604051808303815f875af1158015610f87573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fab9190611771565b9050805f03610fee5760405162461bcd60e51b815260206004820152600f60248201526e6d696e74207a65726f20736861726560881b60448201526064016104a2565b604080518381526020810183905230917f000000000000000000000000422f5accc812c396600010f224b320a743695f856001600160a01b0316917f3b6ddb74a836538977a46805c3f29a3ea63f9caabc0a0ad0ffae36ec611ea35691015b60405180910390a3919050565b5f6110636113bd565b815f036110825760405162461bcd60e51b81526004016104a290611753565b6040516370a0823160e01b81526001600160a01b037f000000000000000000000000a2e3356610840701bdf5611a53974510ae27e2e116906370a08231906110ce9030906004016116e2565b602060405180830381865afa1580156110e9573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061110d9190611771565b60405163f3fef3a360e01b81529091506001600160a01b037f000000000000000000000000422f5accc812c396600010f224b320a743695f85169063f3fef3a39061115e9030908690600401611a22565b5f604051808303815f87803b158015611175575f80fd5b505af1158015611187573d5f803e3d5ffd5b50506040516370a0823160e01b81528392506001600160a01b037f000000000000000000000000a2e3356610840701bdf5611a53974510ae27e2e11691506370a08231906111d99030906004016116e2565b602060405180830381865afa1580156111f4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112189190611771565b6112229190611a0f565b604080518481526020810183905291925030917f000000000000000000000000422f5accc812c396600010f224b320a743695f856001600160a01b0316917f77e35408ff044a9c6ce57c6d1f0795af280d3ca2e043065997f5f92c0af57463910161104d565b7f000000000000000000000000396abf9ff46e21694f4ef01ca77c6d7893a017b26001600160a01b031633146112d05760405162461bcd60e51b81526004016104a2906119e7565b426003546002546112e191906119bc565b11156113235760405162461bcd60e51b81526020600482015260116024820152706174207468652073616d6520626c6f636b60781b60448201526064016104a2565b345f036113425760405162461bcd60e51b81526004016104a290611a3b565b42600255565b6001546001600160a01b031690565b61135f6113bd565b600180546001600160a01b0319166001600160a01b038316908117909155611385610e9c565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b336113c6610e9c565b6001600160a01b031614610e0e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104a2565b5f815f0361143c5760405162461bcd60e51b81526004016104a290611a3b565b50806114687f000000000000000000000000396abf9ff46e21694f4ef01ca77c6d7893a017b28261146d565b919050565b604080515f808252602082019092526001600160a01b0384169083906040516114969190611a5f565b5f6040518083038185875af1925050503d805f81146114d0576040519150601f19603f3d011682016040523d82523d5f602084013e6114d5565b606091505b505090508061150c5760405162461bcd60e51b815260206004820152600360248201526253544560e81b60448201526064016104a2565b505050565b600180546001600160a01b0319169055610e9981611628565b5f80846001600160a01b031663095ea7b360e01b8585604051602401611551929190611a22565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161158f9190611a5f565b5f604051808303815f865af19150503d805f81146115c8576040519150601f19603f3d011682016040523d82523d5f602084013e6115cd565b606091505b50915091508180156115f75750805115806115f75750808060200190518101906115f79190611a7a565b610b465760405162461bcd60e51b8152602060048201526002602482015261534160f01b60448201526064016104a2565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f60208284031215611687575f80fd5b5035919050565b5f5b838110156116a8578181015183820152602001611690565b50505f910152565b602081525f82518060208401526116ce81604085016020870161168e565b601f01601f19169190910160400192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0381168114610e99575f80fd5b5f806040838503121561171b575f80fd5b82359150602083013561172d816116f6565b809150509250929050565b5f60208284031215611748575f80fd5b813561063f816116f6565b6020808252600490820152637a65726f60e01b604082015260600190565b5f60208284031215611781575f80fd5b5051919050565b6020808252600e908201526d6578636565642062616c616e636560901b604082015260600190565b634e487b7160e01b5f52601160045260245ffd5b8082028115828204841417610ac757610ac76117b0565b5f826117f557634e487b7160e01b5f52601260045260245ffd5b500490565b600181811c9082168061180e57607f821691505b60208210810361182c57634e487b7160e01b5f52602260045260245ffd5b50919050565b634e487b7160e01b5f52604160045260245ffd5b60405160c081016001600160401b038111828210171561186857611868611832565b60405290565b604051601f8201601f191681016001600160401b038111828210171561189657611896611832565b604052919050565b80518015158114611468575f80fd5b5f60208083850312156118be575f80fd5b82516001600160401b03808211156118d4575f80fd5b818501915085601f8301126118e7575f80fd5b8151818111156118f9576118f9611832565b611907848260051b0161186e565b818152848101925060c0918202840185019188831115611925575f80fd5b938501935b8285101561199c5780858a031215611941575f8081fd5b611949611846565b8551611954816116f6565b8152858701518782015260408087015190820152606080870151908201526080808701519082015260a061198981880161189e565b908201528452938401939285019261192a565b50979650505050505050565b634e487b7160e01b5f52603260045260245ffd5b80820180821115610ac757610ac76117b0565b5f600182016119e0576119e06117b0565b5060010190565b6020808252600e908201526d3737ba1031b7b73a3937b63632b960911b604082015260600190565b81810381811115610ac757610ac76117b0565b6001600160a01b03929092168252602082015260400190565b6020808252600a90820152697a65726f2076616c756560b01b604082015260600190565b5f8251611a7081846020870161168e565b9190910192915050565b5f60208284031215611a8a575f80fd5b61063f8261189e56fea264697066735822122049366cc25e4f6913a1167a9fbaab3b5807cff3925b4b9dffdddf386dae32703d64736f6c63430008150033
Verified Source Code Full Match
Compiler: v0.8.21+commit.d9974bed
EVM: shanghai
Optimization: Yes (10 runs)
AssetsVault.sol 44 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
import {TransferHelper} from "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol";
contract AssetsVault {
address public stoneVault;
address public strategyController;
modifier onlyPermit() {
require(
stoneVault == msg.sender || strategyController == msg.sender,
"not permit"
);
_;
}
constructor(address _stoneVault, address _strategyController) {
require(
_stoneVault != address(0) && _strategyController != address(0),
"ZERO ADDRESS"
);
stoneVault = _stoneVault;
strategyController = _strategyController;
}
function deposit() external payable {
require(msg.value != 0, "too small");
}
function withdraw(address _to, uint256 _amount) external onlyPermit {
TransferHelper.safeTransferETH(_to, _amount);
}
function setNewVault(address _vault) external onlyPermit {
stoneVault = _vault;
}
function getBalance() external view returns (uint256 amount) {
amount = address(this).balance;
}
receive() external payable {}
}
IWBETH.sol 12 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
interface IWBETH {
function deposit(address referral) external payable;
function exchangeRate() external view returns (uint256 _exchangeRate);
function balanceOf(address account) external view returns (uint256);
function requestWithdrawEth(uint256 wbethAmount) external;
}
Context.sol 24 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
Ownable.sol 83 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
Strategy.sol 92 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
import {StrategyController} from "../strategies/StrategyController.sol";
abstract contract Strategy {
address payable public immutable controller;
address public governance;
uint256 public latestUpdateTime;
uint256 public bufferTime = 12;
string public name;
modifier onlyGovernance() {
require(governance == msg.sender, "not governace");
_;
}
modifier notAtSameBlock() {
require(
latestUpdateTime + bufferTime <= block.timestamp,
"at the same block"
);
_;
}
event TransferGovernance(address oldOwner, address newOwner);
constructor(address payable _controller, string memory _name) {
require(_controller != address(0), "ZERO ADDRESS");
governance = msg.sender;
controller = _controller;
name = _name;
}
modifier onlyController() {
require(controller == msg.sender, "not controller");
_;
}
function deposit() public payable virtual onlyController notAtSameBlock {}
function withdraw(
uint256 _amount
)
public
virtual
onlyController
notAtSameBlock
returns (uint256 actualAmount)
{}
function instantWithdraw(
uint256 _amount
)
public
virtual
onlyController
notAtSameBlock
returns (uint256 actualAmount)
{}
function clear() public virtual onlyController returns (uint256 amount) {}
function execPendingRequest(
uint256 _amount
) public virtual returns (uint256 amount) {}
function getAllValue() public virtual returns (uint256 value) {}
function getPendingValue() public virtual returns (uint256 value) {}
function getInvestedValue() public virtual returns (uint256 value) {}
function checkPendingStatus()
public
virtual
returns (uint256 pending, uint256 executable)
{}
function setGovernance(address governance_) external onlyGovernance {
emit TransferGovernance(governance, governance_);
governance = governance_;
}
function setBufferTime(uint256 _time) external onlyGovernance {
bufferTime = _time;
}
}
StrategyV2.sol 68 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
import {StrategyController} from "../strategies/StrategyController.sol";
import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol";
abstract contract StrategyV2 is Ownable2Step {
address payable public immutable controller;
uint256 public latestUpdateTime;
uint256 public bufferTime;
string public name;
modifier notAtSameBlock() {
require(
latestUpdateTime + bufferTime <= block.timestamp,
"at the same block"
);
_;
}
constructor(address payable _controller, string memory _name) {
require(_controller != address(0), "ZERO ADDRESS");
controller = _controller;
name = _name;
}
modifier onlyController() {
require(controller == msg.sender, "not controller");
_;
}
function deposit() public payable virtual onlyController notAtSameBlock {}
function withdraw(
uint256 _amount
)
public
virtual
onlyController
notAtSameBlock
returns (uint256 actualAmount)
{}
function instantWithdraw(
uint256 _amount
)
public
virtual
onlyController
notAtSameBlock
returns (uint256 actualAmount)
{}
function clear() public virtual onlyController returns (uint256 amount) {}
function getAllValue() public virtual returns (uint256 value) {}
function getPendingValue() public virtual returns (uint256 value) {}
function getInvestedValue() public virtual returns (uint256 value) {}
function setBufferTime(uint256 _time) external onlyOwner {
bufferTime = _time;
}
}
ICollateral.sol 11 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
interface ICollateral {
function deposit(
address recipient,
uint256 amount
) external returns (uint256);
function withdraw(address recipient, uint256 amount) external;
}
IERC20.sol 78 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
Ownable2Step.sol 57 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)
pragma solidity ^0.8.0;
import "./Ownable.sol";
/**
* @dev Contract module which provides access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership} and {acceptOwnership}.
*
* This module is used through inheritance. It will make available all functions
* from parent (Ownable).
*/
abstract contract Ownable2Step is Ownable {
address private _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
/**
* @dev Returns the address of the pending owner.
*/
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
/**
* @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual override onlyOwner {
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
/**
* @dev The new owner accepts the ownership transfer.
*/
function acceptOwnership() public virtual {
address sender = _msgSender();
require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
_transferOwnership(sender);
}
}
IUnwrapTokenV1ETH.sol 40 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
interface IUnwrapTokenV1ETH {
struct WithdrawRequest {
address recipient; // user who withdraw
uint256 wbethAmount; //WBETH
uint256 ethAmount; //ETH
uint256 triggerTime; //user trigger time
uint256 claimTime; //user claim time
bool allocated; //is it allocated
}
function lockTime() external view returns (uint256);
function getUserWithdrawRequests(
address _recipient
) external view returns (WithdrawRequest[] memory);
function getWithdrawRequests(
uint256 _startIndex
) external view returns (WithdrawRequest[] memory);
function claimWithdraw(uint256 _index) external;
// testing
function getNeedRechargeEthAmount() external view returns (uint256);
function allocate(uint256 _maxAllocateNum) external returns (uint256);
function rechargeFromRechargeAddress() external payable;
function startAllocatedEthIndex() external view returns (uint256);
function nextIndex() external view returns (uint256);
function rechargeAddress() external view returns (address);
function operatorAddress() external view returns (address);
}
StrategyController.sol 329 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {TransferHelper} from "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol";
import {Strategy} from "./Strategy.sol";
import {AssetsVault} from "../AssetsVault.sol";
contract StrategyController {
using EnumerableSet for EnumerableSet.AddressSet;
uint256 internal constant ONE_HUNDRED_PERCENT = 1e6;
address public stoneVault;
address payable public immutable assetsVault;
EnumerableSet.AddressSet private strategies;
mapping(address => uint256) public ratios;
struct StrategyDiff {
address strategy;
bool isDeposit;
uint256 amount;
}
modifier onlyVault() {
require(stoneVault == msg.sender, "not vault");
_;
}
constructor(
address payable _assetsVault,
address[] memory _strategies,
uint256[] memory _ratios
) {
require(_assetsVault != address(0), "ZERO ADDRESS");
uint256 length = _strategies.length;
for (uint256 i; i < length; i++) {
require(_strategies[i] != address(0), "ZERO ADDRESS");
}
stoneVault = msg.sender;
assetsVault = _assetsVault;
_initStrategies(_strategies, _ratios);
}
function forceWithdraw(
uint256 _amount
) external onlyVault returns (uint256 actualAmount) {
uint256 balanceBeforeRepay = address(this).balance;
if (balanceBeforeRepay >= _amount) {
_repayToVault();
actualAmount = _amount;
} else {
actualAmount =
_forceWithdraw(_amount - balanceBeforeRepay) +
balanceBeforeRepay;
}
}
function setStrategies(
address[] memory _strategies,
uint256[] memory _ratios
) external onlyVault {
_setStrategies(_strategies, _ratios);
}
function addStrategy(address _strategy) external onlyVault {
require(!strategies.contains(_strategy), "already exist");
strategies.add(_strategy);
}
function rebaseStrategies(
uint256 _in,
uint256 _out
) external payable onlyVault {
_rebase(_in, _out);
}
function destroyStrategy(address _strategy) external onlyVault {
_destoryStrategy(_strategy);
}
function _rebase(uint256 _in, uint256 _out) internal {
require(_in == 0 || _out == 0, "only deposit or withdraw");
if (_in != 0) {
AssetsVault(assetsVault).withdraw(address(this), _in);
}
uint256 total = getAllStrategyValidValue();
if (total < _out) {
total = 0;
} else {
total = total + _in - _out;
}
uint256 length = strategies.length();
StrategyDiff[] memory diffs = new StrategyDiff[](length);
uint256 head;
uint256 tail = length - 1;
for (uint i; i < length; i++) {
address strategy = strategies.at(i);
if (ratios[strategy] == 0) {
_clearStrategy(strategy, true);
continue;
}
uint256 newPosition = (total * ratios[strategy]) /
ONE_HUNDRED_PERCENT;
uint256 position = getStrategyValidValue(strategy);
if (newPosition < position) {
diffs[head] = StrategyDiff(
strategy,
false,
position - newPosition
);
head++;
} else if (newPosition > position) {
diffs[tail] = StrategyDiff(
strategy,
true,
newPosition - position
);
if (tail != 0) {
tail--;
}
}
}
length = diffs.length;
for (uint256 i; i < length; i++) {
StrategyDiff memory diff = diffs[i];
if (diff.amount == 0) {
continue;
}
if (diff.isDeposit) {
if (address(this).balance < diff.amount) {
diff.amount = address(this).balance;
}
_depositToStrategy(diff.strategy, diff.amount);
} else {
_withdrawFromStrategy(diff.strategy, diff.amount);
}
}
_repayToVault();
}
function _repayToVault() internal {
if (address(this).balance != 0) {
TransferHelper.safeTransferETH(assetsVault, address(this).balance);
}
}
function _depositToStrategy(address _strategy, uint256 _amount) internal {
Strategy(_strategy).deposit{value: _amount}();
}
function _withdrawFromStrategy(
address _strategy,
uint256 _amount
) internal {
Strategy(_strategy).withdraw(_amount);
}
function _forceWithdraw(
uint256 _amount
) internal returns (uint256 actualAmount) {
uint256 length = strategies.length();
uint256 allRatios;
for (uint i; i < length; i++) {
address strategy = strategies.at(i);
allRatios += ratios[strategy];
}
for (uint i; i < length; i++) {
address strategy = strategies.at(i);
uint256 withAmount = (_amount * ratios[strategy]) / allRatios;
if (withAmount != 0) {
actualAmount =
Strategy(strategy).instantWithdraw(withAmount) +
actualAmount;
}
}
_repayToVault();
}
function getStrategyValue(
address _strategy
) public returns (uint256 _value) {
return Strategy(_strategy).getAllValue();
}
function getStrategyValidValue(
address _strategy
) public returns (uint256 _value) {
return Strategy(_strategy).getInvestedValue();
}
function getStrategyPendingValue(
address _strategy
) public returns (uint256 _value) {
return Strategy(_strategy).getPendingValue();
}
function getAllStrategiesValue() public returns (uint256 _value) {
uint256 length = strategies.length();
for (uint i; i < length; i++) {
_value = _value + getStrategyValue(strategies.at(i));
}
}
function getAllStrategyValidValue() public returns (uint256 _value) {
uint256 length = strategies.length();
for (uint i; i < length; i++) {
_value = _value + getStrategyValidValue(strategies.at(i));
}
}
function getAllStrategyPendingValue() public returns (uint256 _value) {
uint256 length = strategies.length();
for (uint i; i < length; i++) {
_value = _value + getStrategyPendingValue(strategies.at(i));
}
}
function getStrategies()
public
view
returns (address[] memory addrs, uint256[] memory portions)
{
uint256 length = strategies.length();
addrs = new address[](length);
portions = new uint256[](length);
for (uint256 i; i < length; i++) {
address addr = strategies.at(i);
addrs[i] = addr;
portions[i] = ratios[addr];
}
}
function _initStrategies(
address[] memory _strategies,
uint256[] memory _ratios
) internal {
require(_strategies.length == _ratios.length, "invalid length");
uint256 totalRatio;
uint256 length = _strategies.length;
for (uint i; i < length; i++) {
strategies.add(_strategies[i]);
ratios[_strategies[i]] = _ratios[i];
totalRatio = totalRatio + _ratios[i];
}
require(totalRatio <= ONE_HUNDRED_PERCENT, "exceed 100%");
}
function _setStrategies(
address[] memory _strategies,
uint256[] memory _ratios
) internal {
uint256 length = _strategies.length;
require(length == _ratios.length, "invalid length");
uint256 oldLength = strategies.length();
for (uint i; i < oldLength; i++) {
ratios[strategies.at(i)] = 0;
}
uint256 totalRatio;
for (uint i; i < length; i++) {
require(
Strategy(_strategies[i]).controller() == address(this),
"controller mismatch"
);
strategies.add(_strategies[i]);
ratios[_strategies[i]] = _ratios[i];
totalRatio = totalRatio + _ratios[i];
}
require(totalRatio <= ONE_HUNDRED_PERCENT, "exceed 100%");
}
function clearStrategy(address _strategy) public onlyVault {
_clearStrategy(_strategy, false);
}
function _clearStrategy(address _strategy, bool _isRebase) internal {
Strategy(_strategy).clear();
if (!_isRebase) {
_repayToVault();
}
}
function _destoryStrategy(address _strategy) internal {
require(_couldDestroyStrategy(_strategy), "still active");
strategies.remove(_strategy);
_repayToVault();
}
function _couldDestroyStrategy(
address _strategy
) internal returns (bool status) {
return
ratios[_strategy] == 0 && Strategy(_strategy).getAllValue() < 1e4;
}
function setNewVault(address _vault) external onlyVault {
stoneVault = _vault;
}
receive() external payable {}
}
EnumerableSet.sol 378 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}
TransferHelper.sol 60 lines
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.6.0;
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
library TransferHelper {
/// @notice Transfers tokens from the targeted address to the given destination
/// @notice Errors with 'STF' if transfer fails
/// @param token The contract address of the token to be transferred
/// @param from The originating address from which the tokens will be transferred
/// @param to The destination address of the transfer
/// @param value The amount to be transferred
function safeTransferFrom(
address token,
address from,
address to,
uint256 value
) internal {
(bool success, bytes memory data) =
token.call(abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'STF');
}
/// @notice Transfers tokens from msg.sender to a recipient
/// @dev Errors with ST if transfer fails
/// @param token The contract address of the token which will be transferred
/// @param to The recipient of the transfer
/// @param value The value of the transfer
function safeTransfer(
address token,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'ST');
}
/// @notice Approves the stipulated contract to spend the given allowance in the given token
/// @dev Errors with 'SA' if transfer fails
/// @param token The contract address of the token to be approved
/// @param to The target of the approval
/// @param value The amount of the given token the target will be allowed to spend
function safeApprove(
address token,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.approve.selector, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'SA');
}
/// @notice Transfers ETH to the recipient address
/// @dev Fails with `STE`
/// @param to The destination of the transfer
/// @param value The value to be transferred
function safeTransferETH(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}(new bytes(0));
require(success, 'STE');
}
}
SymbioticDepositWBETHStrategy.sol 216 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
import {TransferHelper} from "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {StrategyV2} from "../strategies/StrategyV2.sol";
import {StrategyController} from "../strategies/StrategyController.sol";
import {IWBETH} from "../interfaces/IWBETH.sol";
import {IUnwrapTokenV1ETH} from "../interfaces/IUnwrapTokenV1ETH.sol";
import {ICollateral} from "../interfaces/ICollateral.sol";
contract SymbioticDepositWBETHStrategy is StrategyV2 {
address public immutable wbETHAddr;
address public immutable unwrapTokenV1ETHAddr;
address public immutable collateralAddr;
uint256 internal immutable MULTIPLIER = 1e18;
event WrapToWBETH(uint256 etherAmount, uint256 wbETHAmount);
event DepositIntoSymbiotic(
address indexed collateral,
address indexed recipient,
uint256 amount,
uint256 share
);
event WithdrawFromSymbiotic(
address indexed collateral,
address indexed recipient,
uint256 share,
uint256 amount
);
constructor(
address payable _controller,
address _wbETHAddr,
address _unwrapTokenV1ETHAddr,
address _collateralAddr,
string memory _name
) StrategyV2(_controller, _name) {
wbETHAddr = _wbETHAddr;
unwrapTokenV1ETHAddr = _unwrapTokenV1ETHAddr;
collateralAddr = _collateralAddr;
}
function deposit() public payable override onlyController notAtSameBlock {
require(msg.value != 0, "zero value");
latestUpdateTime = block.timestamp;
}
function withdraw(
uint256 _amount
) public override onlyController returns (uint256 actualAmount) {
actualAmount = _withdraw(_amount);
}
function instantWithdraw(
uint256 _amount
) public override onlyController returns (uint256 actualAmount) {
actualAmount = _withdraw(_amount);
}
function clear() public override onlyController returns (uint256 amount) {
uint256 balance = address(this).balance;
if (balance != 0) {
TransferHelper.safeTransferETH(controller, balance);
amount = balance;
}
}
function _withdraw(
uint256 _amount
) internal returns (uint256 actualAmount) {
require(_amount != 0, "zero value");
actualAmount = _amount;
TransferHelper.safeTransferETH(controller, actualAmount);
}
function getAllValue() public override returns (uint256 value) {
value = getInvestedValue();
}
function getInvestedValue() public override returns (uint256 value) {
uint256 etherValue = address(this).balance;
(uint256 claimableValue, uint256 pendingValue) = checkPendingAssets();
value = etherValue + claimableValue + pendingValue + getWBETHValue();
}
function getWBETHValue() public view returns (uint256 value) {
uint256 wbBalance = IERC20(wbETHAddr).balanceOf(address(this));
uint256 depositValue = IERC20(collateralAddr).balanceOf(address(this));
value =
((wbBalance + depositValue) * IWBETH(wbETHAddr).exchangeRate()) /
MULTIPLIER;
}
function wrapToWBETH(
uint256 _ethAmount,
address _referral
) external onlyOwner returns (uint256 amount) {
require(_ethAmount != 0, "zero");
require(_ethAmount <= address(this).balance, "exceed balance");
IWBETH wbETH = IWBETH(wbETHAddr);
uint256 balanceBefore = wbETH.balanceOf(address(this));
wbETH.deposit{value: _ethAmount}(_referral);
amount = wbETH.balanceOf(address(this)) - balanceBefore;
emit WrapToWBETH(_ethAmount, amount);
}
function depositIntoSymbiotic(
uint256 _wbETHAmount
) external onlyOwner returns (uint256 shares) {
require(_wbETHAmount != 0, "zero");
TransferHelper.safeApprove(wbETHAddr, collateralAddr, _wbETHAmount);
shares = ICollateral(collateralAddr).deposit(
address(this),
_wbETHAmount
);
require(shares != 0, "mint zero share");
emit DepositIntoSymbiotic(
collateralAddr,
address(this),
_wbETHAmount,
shares
);
}
function withdrawFromSymbiotic(
uint256 _share
) external onlyOwner returns (uint256 wbETHAmount) {
require(_share != 0, "zero");
wbETHAmount = IWBETH(wbETHAddr).balanceOf(address(this));
ICollateral(collateralAddr).withdraw(address(this), _share);
wbETHAmount = IWBETH(wbETHAddr).balanceOf(address(this)) - wbETHAmount;
emit WithdrawFromSymbiotic(
collateralAddr,
address(this),
_share,
wbETHAmount
);
}
function requestToEther(
uint256 _amount
) external onlyOwner returns (uint256 etherAmount) {
IWBETH wbETH = IWBETH(wbETHAddr);
require(_amount != 0, "zero");
require(_amount <= wbETH.balanceOf(address(this)), "exceed balance");
wbETH.requestWithdrawEth(_amount);
etherAmount = (_amount * IWBETH(wbETHAddr).exchangeRate()) / MULTIPLIER;
}
function claimPendingAssets(uint256 _index) external onlyOwner {
IUnwrapTokenV1ETH(unwrapTokenV1ETHAddr).claimWithdraw(_index);
}
function checkPendingAssets()
public
view
returns (uint256 totalClaimable, uint256 totalPending)
{
IUnwrapTokenV1ETH unwrapTokenV1ETH = IUnwrapTokenV1ETH(
unwrapTokenV1ETHAddr
);
IUnwrapTokenV1ETH.WithdrawRequest[]
memory allRequests = unwrapTokenV1ETH.getUserWithdrawRequests(
address(this)
);
uint256 length = allRequests.length;
if (length == 0) {
return (0, 0);
}
uint256 lockTime = unwrapTokenV1ETH.lockTime();
for (uint256 i; i < length; i++) {
IUnwrapTokenV1ETH.WithdrawRequest memory request = allRequests[i];
if (request.claimTime != 0) {
continue;
}
if (
block.timestamp >= request.triggerTime + lockTime &&
request.allocated
) {
totalClaimable = totalClaimable + request.ethAmount;
} else {
totalPending = totalPending + request.ethAmount;
}
}
}
receive() external payable {}
}
Read Contract
bufferTime 0xba7b6703 → uint256
checkPendingAssets 0x1c2ca2fd → uint256, uint256
collateralAddr 0xd4532dfd → address
controller 0xf77c4791 → address
getWBETHValue 0x1f660123 → uint256
latestUpdateTime 0xdd07d288 → uint256
name 0x06fdde03 → string
owner 0x8da5cb5b → address
pendingOwner 0xe30c3978 → address
unwrapTokenV1ETHAddr 0x9d80349b → address
wbETHAddr 0x33ba0957 → address
Write Contract 16 functions
These functions modify contract state and require a wallet transaction to execute.
acceptOwnership 0x79ba5097
No parameters
claimPendingAssets 0x46163299
uint256 _index
clear 0x52efea6e
No parameters
returns: uint256
deposit 0xd0e30db0
No parameters
depositIntoSymbiotic 0xa4ba0b10
uint256 _wbETHAmount
returns: uint256
getAllValue 0x7654f7ab
No parameters
returns: uint256
getInvestedValue 0x6c23ab4c
No parameters
returns: uint256
getPendingValue 0x001a5597
No parameters
returns: uint256
instantWithdraw 0xfd92bff2
uint256 _amount
returns: uint256
renounceOwnership 0x715018a6
No parameters
requestToEther 0x01a4c2f8
uint256 _amount
returns: uint256
setBufferTime 0x1aac030c
uint256 _time
transferOwnership 0xf2fde38b
address newOwner
withdraw 0x2e1a7d4d
uint256 _amount
returns: uint256
withdrawFromSymbiotic 0xb4027ea8
uint256 _share
returns: uint256
wrapToWBETH 0x5f6550d5
uint256 _ethAmount
address _referral
returns: uint256
Recent Transactions
No transactions found for this address