Address Contract Partially Verified
Address
0x3Ae884D1a67650501278001FDa40DCa975D9194D
Balance
0 ETH
Nonce
1
Code Size
4630 bytes
Creator
0xA5B78700...7E48 at tx 0xc3d6998b...129e75
Indexed Transactions
0 (1 on-chain, 1.5% indexed)
Contract Bytecode
4630 bytes
0x60806040526004361015610011575f80fd5b5f3560e01c80634ccb7382146100ef578063576aaf88146100ea578063747edcef146100e55780637b103999146100e05780638321928d146100db5780638980f11f146100d65780638da5cb5b146100b35780639265a7d5146100d1578063969d98aa146100cc578063be338bc6146100c7578063cf33d032146100c2578063e4cedf4b146100bd578063ebfa72f8146100b85763f2f4eb26146100b3575f80fd5b610385565b61075f565b61073b565b6106a1565b61062b565b61052c565b6103c9565b6102e2565b6102b4565b610286565b61021d565b610121565b3461011d575f36600319011261011d5760206040517357ab1e0003f623289cd798b1824be09a793e4bec8152f35b5f80fd5b3461011d575f36600319011261011d57602060ff600254166040519015158152f35b634e487b7160e01b5f52604160045260245ffd5b90601f8019910116810190811067ffffffffffffffff82111761017957604052565b610143565b67ffffffffffffffff81116101795760051b60200190565b6001600160a01b0381160361011d57565b604435906101b482610196565b565b9080601f8301121561011d5781356101cd8161017e565b926101db6040519485610157565b81845260208085019260051b82010192831161011d57602001905b8282106102035750505090565b60208091833561021281610196565b8152019101906101f6565b3461011d57602036600319011261011d5760043567ffffffffffffffff811161011d57604061025a61025560209336906004016101b6565b6108b9565b815192839181835280519182918282860152018484015e5f828201840152601f01601f19168101030190f35b3461011d575f36600319011261011d5760206040517310101010e0c3171d894b71b3400668af311e7d948152f35b3461011d575f36600319011261011d57602060405173cf5540fffcdc3d510b18bfca6d2b9987b07725598152f35b3461011d57604036600319011261011d5761038361036760043561030581610196565b61037560243561033f337f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b031614610999565b60405163a9059cbb60e01b602082015233602482015260448101919091529283906064820190565b03601f198101845283610157565b6001600160a01b03166111b1565b005b3461011d575f36600319011261011d576040517f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b03168152602090f35b3461011d575f36600319011261011d5761040d337f000000000000000000000000c07e000044f95655c11fda4cd37f70a94d7e0a7d6001600160a01b031614610999565b61041f600160ff196002541617600255565b60405163303db68b60e11b81525f816004817310101010e0c3171d894b71b3400668af311e7d945afa9081156104fd575f9161050a575b505f5b81518110156105025780602061049361048761048761047a600496886107eb565b516001600160a01b031690565b6001600160a01b031690565b60405163d8dfeb4560e01b815293849182905afa9182156104fd576001926104c9915f916104cf575b50838060a01b0316610e2e565b01610459565b6104f0915060203d81116104f6575b6104e88183610157565b810190610a5c565b5f6104bc565b503d6104de565b610a51565b610383610f0d565b61052691503d805f833e61051e8183610157565b8101906109cd565b5f610456565b3461011d57608036600319011261011d57610548600435610196565b60443567ffffffffffffffff811161011d576105689036906004016101b6565b610573606435610196565b60025f541461061c575f61058b8192600283556108b9565b6020815191018273cf5540fffcdc3d510b18bfca6d2b9987b07725595af13d15610617573d6105b981610643565b906105c76040519283610157565b81525f60203d92013e5b156105df5761038360015f55565b60405162461bcd60e51b815260206004820152601060248201526f13d91bdcc81cddd85c0819985a5b195960821b6044820152606490fd5b6105d1565b633ee5aeb560e01b5f5260045ffd5b3461011d575f36600319011261011d57610383610a74565b67ffffffffffffffff811161017957601f01601f191660200190565b60206040818301928281528451809452019201905f5b8181106106825750505090565b82516001600160a01b0316845260209384019390920191600101610675565b3461011d57606036600319011261011d5760043567ffffffffffffffff811161011d573660238201121561011d578060040135906106de82610643565b6106eb6040519182610157565b828152366024848401011161011d575f60208461073795602461072b9601838601378301015260243561071d81610196565b6107256101a7565b91610c31565b6040519182918261065f565b0390f35b3461011d575f36600319011261011d576020610755610d8b565b6040519015158152f35b3461011d575f36600319011261011d576020600154604051908152f35b1561078357565b60405162461bcd60e51b815260206004820152600a60248201526908adae0e8f240e0c2e8d60b31b6044820152606490fd5b634e487b7160e01b5f52603260045260245ffd5b8051600110156107d95760400190565b6107b5565b8051156107d95760200190565b80518210156107d95760209160051b010190565b634e487b7160e01b5f52601160045260245ffd5b60011981019190821161082257565b6107ff565b5f1981019190821161082257565b9190820391821161082257565b805191908290602001825e015f815290565b6108619060149392610842565b906bffffffffffffffffffffffff199060601b1681520190565b1561088257565b60405162461bcd60e51b815260206004820152600f60248201526e098cadccee8d040dad2e6dac2e8c6d608b1b6044820152606490fd5b9060606108c88351151561077c565b6108da61048761048761047a866107c9565b926108e58151610813565b60025b81811061095d57506101b49261093e610928879461094c9461090e6109389a6014900690565b918215610954575b6109239161047a916107eb565b610df5565b6040519788936020850190610842565b90610842565b03601f198101865285610157565b83511461087b565b60149250610916565b9260019061099261097161047a87876107eb565b9161098460405193849260208401610854565b03601f198101835282610157565b93016108e8565b156109a057565b60405162461bcd60e51b815260206004820152600560248201526421636f726560d81b6044820152606490fd5b60208183031261011d5780519067ffffffffffffffff821161011d57019080601f8301121561011d578151610a018161017e565b92610a0f6040519485610157565b81845260208085019260051b82010192831161011d57602001905b828210610a375750505090565b602080918351610a4681610196565b815201910190610a2a565b6040513d5f823e3d90fd5b9081602091031261011d5751610a7181610196565b90565b610a83610a7f610d8b565b1590565b6101b45760015460405163303db68b60e11b8152915f836004817310101010e0c3171d894b71b3400668af311e7d945afa9283156104fd575f93610b47575b50905b8251811015610b4057806020610ae661048761048761047a600496896107eb565b60405163d8dfeb4560e01b815293849182905afa9182156104fd57600192610b1c915f91610b22575b50838060a01b0316611017565b01610ac5565b610b3a915060203d81116104f6576104e88183610157565b5f610b0f565b6001559050565b610b5c9193503d805f833e61051e8183610157565b915f610ac2565b906013820180921161082257565b906002820180921161082257565b906001820180921161082257565b906014820180921161082257565b90601f820180921161082257565b9190820180921161082257565b90610bc08261017e565b610bcd6040519182610157565b8281528092610bde601f199161017e565b0190602036910137565b9060148202918083046014149015171561082257565b60408051909190610c0f8382610157565b6014815291601f1901366020840137565b9081518110156107d9570160200190565b92919092805190610c4b610c4483610b63565b6014900490565b91610c81610c68610c63610c5e86610b71565b610b7f565b610bb6565b96610c72886107de565b6001600160a01b039091169052565b610c976001600160a01b038216610c72886107c9565b5f5b838110610cbb57505050506101b490610c72610cb58551610827565b856107eb565b610ce8610cc782610be8565b83610cd182610b8d565b1115610d7957610ce18185610835565b90856110d8565b6014815110610d19575b90610d13610d01600193611163565b610c72610d0d84610b71565b8b6107eb565b01610c99565b93610d2a9796929795919395610bfe565b955f5b8651811015610d675780610d54610d466001938a610c20565b516001600160f81b03191690565b5f1a610d60828b610c20565b5301610d2d565b50969792969195909450909290610cf2565b610ce181610d8681610b8d565b610835565b60ff600254161580610d9a5790565b5060015460405163303db68b60e11b81525f816004817310101010e0c3171d894b71b3400668af311e7d945afa9081156104fd575f91610ddb575b50511190565b610def91503d805f833e61051e8183610157565b5f610dd5565b9190610e19610e0382610643565b91610e116040519384610157565b808352610643565b602082019190601f19013683379260601b9052565b60405163095ea7b360e01b602080830191825273cf5540fffcdc3d510b18bfca6d2b9987b077255960248401525f604484018190529091610e72846064810161093e565b83519082865af15f51903d81610ee1575b501590505b610e90575050565b60405163095ea7b360e01b602082015273cf5540fffcdc3d510b18bfca6d2b9987b077255960248201525f60448201526101b49290610edc90610ed68160648101610984565b826111b1565b6111b1565b15159050610f015750610e886001600160a01b0383163b15155b5f610e83565b6001610e889114610efb565b60405163095ea7b360e01b602080830191825273cf5540fffcdc3d510b18bfca6d2b9987b077255960248401525f604484018190529091610f51846064810161093e565b835190827357ab1e0003f623289cd798b1824be09a793e4bec5af15f51903d81610fe0575b501590505b610f825750565b60405163095ea7b360e01b602082015273cf5540fffcdc3d510b18bfca6d2b9987b077255960248201525f60448201526101b49190610fc690818160648101610984565b7357ab1e0003f623289cd798b1824be09a793e4bec6111b1565b1515905061100b5750610f7b7357ab1e0003f623289cd798b1824be09a793e4bec3b15155b5f610f76565b6001610f7b9114611005565b60405163095ea7b360e01b602080830191825273cf5540fffcdc3d510b18bfca6d2b9987b077255960248401525f196044840152905f90610e72846064810161093e565b1561106257565b60405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606490fd5b1561109f57565b60405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606490fd5b916110ed816110e681610b9b565b101561105b565b61110383516110fc8385610ba9565b1115611098565b8061111b575050506040515f81526020810160405290565b60405192601f821692831560051b80858701019484860193010101905b8084106111505750508252601f01601f191660405290565b9092602080918551815201930190611138565b6014815103611173576014015190565b60405162461bcd60e51b81526020600482015260166024820152754368756e6b206d75737420626520323020627974657360501b6044820152606490fd5b905f602091828151910182855af115610a51575f513d61120057506001600160a01b0381163b155b6111e05750565b635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b600114156111d956fea164736f6c634300081c000a
Verified Source Code Partial Match
Compiler: v0.8.28+commit.7893614a
EVM: cancun
Optimization: Yes (200 runs)
SwapperOdos.sol 150 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import { CoreOwnable } from "src/dependencies/CoreOwnable.sol";
import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import { IResupplyRegistry } from "src/interfaces/IResupplyRegistry.sol";
import { IResupplyPair } from "src/interfaces/IResupplyPair.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { BytesLib } from "solidity-bytes-utils/contracts/BytesLib.sol";
contract SwapperOdos is CoreOwnable, ReentrancyGuard {
using BytesLib for bytes;
using SafeERC20 for IERC20;
address public constant odosRouter = 0xCf5540fFFCdC3d510B18bFcA6d2b9987b0772559;
address public constant registry = 0x10101010E0C3171D894B71B3400668aF311e7D94;
address public constant reusd = 0x57aB1E0003F623289CD798B1824Be09a793e4Bec;
uint256 public nextPairIndex;
bool public approvalsRevoked;
constructor(address _core) CoreOwnable(_core) {
IERC20(reusd).forceApprove(odosRouter, type(uint256).max);
}
/**
* @notice Executes a swap through Odos router using an encoded payload in the path parameter
* @dev This function accepts bytes data encoded as an address[] for compatibility with the legacy interface in PairCore
*/
function swap(
address,
uint256,
address[] memory _path,
address
) external nonReentrant {
bytes memory payload = decode(_path);
(bool success, bytes memory result) = odosRouter.call{value: 0}(payload);
require(success, "Odos swap failed");
}
/**
* @notice Permissionless function to update the approvals for the collateral tokens that have not yet been approved
*/
function updateApprovals() external {
if (!canUpdateApprovals()) return;
uint256 _nextIndex = nextPairIndex;
address[] memory pairs = IResupplyRegistry(registry).getAllPairAddresses();
for (; _nextIndex < pairs.length; _nextIndex++) {
address _pair = pairs[_nextIndex];
address _collateral = IResupplyPair(_pair).collateral();
IERC20(_collateral).forceApprove(odosRouter, type(uint256).max);
}
nextPairIndex = _nextIndex;
}
function revokeApprovals() external onlyOwner {
approvalsRevoked = true;
address[] memory pairs = IResupplyRegistry(registry).getAllPairAddresses();
for (uint256 i = 0; i < pairs.length; i++) {
address _pair = pairs[i];
address _collateral = IResupplyPair(_pair).collateral();
IERC20(_collateral).forceApprove(odosRouter, 0);
}
IERC20(reusd).forceApprove(odosRouter, 0);
}
/**
* @notice Returns true if there are new pairs to update approvals for
*/
function canUpdateApprovals() public view returns (bool) {
return !approvalsRevoked && nextPairIndex < IResupplyRegistry(registry).getAllPairAddresses().length;
}
/**
* @notice Encodes any-length bytes into address[] data type for transport via the interface on Resupply pairs
* @dev This function is not gas efficient, and should only be used by off-chain calls
to prepare a payload for the leveragedPosition or repayWithCollateral functions in a pair.
* @param payload The bytes payload to encode
* @return path The encoded address[]
*/
function encode(bytes memory payload, address _sellToken, address _buyToken) external pure returns (address[] memory path) {
uint totalLen = payload.length;
// determine the total number of chunks needed to store the payload
// each chunk is 20 bytes, so we add 19 to the total length to ensure result is always rounded up
uint chunkCount = (totalLen + 19) / 20;
uint dataStartIndex = 2; // index 0 = sell token, index 1 = payload length
path = new address[](chunkCount + dataStartIndex + 1);
path[0] = _sellToken;
path[1] = address(uint160(totalLen)); // packs into the low 20 bytes (safe)
for (uint i = 0; i < chunkCount; i++) {
uint offset = i * 20;
uint end = offset + 20 > totalLen ? totalLen : offset + 20;
bytes memory chunk = payload.slice(offset, end - offset);
// Pad to 20 bytes if needed
if (chunk.length < 20) {
bytes memory padded = new bytes(20);
for (uint j = 0; j < chunk.length; j++) {
padded[j] = chunk[j];
}
chunk = padded;
}
path[i + dataStartIndex] = bytesToAddress(chunk);
}
path[path.length - 1] = _buyToken; // final item is the buy token
}
/**
* @notice Decodes an address array back into its original bytes payload
* @dev The first address in the path contains the total length of the original payload as a uint96
* @dev Each subsequent address contains 20 bytes of the original payload
* @param path The address array containing the encoded payload
* @return payload The decoded bytes payload
*/
function decode(address[] memory path) public pure returns (bytes memory payload) {
require(path.length > 0, "Empty path");
uint totalLen = uint(uint160(path[1]));
uint dataStartIndex = 2;
uint lastDataIndex = path.length - 2;
// Append all complete chunks using abi.encodePacked
for (uint i = dataStartIndex; i < lastDataIndex;) {
payload = abi.encodePacked(payload, path[i]);
unchecked { i++; }
}
uint remainingBytes = totalLen % 20;
if(remainingBytes == 0){
remainingBytes = 20;
}
payload = abi.encodePacked(payload, addressToBytes(path[lastDataIndex], remainingBytes));
require(payload.length == totalLen, "Length mismatch");
}
function recoverERC20(address token, uint256 amount) external onlyOwner {
IERC20(token).safeTransfer(msg.sender, amount);
}
function bytesToAddress(bytes memory b) internal pure returns (address a) {
require(b.length == 20, "Chunk must be 20 bytes");
assembly {
a := mload(add(b, 20))
}
}
function addressToBytes(address a, uint256 size) internal pure returns (bytes memory b) {
b = new bytes(size);
assembly {
mstore(add(b, 32), shl(96, a))
}
}
}
CoreOwnable.sol 27 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {ICore} from "../interfaces/ICore.sol";
/**
@title Core Ownable
@author Prisma Finance (with edits by Resupply Finance)
@notice Contracts inheriting `CoreOwnable` have the same owner as `Core`.
The ownership cannot be independently modified or renounced.
*/
contract CoreOwnable {
ICore public immutable core;
constructor(address _core) {
core = ICore(_core);
}
modifier onlyOwner() {
require(msg.sender == address(core), "!core");
_;
}
function owner() public view returns (address) {
return address(core);
}
}
ReentrancyGuard.sol 87 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
* consider using {ReentrancyGuardTransient} instead.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be NOT_ENTERED
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
_status = ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}
IResupplyRegistry.sol 73 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
interface IResupplyRegistry {
event AddPair(address pairAddress);
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
event SetDeployer(address deployer, bool _bool);
event DefaultSwappersSet(address[] addresses);
event EntryUpdated(string indexed key, address indexed addr);
event WithdrawTo(address indexed user, uint256 amount);
// Protected keys
function LIQUIDATION_HANDLER() external pure returns (string memory);
function FEE_DEPOSIT() external pure returns (string memory);
function REDEMPTION_HANDLER() external pure returns (string memory);
function INSURANCE_POOL() external pure returns (string memory);
function REWARD_HANDLER() external pure returns (string memory);
function TREASURY() external pure returns (string memory);
function STAKER() external pure returns (string memory);
function L2_MANAGER() external pure returns (string memory);
function VEST_MANAGER() external pure returns (string memory);
// Other public functions
function token() external view returns (address);
function govToken() external view returns (address);
function getAddress(string memory key) external view returns (address);
function getAllKeys() external view returns (string[] memory);
function getAllAddresses() external view returns (address[] memory);
function getProtectedKeys() external pure returns (string[] memory);
function keyExists(string memory) external view returns (bool);
function hashToKey(bytes32) external view returns (string memory);
function setAddress(string memory key, address addr) external;
function acceptOwnership() external;
function addPair(address _pairAddress) external;
function registeredPairs(uint256) external view returns (address);
function pairsByName(string memory) external view returns (address);
function registeredPairsLength() external view returns (uint256);
function getAllPairAddresses() external view returns (address[] memory _deployedPairsArray);
function defaultSwappers(uint256 _index) external view returns (address);
function owner() external view returns (address);
function pendingOwner() external view returns (address);
function renounceOwnership() external;
function transferOwnership(address newOwner) external;
function claimFees(address _pair) external;
function claimRewards(address _pair) external;
function claimInsuranceRewards() external;
function withdrawTo(address _asset, uint256 _amount, address _to) external;
function mint(address receiver, uint256 amount) external;
function burn(address target, uint256 amount) external;
function liquidationHandler() external view returns(address);
function feeDeposit() external view returns(address);
function redemptionHandler() external view returns(address);
function rewardHandler() external view returns(address);
function insurancePool() external view returns(address);
function setRewardClaimer(address _newAddress) external;
function setRedemptionHandler(address _newAddress) external;
function setFeeDeposit(address _newAddress) external;
function setLiquidationHandler(address _newAddress) external;
function setInsurancePool(address _newAddress) external;
function setStaker(address _newAddress) external;
function setTreasury(address _newAddress) external;
function staker() external view returns(address);
function treasury() external view returns(address);
function l2manager() external view returns(address);
function setRewardHandler(address _newAddress) external;
function setVestManager(address _newAddress) external;
function setDefaultSwappers(address[] memory _swappers) external;
function collateralId(address _collateral) external view returns(uint256);
error NameMustBeUnique();
error ProtectedKey(string key);
}
IResupplyPair.sol 162 lines
pragma solidity 0.8.28;
interface IResupplyPair {
struct CurrentRateInfo {
uint64 lastTimestamp;
uint64 ratePerSec;
uint128 lastShares;
}
struct VaultAccount {
uint128 amount;
uint128 shares;
}
struct EarnedData {
address token;
uint256 amount;
}
function CRV( ) external view returns (address ) ;
function CVX( ) external view returns (address ) ;
function EXCHANGE_PRECISION( ) external view returns (uint256 ) ;
function LIQ_PRECISION( ) external view returns (uint256 ) ;
function LTV_PRECISION( ) external view returns (uint256 ) ;
function PAIR_DECIMALS( ) external view returns (uint256 ) ;
function RATE_PRECISION( ) external view returns (uint256 ) ;
function SHARE_REFACTOR_PRECISION( ) external view returns (uint256 ) ;
function addCollateral( uint256 _amount,address _borrower ) external ;
function addCollateralVault( uint256 _collateralAmount,address _borrower ) external ;
function addExtraReward( address _token ) external ;
function addInterest( bool _returnAccounting ) external returns (uint256 _interestEarned, CurrentRateInfo memory _currentRateInfo, uint256 _claimableFees, VaultAccount memory _totalBorrow) ;
function borrow( uint256 _borrowAmount,uint256 _underlyingAmount,address _receiver ) external returns (uint256 _shares) ;
function borrowLimit( ) external view returns (uint256 ) ;
function claimableFees( ) external view returns (uint256 ) ;
function claimableOtherFees( ) external view returns (uint256 ) ;
function claimable_reward( address ,address ) external view returns (uint256 ) ;
function collateral( ) external view returns (address ) ;
function convexBooster( ) external view returns (address ) ;
function convexPid( ) external view returns (uint256 ) ;
function core( ) external view returns (address ) ;
function currentRateInfo( ) external view returns (uint64 lastTimestamp, uint64 ratePerSec, uint128 lastShares) ;
function currentRewardEpoch( ) external view returns (uint256 ) ;
function currentUtilization( ) external view returns (uint256 ) ;
function earned( address _account ) external returns (EarnedData[] memory claimable) ;
function epochLength( ) external view returns (uint256 ) ;
function exchangeRateInfo( ) external view returns (address oracle, uint96 lastTimestamp, uint256 exchangeRate) ;
function getConstants( ) external pure returns (uint256 _LTV_PRECISION, uint256 _LIQ_PRECISION, uint256 _EXCHANGE_PRECISION, uint256 _RATE_PRECISION) ;
function getEpoch( ) external view returns (uint256 epoch) ;
function getPairAccounting( ) external view returns (uint256 _claimableFees, uint128 _totalBorrowAmount, uint128 _totalBorrowShares, uint256 _totalCollateral) ;
function getReward( address _account,address _forwardTo ) external ;
function getReward( address _account ) external ;
function getUserSnapshot( address _address ) external returns (uint256 _borrowShares, uint256 _collateralBalance) ;
function global_reward_integral( uint256 ,address ) external view returns (uint256 ) ;
function invalidateReward( address _token ) external ;
function lastFeeEpoch( ) external view returns (uint256 ) ;
function leveragedPosition( address _swapperAddress,uint256 _borrowAmount,uint256 _initialUnderlyingAmount,uint256 _amountCollateralOutMin,address[] memory _path ) external returns (uint256 _totalCollateralBalance) ;
function liquidate( address _borrower ) external returns (uint256 _collateralForLiquidator) ;
function liquidationFee( ) external view returns (uint256 ) ;
function maxLTV( ) external view returns (uint256 ) ;
function maxRewards( ) external pure returns (uint256 ) ;
function minimumBorrowAmount( ) external view returns (uint256 ) ;
function minimumLeftoverDebt( ) external view returns (uint256 ) ;
function minimumRedemption( ) external view returns (uint256 ) ;
function mintFee( ) external view returns (uint256 ) ;
function name( ) external view returns (string memory ) ;
function owner( ) external view returns (address ) ;
function pause( ) external ;
function previewAddInterest( ) external view returns (uint256 _interestEarned, CurrentRateInfo memory _newCurrentRateInfo, uint256 _claimableFees, VaultAccount memory _totalBorrow) ;
function protocolRedemptionFee( ) external view returns (uint256 ) ;
function rateCalculator( ) external view returns (address ) ;
function redeemCollateral( address _caller,uint256 _amount,uint256 _totalFeePct,address _receiver ) external returns (address _collateralToken, uint256 _collateralFreed) ;
function redemptionWriteOff( ) external view returns (address ) ;
function registry( ) external view returns (address ) ;
function removeCollateral( uint256 _collateralAmount,address _receiver ) external ;
function removeCollateralVault( uint256 _collateralAmount,address _receiver ) external ;
function repay( uint256 _shares,address _borrower ) external returns (uint256 _amountToRepay) ;
function repayWithCollateral( address _swapperAddress,uint256 _collateralToSwap,uint256 _amountOutMin,address[] memory _path ) external returns (uint256 _amountOut) ;
function rewardLength( ) external view returns (uint256 ) ;
function rewardMap( address ) external view returns (uint256 ) ;
function rewardRedirect( address ) external view returns (address ) ;
function reward_integral_for( uint256 ,address ,address ) external view returns (uint256 ) ;
function rewards( uint256 ) external view returns (address reward_token, bool is_non_claimable, uint256 reward_remaining) ;
function setBorrowLimit( uint256 _limit ) external ;
function setConvexPool( uint256 pid ) external ;
function setLiquidationFees( uint256 _newLiquidationFee ) external ;
function setMaxLTV( uint256 _newMaxLTV ) external ;
function setMinimumBorrowAmount( uint256 _min ) external ;
function setMinimumLeftoverDebt( uint256 _min ) external ;
function setMinimumRedemption( uint256 _min ) external ;
function setMintFees( uint256 _newMintFee ) external ;
function setOracle( address _newOracle ) external ;
function setProtocolRedemptionFee( uint256 _fee ) external ;
function setRateCalculator( address _newRateCalculator,bool _updateInterest ) external ;
function setRewardRedirect( address _to ) external ;
function setSwapper( address _swapper,bool _approval ) external ;
function startTime( ) external view returns (uint256 ) ;
function swappers( address ) external view returns (bool ) ;
function toBorrowAmount( uint256 _shares,bool _roundUp,bool _previewInterest ) external view returns (uint256 _amount) ;
function toBorrowShares( uint256 _amount,bool _roundUp,bool _previewInterest ) external view returns (uint256 _shares) ;
function totalBorrow( ) external view returns (uint128 amount, uint128 shares) ;
function totalCollateral( ) external view returns (uint256 _totalCollateralBalance) ;
function totalDebtAvailable( ) external view returns (uint256 ) ;
function underlying( ) external view returns (address ) ;
function unpause( ) external ;
function updateExchangeRate( ) external returns (uint256 _exchangeRate) ;
function userBorrowShares( address _account ) external view returns (uint256 borrowShares) ;
function userCollateralBalance( address _account ) external returns (uint256 _collateralAmount) ;
function userRewardEpoch( address ) external view returns (uint256 ) ;
function user_checkpoint( address _account,uint256 _epochloops ) external returns (bool ) ;
function version( ) external pure returns (uint256 _major, uint256 _minor, uint256 _patch) ;
function withdrawFees( ) external returns (uint256 _fees, uint256 _otherFees) ;
error BadSwapper( );
error BorrowerSolvent( );
error FeesAlreadyDistributed( );
error IncorrectStakeBalance( );
error Insolvent( uint256 _borrow,uint256 _collateral,uint256 _exchangeRate );
error InsufficientBorrowAmount( );
error InsufficientDebtAvailable( uint256 _assets,uint256 _request );
error InsufficientDebtToRedeem( );
error InvalidLiquidator( );
error InvalidParameter( );
error InvalidPath( address _expected,address _actual );
error InvalidReceiver( );
error InvalidRedemptionHandler( );
error MinimumRedemption( );
error OnlyProtocolOrOwner( );
error ReentrancyGuardReentrantCall( );
error SafeCastOverflowedUintDowncast( uint8 bits,uint256 value );
error SafeERC20FailedOperation( address token );
error SlippageTooHigh( uint256 _minOut,uint256 _actual );
event AddCollateral( address indexed borrower,uint256 collateralAmount ) ;
event AddInterest( uint256 interestEarned,uint256 rate ) ;
event Borrow( address indexed _borrower,address indexed _receiver,uint256 _borrowAmount,uint256 _sharesAdded,uint256 _mintFees ) ;
event LeveragedPosition( address indexed _borrower,address _swapperAddress,uint256 _borrowAmount,uint256 _borrowShares,uint256 _initialUnderlyingAmount,uint256 _amountCollateralOut ) ;
event Liquidate( address indexed _borrower,uint256 _collateralForLiquidator,uint256 _sharesLiquidated,uint256 _amountLiquidatorToRepay ) ;
event NewEpoch( uint256 indexed _epoch ) ;
event Redeemed( address indexed _caller,uint256 _amount,uint256 _collateralFreed,uint256 _protocolFee,uint256 _debtReduction ) ;
event RemoveCollateral( uint256 _collateralAmount,address indexed _receiver,address indexed _borrower ) ;
event Repay( address indexed payer,address indexed borrower,uint256 amountToRepay,uint256 shares ) ;
event RepayWithCollateral( address indexed _borrower,address _swapperAddress,uint256 _collateralToSwap,uint256 _amountAssetOut,uint256 _sharesRepaid ) ;
event RewardAdded( address indexed _rewardToken ) ;
event RewardInvalidated( address indexed _rewardToken ) ;
event RewardPaid( address indexed _user,address indexed _rewardToken,address indexed _receiver,uint256 _rewardAmount ) ;
event RewardRedirected( address indexed _account,address _forward ) ;
event SetBorrowLimit( uint256 limit ) ;
event SetConvexPool( uint256 pid ) ;
event SetLiquidationFees( uint256 oldLiquidationFee,uint256 newLiquidationFee ) ;
event SetMaxLTV( uint256 oldMaxLTV,uint256 newMaxLTV ) ;
event SetMinimumBorrowAmount( uint256 min ) ;
event SetMinimumLeftover( uint256 min ) ;
event SetMinimumRedemption( uint256 min ) ;
event SetMintFees( uint256 oldMintFee,uint256 newMintFee ) ;
event SetOracleInfo( address oldOracle,address newOracle ) ;
event SetProtocolRedemptionFee( uint256 fee ) ;
event SetRateCalculator( address oldRateCalculator,address newRateCalculator ) ;
event SetSwapper( address swapper,bool approval ) ;
event UpdateExchangeRate( uint256 exchangeRate ) ;
event UpdateRate( uint256 oldRatePerSec,uint128 oldShares,uint256 newRatePerSec,uint128 newShares ) ;
event WithdrawFees( address recipient,uint256 interestFees,uint256 otherFees ) ;
}
IERC20.sol 79 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
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 value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` 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 value) external returns (bool);
}
SafeERC20.sol 212 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
// bubble errors
if iszero(success) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
returnSize := returndatasize()
returnValue := mload(0)
}
if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
returnSize := returndatasize()
returnValue := mload(0)
}
return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
}
}
BytesLib.sol 510 lines
// SPDX-License-Identifier: Unlicense /* * @title Solidity Bytes Arrays Utils * @author Gonçalo Sá <[email protected]> * * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. */ pragma solidity >=0.8.0 <0.9.0; library BytesLib { function concat( bytes memory _preBytes, bytes memory _postBytes ) internal pure returns (bytes memory) { bytes memory tempBytes; assembly { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // Store the length of the first bytes array at the beginning of // the memory for tempBytes. let length := mload(_preBytes) mstore(tempBytes, length) // Maintain a memory counter for the current write location in the // temp bytes array by adding the 32 bytes for the array length to // the starting location. let mc := add(tempBytes, 0x20) // Stop copying when the memory counter reaches the length of the // first bytes array. let end := add(mc, length) for { // Initialize a copy counter to the start of the _preBytes data, // 32 bytes into its memory. let cc := add(_preBytes, 0x20) } lt(mc, end) { // Increase both counters by 32 bytes each iteration. mc := add(mc, 0x20) cc := add(cc, 0x20) } { // Write the _preBytes data into the tempBytes memory 32 bytes // at a time. mstore(mc, mload(cc)) } // Add the length of _postBytes to the current length of tempBytes // and store it as the new length in the first 32 bytes of the // tempBytes memory. length := mload(_postBytes) mstore(tempBytes, add(length, mload(tempBytes))) // Move the memory counter back from a multiple of 0x20 to the // actual end of the _preBytes data. mc := end // Stop copying when the memory counter reaches the new combined // length of the arrays. end := add(mc, length) for { let cc := add(_postBytes, 0x20) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } // Update the free-memory pointer by padding our last write location // to 32 bytes: add 31 bytes to the end of tempBytes to move to the // next 32 byte block, then round down to the nearest multiple of // 32. If the sum of the length of the two arrays is zero then add // one before rounding down to leave a blank 32 bytes (the length block with 0). mstore(0x40, and( add(add(end, iszero(add(length, mload(_preBytes)))), 31), not(31) // Round down to the nearest 32 bytes. )) } return tempBytes; } function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal { assembly { // Read the first 32 bytes of _preBytes storage, which is the length // of the array. (We don't need to use the offset into the slot // because arrays use the entire slot.) let fslot := sload(_preBytes.slot) // Arrays of 31 bytes or less have an even value in their slot, // while longer arrays have an odd value. The actual length is // the slot divided by two for odd values, and the lowest order // byte divided by two for even values. // If the slot is even, bitwise and the slot with 255 and divide by // two to get the length. If the slot is odd, bitwise and the slot // with -1 and divide by two. let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) let newlength := add(slength, mlength) // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage switch add(lt(slength, 32), lt(newlength, 32)) case 2 { // Since the new array still fits in the slot, we just need to // update the contents of the slot. // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length sstore( _preBytes.slot, // all the modifications to the slot are inside this // next block add( // we can just add to the slot contents because the // bytes we want to change are the LSBs fslot, add( mul( div( // load the bytes from memory mload(add(_postBytes, 0x20)), // zero all bytes to the right exp(0x100, sub(32, mlength)) ), // and now shift left the number of bytes to // leave space for the length in the slot exp(0x100, sub(32, newlength)) ), // increase length by the double of the memory // bytes length mul(mlength, 2) ) ) ) } case 1 { // The stored value fits in the slot, but the combined value // will exceed it. // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // The contents of the _postBytes array start 32 bytes into // the structure. Our first read should obtain the `submod` // bytes that can fit into the unused space in the last word // of the stored array. To get this, we read 32 bytes starting // from `submod`, so the data we read overlaps with the array // contents by `submod` bytes. Masking the lowest-order // `submod` bytes allows us to add that value directly to the // stored value. let submod := sub(32, slength) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore( sc, add( and( fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 ), and(mload(mc), mask) ) ) for { mc := add(mc, 0x20) sc := add(sc, 1) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } default { // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) // Start copying to the last used word of the stored array. let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // Copy over the first `submod` bytes of the new data as in // case 1 above. let slengthmod := mod(slength, 32) let mlengthmod := mod(mlength, 32) let submod := sub(32, slengthmod) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore(sc, add(sload(sc), and(mload(mc), mask))) for { sc := add(sc, 1) mc := add(mc, 0x20) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } } } function slice( bytes memory _bytes, uint256 _start, uint256 _length ) internal pure returns (bytes memory) { require(_length + 31 >= _length, "slice_overflow"); require(_bytes.length >= _start + _length, "slice_outOfBounds"); bytes memory tempBytes; assembly { switch iszero(_length) case 0 { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // The first word of the slice result is potentially a partial // word read from the original array. To read it, we calculate // the length of that partial word and start copying that many // bytes into the array. The first word we copy will start with // data we don't care about, but the last `lengthmod` bytes will // land at the beginning of the contents of the new array. When // we're done copying, we overwrite the full first word with // the actual length of the slice. let lengthmod := and(_length, 31) // The multiplication in the next line is necessary // because when slicing multiples of 32 bytes (lengthmod == 0) // the following copy loop was copying the origin's length // and then ending prematurely not copying everything it should. let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) let end := add(mc, _length) for { // The multiplication in the next line has the same exact purpose // as the one above. let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } mstore(tempBytes, _length) //update free-memory pointer //allocating the array padded to 32 bytes like the compiler does now mstore(0x40, and(add(mc, 31), not(31))) } //if we want a zero-length slice let's just return a zero-length array default { tempBytes := mload(0x40) //zero out the 32 bytes slice we are about to return //we need to do it because Solidity does not garbage collect mstore(tempBytes, 0) mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { require(_bytes.length >= _start + 20, "toAddress_outOfBounds"); address tempAddress; assembly { tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000) } return tempAddress; } function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) { require(_bytes.length >= _start + 1 , "toUint8_outOfBounds"); uint8 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x1), _start)) } return tempUint; } function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) { require(_bytes.length >= _start + 2, "toUint16_outOfBounds"); uint16 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x2), _start)) } return tempUint; } function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) { require(_bytes.length >= _start + 4, "toUint32_outOfBounds"); uint32 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x4), _start)) } return tempUint; } function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) { require(_bytes.length >= _start + 8, "toUint64_outOfBounds"); uint64 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x8), _start)) } return tempUint; } function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) { require(_bytes.length >= _start + 12, "toUint96_outOfBounds"); uint96 tempUint; assembly { tempUint := mload(add(add(_bytes, 0xc), _start)) } return tempUint; } function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) { require(_bytes.length >= _start + 16, "toUint128_outOfBounds"); uint128 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x10), _start)) } return tempUint; } function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) { require(_bytes.length >= _start + 32, "toUint256_outOfBounds"); uint256 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x20), _start)) } return tempUint; } function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) { require(_bytes.length >= _start + 32, "toBytes32_outOfBounds"); bytes32 tempBytes32; assembly { tempBytes32 := mload(add(add(_bytes, 0x20), _start)) } return tempBytes32; } function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) { bool success = true; assembly { let length := mload(_preBytes) // if lengths don't match the arrays are not equal switch eq(length, mload(_postBytes)) case 1 { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 let mc := add(_preBytes, 0x20) let end := add(mc, length) for { let cc := add(_postBytes, 0x20) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) } eq(add(lt(mc, end), cb), 2) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { // if any of these checks fails then arrays are not equal if iszero(eq(mload(mc), mload(cc))) { // unsuccess: success := 0 cb := 0 } } } default { // unsuccess: success := 0 } } return success; } function equalStorage( bytes storage _preBytes, bytes memory _postBytes ) internal view returns (bool) { bool success = true; assembly { // we know _preBytes_offset is 0 let fslot := sload(_preBytes.slot) // Decode the length of the stored array like in concatStorage(). let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) // if lengths don't match the arrays are not equal switch eq(slength, mlength) case 1 { // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage if iszero(iszero(slength)) { switch lt(slength, 32) case 1 { // blank the last byte which is the length fslot := mul(div(fslot, 0x100), 0x100) if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) { // unsuccess: success := 0 } } default { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := keccak256(0x0, 0x20) let mc := add(_postBytes, 0x20) let end := add(mc, mlength) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) for {} eq(add(lt(mc, end), cb), 2) { sc := add(sc, 1) mc := add(mc, 0x20) } { if iszero(eq(sload(sc), mload(mc))) { // unsuccess: success := 0 cb := 0 } } } } } default { // unsuccess: success := 0 } } return success; } }
ICore.sol 31 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import { IAuthHook } from './IAuthHook.sol';
interface ICore {
struct OperatorAuth {
bool authorized;
IAuthHook hook;
}
event VoterSet(address indexed newVoter);
event OperatorExecuted(address indexed caller, address indexed target, bytes data);
event OperatorSet(address indexed caller, address indexed target, bool authorized, bytes4 selector, IAuthHook authHook);
function execute(address target, bytes calldata data) external returns (bytes memory);
function epochLength() external view returns (uint256);
function startTime() external view returns (uint256);
function voter() external view returns (address);
function ownershipTransferDeadline() external view returns (uint256);
function pendingOwner() external view returns (address);
function setOperatorPermissions(
address caller,
address target,
bytes4 selector,
bool authorized,
IAuthHook authHook
) external;
function setVoter(address newVoter) external;
function operatorPermissions(address caller, address target, bytes4 selector) external view returns (bool authorized, IAuthHook hook);
}
IERC1363.sol 86 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}
IAuthHook.sol 7 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
interface IAuthHook {
function preHook(address operator, address target, bytes calldata data) external returns (bool);
function postHook(bytes memory result, address operator, address target, bytes calldata data) external returns (bool);
}
IERC20.sol 6 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";
IERC165.sol 6 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";
IERC165.sol 25 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
Read Contract
approvalsRevoked 0x576aaf88 → bool
canUpdateApprovals 0xe4cedf4b → bool
core 0xf2f4eb26 → address
decode 0x747edcef → bytes
encode 0xcf33d032 → address[]
nextPairIndex 0xebfa72f8 → uint256
odosRouter 0x8321928d → address
owner 0x8da5cb5b → address
registry 0x7b103999 → address
reusd 0x4ccb7382 → address
Write Contract 4 functions
These functions modify contract state and require a wallet transaction to execute.
recoverERC20 0x8980f11f
address token
uint256 amount
revokeApprovals 0x9265a7d5
No parameters
swap 0x969d98aa
address
uint256
address[] _path
address
updateApprovals 0xbe338bc6
No parameters
Recent Transactions
This address has 1 on-chain transactions, but only 1.5% of the chain is indexed. Transactions will appear as indexing progresses. View on Etherscan →