OrigamiSuperSkyRewardsHarvester

Description:

Proxy contract enabling upgradeable smart contract patterns. Delegates calls to an implementation contract.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "@openzeppelin/contracts/interfaces/IERC165.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol)

pragma solidity ^0.8.0;

import "../utils/introspection/IERC165.sol";
"
    },
    "@openzeppelin/contracts/interfaces/IERC4626.sol": {
      "content": "// 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);
}
"
    },
    "@openzeppelin/contracts/interfaces/IERC5267.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC5267.sol)

pragma solidity ^0.8.0;

interface IERC5267 {
    /**
     * @dev MAY be emitted to signal that the domain could have changed.
     */
    event EIP712DomainChanged();

    /**
     * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
     * signature.
     */
    function eip712Domain()
        external
        view
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        );
}
"
    },
    "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": {
      "content": "// 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);
}
"
    },
    "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol": {
      "content": "// 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);
}
"
    },
    "@openzeppelin/contracts/token/ERC20/IERC20.sol": {
      "content": "// 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);
}
"
    },
    "@openzeppelin/contracts/utils/introspection/IERC165.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
"
    },
    "contracts/interfaces/common/IOrigamiErc4626.sol": {
      "content": "pragma solidity ^0.8.4;
// SPDX-License-Identifier: AGPL-3.0-or-later
// Origami (interfaces/common/IOrigamiErc4626.sol)

import { IERC20Permit } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol";
import { IERC5267 } from "@openzeppelin/contracts/interfaces/IERC5267.sol";
import { IERC4626 } from "@openzeppelin/contracts/interfaces/IERC4626.sol";
import { IERC165 } from "@openzeppelin/contracts/interfaces/IERC165.sol";

/**
 * @title Origami ERC-4626
 * @notice A fork of the openzeppelin ERC-4626, with:
 *  - `_decimalsOffset()` set to zero (OZ defaults to zero anyway)
 *  - Always has decimals() of 18dp (rather than using the underlying asset)
 *  - Deposit and Withdraw fees, which are taken from the _shares_ of the user,
 *    benefiting the existing vault holders.
 *  - Permit support
 *  - IERC165 support
 *  - Reentrancy guard on deposit/mint/withdraw/redeem
 *  - maxRedeem & maxWithdraw for address(0) returns the total vault capacity (given any caps within the implementation) 
 *    which can be withdrawn/redeemed (rather than always returning zero)
 */
interface IOrigamiErc4626 is 
    IERC4626, 
    IERC20Permit, 
    IERC165, 
    IERC5267
{
    /// @dev Attempted to deposit more assets than the max amount for `receiver`.
    error ERC4626ExceededMaxDeposit(address receiver, uint256 assets, uint256 max);

    /// @dev Attempted to mint more shares than the max amount for `receiver`.
    error ERC4626ExceededMaxMint(address receiver, uint256 shares, uint256 max);

    /// @dev Attempted to withdraw more assets than the max amount for `receiver`.
    error ERC4626ExceededMaxWithdraw(address owner, uint256 assets, uint256 max);

    /// @dev Attempted to redeem more shares than the max amount for `receiver`.
    error ERC4626ExceededMaxRedeem(address owner, uint256 shares, uint256 max);

    /// @dev Permit deadline has expired.
    error ERC2612ExpiredSignature(uint256 deadline);

    /// @dev Mismatched signature.
    error ERC2612InvalidSigner(address signer, address tokensOwner);

    /// @dev What kind of fees - either Deposit or withdrawal
    enum FeeType {
        DEPOSIT_FEE,
        WITHDRAWAL_FEE
    }

    /// @dev Either deposit or withdrawal fees have been updated
    event FeeBpsSet(FeeType feeType, uint256 feeBps);

    /// @dev Either deposit or withdrawal fees have been applied
    event InKindFees(FeeType feeType, uint256 feeBps, uint256 feeAmount);

    /// @dev A client implementation may emit if the max total supply has been changed
    event MaxTotalSupplySet(uint256 maxTotalSupply);

    /// @notice Set the max total supply allowed for this vault
    /// @dev Will revert if the current totalSupply is zero as
    /// `seedDeposit()` needs to be called first
    function setMaxTotalSupply(uint256 maxTotalSupply) external;

    /// @notice Origami protocol seeds the initial deposit
    /// @dev The new maxTotalSupply is set and a trusted deposit
    /// is made
    function seedDeposit(
        uint256 assets,
        address receiver,
        uint256 maxTotalSupply
    ) external returns (uint256 shares);

    /// @notice The current deposit fee in basis points.
    function depositFeeBps() external view returns (uint256);

    /// @notice The current withdrawal fee in basis points.
    function withdrawalFeeBps() external view returns (uint256);

    /// @notice The current maximum total supply of vault tokens.
    function maxTotalSupply() external view returns (uint256);

    /// @notice Whether deposit/mint is currently paused
    function areDepositsPaused() external view returns (bool);

    /// @notice Whether withdrawal/redeem is currently paused
    function areWithdrawalsPaused() external view returns (bool);
}
"
    },
    "contracts/interfaces/common/ITokenPrices.sol": {
      "content": "pragma solidity ^0.8.4;
// SPDX-License-Identifier: AGPL-3.0-or-later
// Origami (interfaces/common/ITokenPrices.sol)

/// @title Token Prices
/// @notice A utility contract to pull token prices from on-chain.
/// @dev composable functions (uisng encoded function calldata) to build up price formulas
interface ITokenPrices {
    /// @notice How many decimals places are the token prices reported in
    function decimals() external view returns (uint8);

    /// @notice Retrieve the price for a given token.
    /// @dev If not mapped, or an underlying error occurs, FailedPriceLookup will be thrown.
    /// @dev 0x000...0 is the native chain token (ETH/AVAX/etc)
    function tokenPrice(address token) external view returns (uint256 price);

    /// @notice Token address to function calldata for how to lookup the price for this token
    function priceFnCalldata(address token) external view returns (bytes memory fnCalldata);

    /// @notice Retrieve the price for a list of tokens.
    /// @dev If any aren't mapped, or an underlying error occurs, FailedPriceLookup will be thrown.
    /// @dev Not particularly gas efficient - wouldn't recommend to use on-chain
    function tokenPrices(address[] memory tokens) external view returns (uint256[] memory prices);

    /// @notice The set of all mapped tokens
    function mappedTokenAt(uint256 i) external view returns (address token);

    /// @notice The set of all mapped tokens
    function allMappedTokens() external view returns (address[] memory);

    /// @notice The number of mapped tokens
    function numMappedTokens() external view returns (uint256);
}"
    },
    "contracts/interfaces/external/sky/ISkyLockstakeEngine.sol": {
      "content": "pragma solidity ^0.8.4;
// SPDX-License-Identifier: AGPL-3.0-or-later
// Origami (interfaces/external/sky/ISkyLockstakeEngine.sol)

interface ISkyLockstakeEngine {
    enum FarmStatus { UNSUPPORTED, ACTIVE, DELETED }

    // --- Events ---
    event Rely(address indexed usr);
    event Deny(address indexed usr);
    event File(bytes32 indexed what, address data);
    event AddFarm(address farm);
    event DelFarm(address farm);
    event Open(address indexed owner, uint256 indexed index, address urn);
    event Hope(address indexed owner, uint256 indexed index, address indexed usr);
    event Nope(address indexed owner, uint256 indexed index, address indexed usr);
    event SelectVoteDelegate(address indexed owner, uint256 indexed index, address indexed voteDelegate);
    event SelectFarm(address indexed owner, uint256 indexed index, address indexed farm, uint16 ref);
    event Lock(address indexed owner, uint256 indexed index, uint256 wad, uint16 ref);
    event Free(address indexed owner, uint256 indexed index, address to, uint256 wad, uint256 freed);
    event FreeNoFee(address indexed owner, uint256 indexed index, address to, uint256 wad);
    event Draw(address indexed owner, uint256 indexed index, address to, uint256 wad);
    event Wipe(address indexed owner, uint256 indexed index, uint256 wad);
    event GetReward(address indexed owner, uint256 indexed index, address indexed farm, address to, uint256 amt);
    event OnKick(address indexed urn, uint256 wad);
    event OnTake(address indexed urn, address indexed who, uint256 wad);
    event OnRemove(address indexed urn, uint256 sold, uint256 burn, uint256 refund);

    // --- Constants ---
    function WAD() external pure returns (uint256);
    function RAY() external pure returns (uint256);

    // --- Immutable Getters ---
    function voteDelegateFactory() external view returns (address);
    function vat() external view returns (address);
    function usdsJoin() external view returns (address);
    function usds() external view returns (address);
    function ilk() external view returns (bytes32);
    function sky() external view returns (address);
    function lssky() external view returns (address);
    function urnImplementation() external view returns (address);
    function fee() external view returns (uint256);

    // --- Storage Getters ---
    function wards(address usr) external view returns (uint256 allowed);
    function farms(address farm) external view returns (FarmStatus);
    function ownerUrnsCount(address owner) external view returns (uint256 count);
    function ownerUrns(address owner, uint256 index) external view returns (address urn);
    function urnOwners(address urn) external view returns (address owner);
    function urnCan(address urn, address usr) external view returns (uint256 allowed);
    function urnVoteDelegates(address urn) external view returns (address voteDelegate);
    function urnFarms(address urn) external view returns (address farm);
    function urnAuctions(address urn) external view returns (uint256 auctionsCount);
    function jug() external view returns (address);

    // --- Admin ---
    function rely(address usr) external;
    function deny(address usr) external;
    function file(bytes32 what, address data) external;
    function addFarm(address farm) external;
    function delFarm(address farm) external;

    // --- Getters ---
    function isUrnAuth(address owner, uint256 index, address usr) external view returns (bool ok);

    // --- Urn Management ---
    function open(uint256 index) external returns (address urn);
    function hope(address owner, uint256 index, address usr) external;
    function nope(address owner, uint256 index, address usr) external;

    // --- Delegation / Staking ---
    function selectVoteDelegate(address owner, uint256 index, address voteDelegate) external;
    function selectFarm(address owner, uint256 index, address farm, uint16 ref) external;

    // --- Collateral ---
    function lock(address owner, uint256 index, uint256 wad, uint16 ref) external;
    function free(address owner, uint256 index, address to, uint256 wad) external returns (uint256 freed);
    function freeNoFee(address owner, uint256 index, address to, uint256 wad) external;

    // --- Loan ---
    function draw(address owner, uint256 index, address to, uint256 wad) external;
    function wipe(address owner, uint256 index, uint256 wad) external;
    function wipeAll(address owner, uint256 index) external returns (uint256 wad);

    // --- Rewards ---
    function getReward(address owner, uint256 index, address farm, address to) external returns (uint256 amt);

    // --- Liquidation ---
    function onKick(address urn, uint256 wad) external;
    function onTake(address urn, address who, uint256 wad) external;
    function onRemove(address urn, uint256 sold, uint256 left) external;
}
"
    },
    "contracts/interfaces/external/sky/ISkyStakingRewards.sol": {
      "content": "// SPDX-FileCopyrightText: © 2019-2021 Synthetix
// SPDX-FileCopyrightText: © 2023 Dai Foundation <www.daifoundation.org>
// SPDX-License-Identifier: MIT AND AGPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
pragma solidity ^0.8.4;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

// https://docs.synthetix.io/contracts/source/interfaces/istakingrewards
interface ISkyStakingRewards {
    event RewardAdded(uint256 reward);
    event Staked(address indexed user, uint256 amount);
    event Referral(uint16 indexed referral, address indexed user, uint256 amount);
    event Withdrawn(address indexed user, uint256 amount);
    event RewardPaid(address indexed user, uint256 reward);
    event RewardsDurationUpdated(uint256 newDuration);
    event RewardsDistributionUpdated(address newRewardsDistribution);
    event Recovered(address token, uint256 amount);

    // Views

    function balanceOf(address account) external view returns (uint256);

    function earned(address account) external view returns (uint256);

    function rewardRate() external view returns (uint256);

    function getRewardForDuration() external view returns (uint256);

    function lastTimeRewardApplicable() external view returns (uint256);

    function rewardPerToken() external view returns (uint256);

    function rewardsDistribution() external view returns (address);

    function rewardsToken() external view returns (IERC20);

    function stakingToken() external view returns (IERC20);

    function totalSupply() external view returns (uint256);

    function userRewardPerTokenPaid(address account) external view returns (uint256);

    function rewards(address account) external view returns (uint256);

    function rewardPerTokenStored() external view returns (uint256);

    function lastUpdateTime() external view returns (uint256);

    function periodFinish() external view returns (uint256);

    function rewardsDuration() external view returns (uint256);

    // Mutative

    function exit() external;

    function getReward() external;

    function stake(uint256 amount) external;

    function stake(uint256 amount, uint16 referral) external;

    function withdraw(uint256 amount) external;

    function notifyRewardAmount(uint256 reward) external;

    function setRewardsDistribution(address _rewardsDistribution) external;

    function setRewardsDuration(uint256 _rewardsDuration) external;
}
"
    },
    "contracts/interfaces/investments/erc4626/IOrigamiDelegated4626Vault.sol": {
      "content": "pragma solidity ^0.8.4;
// SPDX-License-Identifier: AGPL-3.0-or-later
// Origami (investments/erc4626/IOrigamiDelegated4626Vault.sol)

import { ITokenPrices } from "contracts/interfaces/common/ITokenPrices.sol";
import { IOrigamiErc4626 } from "contracts/interfaces/common/IOrigamiErc4626.sol";

/** 
 * @title Origami Delegated ERC4626 Vault
 * @notice An Origami ERC4626 Vault, which delegates the handling of deposited assets
 * to a manager
 */
interface IOrigamiDelegated4626Vault is IOrigamiErc4626 {
    event TokenPricesSet(address indexed _tokenPrices);
    event ManagerSet(address indexed manager);
    event PerformanceFeeSet(uint256 fee);

    /**
     * @notice Set the helper to calculate current off-chain/subgraph integration
     */
    function setTokenPrices(address tokenPrices) external;

    /**
     * @notice Set the Origami delegated manager 
     * @dev If there was a prior manager set, then the totalAssets will be withdrawn
     * from existing manager and deposited into the new manager.
     * The new manager must have a min number of migrated assets - it may differ slightly
     * from rounding - eg if the underlying is an ERC4626 vault, or there are fees, etc.
     */
    function setManager(address manager, uint256 minMigratedAssets) external;

    /**
     * @notice The performance fee to Origami treasury
     * Represented in basis points
     */
    function performanceFeeBps() external view returns (uint48);

    /**
     * @notice The helper contract to retrieve Origami USD prices
     * @dev Required for off-chain/subgraph integration
     */
    function tokenPrices() external view returns (ITokenPrices);

    /**
     * @notice The Origami contract managing the application of
     * the deposit tokens into the underlying protocol
     */
    function manager() external view returns (address);
}
"
    },
    "contracts/interfaces/investments/erc4626/IOrigamiDelegated4626VaultManager.sol": {
      "content": "pragma solidity ^0.8.4;
// SPDX-License-Identifier: AGPL-3.0-or-later
// Origami (investments/erc4626/IOrigamiDelegated4626VaultManager.sol)

import { IERC165 } from "@openzeppelin/contracts/interfaces/IERC165.sol";
import { IOrigamiDelegated4626Vault } from "contracts/interfaces/investments/erc4626/IOrigamiDelegated4626Vault.sol";

/** 
 * @title Origami Delegated ERC4626 Vault Manager
 * @notice An Origami ERC4626 Vault Manager, which handles the deposited assets from a
 * IOrigamiDelegated4626Vault
 */
interface IOrigamiDelegated4626VaultManager is IERC165 {
    event FeeBpsSet(uint16 depositFeeBps, uint16 withdrawalFeeBps);
    event FeeCollectorSet(address indexed feeCollector);

    /// @notice Deposit tokens into the underlying protocol
    /// @dev Implementation SHOULD assume the tokens have already been sent to this contract
    /// @param assetsAmount The amount of assets to deposit. Implementation MAY choose to accept 
    /// type(uint256).max as a special value indicating the full balance of the contract
    function deposit(uint256 assetsAmount) external returns (
        uint256 assetsDeposited
    );

    /// @notice Withdraw tokens from the underlying protocol to a given receiver
    /// @dev
    /// - Fails if it can't withdraw that amount
    /// - type(uint256).max is accepted, meaning the entire balance
    function withdraw(
        uint256 assetsAmount,
        address receiver
    ) external returns (uint256 assetsWithdrawn);

    /// @notice The Origami vault this is managing
    function vault() external view returns (IOrigamiDelegated4626Vault);

    /// @notice Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
    /// @dev
    /// - MUST be an ERC-20 token contract.
    /// - MUST NOT revert.
    function asset() external view returns (address assetTokenAddress);

    /// @notice Returns the total amount of the underlying asset that is “managed” by Vault.
    /// @dev
    /// - 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);

    /// @notice Returns the amount of the underlying asset that is not yet allocated to any strategy
    function unallocatedAssets() external view returns (uint256);
    
    /// @notice The performance fee to the caller (to compensate for gas) and Origami treasury.
    /// @dev Represented in basis points.
    function performanceFeeBps() external view returns (uint16 forCaller, uint16 forOrigami);

    /// @notice Whether deposits and mints are currently paused
    function areDepositsPaused() external view returns (bool);

    /// @notice Whether withdrawals and redemptions are currently paused
    function areWithdrawalsPaused() external view returns (bool);

    /// @notice The current deposit fee in basis points
    function depositFeeBps() external view returns (uint16);

    /// @notice The current withdrawal fee in basis points
    function withdrawalFeeBps() external view returns (uint16);

    /// @notice The current max deposit amount of assets.
    /// type(uint256).max if no limit
    function maxDeposit() external view returns (uint256);

    /// @notice The current max withdraw amount of assets.
    /// type(uint256).max if no limit
    function maxWithdraw() external view returns (uint256);
}
"
    },
    "contracts/interfaces/investments/sky/IOrigamiSuperSkyManager.sol": {
      "content": "pragma solidity ^0.8.4;
// SPDX-License-Identifier: AGPL-3.0-or-later
// Origami (interfaces/sky/IOrigamiSuperSkyManager.sol)

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { ISkyLockstakeEngine } from "contracts/interfaces/external/sky/ISkyLockstakeEngine.sol";

import { IOrigamiDelegated4626VaultManager } from "contracts/interfaces/investments/erc4626/IOrigamiDelegated4626VaultManager.sol";
import { ISkyStakingRewards } from "contracts/interfaces/external/sky/ISkyStakingRewards.sol";

/**
 * @title Origami Staked Sky Auto-compounder Manager
 * @notice Handles SKY deposits and switching between farms.
 * @dev Uses an immutable SKY Lockstake Engine. If that ever changes, a new vault will be deployed.
 * Users would need to withdraw from Origami Vault A and deposit into Origami Vault B.
 */
interface IOrigamiSuperSkyManager is IOrigamiDelegated4626VaultManager {
    error InvalidFarm(uint32 farmIndex);
    error FarmStillInUse(uint32 farmIndex);
    error BeforeCooldownEnd();
    error MaxFarms();
    error FarmExistsAlready(address stakingAddress);

    event FarmReferralCodeSet(uint32 indexed farmIndex, uint16 referralCode);

    event SwitchFarmCooldownSet(uint32 cooldown);

    event SwapperSet(address indexed newSwapper);

    event FarmAdded(
        uint32 indexed farmIndex,
        address indexed stakingAddress,
        address indexed rewardsToken,
        uint16 referralCode
    );

    event FarmRemoved(
        uint32 indexed farmIndex,
        address indexed stakingAddress,
        address indexed rewardsToken
    );

    event SwitchedFarms(
        uint32 indexed oldFarmIndex, 
        uint32 indexed newFarmIndex, 
        uint256 amountWithdrawn, 
        uint256 amountDeposited
    );

    event ClaimedReward(
        uint32 indexed farmIndex, 
        address indexed rewardsToken, 
        uint256 amountForCaller, 
        uint256 amountForOrigami, 
        uint256 amountForVault
    );

    event Reinvest(uint256 amount);

    /// @dev Configuration required for a SKY farm
    struct Farm {
        /// @dev The address of the Synthetix-like SKY staking contract
        ISkyStakingRewards staking;

        /// @dev The rewards token for this given staking contract
        IERC20 rewardsToken;

        /// @dev The referral code representing Origami
        uint16 referral;
    }

    /**
     * @notice Set the performance fees for the caller and origami
     * @dev Total fees cannot increase, but the ratio can be changed.
     * Fees are distributed when claimFarmRewards() is called
     */
    function setPerformanceFees(uint16 callerFeeBps, uint16 origamiFeeBps) external;

    /**
     * @notice Set the address used to collect the Origami performance fees.
     */
    function setFeeCollector(address _feeCollector) external;

    /**
     * @notice Set the swapper contract responsible for swapping 
     * farm reward tokens into SKY
     */
    function setSwapper(address swapper) external;

    /**
     * @notice Set the cooldown for how frequently this contract is allowed to switch between
     * farms. Used to avoid thrashing.
     */
    function setSwitchFarmCooldown(uint32 cooldown) external;

    /**
     * @notice Add a new SKY farm configuration 
     * @dev Only a maximum of 100 farms can be added. Will revert if the same `stakingAddress` is 
     * added a second time.
     */ 
    function addFarm(
        address stakingAddress, 
        uint16 referralCode
    ) external returns (
        uint32 newFarmIndex
    );

    /**
     * @notice Remove a deprecated farm configuration item for house keeping
     * @dev This will revert if there's still a staked balance or rewards to claim.
     * If a farm is removed, the `maxFarmIndex` doesn't decrease
     */ 
    function removeFarm(uint32 farmIndex) external;

    /**
     * @notice Set the referral code for a given SKY staking contract
     */
    function setFarmReferralCode(
        uint32 farmIndex,
        uint16 referralCode
    ) external;

    /**
     * @notice Elevated access can decide to switch which farm to use if the yield is greater
     */
    function switchFarms(uint32 newFarmIndex) external returns (
        uint256 amountWithdrawn,
        uint256 amountDeposited
    );

    /**
     * @notice A permissionless function to claim farm rewards from a given farm
     * - The caller can nominate an address to receive a portion of these rewards (to compensate for gas)
     * - Origami will earn a portion of these rewards (as performance fee)
     * - The remainder is sent to a swapper contract to swap for SKY.
     * SKY proceeds from the swap will sent back to this contract, ready to add to the
     * current farm on the next deposit.
     */
    function claimFarmRewards(
        uint32[] calldata farmIndexes,
        address incentivesReceiver
    ) external;

    /**
     * @notice Reinvest any unallocated assets into the currently active farm
     */
    function reinvest() external;

    /**
     * @notice The Sky contract
     */
    function SKY() external view returns (IERC20);

    /**
     * @notice The Locked SKY contract, which is staked into farms
     * @dev rate: 1 SKY === 1 LSSKY
     */
    function LSSKY() external view returns (IERC20);

    /**
     * @notice The Sky Lockstake Engine contract
     */
    function LOCKSTAKE_ENGINE() external view returns (ISkyLockstakeEngine);

    /**
     * @notice The address of this contract's urn in the Sky lockstake engine
     */
    function URN_ADDRESS() external view returns (address);

    /**
     * @notice The performance fee to the caller (to compensate for gas) and Origami treasury
     * Represented in basis points
     */
    function performanceFeeBps() external view returns (uint16 forCaller, uint16 forOrigami);

    /**
     * @notice The address used to collect the Origami performance fees.
     */
    function feeCollector() external view returns (address);

    /**
     * @notice The swapper contract responsible for swapping 
     * farm reward tokens into SKY
     */
    function swapper() external view returns (address);

    /**
     * @notice The cooldown for how frequently this contract is allowed to switch between
     * farms. Used to avoid thrashing.
     */
    function switchFarmCooldown() external view returns (uint32);

    /**
     * @notice The last time that the farm was switched
     */
    function lastSwitchTime() external view returns (uint32);

    /**
     * @notice The number of Sky farms, not including holding raw
     * SKY in the urn rather than farming
     */
    function maxFarmIndex() external view returns (uint32);

    /**
     * @notice The currently selected farm for deposits.
     * @dev
     * - index 0: Raw SKY is held in the assigned Lockstake Engine urn
     * - index 1+: A SKY is staked in a farm
     */
    function currentFarmIndex() external view returns (uint32);
    
    /**
     * @notice The farm config of a particular index
     * @dev Does not revert - A farm index is invalid if the farmIndex is > 0 and
     * `farm.staking` is address(0)
     */
    function getFarm(uint256 farmIndex) external view returns (Farm memory farm);

    struct FarmDetails {
        /// @dev The farm configuration
        Farm farm;

        /// @dev The amount of SKY staked in the farm
        /// If no farm is chosen, this will be the balance of LSSKY
        /// held in the assigned urn
        uint256 stakedBalance;

        /// @dev The total amount of SKY staked in the farm across
        /// all stakers
        /// If no farm is chosen, this will be the total supply of LSSKY
        uint256 totalSupply;

        /// @dev The current rate of emissions from the farm
        /// If no farm is chosen, this will be zero
        uint256 rewardRate;

        /// @dev The amount of emissions earned which can
        /// currently be claimed.
        /// If no farm is chosen, this will be zero
        uint256 unclaimedRewards;        
    }

    /** 
     * @notice A helper to show the current positions for a set of farm indexes.
     * @dev If the farmIndex is not valid/removed that item will remain 
     * empty
     */
    function farmDetails(uint32[] calldata farmIndexes) external view returns (
        FarmDetails[] memory
    );

    /**
     * @notice Return the current SKY balance staked in the lockstake engine
     */
    function stakedBalance() external view returns (uint256);
}
"
    },
    "contracts/investments/sky/OrigamiSuperSkyRewardsHarvester.sol": {
      "content": "pragma solidity ^0.8.19;
// SPDX-License-Identifier: AGPL-3.0-or-later
// Origami (investments/sky/OrigamiSuperSkyRewardsHarvester.sol)

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IOrigamiSuperSkyManager } from "contracts/interfaces/investments/sky/IOrigamiSuperSkyManager.sol";

interface IOrigamiSwapper {
    /// @notice The rewards harvester is granted access to recover reward tokens from
    /// the current swapper
    function recoverToken(address token, address to, uint256 amount) external;
}

/// @title Origami SKY+ Rewards Harvester
/// @notice Harvest SKY token rewards and reinvest in the Sky+ manager
contract OrigamiSuperSkyRewardsHarvester {
    /// @notice The SKY+ Manager
    IOrigamiSuperSkyManager public immutable MANAGER;

    /// @notice The SKY token
    IERC20 public immutable SKY;

    constructor(address _skyManager) {
        MANAGER = IOrigamiSuperSkyManager(_skyManager);
        SKY = MANAGER.SKY();
    }

    /// @notice Harvest any balance of SKY tokens in the swapper and reinvest
    /// As part of the claim
    function claimFarmRewards(
        uint32[] calldata farmIndexes,
        address incentivesReceiver
    ) external {
        MANAGER.claimFarmRewards(farmIndexes, incentivesReceiver);

        address swapper = MANAGER.swapper();
        uint256 balance = SKY.balanceOf(swapper);
        if (balance > 0) {
            IOrigamiSwapper(swapper).recoverToken(address(SKY), address(MANAGER), balance);
            MANAGER.reinvest();
        }
    }
}
"
    }
  },
  "settings": {
    "optimizer": {
      "enabled": true,
      "runs": 9999
    },
    "evmVersion": "paris",
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    }
  }
}}

Tags:
ERC20, ERC165, Proxy, Mintable, Swap, Staking, Yield, Voting, Timelock, Upgradeable, Factory|addr:0xcb782f6dd2d27fb681d0bee2df0796b6fedd70b0|verified:true|block:23729616|tx:0xcce941c1b933dc4d897bc47389f6da22435716b54c6d59f9e20f7c154c64baca|first_check:1762339702

Submitted on: 2025-11-05 11:48:24

Comments

Log in to comment.

No comments yet.