Address Contract Verified
Address
0xF81Bb8Aab5D4b87C53A09659F34a549aEDd59748
Balance
0 ETH
Nonce
1
Code Size
4470 bytes
Creator
0x45d146CA...c873 at tx 0x97ef0a57...931d52
Indexed Transactions
0
Contract Bytecode
4470 bytes
0x608060405234801561001057600080fd5b50600436106100d45760003560e01c80636f307dc311610081578063b3d454331161005b578063b3d45433146101ea578063d0202d3b146101fd578063ef8b30f71461022357600080fd5b80636f307dc31461019d5780637bde82f2146101c4578063b086726b146101d757600080fd5b806350921b23116100b257806350921b23146101515780636daf390b146101645780636e553f651461018a57600080fd5b806316f0115b146100d9578063216455791461011d5780634cdad5061461013e575b600080fd5b6101007f000000000000000000000000da00000035fef4082f78def6a8903bee419fbf8e81565b6040516001600160a01b0390911681526020015b60405180910390f35b61013061012b366004610ff2565b610236565b604051908152602001610114565b61013061014c366004611055565b61025e565b61013061015f36600461106e565b6103dd565b7f000000000000000000000000c411db5f5eb3f7d552f9b8454b2d74097ccde6e3610100565b6101306101983660046110c6565b610404565b6101007f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881565b6101306101d23660046110c6565b61041a565b6101306101e536600461106e565b610427565b6101306101f83660046110f2565b6104d5565b7f0000000000000000000000009ef444a6d7f4a5adcd68fd5329aa5240c90e14d2610100565b610130610231366004611055565b6104e4565b600061024588868686866106dc565b6102528888600189610784565b98975050505050505050565b6000806001600160a01b037f000000000000000000000000da00000035fef4082f78def6a8903bee419fbf8e167f0000000000000000000000009ef444a6d7f4a5adcd68fd5329aa5240c90e14d26001600160a01b0316146102c057826102c2565b825b6040517f4cdad506000000000000000000000000000000000000000000000000000000008152600481018290529091506000906001600160a01b037f000000000000000000000000da00000035fef4082f78def6a8903bee419fbf8e1690634cdad50690602401602060405180830381865afa158015610346573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061036a9190611127565b90506001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48167f000000000000000000000000c411db5f5eb3f7d552f9b8454b2d74097ccde6e36001600160a01b0316146103d3576103ce8161099e565b6103d5565b805b949350505050565b60006103ec87868686866106dc565b6103f98787600080610784565b979650505050505050565b60006104138383600080610784565b9392505050565b60006104138383336109d2565b60007f0000000000000000000000009ef444a6d7f4a5adcd68fd5329aa5240c90e14d260405163d505accf60e01b8152336004820152306024820152604481018990526064810187905260ff8616608482015260a4810185905260c481018490526001600160a01b03919091169063d505accf9060e401600060405180830381600087803b1580156104b857600080fd5b505af19250505080156104c9575060015b506103f98787336109d2565b60006103d58484600185610784565b6000806001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48167f000000000000000000000000c411db5f5eb3f7d552f9b8454b2d74097ccde6e36001600160a01b03161461054e5761054983610b73565b610550565b825b6040517fef8b30f7000000000000000000000000000000000000000000000000000000008152600481018290529091506000906001600160a01b037f000000000000000000000000da00000035fef4082f78def6a8903bee419fbf8e169063ef8b30f790602401602060405180830381865afa1580156105d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105f89190611127565b90506001600160a01b037f000000000000000000000000da00000035fef4082f78def6a8903bee419fbf8e167f0000000000000000000000009ef444a6d7f4a5adcd68fd5329aa5240c90e14d26001600160a01b0316146103d357806103d5565b61066c8363095ea7b360e01b8484610c1e565b6106d7576106848363095ea7b360e01b846000610c1e565b15806106a0575061069e8363095ea7b360e01b8484610c1e565b155b156106d7576040517f19be9a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050565b7f000000000000000000000000c411db5f5eb3f7d552f9b8454b2d74097ccde6e360405163d505accf60e01b8152336004820152306024820152604481018790526064810186905260ff8516608482015260a4810184905260c481018390526001600160a01b03919091169063d505accf9060e401600060405180830381600087803b15801561076b57600080fd5b505af192505050801561077c575060015b505050505050565b6000806001600160a01b037f000000000000000000000000da00000035fef4082f78def6a8903bee419fbf8e167f0000000000000000000000009ef444a6d7f4a5adcd68fd5329aa5240c90e14d26001600160a01b031614905060006107e987610c71565b90506000856108bc577f000000000000000000000000da00000035fef4082f78def6a8903bee419fbf8e6001600160a01b0316636e553f65838561082d573061082f565b895b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815260048101929092526001600160a01b031660248201526044016020604051808303816000875af1158015610893573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b79190611127565b610988565b7f000000000000000000000000da00000035fef4082f78def6a8903bee419fbf8e6001600160a01b031663b3d4543383856108f757306108f9565b895b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815260048101929092526001600160a01b03166024820152604481018890526064016020604051808303816000875af1158015610964573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109889190611127565b9050826103f9576109998188610d2e565b610252565b60006040517f24e46f7000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007f000000000000000000000000da00000035fef4082f78def6a8903bee419fbf8e6001600160a01b039081167f0000000000000000000000009ef444a6d7f4a5adcd68fd5329aa5240c90e14d2821614907f000000000000000000000000c411db5f5eb3f7d552f9b8454b2d74097ccde6e381167f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48909116148282610a8257610a7d8786610dfd565b610a84565b865b905060007f000000000000000000000000da00000035fef4082f78def6a8903bee419fbf8e6001600160a01b031663ba0876528385610ac35730610ac5565b895b87610ad05730610ad2565b895b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815260048101939093526001600160a01b0391821660248401521660448201526064016020604051808303816000875af1158015610b3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b629190611127565b9050826103f957610999818861099e565b6040517f5427c938000000000000000000000000000000000000000000000000000000008152600481018290526000907f00000000000000000000000086130bdd69143d8a4e5fc50bf4323d48049e98e46001600160a01b031690635427c93890602401602060405180830381865afa158015610bf4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c189190611127565b92915050565b60006040518481528360048201528260248201526020600060448360008a5af191505080156103d5573d8015610c6057600160005114601f3d11169150610c68565b6000863b1191505b50949350505050565b6000610ca86001600160a01b037f000000000000000000000000c411db5f5eb3f7d552f9b8454b2d74097ccde6e316333085610ece565b6040517f05fe138b000000000000000000000000000000000000000000000000000000008152600481018390523060248201527f00000000000000000000000086130bdd69143d8a4e5fc50bf4323d48049e98e46001600160a01b0316906305fe138b906044016020604051808303816000875af1158015610bf4573d6000803e3d6000fd5b6040517fb6b55f25000000000000000000000000000000000000000000000000000000008152600481018390526000907f0000000000000000000000009ef444a6d7f4a5adcd68fd5329aa5240c90e14d26001600160a01b03169063b6b55f2590602401600060405180830381600087803b158015610dac57600080fd5b505af1158015610dc0573d6000803e3d6000fd5b50859350610c189250506001600160a01b037f0000000000000000000000009ef444a6d7f4a5adcd68fd5329aa5240c90e14d21690508383610f63565b6000610e346001600160a01b037f0000000000000000000000009ef444a6d7f4a5adcd68fd5329aa5240c90e14d216833086610ece565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018490527f0000000000000000000000009ef444a6d7f4a5adcd68fd5329aa5240c90e14d26001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015610eaf57600080fd5b505af1158015610ec3573d6000803e3d6000fd5b509495945050505050565b60006323b872dd60e01b905060006040518281528560048201528460248201528360448201526020600060648360008b5af19150508015610f2c573d8015610f2257600160005114601f3d11169150610f2a565b6000873b1191505b505b8061077c576040517ff405907100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f8f837fa9059cbb000000000000000000000000000000000000000000000000000000008484610c1e565b6106d7576040517ffb7f507900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80356001600160a01b0381168114610fdc57600080fd5b919050565b803560ff81168114610fdc57600080fd5b600080600080600080600060e0888a03121561100d57600080fd5b8735965061101d60208901610fc5565b9550604088013594506060880135935061103960808901610fe1565b925060a0880135915060c0880135905092959891949750929550565b60006020828403121561106757600080fd5b5035919050565b60008060008060008060c0878903121561108757600080fd5b8635955061109760208801610fc5565b9450604087013593506110ac60608801610fe1565b92506080870135915060a087013590509295509295509295565b600080604083850312156110d957600080fd5b823591506110e960208401610fc5565b90509250929050565b60008060006060848603121561110757600080fd5b8335925061111760208501610fc5565b9150604084013590509250925092565b60006020828403121561113957600080fd5b505191905056fea26469706673582212209449fd3a4a98c4fb45509e003c10becb7eaed499e6caf97c585d96f9e055a00964736f6c63430008110033
Verified Source Code Full Match
Compiler: v0.8.17+commit.8df45f5f
EVM: london
Optimization: Yes (1000 runs)
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);
}
}
Math.sol 339 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}
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);
}
IERC4626.sol 232 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC4626.sol)
pragma solidity ^0.8.0;
import "../token/ERC20/IERC20.sol";
import "../token/ERC20/extensions/IERC20Metadata.sol";
/**
* @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in
* https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].
*
* _Available since v4.7._
*/
interface IERC4626 is IERC20, IERC20Metadata {
event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(
address indexed sender,
address indexed receiver,
address indexed owner,
uint256 assets,
uint256 shares
);
/**
* @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
*
* - MUST be an ERC-20 token contract.
* - MUST NOT revert.
*/
function asset() external view returns (address assetTokenAddress);
/**
* @dev Returns the total amount of the underlying asset that is “managed” by Vault.
*
* - SHOULD include any compounding that occurs from yield.
* - MUST be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT revert.
*/
function totalAssets() external view returns (uint256 totalManagedAssets);
/**
* @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToShares(uint256 assets) external view returns (uint256 shares);
/**
* @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToAssets(uint256 shares) external view returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
* through a deposit call.
*
* - MUST return a limited value if receiver is subject to some deposit limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
* - MUST NOT revert.
*/
function maxDeposit(address receiver) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
* call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
* in the same transaction.
* - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
* deposit would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewDeposit(uint256 assets) external view returns (uint256 shares);
/**
* @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* deposit execution, and are accounted for during deposit.
* - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
* - MUST return a limited value if receiver is subject to some mint limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
* - MUST NOT revert.
*/
function maxMint(address receiver) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
* in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
* same transaction.
* - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
* would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by minting.
*/
function previewMint(uint256 shares) external view returns (uint256 assets);
/**
* @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
* execution, and are accounted for during mint.
* - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function mint(uint256 shares, address receiver) external returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
* Vault, through a withdraw call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxWithdraw(address owner) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
* call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
* called
* in the same transaction.
* - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
* the withdrawal would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
/**
* @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* withdraw execution, and are accounted for during withdraw.
* - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
* through a redeem call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxRedeem(address owner) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
* in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
* same transaction.
* - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
* redemption would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by redeeming.
*/
function previewRedeem(uint256 shares) external view returns (uint256 assets);
/**
* @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* redeem execution, and are accounted for during redeem.
* - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
}
IFarmingPool.sol 29 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { FarmAccounting } from "../accounting/FarmAccounting.sol";
interface IFarmingPool is IERC20 {
event DistributorChanged(address oldDistributor, address newDistributor);
event RewardUpdated(uint256 reward, uint256 duration);
// View functions
function distributor() external view returns(address);
function farmInfo() external view returns(FarmAccounting.Info memory);
function farmed(address account) external view returns(uint256);
// User functions
function deposit(uint256 amount) external;
function withdraw(uint256 amount) external;
function claim() external;
function exit() external;
// Owner functions
function setDistributor(address distributor_) external;
// Distributor functions
function startFarming(uint256 amount, uint256 period) external;
function rescueFunds(IERC20 token, uint256 amount) external;
}
IWETH.sol 11 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IWETH is IERC20 {
function deposit() external payable;
function withdraw(uint256 amount) external;
}
FarmAccounting.sol 68 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
library FarmAccounting {
error ZeroDuration();
error DurationTooLarge();
error AmountTooLarge();
struct Info {
uint40 finished;
uint32 duration;
uint184 reward;
uint256 balance;
}
uint256 internal constant _MAX_REWARD_AMOUNT = 1e32; // 108 bits
uint256 internal constant _SCALE = 1e18; // 60 bits
/// @dev Requires extra 18 decimals for precision, result fits in 168 bits
function farmedSinceCheckpointScaled(Info storage info, uint256 checkpoint) internal view returns(uint256 amount) {
unchecked {
(uint40 finished, uint32 duration, uint184 reward) = (info.finished, info.duration, info.reward);
if (duration > 0) {
uint256 elapsed = Math.min(block.timestamp, finished) - Math.min(checkpoint, finished);
// size of (type(uint32).max * _MAX_REWARD_AMOUNT * _SCALE) is less than 200 bits, so there is no overflow
return elapsed * reward * _SCALE / duration;
}
}
}
function startFarming(Info storage info, uint256 amount, uint256 period) internal returns(uint256) {
if (period == 0) revert ZeroDuration();
if (period > type(uint32).max) revert DurationTooLarge();
// If something left from prev farming add it to the new farming
(uint40 finished, uint32 duration, uint184 reward, uint256 balance) = (info.finished, info.duration, info.reward, info.balance);
if (block.timestamp < finished) {
amount += reward - farmedSinceCheckpointScaled(info, finished - duration) / _SCALE;
}
if (amount > _MAX_REWARD_AMOUNT) revert AmountTooLarge();
(info.finished, info.duration, info.reward, info.balance) = (
uint40(block.timestamp + period),
uint32(period),
uint184(amount),
balance + amount
);
return amount;
}
function stopFarming(Info storage info) internal returns(uint256 leftover) {
leftover = info.reward - farmedSinceCheckpointScaled(info, info.finished - info.duration) / _SCALE;
(info.finished, info.duration, info.reward, info.balance) = (
uint40(block.timestamp),
uint32(0),
uint184(0),
info.balance - leftover
);
}
function claim(Info storage info, uint256 amount) internal {
info.balance -= amount;
}
}
IPermit2.sol 40 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IPermit2 {
struct PermitDetails {
// ERC20 token address
address token;
// the maximum amount allowed to spend
uint160 amount;
// timestamp at which a spender's token allowances become invalid
uint48 expiration;
// an incrementing value indexed per owner,token,and spender for each signature
uint48 nonce;
}
/// @notice The permit message signed for a single token allownce
struct PermitSingle {
// the permit data for a single token alownce
PermitDetails details;
// address permissioned on the allowed tokens
address spender;
// deadline on the permit signature
uint256 sigDeadline;
}
/// @notice Packed allowance
struct PackedAllowance {
// amount allowed
uint160 amount;
// permission expiry
uint48 expiration;
// an incrementing value indexed per owner,token,and spender for each signature
uint48 nonce;
}
function transferFrom(address user, address spender, uint160 amount, address token) external;
function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external;
function allowance(address user, address token, address spender) external view returns (PackedAllowance memory);
}
SafeERC20.sol 328 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol";
import "../interfaces/IDaiLikePermit.sol";
import "../interfaces/IPermit2.sol";
import "../interfaces/IWETH.sol";
import "../libraries/RevertReasonForwarder.sol";
/// @title Implements efficient safe methods for ERC20 interface.
library SafeERC20 {
error SafeTransferFailed();
error SafeTransferFromFailed();
error ForceApproveFailed();
error SafeIncreaseAllowanceFailed();
error SafeDecreaseAllowanceFailed();
error SafePermitBadLength();
error Permit2TransferAmountTooHigh();
address private constant _PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;
bytes4 private constant _PERMIT_LENGTH_ERROR = 0x68275857; // SafePermitBadLength.selector
uint256 private constant _RAW_CALL_GAS_LIMIT = 5000;
function safeBalanceOf(
IERC20 token,
address account
) internal view returns(uint256 tokenBalance) {
bytes4 selector = IERC20.balanceOf.selector;
assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
mstore(0x00, selector)
mstore(0x04, account)
let success := staticcall(gas(), token, 0x00, 0x24, 0x00, 0x20)
tokenBalance := mload(0)
if or(iszero(success), lt(returndatasize(), 0x20)) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
}
}
/// @dev Ensures method do not revert or return boolean `true`, admits call to non-smart-contract.
function safeTransferFromUniversal(
IERC20 token,
address from,
address to,
uint256 amount,
bool permit2
) internal {
if (permit2) {
safeTransferFromPermit2(token, from, to, amount);
} else {
safeTransferFrom(token, from, to, amount);
}
}
/// @dev Ensures method do not revert or return boolean `true`, admits call to non-smart-contract.
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 amount
) internal {
bytes4 selector = token.transferFrom.selector;
bool success;
assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
let data := mload(0x40)
mstore(data, selector)
mstore(add(data, 0x04), from)
mstore(add(data, 0x24), to)
mstore(add(data, 0x44), amount)
success := call(gas(), token, 0, data, 100, 0x0, 0x20)
if success {
switch returndatasize()
case 0 {
success := gt(extcodesize(token), 0)
}
default {
success := and(gt(returndatasize(), 31), eq(mload(0), 1))
}
}
}
if (!success) revert SafeTransferFromFailed();
}
/// @dev Permit2 version of safeTransferFrom above.
function safeTransferFromPermit2(
IERC20 token,
address from,
address to,
uint256 amount
) internal {
if (amount > type(uint160).max) revert Permit2TransferAmountTooHigh();
bytes4 selector = IPermit2.transferFrom.selector;
bool success;
assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
let data := mload(0x40)
mstore(data, selector)
mstore(add(data, 0x04), from)
mstore(add(data, 0x24), to)
mstore(add(data, 0x44), amount)
mstore(add(data, 0x64), token)
success := call(gas(), _PERMIT2, 0, data, 0x84, 0x0, 0x0)
if success {
success := gt(extcodesize(_PERMIT2), 0)
}
}
if (!success) revert SafeTransferFromFailed();
}
/// @dev Ensures method do not revert or return boolean `true`, admits call to non-smart-contract.
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
if (!_makeCall(token, token.transfer.selector, to, value)) {
revert SafeTransferFailed();
}
}
/// @dev If `approve(from, to, amount)` fails, try to `approve(from, to, 0)` before retry.
function forceApprove(
IERC20 token,
address spender,
uint256 value
) internal {
if (!_makeCall(token, token.approve.selector, spender, value)) {
if (
!_makeCall(token, token.approve.selector, spender, 0) ||
!_makeCall(token, token.approve.selector, spender, value)
) {
revert ForceApproveFailed();
}
}
}
/// @dev Allowance increase with safe math check.
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 allowance = token.allowance(address(this), spender);
if (value > type(uint256).max - allowance) revert SafeIncreaseAllowanceFailed();
forceApprove(token, spender, allowance + value);
}
/// @dev Allowance decrease with safe math check.
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 allowance = token.allowance(address(this), spender);
if (value > allowance) revert SafeDecreaseAllowanceFailed();
forceApprove(token, spender, allowance - value);
}
function safePermit(IERC20 token, bytes calldata permit) internal {
if (!tryPermit(token, msg.sender, address(this), permit)) RevertReasonForwarder.reRevert();
}
function safePermit(IERC20 token, address owner, address spender, bytes calldata permit) internal {
if (!tryPermit(token, owner, spender, permit)) RevertReasonForwarder.reRevert();
}
function tryPermit(IERC20 token, bytes calldata permit) internal returns(bool success) {
return tryPermit(token, msg.sender, address(this), permit);
}
function tryPermit(IERC20 token, address owner, address spender, bytes calldata permit) internal returns(bool success) {
bytes4 permitSelector = IERC20Permit.permit.selector;
bytes4 daiPermitSelector = IDaiLikePermit.permit.selector;
bytes4 permit2Selector = IPermit2.permit.selector;
assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
let ptr := mload(0x40)
switch permit.length
case 100 {
mstore(ptr, permitSelector)
mstore(add(ptr, 0x04), owner)
mstore(add(ptr, 0x24), spender)
// Compact IERC20Permit.permit(uint256 value, uint32 deadline, uint256 r, uint256 vs)
{ // stack too deep
let deadline := shr(224, calldataload(add(permit.offset, 0x20)))
let vs := calldataload(add(permit.offset, 0x44))
calldatacopy(add(ptr, 0x44), permit.offset, 0x20) // value
mstore(add(ptr, 0x64), sub(deadline, 1))
mstore(add(ptr, 0x84), add(27, shr(255, vs)))
calldatacopy(add(ptr, 0xa4), add(permit.offset, 0x24), 0x20) // r
mstore(add(ptr, 0xc4), shr(1, shl(1, vs)))
}
// IERC20Permit.permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
success := call(gas(), token, 0, ptr, 0xe4, 0, 0)
}
case 72 {
mstore(ptr, daiPermitSelector)
mstore(add(ptr, 0x04), owner)
mstore(add(ptr, 0x24), spender)
// Compact IDaiLikePermit.permit(uint32 nonce, uint32 expiry, uint256 r, uint256 vs)
{ // stack too deep
let expiry := shr(224, calldataload(add(permit.offset, 0x04)))
let vs := calldataload(add(permit.offset, 0x28))
mstore(add(ptr, 0x44), shr(224, calldataload(permit.offset)))
mstore(add(ptr, 0x64), sub(expiry, 1))
mstore(add(ptr, 0x84), true)
mstore(add(ptr, 0xa4), add(27, shr(255, vs)))
calldatacopy(add(ptr, 0xc4), add(permit.offset, 0x08), 0x20) // r
mstore(add(ptr, 0xe4), shr(1, shl(1, vs)))
}
// IDaiLikePermit.permit(address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s)
success := call(gas(), token, 0, ptr, 0x104, 0, 0)
}
case 224 {
mstore(ptr, permitSelector)
calldatacopy(add(ptr, 0x04), permit.offset, permit.length)
// IERC20Permit.permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
success := call(gas(), token, 0, ptr, 0xe4, 0, 0)
}
case 256 {
mstore(ptr, daiPermitSelector)
calldatacopy(add(ptr, 0x04), permit.offset, permit.length)
// IDaiLikePermit.permit(address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s)
success := call(gas(), token, 0, ptr, 0x104, 0, 0)
}
case 96 {
// Compact IPermit2.permit(uint160 amount, uint32 expiration, uint32 nonce, uint32 sigDeadline, uint256 r, uint256 vs)
mstore(ptr, permit2Selector)
mstore(add(ptr, 0x04), owner)
mstore(add(ptr, 0x24), token)
calldatacopy(add(ptr, 0x50), permit.offset, 0x14) // amount
mstore(add(ptr, 0x64), and(0xffffffffffff, sub(shr(224, calldataload(add(permit.offset, 0x14))), 1))) // expiration
mstore(add(ptr, 0x84), shr(224, calldataload(add(permit.offset, 0x18)))) // nonce
mstore(add(ptr, 0xa4), spender)
mstore(add(ptr, 0xc4), and(0xffffffffffff, sub(shr(224, calldataload(add(permit.offset, 0x1c))), 1))) // sigDeadline
mstore(add(ptr, 0xe4), 0x100)
mstore(add(ptr, 0x104), 0x40)
calldatacopy(add(ptr, 0x124), add(permit.offset, 0x20), 0x20) // r
calldatacopy(add(ptr, 0x144), add(permit.offset, 0x40), 0x20) // vs
// IPermit2.permit(address owner, PermitSingle calldata permitSingle, bytes calldata signature)
success := call(gas(), _PERMIT2, 0, ptr, 0x164, 0, 0)
}
case 352 {
mstore(ptr, permit2Selector)
calldatacopy(add(ptr, 0x04), permit.offset, permit.length)
// IPermit2.permit(address owner, PermitSingle calldata permitSingle, bytes calldata signature)
success := call(gas(), _PERMIT2, 0, ptr, 0x164, 0, 0)
}
default {
mstore(ptr, _PERMIT_LENGTH_ERROR)
revert(ptr, 4)
}
}
}
function _makeCall(
IERC20 token,
bytes4 selector,
address to,
uint256 amount
) private returns (bool success) {
assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
let data := mload(0x40)
mstore(data, selector)
mstore(add(data, 0x04), to)
mstore(add(data, 0x24), amount)
success := call(gas(), token, 0, data, 0x44, 0x0, 0x20)
if success {
switch returndatasize()
case 0 {
success := gt(extcodesize(token), 0)
}
default {
success := and(gt(returndatasize(), 31), eq(mload(0), 1))
}
}
}
}
function safeDeposit(IWETH weth, uint256 amount) internal {
if (amount > 0) {
bytes4 selector = IWETH.deposit.selector;
assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
mstore(0, selector)
if iszero(call(gas(), weth, amount, 0, 4, 0, 0)) {
returndatacopy(0, 0, returndatasize())
revert(0, returndatasize())
}
}
}
}
function safeWithdraw(IWETH weth, uint256 amount) internal {
bytes4 selector = IWETH.withdraw.selector;
assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
mstore(0, selector)
mstore(4, amount)
if iszero(call(gas(), weth, 0, 0, 0x24, 0, 0)) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
}
}
function safeWithdrawTo(IWETH weth, uint256 amount, address to) internal {
safeWithdraw(weth, amount);
if (to != address(this)) {
assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
if iszero(call(_RAW_CALL_GAS_LIMIT, to, amount, 0, 0, 0, 0)) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
}
}
}
}
Errors.sol 81 lines
// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Holdings, 2022
pragma solidity ^0.8.10;
/// @title Errors library
library Errors {
//
// COMMON
//
string public constant ZERO_ADDRESS_IS_NOT_ALLOWED = "Z0";
string public constant NOT_IMPLEMENTED = "NI";
string public constant INCORRECT_PATH_LENGTH = "PL";
string public constant INCORRECT_ARRAY_LENGTH = "CR";
string public constant REGISTERED_CREDIT_ACCOUNT_MANAGERS_ONLY = "CP";
string public constant REGISTERED_POOLS_ONLY = "RP";
string public constant INCORRECT_PARAMETER = "IP";
//
// MATH
//
string public constant MATH_MULTIPLICATION_OVERFLOW = "M1";
string public constant MATH_ADDITION_OVERFLOW = "M2";
string public constant MATH_DIVISION_BY_ZERO = "M3";
//
// POOL
//
string public constant POOL_CONNECTED_CREDIT_MANAGERS_ONLY = "PS0";
string public constant POOL_INCOMPATIBLE_CREDIT_ACCOUNT_MANAGER = "PS1";
string public constant POOL_MORE_THAN_EXPECTED_LIQUIDITY_LIMIT = "PS2";
string public constant POOL_INCORRECT_WITHDRAW_FEE = "PS3";
string public constant POOL_CANT_ADD_CREDIT_MANAGER_TWICE = "PS4";
//
// ACCOUNT FACTORY
//
string public constant AF_CANT_CLOSE_CREDIT_ACCOUNT_IN_THE_SAME_BLOCK =
"AF1";
string public constant AF_MINING_IS_FINISHED = "AF2";
string public constant AF_CREDIT_ACCOUNT_NOT_IN_STOCK = "AF3";
string public constant AF_EXTERNAL_ACCOUNTS_ARE_FORBIDDEN = "AF4";
//
// ADDRESS PROVIDER
//
string public constant AS_ADDRESS_NOT_FOUND = "AP1";
//
// CONTRACTS REGISTER
//
string public constant CR_POOL_ALREADY_ADDED = "CR1";
string public constant CR_CREDIT_MANAGER_ALREADY_ADDED = "CR2";
//
// CREDIT ACCOUNT
//
string public constant CA_CONNECTED_CREDIT_MANAGER_ONLY = "CA1";
string public constant CA_FACTORY_ONLY = "CA2";
//
// ACL
//
string public constant ACL_CALLER_NOT_PAUSABLE_ADMIN = "ACL1";
string public constant ACL_CALLER_NOT_CONFIGURATOR = "ACL2";
//
// WETH GATEWAY
//
string public constant WG_DESTINATION_IS_NOT_WETH_COMPATIBLE = "WG1";
string public constant WG_RECEIVE_IS_NOT_ALLOWED = "WG2";
string public constant WG_NOT_ENOUGH_FUNDS = "WG3";
//
// TOKEN DISTRIBUTOR
//
string public constant TD_WALLET_IS_ALREADY_CONNECTED_TO_VC = "TD1";
string public constant TD_INCORRECT_WEIGHTS = "TD2";
string public constant TD_NON_ZERO_BALANCE_AFTER_DISTRIBUTION = "TD3";
string public constant TD_CONTRIBUTOR_IS_NOT_REGISTERED = "TD4";
}
IPoolV3.sol 134 lines
// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2023.
pragma solidity ^0.8.17;
pragma abicoder v1;
import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol";
import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol";
import {IVersion} from "@gearbox-protocol/core-v2/contracts/interfaces/IVersion.sol";
interface IPoolV3Events {
/// @notice Emitted when depositing liquidity with referral code
event Refer(address indexed onBehalfOf, uint256 indexed referralCode, uint256 amount);
/// @notice Emitted when credit account borrows funds from the pool
event Borrow(address indexed creditManager, address indexed creditAccount, uint256 amount);
/// @notice Emitted when credit account's debt is repaid to the pool
event Repay(address indexed creditManager, uint256 borrowedAmount, uint256 profit, uint256 loss);
/// @notice Emitted when incurred loss can't be fully covered by burning treasury's shares
event IncurUncoveredLoss(address indexed creditManager, uint256 loss);
/// @notice Emitted when new interest rate model contract is set
event SetInterestRateModel(address indexed newInterestRateModel);
/// @notice Emitted when new pool quota keeper contract is set
event SetPoolQuotaKeeper(address indexed newPoolQuotaKeeper);
/// @notice Emitted when new total debt limit is set
event SetTotalDebtLimit(uint256 limit);
/// @notice Emitted when new credit manager is connected to the pool
event AddCreditManager(address indexed creditManager);
/// @notice Emitted when new debt limit is set for a credit manager
event SetCreditManagerDebtLimit(address indexed creditManager, uint256 newLimit);
/// @notice Emitted when new withdrawal fee is set
event SetWithdrawFee(uint256 fee);
}
/// @title Pool V3 interface
interface IPoolV3 is IVersion, IPoolV3Events, IERC4626, IERC20Permit {
function addressProvider() external view returns (address);
function underlyingToken() external view returns (address);
function treasury() external view returns (address);
function withdrawFee() external view returns (uint16);
function creditManagers() external view returns (address[] memory);
function availableLiquidity() external view returns (uint256);
function expectedLiquidity() external view returns (uint256);
function expectedLiquidityLU() external view returns (uint256);
// ---------------- //
// ERC-4626 LENDING //
// ---------------- //
function depositWithReferral(uint256 assets, address receiver, uint256 referralCode)
external
returns (uint256 shares);
function mintWithReferral(uint256 shares, address receiver, uint256 referralCode)
external
returns (uint256 assets);
// --------- //
// BORROWING //
// --------- //
function totalBorrowed() external view returns (uint256);
function totalDebtLimit() external view returns (uint256);
function creditManagerBorrowed(address creditManager) external view returns (uint256);
function creditManagerDebtLimit(address creditManager) external view returns (uint256);
function creditManagerBorrowable(address creditManager) external view returns (uint256 borrowable);
function lendCreditAccount(uint256 borrowedAmount, address creditAccount) external;
function repayCreditAccount(uint256 repaidAmount, uint256 profit, uint256 loss) external;
// ------------- //
// INTEREST RATE //
// ------------- //
function interestRateModel() external view returns (address);
function baseInterestRate() external view returns (uint256);
function supplyRate() external view returns (uint256);
function baseInterestIndex() external view returns (uint256);
function baseInterestIndexLU() external view returns (uint256);
function lastBaseInterestUpdate() external view returns (uint40);
// ------ //
// QUOTAS //
// ------ //
function poolQuotaKeeper() external view returns (address);
function quotaRevenue() external view returns (uint256);
function lastQuotaRevenueUpdate() external view returns (uint40);
function updateQuotaRevenue(int256 quotaRevenueDelta) external;
function setQuotaRevenue(uint256 newQuotaRevenue) external;
// ------------- //
// CONFIGURATION //
// ------------- //
function setInterestRateModel(address newInterestRateModel) external;
function setPoolQuotaKeeper(address newPoolQuotaKeeper) external;
function setTotalDebtLimit(uint256 newLimit) external;
function setCreditManagerDebtLimit(address creditManager, uint256 newLimit) external;
function setWithdrawFee(uint256 newWithdrawFee) external;
}
IVersion.sol 11 lines
// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Holdings, 2022
pragma solidity ^0.8.10;
/// @title Version interface
/// @notice Defines contract version
interface IVersion {
/// @notice Contract version
function version() external view returns (uint256);
}
AddressProvider.sol 212 lines
// SPDX-License-Identifier: BUSL-1.1
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Holdings, 2022
pragma solidity ^0.8.10;
import { IAddressProvider } from "../interfaces/IAddressProvider.sol";
import { Claimable } from "./access/Claimable.sol";
import { Errors } from "../libraries/Errors.sol";
// Repositories & services
bytes32 constant CONTRACTS_REGISTER = "CONTRACTS_REGISTER";
bytes32 constant ACL = "ACL";
bytes32 constant PRICE_ORACLE = "PRICE_ORACLE";
bytes32 constant ACCOUNT_FACTORY = "ACCOUNT_FACTORY";
bytes32 constant DATA_COMPRESSOR = "DATA_COMPRESSOR";
bytes32 constant TREASURY_CONTRACT = "TREASURY_CONTRACT";
bytes32 constant GEAR_TOKEN = "GEAR_TOKEN";
bytes32 constant WETH_TOKEN = "WETH_TOKEN";
bytes32 constant WETH_GATEWAY = "WETH_GATEWAY";
bytes32 constant LEVERAGED_ACTIONS = "LEVERAGED_ACTIONS";
/// @title AddressRepository
/// @notice Stores addresses of deployed contracts
contract AddressProvider is Claimable, IAddressProvider {
// Mapping from contract keys to respective addresses
mapping(bytes32 => address) public addresses;
/// @dev Contract version
function version() external view virtual override returns (uint256) {
return 2;
}
constructor() {
// @dev Emits first event for contract discovery
emit AddressSet("ADDRESS_PROVIDER", address(this));
}
/// @return Address of ACL contract
function getACL() external view returns (address) {
return _getAddress(ACL); // F:[AP-3]
}
/// @dev Sets address of ACL contract
/// @param _address Address of ACL contract
function setACL(
address _address
)
external
onlyOwner // F:[AP-12]
{
_setAddress(ACL, _address); // F:[AP-3]
}
/// @return Address of ContractsRegister
function getContractsRegister() external view returns (address) {
return _getAddress(CONTRACTS_REGISTER); // F:[AP-4]
}
/// @dev Sets address of ContractsRegister
/// @param _address Address of ContractsRegister
function setContractsRegister(
address _address
)
external
onlyOwner // F:[AP-12]
{
_setAddress(CONTRACTS_REGISTER, _address); // F:[AP-4]
}
/// @return Address of PriceOracleV2
function getPriceOracle() external view override returns (address) {
return _getAddress(PRICE_ORACLE); // F:[AP-5]
}
/// @dev Sets address of PriceOracleV2
/// @param _address Address of PriceOracleV2
function setPriceOracle(
address _address
)
external
onlyOwner // F:[AP-12]
{
_setAddress(PRICE_ORACLE, _address); // F:[AP-5]
}
/// @return Address of AccountFactory
function getAccountFactory() external view returns (address) {
return _getAddress(ACCOUNT_FACTORY); // F:[AP-6]
}
/// @dev Sets address of AccountFactory
/// @param _address Address of AccountFactory
function setAccountFactory(
address _address
)
external
onlyOwner // F:[AP-12]
{
_setAddress(ACCOUNT_FACTORY, _address); // F:[AP-6]
}
/// @return Address of DataCompressor
function getDataCompressor() external view override returns (address) {
return _getAddress(DATA_COMPRESSOR); // F:[AP-7]
}
/// @dev Sets address of AccountFactory
/// @param _address Address of AccountFactory
function setDataCompressor(
address _address
)
external
onlyOwner // F:[AP-12]
{
_setAddress(DATA_COMPRESSOR, _address); // F:[AP-7]
}
/// @return Address of Treasury contract
function getTreasuryContract() external view returns (address) {
return _getAddress(TREASURY_CONTRACT); // F:[AP-8]
}
/// @dev Sets address of Treasury Contract
/// @param _address Address of Treasury Contract
function setTreasuryContract(
address _address
)
external
onlyOwner // F:[AP-12]
{
_setAddress(TREASURY_CONTRACT, _address); // F:[AP-8]
}
/// @return Address of GEAR token
function getGearToken() external view override returns (address) {
return _getAddress(GEAR_TOKEN); // F:[AP-9]
}
/// @dev Sets address of GEAR token
/// @param _address Address of GEAR token
function setGearToken(
address _address
)
external
onlyOwner // F:[AP-12]
{
_setAddress(GEAR_TOKEN, _address); // F:[AP-9]
}
/// @return Address of WETH token
function getWethToken() external view override returns (address) {
return _getAddress(WETH_TOKEN); // F:[AP-10]
}
/// @dev Sets address of WETH token
/// @param _address Address of WETH token
function setWethToken(
address _address
)
external
onlyOwner // F:[AP-12]
{
_setAddress(WETH_TOKEN, _address); // F:[AP-10]
}
/// @return Address of WETH token
function getWETHGateway() external view override returns (address) {
return _getAddress(WETH_GATEWAY); // F:[AP-11]
}
/// @dev Sets address of WETH token
/// @param _address Address of WETH token
function setWETHGateway(
address _address
)
external
onlyOwner // F:[AP-12]
{
_setAddress(WETH_GATEWAY, _address); // F:[AP-11]
}
/// @return Address of PathFinder
function getLeveragedActions() external view returns (address) {
return _getAddress(LEVERAGED_ACTIONS); // T:[AP-7]
}
/// @dev Sets address of PathFinder
/// @param _address Address of PathFinder
function setLeveragedActions(
address _address
)
external
onlyOwner // T:[AP-15]
{
_setAddress(LEVERAGED_ACTIONS, _address); // T:[AP-7]
}
/// @return Address of key, reverts if the key doesn't exist
function _getAddress(bytes32 key) internal view returns (address) {
address result = addresses[key];
require(result != address(0), Errors.AS_ADDRESS_NOT_FOUND); // F:[AP-1]
return result; // F:[AP-3, 4, 5, 6, 7, 8, 9, 10, 11]
}
/// @dev Sets address to map by its key
/// @param key Key in string format
/// @param value Address
function _setAddress(bytes32 key, address value) internal {
addresses[key] = value; // F:[AP-3, 4, 5, 6, 7, 8, 9, 10, 11]
emit AddressSet(key, value); // F:[AP-2]
}
}
IDaiLikePermit.sol 16 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IDaiLikePermit {
function permit(
address holder,
address spender,
uint256 nonce,
uint256 expiry,
bool allowed,
uint8 v,
bytes32 r,
bytes32 s
) external;
}
Claimable.sol 38 lines
// SPDX-License-Identifier: BUSL-1.1
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Holdings, 2022
pragma solidity ^0.8.10;
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
/// @title Claimable
/// @dev Implements logic for a two-step ownership transfer on top of Ownable
contract Claimable is Ownable {
/// @dev The new owner that has not claimed ownership yet
address public pendingOwner;
/// @dev A modifier that restricts the function to the pending owner only
modifier onlyPendingOwner() {
if (msg.sender != pendingOwner) {
revert("Claimable: Sender is not pending owner");
}
_;
}
/// @dev Sets pending owner to the new owner, but does not
/// transfer ownership yet
/// @param newOwner The address to become the future owner
function transferOwnership(address newOwner) public override onlyOwner {
require(
newOwner != address(0),
"Claimable: new owner is the zero address"
);
pendingOwner = newOwner;
}
/// @dev Used by the pending owner to claim ownership after transferOwnership
function claimOwnership() external onlyPendingOwner {
_transferOwnership(pendingOwner);
pendingOwner = address(0);
}
}
IExceptions.sol 319 lines
// SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2023. pragma solidity ^0.8.17; // ------- // // GENERAL // // ------- // /// @notice Thrown on attempting to set an important address to zero address error ZeroAddressException(); /// @notice Thrown when attempting to pass a zero amount to a funding-related operation error AmountCantBeZeroException(); /// @notice Thrown on incorrect input parameter error IncorrectParameterException(); /// @notice Thrown when balance is insufficient to perform an operation error InsufficientBalanceException(); /// @notice Thrown if parameter is out of range error ValueOutOfRangeException(); /// @notice Thrown when trying to send ETH to a contract that is not allowed to receive ETH directly error ReceiveIsNotAllowedException(); /// @notice Thrown on attempting to set an EOA as an important contract in the system error AddressIsNotContractException(address); /// @notice Thrown on attempting to receive a token that is not a collateral token or was forbidden error TokenNotAllowedException(); /// @notice Thrown on attempting to add a token that is already in a collateral list error TokenAlreadyAddedException(); /// @notice Thrown when attempting to use quota-related logic for a token that is not quoted in quota keeper error TokenIsNotQuotedException(); /// @notice Thrown on attempting to interact with an address that is not a valid target contract error TargetContractNotAllowedException(); /// @notice Thrown if function is not implemented error NotImplementedException(); // ------------------ // // CONTRACTS REGISTER // // ------------------ // /// @notice Thrown when an address is expected to be a registered credit manager, but is not error RegisteredCreditManagerOnlyException(); /// @notice Thrown when an address is expected to be a registered pool, but is not error RegisteredPoolOnlyException(); // ---------------- // // ADDRESS PROVIDER // // ---------------- // /// @notice Reverts if address key isn't found in address provider error AddressNotFoundException(); // ----------------- // // POOL, PQK, GAUGES // // ----------------- // /// @notice Thrown by pool-adjacent contracts when a credit manager being connected has a wrong pool address error IncompatibleCreditManagerException(); /// @notice Thrown when attempting to set an incompatible successor staking contract error IncompatibleSuccessorException(); /// @notice Thrown when attempting to vote in a non-approved contract error VotingContractNotAllowedException(); /// @notice Thrown when attempting to unvote more votes than there are error InsufficientVotesException(); /// @notice Thrown when attempting to borrow more than the second point on a two-point curve error BorrowingMoreThanU2ForbiddenException(); /// @notice Thrown when a credit manager attempts to borrow more than its limit in the current block, or in general error CreditManagerCantBorrowException(); /// @notice Thrown when attempting to connect a quota keeper to an incompatible pool error IncompatiblePoolQuotaKeeperException(); /// @notice Thrown when the quota is outside of min/max bounds error QuotaIsOutOfBoundsException(); // -------------- // // CREDIT MANAGER // // -------------- // /// @notice Thrown on failing a full collateral check after multicall error NotEnoughCollateralException(); /// @notice Thrown if an attempt to approve a collateral token to adapter's target contract fails error AllowanceFailedException(); /// @notice Thrown on attempting to perform an action for a credit account that does not exist error CreditAccountDoesNotExistException(); /// @notice Thrown on configurator attempting to add more than 255 collateral tokens error TooManyTokensException(); /// @notice Thrown if more than the maximum number of tokens were enabled on a credit account error TooManyEnabledTokensException(); /// @notice Thrown when attempting to execute a protocol interaction without active credit account set error ActiveCreditAccountNotSetException(); /// @notice Thrown when trying to update credit account's debt more than once in the same block error DebtUpdatedTwiceInOneBlockException(); /// @notice Thrown when trying to repay all debt while having active quotas error DebtToZeroWithActiveQuotasException(); /// @notice Thrown when a zero-debt account attempts to update quota error UpdateQuotaOnZeroDebtAccountException(); /// @notice Thrown when attempting to close an account with non-zero debt error CloseAccountWithNonZeroDebtException(); /// @notice Thrown when value of funds remaining on the account after liquidation is insufficient error InsufficientRemainingFundsException(); /// @notice Thrown when Credit Facade tries to write over a non-zero active Credit Account error ActiveCreditAccountOverridenException(); // ------------------- // // CREDIT CONFIGURATOR // // ------------------- // /// @notice Thrown on attempting to use a non-ERC20 contract or an EOA as a token error IncorrectTokenContractException(); /// @notice Thrown if the newly set LT if zero or greater than the underlying's LT error IncorrectLiquidationThresholdException(); /// @notice Thrown if borrowing limits are incorrect: minLimit > maxLimit or maxLimit > blockLimit error IncorrectLimitsException(); /// @notice Thrown if the new expiration date is less than the current expiration date or current timestamp error IncorrectExpirationDateException(); /// @notice Thrown if a contract returns a wrong credit manager or reverts when trying to retrieve it error IncompatibleContractException(); /// @notice Thrown if attempting to forbid an adapter that is not registered in the credit manager error AdapterIsNotRegisteredException(); /// @notice Thrown when trying to manually set total debt parameters in a credit facade that doesn't track them error TotalDebtNotTrackedException(); // ------------- // // CREDIT FACADE // // ------------- // /// @notice Thrown when attempting to perform an action that is forbidden in whitelisted mode error ForbiddenInWhitelistedModeException(); /// @notice Thrown if credit facade is not expirable, and attempted aciton requires expirability error NotAllowedWhenNotExpirableException(); /// @notice Thrown if a selector that doesn't match any allowed function is passed to the credit facade in a multicall error UnknownMethodException(); /// @notice Thrown when trying to close an account with enabled tokens error CloseAccountWithEnabledTokensException(); /// @notice Thrown if a liquidator tries to liquidate an account with a health factor above 1 error CreditAccountNotLiquidatableException(); /// @notice Thrown if too much new debt was taken within a single block error BorrowedBlockLimitException(); /// @notice Thrown if the new debt principal for a credit account falls outside of borrowing limits error BorrowAmountOutOfLimitsException(); /// @notice Thrown if a user attempts to open an account via an expired credit facade error NotAllowedAfterExpirationException(); /// @notice Thrown if expected balances are attempted to be set twice without performing a slippage check error ExpectedBalancesAlreadySetException(); /// @notice Thrown if attempting to perform a slippage check when excepted balances are not set error ExpectedBalancesNotSetException(); /// @notice Thrown if balance of at least one token is less than expected during a slippage check error BalanceLessThanExpectedException(); /// @notice Thrown when trying to perform an action that is forbidden when credit account has enabled forbidden tokens error ForbiddenTokensException(); /// @notice Thrown when new forbidden tokens are enabled during the multicall error ForbiddenTokenEnabledException(); /// @notice Thrown when enabled forbidden token balance is increased during the multicall error ForbiddenTokenBalanceIncreasedException(); /// @notice Thrown when the remaining token balance is increased during the liquidation error RemainingTokenBalanceIncreasedException(); /// @notice Thrown if `botMulticall` is called by an address that is not approved by account owner or is forbidden error NotApprovedBotException(); /// @notice Thrown when attempting to perform a multicall action with no permission for it error NoPermissionException(uint256 permission); /// @notice Thrown when attempting to give a bot unexpected permissions error UnexpectedPermissionsException(); /// @notice Thrown when a custom HF parameter lower than 10000 is passed into the full collateral check error CustomHealthFactorTooLowException(); /// @notice Thrown when submitted collateral hint is not a valid token mask error InvalidCollateralHintException(); // ------ // // ACCESS // // ------ // /// @notice Thrown on attempting to call an access restricted function not as credit account owner error CallerNotCreditAccountOwnerException(); /// @notice Thrown on attempting to call an access restricted function not as configurator error CallerNotConfiguratorException(); /// @notice Thrown on attempting to call an access-restructed function not as account factory error CallerNotAccountFactoryException(); /// @notice Thrown on attempting to call an access restricted function not as credit manager error CallerNotCreditManagerException(); /// @notice Thrown on attempting to call an access restricted function not as credit facade error CallerNotCreditFacadeException(); /// @notice Thrown on attempting to call an access restricted function not as controller or configurator error CallerNotControllerException(); /// @notice Thrown on attempting to pause a contract without pausable admin rights error CallerNotPausableAdminException(); /// @notice Thrown on attempting to unpause a contract without unpausable admin rights error CallerNotUnpausableAdminException(); /// @notice Thrown on attempting to call an access restricted function not as gauge error CallerNotGaugeException(); /// @notice Thrown on attempting to call an access restricted function not as quota keeper error CallerNotPoolQuotaKeeperException(); /// @notice Thrown on attempting to call an access restricted function not as voter error CallerNotVoterException(); /// @notice Thrown on attempting to call an access restricted function not as allowed adapter error CallerNotAdapterException(); /// @notice Thrown on attempting to call an access restricted function not as migrator error CallerNotMigratorException(); /// @notice Thrown when an address that is not the designated executor attempts to execute a transaction error CallerNotExecutorException(); /// @notice Thrown on attempting to call an access restricted function not as veto admin error CallerNotVetoAdminException(); // ------------------- // // CONTROLLER TIMELOCK // // ------------------- // /// @notice Thrown when the new parameter values do not satisfy required conditions error ParameterChecksFailedException(); /// @notice Thrown when attempting to execute a non-queued transaction error TxNotQueuedException(); /// @notice Thrown when attempting to execute a transaction that is either immature or stale error TxExecutedOutsideTimeWindowException(); /// @notice Thrown when execution of a transaction fails error TxExecutionRevertedException(); /// @notice Thrown when the value of a parameter on execution is different from the value on queue error ParameterChangedAfterQueuedTxException(); // -------- // // BOT LIST // // -------- // /// @notice Thrown when attempting to set non-zero permissions for a forbidden or special bot error InvalidBotException(); // --------------- // // ACCOUNT FACTORY // // --------------- // /// @notice Thrown when trying to deploy second master credit account for a credit manager error MasterCreditAccountAlreadyDeployedException(); /// @notice Thrown when trying to rescue funds from a credit account that is currently in use error CreditAccountIsInUseException(); // ------------ // // PRICE ORACLE // // ------------ // /// @notice Thrown on attempting to set a token price feed to an address that is not a correct price feed error IncorrectPriceFeedException(); /// @notice Thrown on attempting to interact with a price feed for a token not added to the price oracle error PriceFeedDoesNotExistException(); /// @notice Thrown when price feed returns incorrect price for a token error IncorrectPriceException(); /// @notice Thrown when token's price feed becomes stale error StalePriceException();
IPoolService.sol 201 lines
// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Holdings, 2022
pragma solidity ^0.8.10;
import "../core/AddressProvider.sol";
import { IVersion } from "./IVersion.sol";
interface IPoolServiceEvents {
/// @dev Emits on new liquidity being added to the pool
event AddLiquidity(
address indexed sender,
address indexed onBehalfOf,
uint256 amount,
uint256 referralCode
);
/// @dev Emits on liquidity being removed to the pool
event RemoveLiquidity(
address indexed sender,
address indexed to,
uint256 amount
);
/// @dev Emits on a Credit Manager borrowing funds for a Credit Account
event Borrow(
address indexed creditManager,
address indexed creditAccount,
uint256 amount
);
/// @dev Emits on repayment of a Credit Account's debt
event Repay(
address indexed creditManager,
uint256 borrowedAmount,
uint256 profit,
uint256 loss
);
/// @dev Emits on updating the interest rate model
event NewInterestRateModel(address indexed newInterestRateModel);
/// @dev Emits on connecting a new Credit Manager
event NewCreditManagerConnected(address indexed creditManager);
/// @dev Emits when a Credit Manager is forbidden to borrow
event BorrowForbidden(address indexed creditManager);
/// @dev Emitted when loss is incurred that can't be covered by treasury funds
event UncoveredLoss(address indexed creditManager, uint256 loss);
/// @dev Emits when the liquidity limit is changed
event NewExpectedLiquidityLimit(uint256 newLimit);
/// @dev Emits when the withdrawal fee is changed
event NewWithdrawFee(uint256 fee);
}
/// @title Pool Service Interface
/// @notice Implements business logic:
/// - Adding/removing pool liquidity
/// - Managing diesel tokens & diesel rates
/// - Taking/repaying Credit Manager debt
/// More: https://dev.gearbox.fi/developers/pool/abstractpoolservice
interface IPoolService is IPoolServiceEvents, IVersion {
//
// LIQUIDITY MANAGEMENT
//
/**
* @dev Adds liquidity to pool
* - transfers the underlying to the pool
* - mints Diesel (LP) tokens to onBehalfOf
* @param amount Amount of tokens to be deposited
* @param onBehalfOf The address that will receive the dToken
* @param referralCode Code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without a facilitator.
*/
function addLiquidity(
uint256 amount,
address onBehalfOf,
uint256 referralCode
) external;
/**
* @dev Removes liquidity from pool
* - burns LP's Diesel (LP) tokens
* - returns the equivalent amount of underlying to 'to'
* @param amount Amount of Diesel tokens to burn
* @param to Address to transfer the underlying to
*/
function removeLiquidity(uint256 amount, address to)
external
returns (uint256);
/**
* @dev Lends pool funds to a Credit Account
* @param borrowedAmount Credit Account's debt principal
* @param creditAccount Credit Account's address
*/
function lendCreditAccount(uint256 borrowedAmount, address creditAccount)
external;
/**
* @dev Repays the Credit Account's debt
* @param borrowedAmount Amount of principal ro repay
* @param profit The treasury profit from repayment
* @param loss Amount of underlying that the CA wan't able to repay
* @notice Assumes that the underlying (including principal + interest + fees)
* was already transferred
*/
function repayCreditAccount(
uint256 borrowedAmount,
uint256 profit,
uint256 loss
) external;
//
// GETTERS
//
/**
* @dev Returns the total amount of liquidity in the pool, including borrowed and available funds
*/
function expectedLiquidity() external view returns (uint256);
/**
* @dev Returns the limit on total liquidity
*/
function expectedLiquidityLimit() external view returns (uint256);
/**
* @dev Returns the available liquidity, which is expectedLiquidity - totalBorrowed
*/
function availableLiquidity() external view returns (uint256);
/**
* @dev Calculates the current interest index, RAY format
*/
function calcLinearCumulative_RAY() external view returns (uint256);
/**
* @dev Calculates the current borrow rate, RAY format
*/
function borrowAPY_RAY() external view returns (uint256);
/**
* @dev Returns the total borrowed amount (includes principal only)
*/
function totalBorrowed() external view returns (uint256);
/**
* ç
**/
function getDieselRate_RAY() external view returns (uint256);
/**
* @dev Returns the address of the underlying
*/
function underlyingToken() external view returns (address);
/**
* @dev Returns the address of the diesel token
*/
function dieselToken() external view returns (address);
/**
* @dev Returns the address of a Credit Manager by its id
*/
function creditManagers(uint256 id) external view returns (address);
/**
* @dev Returns the number of known Credit Managers
*/
function creditManagersCount() external view returns (uint256);
/**
* @dev Maps Credit Manager addresses to their status as a borrower.
* Returns false if borrowing is not allowed.
*/
function creditManagersCanBorrow(address id) external view returns (bool);
/// @dev Converts a quantity of the underlying to Diesel tokens
function toDiesel(uint256 amount) external view returns (uint256);
/// @dev Converts a quantity of Diesel tokens to the underlying
function fromDiesel(uint256 amount) external view returns (uint256);
/// @dev Returns the withdrawal fee
function withdrawFee() external view returns (uint256);
/// @dev Returns the timestamp of the pool's last update
function _timestampLU() external view returns (uint256);
/// @dev Returns the interest index at the last pool update
function _cumulativeIndex_RAY() external view returns (uint256);
/// @dev Returns the address provider
function addressProvider() external view returns (AddressProvider);
}
IERC20Permit.sol 60 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
IERC20Metadata.sol 28 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
ZapperBase.sol 148 lines
// SPDX-License-Identifier: GPL-2.0-or-later
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2023.
pragma solidity ^0.8.17;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol";
import {SafeERC20} from "@1inch/solidity-utils/contracts/libraries/SafeERC20.sol";
import {IPoolV3} from "@gearbox-protocol/core-v3/contracts/interfaces/IPoolV3.sol";
import {IZapper} from "../interfaces/zappers/IZapper.sol";
/// @title Zapper base
/// @notice Base contract for zappers that combine depositing/redeeming funds to/from a Gearbox pool
/// and other operations, such as wrapping tokens or staking pool shares, into a single call
abstract contract ZapperBase is IZapper {
using SafeERC20 for IERC20;
/// @notice Pool this zapper is connected to
address public immutable pool;
/// @notice `pool`'s underlying token
address public immutable underlying;
/// @notice Constructor
/// @param pool_ Pool to connect a new zapper to
constructor(address pool_) {
pool = pool_; // U:[ZB-1]
underlying = IPoolV3(pool_).underlyingToken(); // U:[ZB-1]
_resetAllowance(underlying, pool); // U:[ZB-1]
}
/// @notice Zapper's input token
function tokenIn() public view virtual returns (address);
/// @notice Zapper's output token
function tokenOut() public view virtual returns (address);
// ------- //
// PREVIEW //
// ------- //
/// @notice Returns the amount of `tokenOut` one would receive by depositing `tokenInAmount` of `tokenIn`
function previewDeposit(uint256 tokenInAmount) external view returns (uint256 tokenOutAmount) {
uint256 assets = tokenIn() == underlying ? tokenInAmount : _previewTokenInToUnderlying(tokenInAmount); // U:[ZB-2]
uint256 shares = IPoolV3(pool).previewDeposit(assets); // U:[ZB-2]
tokenOutAmount = tokenOut() == pool ? shares : _previewSharesToTokenOut(shares); // U:[ZB-2]
}
/// @notice Returns the amount of `tokenIn` one would receive by redeeming `tokenOutAmount` of `tokenOut`
function previewRedeem(uint256 tokenOutAmount) external view returns (uint256 tokenInAmount) {
uint256 shares = tokenOut() == pool ? tokenOutAmount : _previewTokenOutToShares(tokenOutAmount); // U:[ZB-3]
uint256 assets = IPoolV3(pool).previewRedeem(shares); // U:[ZB-3]
tokenInAmount = tokenIn() == underlying ? assets : _previewUnderlyingToTokenIn(assets); // U:[ZB-3]
}
/// @dev Returns the amount of `underlying` one would receive by converting `tokenInAmount` of `tokenIn`
function _previewTokenInToUnderlying(uint256 tokenInAmount) internal view virtual returns (uint256 assets);
/// @dev Returns the amount of `tokenIn` one would receive by converting `assets` of `underlying`
function _previewUnderlyingToTokenIn(uint256 assets) internal view virtual returns (uint256 tokenInAmount);
/// @dev Returns the amount of `tokenOut` one would receive by converting `shares` of `pool`'s shares
function _previewSharesToTokenOut(uint256 shares) internal view virtual returns (uint256 tokenOutAmount);
/// @dev Returns the amount of `pool`'s shares one would receive by converting `tokenOutAmount` of `tokenOut`
function _previewTokenOutToShares(uint256 tokenOutAmount) internal view virtual returns (uint256 shares);
// --- //
// ZAP //
// --- //
/// @notice Performs redeem zap:
/// - receives `tokenOut` from `msg.sender` and converts it to `pool`'s shares
/// - redeems `pool`'s shares for `underlying`
/// - converts `underlying` to `tokenIn` and sends it to `receiver`
/// @dev Requires approval from `msg.sender` for `tokenOut` to this contract
function redeem(uint256 tokenOutAmount, address receiver) external returns (uint256 tokenInAmount) {
tokenInAmount = _redeem(tokenOutAmount, receiver, msg.sender);
}
/// @notice Performs redeem zap using signed EIP-2612 permit message for zapper's output token:
/// - receives `tokenOut` from `msg.sender` and converts it to `pool`'s shares
/// - redeems `pool`'s shares for `underlying`
/// - converts `underlying` to `tokenIn` and sends it to `receiver`
/// @dev `v`, `r`, `s` must be a valid signature of the permit message from `msg.sender` for `tokenOut` to this contract
function redeemWithPermit(uint256 tokenOutAmount, address receiver, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
external
returns (uint256 tokenInAmount)
{
try IERC20Permit(tokenOut()).permit(msg.sender, address(this), tokenOutAmount, deadline, v, r, s) {} catch {} // U:[ZB-5]
tokenInAmount = _redeem(tokenOutAmount, receiver, msg.sender);
}
/// @dev `deposit` and `depositWithReferral` implementation
/// @dev If `tokenOut` is `pool`, skips `_sharesToTokenOut` and mints shares directly to `receiver` on deposit
function _deposit(uint256 tokenInAmount, address receiver, bool withReferral, uint256 referralCode)
internal
virtual
returns (uint256 tokenOutAmount)
{
bool tokenOutIsPool = tokenOut() == pool;
uint256 assets = _tokenInToUnderlying(tokenInAmount); // U:[ZB-4]
uint256 shares = withReferral
? IPoolV3(pool).depositWithReferral(assets, tokenOutIsPool ? receiver : address(this), referralCode)
: IPoolV3(pool).deposit(assets, tokenOutIsPool ? receiver : address(this)); // U:[ZB-4]
tokenOutAmount = tokenOutIsPool ? shares : _sharesToTokenOut(shares, receiver); // U:[ZB-4]
}
/// @dev `redeem` and `redeemWithReferral` implementation
/// @dev If `tokenOut` is `pool`, skips `_tokenOutToShares` and burns shares directly from `owner` on redeem
/// @dev If `tokenIn` is `underlying`, skips `_underlyingToTokenIn` and sends tokens directly to `receiver` on redeem
function _redeem(uint256 tokenOutAmount, address receiver, address owner)
internal
virtual
returns (uint256 tokenInAmount)
{
bool tokenOutIsPool = tokenOut() == pool;
bool tokenInIsUnderlying = tokenIn() == underlying;
uint256 shares = tokenOutIsPool ? tokenOutAmount : _tokenOutToShares(tokenOutAmount, owner); // U:[ZB-5]
uint256 assets = IPoolV3(pool).redeem({
shares: shares,
receiver: tokenInIsUnderlying ? receiver : address(this),
owner: tokenOutIsPool ? owner : address(this)
}); // U:[ZB-5]
tokenInAmount = tokenInIsUnderlying ? assets : _underlyingToTokenIn(assets, receiver); // U:[ZB-5]
}
/// @dev Receives `tokenInAmount` of `tokenIn` from `msg.sender` and converts it to `underlying`
function _tokenInToUnderlying(uint256 tokenInAmount) internal virtual returns (uint256 assets);
/// @dev Converts `assets` of `underlying` to `tokenIn` and sends it to `receiver`
function _underlyingToTokenIn(uint256 assets, address receiver) internal virtual returns (uint256 tokenInAmount);
/// @dev Converts `shares` of `pool`'s shares to `tokenOut` and sends it to `receiver`
function _sharesToTokenOut(uint256 shares, address receiver) internal virtual returns (uint256 tokenOutAmount);
/// @dev Receives `tokenOutAmount` of `tokenOut` from `owner` and converts it to `pool`'s shares
function _tokenOutToShares(uint256 tokenOutAmount, address owner) internal virtual returns (uint256 shares);
// --------- //
// INTERNALS //
// --------- //
/// @dev Gives `spender` max allowance for this contract's `token`
function _resetAllowance(address token, address spender) internal {
IERC20(token).forceApprove(spender, type(uint256).max);
}
}
RevertReasonForwarder.sol 16 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title Revert reason forwarder.
library RevertReasonForwarder {
/// @dev Forwards latest externall call revert.
function reRevert() internal pure {
// bubble up revert reason from latest external call
assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
}
}
IAddressProvider.sol 43 lines
// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Holdings, 2022
pragma solidity ^0.8.10;
import { IVersion } from "./IVersion.sol";
interface IAddressProviderEvents {
/// @dev Emits when an address is set for a contract role
event AddressSet(bytes32 indexed service, address indexed newAddress);
}
/// @title Optimised for front-end Address Provider interface
interface IAddressProvider is IAddressProviderEvents, IVersion {
/// @return Address of ACL contract
function getACL() external view returns (address);
/// @return Address of ContractsRegister
function getContractsRegister() external view returns (address);
/// @return Address of AccountFactory
function getAccountFactory() external view returns (address);
/// @return Address of DataCompressor
function getDataCompressor() external view returns (address);
/// @return Address of GEAR token
function getGearToken() external view returns (address);
/// @return Address of WETH token
function getWethToken() external view returns (address);
/// @return Address of WETH Gateway
function getWETHGateway() external view returns (address);
/// @return Address of PriceOracleV2
function getPriceOracle() external view returns (address);
/// @return Address of DAO Treasury Multisig
function getTreasuryContract() external view returns (address);
/// @return Address of PathFinder
function getLeveragedActions() external view returns (address);
}
draft-IERC20Permit.sol 8 lines
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; // EIP-2612 is Final as of 2022-11-01. This file is deprecated. import "./IERC20Permit.sol";
ERC20ZapperBase.sol 61 lines
// SPDX-License-Identifier: GPL-2.0-or-later
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2023.
pragma solidity ^0.8.17;
import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol";
import {ZapperBase} from "./ZapperBase.sol";
import {IERC20ZapperDeposits} from "../interfaces/zappers/IERC20ZapperDeposits.sol";
/// @title ERC20 zapper base
/// @notice Base contract for zappers with ERC20 input token
abstract contract ERC20ZapperBase is ZapperBase, IERC20ZapperDeposits {
/// @notice Performs deposit zap:
/// - receives `tokenInAmount` of `tokenIn` from `msg.sender` and converts it to `underlying`
/// - deposits `underlying` into `pool`
/// - converts `pool`'s shares to `tokenOutAmount` of `tokenOut` and sends it to `receiver`
/// @dev Requires approval from `msg.sender` for `tokenIn` to this contract
function deposit(uint256 tokenInAmount, address receiver) external returns (uint256 tokenOutAmount) {
tokenOutAmount = _deposit(tokenInAmount, receiver, false, 0);
}
/// @notice Performs deposit zap using signed EIP-2612 permit message for zapper's input token:
/// - receives `tokenInAmount` of `tokenIn` from `msg.sender` and converts it to `underlying`
/// - deposits `underlying` into `pool`
/// - converts `pool`'s shares to `tokenOutAmount` of `tokenOut` and sends it to `receiver`
/// @dev `v`, `r`, `s` must be a valid signature of the permit message from `msg.sender` for `tokenIn` to this contract
function depositWithPermit(uint256 tokenInAmount, address receiver, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
external
returns (uint256 tokenOutAmount)
{
_permitTokenIn(tokenInAmount, deadline, v, r, s);
tokenOutAmount = _deposit(tokenInAmount, receiver, false, 0);
}
/// @notice Same as `deposit` but allows specifying the `referralCode` when depositing into the pool
function depositWithReferral(uint256 tokenInAmount, address receiver, uint256 referralCode)
external
returns (uint256 tokenOutAmount)
{
tokenOutAmount = _deposit(tokenInAmount, receiver, true, referralCode);
}
/// @notice Same as `depositWithPermit` but allows specifying the `referralCode` when depositing into the pool
function depositWithReferralAndPermit(
uint256 tokenInAmount,
address receiver,
uint256 referralCode,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 tokenOutAmount) {
_permitTokenIn(tokenInAmount, deadline, v, r, s);
tokenOutAmount = _deposit(tokenInAmount, receiver, true, referralCode);
}
/// @dev Executes `tokenIn` permit from `msg.sender` to this contract
function _permitTokenIn(uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) internal {
try IERC20Permit(tokenIn()).permit(msg.sender, address(this), amount, deadline, v, r, s) {} catch {}
}
}
IZapper.sol 24 lines
// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2023.
pragma solidity ^0.8.17;
interface IZapper {
function pool() external view returns (address);
function underlying() external view returns (address);
function tokenIn() external view returns (address);
function tokenOut() external view returns (address);
function previewDeposit(uint256 tokenInAmount) external view returns (uint256 tokenOutAmount);
function previewRedeem(uint256 tokenOutAmount) external view returns (uint256 tokenInAmount);
function redeem(uint256 tokenOutAmount, address receiver) external returns (uint256 tokenInAmount);
function redeemWithPermit(uint256 tokenOutAmount, address receiver, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
external
returns (uint256 tokenInAmount);
}
DTokenTrait.sol 64 lines
// SPDX-License-Identifier: GPL-2.0-or-later
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2023.
pragma solidity ^0.8.17;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@1inch/solidity-utils/contracts/libraries/SafeERC20.sol";
import {IPoolService} from "@gearbox-protocol/core-v2/contracts/interfaces/IPoolService.sol";
import {
IncompatibleContractException,
NotImplementedException
} from "@gearbox-protocol/core-v3/contracts/interfaces/IExceptions.sol";
import {ERC20ZapperBase} from "../ERC20ZapperBase.sol";
import {ZapperBase} from "../ZapperBase.sol";
/// @title dToken trait
/// @notice Implements tokenIn -> underlying conversion for pools with older diesel tokens as input tokens
abstract contract DTokenTrait is ERC20ZapperBase {
using SafeERC20 for IERC20;
/// @dev Old pool address
address internal immutable _pool;
/// @dev Old diesel token address
address internal immutable _dToken;
/// @notice Constructor
/// @param pool Old pool address
constructor(address pool) {
if (IPoolService(pool).underlyingToken() != underlying) revert IncompatibleContractException();
_pool = pool;
_dToken = IPoolService(pool).dieselToken();
}
/// @inheritdoc ZapperBase
/// @dev Returns older pool's diesel token address
function tokenIn() public view override returns (address) {
return _dToken;
}
/// @inheritdoc ZapperBase
function _previewTokenInToUnderlying(uint256 tokenInAmount) internal view override returns (uint256 assets) {
assets = IPoolService(_pool).fromDiesel(tokenInAmount);
}
/// @inheritdoc ZapperBase
/// @dev Reverts as conversion back to older diesel tokens is not supported
function _previewUnderlyingToTokenIn(uint256) internal pure override returns (uint256) {
revert NotImplementedException();
}
/// @inheritdoc ZapperBase
function _tokenInToUnderlying(uint256 tokenInAmount) internal override returns (uint256 assets) {
IERC20(_dToken).safeTransferFrom(msg.sender, address(this), tokenInAmount);
assets = IPoolService(_pool).removeLiquidity(tokenInAmount, address(this));
}
/// @inheritdoc ZapperBase
/// @dev Reverts as conversion back to older diesel tokens is not supported
function _underlyingToTokenIn(uint256, address) internal pure override returns (uint256) {
revert NotImplementedException();
}
}
DTokenFarmingZapper.sol 18 lines
// SPDX-License-Identifier: GPL-2.0-or-later
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2023.
pragma solidity ^0.8.17;
import {FarmingTrait} from "./traits/FarmingTrait.sol";
import {DTokenTrait} from "./traits/DTokenTrait.sol";
import {ZapperBase} from "./ZapperBase.sol";
/// @title Diesel token farming zapper
/// @notice Zapper that allows to migrate liquidity from older to newer pools and stake shares in 1inch farming contract
contract DTokenFarmingZapper is DTokenTrait, FarmingTrait {
constructor(address newPool, address oldPool, address farmingPool)
ZapperBase(newPool)
DTokenTrait(oldPool)
FarmingTrait(farmingPool)
{}
}
FarmingTrait.sol 59 lines
// SPDX-License-Identifier: GPL-2.0-or-later
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2023.
pragma solidity ^0.8.17;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@1inch/solidity-utils/contracts/libraries/SafeERC20.sol";
import {IFarmingPool} from "@1inch/farming/contracts/interfaces/IFarmingPool.sol";
import {ZapperBase} from "../ZapperBase.sol";
/// @title Farming trait
/// @dev Implements shares <-> tokenOut conversion functions for zappers that stake shares in 1inch `FarmingPool` contract
abstract contract FarmingTrait is ZapperBase {
using SafeERC20 for IERC20;
/// @dev Farming pool to stake shares at
address internal immutable _farmingPool;
/// @notice Constructor
/// @param farmingPool Farming pool to stake shares at
constructor(address farmingPool) {
_farmingPool = farmingPool;
_resetAllowance(pool, farmingPool);
}
/// @inheritdoc ZapperBase
/// @dev Returns farming pool address
function tokenOut() public view override returns (address) {
return _farmingPool;
}
/// @inheritdoc ZapperBase
/// @dev Returns `shares` since farming pool balance is the same as staked amount
function _previewSharesToTokenOut(uint256 shares) internal pure override returns (uint256 tokenOutAmount) {
tokenOutAmount = shares;
}
/// @inheritdoc ZapperBase
/// @dev Returns `tokenOutAmount` since farming pool balance is the same as staked amount
function _previewTokenOutToShares(uint256 tokenOutAmount) internal pure override returns (uint256 shares) {
shares = tokenOutAmount;
}
/// @inheritdoc ZapperBase
/// @dev Returns `shares` since farming pool balance is the same as staked amount
function _sharesToTokenOut(uint256 shares, address receiver) internal override returns (uint256 tokenOutAmount) {
IFarmingPool(_farmingPool).deposit(shares);
tokenOutAmount = shares;
IERC20(_farmingPool).safeTransfer(receiver, tokenOutAmount);
}
/// @inheritdoc ZapperBase
/// @dev Returns `tokenOutAmount` since farming pool balance is the same as staked amount
function _tokenOutToShares(uint256 tokenOutAmount, address owner) internal override returns (uint256 shares) {
IERC20(_farmingPool).safeTransferFrom(owner, address(this), tokenOutAmount);
IFarmingPool(_farmingPool).withdraw(tokenOutAmount);
shares = tokenOutAmount;
}
}
IERC20ZapperDeposits.sol 26 lines
// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2023.
pragma solidity ^0.8.17;
interface IERC20ZapperDeposits {
function deposit(uint256 tokenInAmount, address receiver) external returns (uint256 tokenOutAmount);
function depositWithPermit(uint256 tokenInAmount, address receiver, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
external
returns (uint256 tokenOutAmount);
function depositWithReferral(uint256 tokenInAmount, address receiver, uint256 referralCode)
external
returns (uint256 tokenOutAmount);
function depositWithReferralAndPermit(
uint256 tokenInAmount,
address receiver,
uint256 referralCode,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 tokenOutAmount);
}
Read Contract
pool 0x16f0115b → address
previewDeposit 0xef8b30f7 → uint256
previewRedeem 0x4cdad506 → uint256
tokenIn 0x6daf390b → address
tokenOut 0xd0202d3b → address
underlying 0x6f307dc3 → address
Write Contract 6 functions
These functions modify contract state and require a wallet transaction to execute.
deposit 0x6e553f65
uint256 tokenInAmount
address receiver
returns: uint256
depositWithPermit 0x50921b23
uint256 tokenInAmount
address receiver
uint256 deadline
uint8 v
bytes32 r
bytes32 s
returns: uint256
depositWithReferral 0xb3d45433
uint256 tokenInAmount
address receiver
uint256 referralCode
returns: uint256
depositWithReferralAndPermit 0x21645579
uint256 tokenInAmount
address receiver
uint256 referralCode
uint256 deadline
uint8 v
bytes32 r
bytes32 s
returns: uint256
redeem 0x7bde82f2
uint256 tokenOutAmount
address receiver
returns: uint256
redeemWithPermit 0xb086726b
uint256 tokenOutAmount
address receiver
uint256 deadline
uint8 v
bytes32 r
bytes32 s
returns: uint256
Recent Transactions
No transactions found for this address