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"
]
}
}
}
}}
Submitted on: 2025-11-05 11:48:24
Comments
Log in to comment.
No comments yet.