Source Code
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Latest 4 Deposits
| L2 Txn Hash | L1 Deposit Txn | Value | Token | |
|---|---|---|---|---|
| 0x822d68604d2ad2268961ff7edd9797b1b97bbea7031faf5dd2539ed8522c514f | 382 days ago | 45,712.411410043880540729 | ||
| 0x5572c2ebf0147d637c97bffdacf6b43f5ed9d6c6e4f3309cbf852f13681e2c47 | 401 days ago | 31,433.424505716178623607 | ||
| 0x16c45913640e79c984c7d9e7e13277603a9ecc95f80d5eea4db6942cc5b87e86 | 401 days ago | 72,478.14205704801064903 | ||
| 0x0af8abe6b03b2f913347bbd41752342504102e288e4307e51d65520e80bc5dfd | 529 days ago | 7.915469703274746217 |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
L1QuitCreditorReceiverConverterTimedLocker
Compiler Version
v0.8.26+commit.8a97fa7a
Contract Source Code (Solidity)
/**
*Submitted for verification at fraxscan.com on 2024-08-16
*/
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;
// node_modules/@openzeppelin/contracts/security/ReentrancyGuard.sol
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}
// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
/**
* @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);
}
// node_modules/@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
/**
* @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);
}
// node_modules/@openzeppelin/contracts/utils/Address.sol
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
// node_modules/@openzeppelin/contracts/utils/Context.sol
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
// node_modules/@openzeppelin/contracts/utils/math/Math.sol
// OpenZeppelin Contracts (last updated v4.7.0) (utils/math/Math.sol)
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1);
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator,
Rounding rounding
) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. It the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`.
// We also know that `k`, the position of the most significant bit, is such that `msb(a) = 2**k`.
// This gives `2**k < a <= 2**(k+1)` → `2**(k/2) <= sqrt(a) < 2 ** (k/2+1)`.
// Using an algorithm similar to the msb conmputation, we are able to compute `result = 2**(k/2)` which is a
// good first aproximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1;
uint256 x = a;
if (x >> 128 > 0) {
x >>= 128;
result <<= 64;
}
if (x >> 64 > 0) {
x >>= 64;
result <<= 32;
}
if (x >> 32 > 0) {
x >>= 32;
result <<= 16;
}
if (x >> 16 > 0) {
x >>= 16;
result <<= 8;
}
if (x >> 8 > 0) {
x >>= 8;
result <<= 4;
}
if (x >> 4 > 0) {
x >>= 4;
result <<= 2;
}
if (x >> 2 > 0) {
result <<= 1;
}
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
uint256 result = sqrt(a);
if (rounding == Rounding.Up && result * result < a) {
result += 1;
}
return result;
}
}
// src/contracts/Miscellany/FraxFarmQuitCreditor/ICrossDomainMessenger.sol
interface ICrossDomainMessenger {
function MESSAGE_VERSION() external view returns (uint16);
function MIN_GAS_CALLDATA_OVERHEAD() external view returns (uint64);
function MIN_GAS_DYNAMIC_OVERHEAD_DENOMINATOR() external view returns (uint64);
function MIN_GAS_DYNAMIC_OVERHEAD_NUMERATOR() external view returns (uint64);
function OTHER_MESSENGER() external view returns (address);
function RELAY_CALL_OVERHEAD() external view returns (uint64);
function RELAY_CONSTANT_OVERHEAD() external view returns (uint64);
function RELAY_GAS_CHECK_BUFFER() external view returns (uint64);
function RELAY_RESERVED_GAS() external view returns (uint64);
function baseGas(bytes memory _message, uint32 _minGasLimit) external pure returns (uint64);
function failedMessages(bytes32) external view returns (bool);
function initialize() external;
function l1CrossDomainMessenger() external view returns (address);
function messageNonce() external view returns (uint256);
function paused() external view returns (bool);
function relayMessage(
uint256 _nonce,
address _sender,
address _target,
uint256 _value,
uint256 _minGasLimit,
bytes memory _message
) external;
function sendMessage(address _target, bytes memory _message, uint32 _minGasLimit) external;
function successfulMessages(bytes32) external view returns (bool);
function version() external view returns (string memory);
function xDomainMessageSender() external view returns (address);
}
// src/contracts/Miscellany/FraxFarmQuitCreditor/IExponentialPriceOracle.sol
interface IExponentialPriceOracle {
function getPrices() external view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh);
function priceEnd() external view returns (uint256);
function pricePerShare() external view returns (uint256 _price);
function priceStart() external view returns (uint256);
function timeEnd() external view returns (uint256);
function timeStart() external view returns (uint256);
}
// src/contracts/Miscellany/OwnedV2.sol
// https://docs.synthetix.io/contracts/Owned
contract OwnedV2 {
error OwnerCannotBeZero();
error InvalidOwnershipAcceptance();
error OnlyOwner();
address public owner;
address public nominatedOwner;
constructor(address _owner) {
// require(_owner != address(0), "Owner address cannot be 0");
if (_owner == address(0)) revert OwnerCannotBeZero();
owner = _owner;
emit OwnerChanged(address(0), _owner);
}
function nominateNewOwner(address _owner) external onlyOwner {
nominatedOwner = _owner;
emit OwnerNominated(_owner);
}
function acceptOwnership() external {
// require(msg.sender == nominatedOwner, "You must be nominated before you can accept ownership");
if (msg.sender != nominatedOwner) revert InvalidOwnershipAcceptance();
emit OwnerChanged(owner, nominatedOwner);
owner = nominatedOwner;
nominatedOwner = address(0);
}
modifier onlyOwner() {
// require(msg.sender == owner, "Only the contract owner may perform this action");
if (msg.sender != owner) revert OnlyOwner();
_;
}
event OwnerNominated(address newOwner);
event OwnerChanged(address oldOwner, address newOwner);
}
// src/contracts/VestedFXS-and-Flox/Flox/TransferHelper.sol
// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
library TransferHelper {
error TransferHelperApproveFailed();
error TransferHelperTransferFailed();
error TransferHelperTransferFromFailed();
error TransferHelperTransferETHFailed();
function safeApprove(address token, address to, uint256 value) internal {
// bytes4(keccak256(bytes('approve(address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
// require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED');
if (!success || (data.length != 0 && !abi.decode(data, (bool)))) revert TransferHelperApproveFailed();
}
function safeTransfer(address token, address to, uint256 value) internal {
// bytes4(keccak256(bytes('transfer(address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
// require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED');
if (!success || (data.length != 0 && !abi.decode(data, (bool)))) revert TransferHelperTransferFailed();
}
function safeTransferFrom(address token, address from, address to, uint256 value) internal {
// bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
// require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED');
if (!success || (data.length != 0 && !abi.decode(data, (bool)))) revert TransferHelperTransferFromFailed();
}
function safeTransferETH(address to, uint256 value) internal {
(bool success, ) = to.call{ value: value }(new bytes(0));
// require(success, 'TransferHelper: ETH_TRANSFER_FAILED');
if (!success) revert TransferHelperTransferETHFailed();
}
}
// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.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);
}
// node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* The default value of {decimals} is 18. To select a different value for
* {decimals} you should overload it.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the value {ERC20} uses, unless this function is
* overridden;
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual override returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
* - the caller must have allowance for ``from``'s tokens of at least
* `amount`.
*/
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `amount` of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
*/
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
}
_balances[to] += amount;
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
_balances[account] += amount;
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
}
_totalSupply -= amount;
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `amount`.
*
* Does not update the allowance amount in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Might emit an {Approval} event.
*/
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* has been transferred to `to`.
* - when `from` is zero, `amount` tokens have been minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens have been burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
}
// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
// src/contracts/Miscellany/TimedLocker.sol
// @version 0.2.8
/**
* ====================================================================
* | ______ _______ |
* | / _____________ __ __ / ____(_____ ____ _____ ________ |
* | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
* | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
* | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
* | |
* ====================================================================
* =========================== TimedLocker ============================
* ====================================================================
* Fixed-rate FXS rewards for locking tokens.
* Total amount of staking token lockable is capped
* Locked positions are transferable as vault tokens
* After a set ending timestamp, all positions are unlockable
* Frax Finance: https://github.com/FraxFinance
*/
// import "forge-std/console2.sol";
contract TimedLocker is ERC20, OwnedV2, ReentrancyGuard {
/* ========== STATE VARIABLES ========== */
// Core variables
// ----------------------------------------
/// @notice When the locker was deployed
uint256 public immutable deployTimestamp;
/// @notice When the locker ends
uint256 public immutable endingTimestamp;
/// @notice Maximum amount of staking token that can be staked
/// @dev Can be increased only if more reward tokens are simultaneously provided, to keep the new rewardPerSecondPerToken >= old rewardPerSecondPerToken
uint256 public cap;
/// @notice The token being staked
ERC20 public stakingToken;
// Global reward-related
// ----------------------------------------
/// @notice Helper to see if a token is a reward token on this locker
mapping(address => bool) public isRewardToken;
/// @notice The last time rewards were sent in
uint256 public lastRewardPull;
/// @notice The last time this contract was updated
uint256 public lastUpdateTime;
/// @notice The time the rewards period should finish. Should be endingTimestamp
uint256 public immutable periodFinish;
/// @notice The duration of the reward period. Should be endingTimestamp - deploy block.timestamp
uint256 public immutable rewardsDuration;
/// @notice Mapping of addresses that are allowed to deposit reward tokens
mapping(address => bool) public rewardNotifiers;
/// @notice Accumulator for rewardsPerToken
// https://www.paradigm.xyz/2021/05/liquidity-mining-on-uniswap-v3
uint256[] public rewardsPerTokenStored;
/// @notice The reward tokens per second
uint256[] public rewardRates;
/// @notice Helper to get the reward token index, given the address of the token
mapping(address => uint256) public rewardTokenAddrToIdx;
/// @notice Array of all the reward tokens
address[] public rewardTokens;
// User reward-related
// ----------------------------------------
/// @notice The last time a farmer claimed their rewards
mapping(address => uint256) public lastRewardClaimTime; // staker addr -> timestamp
/// @notice Used for tracking stored/collectible rewards. earned()
mapping(address => mapping(uint256 => uint256)) public rewards; // staker addr -> token id -> reward amount
/// @notice Accumulator for userRewardsPerTokenPaid
mapping(address => mapping(uint256 => uint256)) public userRewardsPerTokenPaid; // staker addr -> token id -> paid amount
// Emergency variables
// ----------------------------------------
/// @notice If external syncEarned calls via bulkSyncEarnedUsers are allowed
bool public externalSyncEarningPaused;
/// @notice If reward collections are paused
bool public rewardsCollectionPaused;
/// @notice If staking is paused
bool public stakingPaused;
/// @notice Release locked stakes in case of system migration or emergency
bool public stakesUnlocked;
// For emergencies if a token is overemitted or something else. Only callable once.
// Bypasses certain logic, which will cause reward calculations to be off
// But the goal is for the users to recover LP, and they couldn't claim the erroneous rewards anyways.
// Reward reimbursement claims would be handled with pre-issue earned() snapshots and a claim contract, or similar.
bool public withdrawalOnlyShutdown;
/// @notice If withdrawals are paused
bool public withdrawalsPaused;
/* ========== CONSTRUCTOR ========== */
/// @notice Constructor
/// @param _owner The owner of the locker
/// @param _rewardTokens Array of reward tokens
/// @param _name Name for the vault token
/// @param _symbol Symbol for the vault token
/// @param _stakingToken The token being staked
/// @param _endingTimestamp Timestamp when all locks become unlocked
/// @param _cap Maximum amount of staking tokens allowed to be locked
/// @param _extraNotifier Additional reward notifier to add when constructing. Can add more / remove later
constructor(
address _owner,
address[] memory _rewardTokens,
address _stakingToken,
string memory _name,
string memory _symbol,
uint256 _endingTimestamp,
uint256 _cap,
address _extraNotifier
) ERC20(_name, _symbol) OwnedV2(_owner) {
// Set state variables
stakingToken = ERC20(_stakingToken);
rewardTokens = _rewardTokens;
endingTimestamp = _endingTimestamp;
cap = _cap;
// Loop through the reward tokens
for (uint256 i = 0; i < _rewardTokens.length; i++) {
// For fast token address -> token ID lookups later
rewardTokenAddrToIdx[_rewardTokens[i]] = i;
// Add to the mapping
isRewardToken[_rewardTokens[i]] = true;
// Initialize the stored rewards
rewardsPerTokenStored.push(0);
// Initialize the reward rates
rewardRates.push(0);
}
// Set the owner as an allowed reward notifier
rewardNotifiers[_owner] = true;
// Add the additional reward notifier, if present
if (_extraNotifier != address(0)) rewardNotifiers[_extraNotifier] = true;
// Other booleans
stakesUnlocked = false;
// For initialization
deployTimestamp = block.timestamp;
lastUpdateTime = block.timestamp;
rewardsDuration = _endingTimestamp - block.timestamp;
periodFinish = _endingTimestamp;
}
/* ========== MODIFIERS ========== */
/// @notice Staking should not be paused
modifier notStakingPaused() {
require(!stakingPaused, "Staking paused");
_;
}
/// @notice Update rewards and balances
modifier updateRewards(address account) {
_updateRewards(account);
_;
}
/* ========== VIEWS ========== */
/// @notice Remaining amount of stakingToken you can lock before hitting the cap
/// @return _amount The amount
function availableToLock() public view returns (uint256 _amount) {
_amount = (cap - totalSupply());
}
/// @notice The last time rewards were applicable. Should be the lesser of the current timestamp, or the end of the last period
/// @return uint256 The last timestamp where rewards were applicable
function lastTimeRewardApplicable() internal view returns (uint256) {
return Math.min(block.timestamp, periodFinish);
}
/// @notice Minimum amount of additional reward tokens needed so rewardPerSecondPerToken remains the same after a cap increase
/// @param _newCap The new cap you want to increase to
/// @return _minRewRates Minimum rewardRate needed after the cap is raised
/// @return _minAddlTkns Minimum amount of additional reward tokens needed
function minAddlRewTknsForCapIncrease(
uint256 _newCap
) public view returns (uint256[] memory _minRewRates, uint256[] memory _minAddlTkns) {
// Cap can only increase
if (_newCap < cap) revert CapCanOnlyIncrease();
// Initialize return arrays
_minRewRates = new uint256[](rewardTokens.length);
_minAddlTkns = new uint256[](rewardTokens.length);
// See how much time is left
uint256 _timeLeft = endingTimestamp - block.timestamp;
// Loop through the reward tokens
for (uint256 i = 0; i < rewardTokens.length; ) {
// Solve for the new reward rate, assuming (Rate / Tokens) is constant
// Round up by 1 wei
_minRewRates[i] = ((rewardRates[i] * _newCap) + 1) / cap;
// Calculate the additional tokens needed
_minAddlTkns[i] = _timeLeft * (_minRewRates[i] - rewardRates[i]);
unchecked {
++i;
}
}
}
/// @notice The calculated rewardPerTokenStored accumulator
/// @return _rtnRewardsPerTokenStored Array of rewardsPerTokenStored
function rewardPerToken() public view returns (uint256[] memory _rtnRewardsPerTokenStored) {
// Prepare the return variable
_rtnRewardsPerTokenStored = new uint256[](rewardTokens.length);
// Calculate
if (totalSupply() == 0) {
// Return 0 if there are no vault tokens
_rtnRewardsPerTokenStored = rewardsPerTokenStored;
} else {
// Loop through the reward tokens
for (uint256 i = 0; i < rewardTokens.length; ) {
_rtnRewardsPerTokenStored[i] =
rewardsPerTokenStored[i] +
(((lastTimeRewardApplicable() - lastUpdateTime) * rewardRates[i] * 1e18) / totalSupply());
unchecked {
++i;
}
}
}
}
/// @notice The currently earned rewards for a user
/// @param _account The staker's address
/// @return _rtnEarned Array of the amounts of reward tokens the staker can currently collect
function earned(address _account) public view returns (uint256[] memory _rtnEarned) {
// Prepare the return variable
_rtnEarned = new uint256[](rewardTokens.length);
// Get the reward rate per token
uint256[] memory _rtnRewardsPerToken = rewardPerToken();
// Loop through the reward tokens
for (uint256 i = 0; i < rewardTokens.length; ) {
_rtnEarned[i] =
rewards[_account][i] +
((balanceOf(_account) * ((_rtnRewardsPerToken[i] - userRewardsPerTokenPaid[_account][i]))) / 1e18);
unchecked {
++i;
}
}
}
/// @notice Amount of rewards remaining
/// @return _rtnRewardsRemaining Array of the amounts of the reward tokens
function getRewardsRemaining() external view returns (uint256[] memory _rtnRewardsRemaining) {
// Prepare the return variable
_rtnRewardsRemaining = new uint256[](rewardTokens.length);
// Return 0 if the locker has already ended
if (endingTimestamp <= block.timestamp) return _rtnRewardsRemaining;
// See how much time is left
uint256 _timeLeft = endingTimestamp - block.timestamp;
// Calculate the duration rewards
for (uint256 i = 0; i < rewardTokens.length; ) {
_rtnRewardsRemaining[i] = rewardRates[i] * _timeLeft;
unchecked {
++i;
}
}
}
/* ========== ERC20 OVERRIDES ========== */
/// @notice Override the _update logic to claim/sync earnings before transferring.
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(address from, address to, uint256 value) internal override {
// TODO for auditors: Make sure this is not manipulatable
// If you aren't minting, sync rewards first so the owner doesn't lose them after transferring
// Also so the recipient doesn't get free rewards
// withdrawalOnlyShutdown sacrifices rewards buts lets the token move, for emergencies only.
if (!withdrawalOnlyShutdown && (from != address(0))) {
sync();
_syncEarnedInner(from);
_syncEarnedInner(to);
}
}
/* ========== MUTATIVE FUNCTIONS ========== */
/// @notice Sync earnings for many users. Convenience function
/// @param _users The account to sync
/// @dev _beforeTokenTransfer essentially does this
function bulkSyncEarnedUsers(address[] memory _users) external {
// Check for withdrawal-only shutdown as well as the pause
if (withdrawalOnlyShutdown || externalSyncEarningPaused) revert ExternalSyncEarningPaused();
// Sync normally first
sync();
// Loop through the users and sync them. Skip global sync() to save gas
for (uint256 i = 0; i < _users.length; ) {
_syncEarnedInner(_users[i]);
unchecked {
++i;
}
}
}
/// @notice Sync contract-wide variables
function sync() public {
// Update rewardsPerTokenStored
rewardsPerTokenStored = rewardPerToken();
// Update the last update time
lastUpdateTime = lastTimeRewardApplicable();
}
/// @notice Update the reward and balance state for a staker
/// @param account The address of the user
function _updateRewards(address account) internal {
if (account != address(0)) {
// Calculate the earnings first
// Skip if we are in emergency shutdown
if (!withdrawalOnlyShutdown) _syncEarned(account);
}
}
/// @notice [MUST be proceeded by global sync()] Sync earnings for a specific staker. Skips the global sync() to save gas (mainly for bulkSyncEarnedUsers())
/// @param _account The account to sync
function _syncEarnedInner(address _account) internal {
if (_account != address(0)) {
// Calculate the earnings
uint256[] memory _earneds = earned(_account);
// Update the stake
for (uint256 i = 0; i < rewardTokens.length; ) {
rewards[_account][i] = _earneds[i];
userRewardsPerTokenPaid[_account][i] = rewardsPerTokenStored[i];
unchecked {
++i;
}
}
}
}
/// @notice Sync earnings for a specific staker
/// @param _account The account to sync
function _syncEarned(address _account) internal {
// Update rewardsPerTokenStored and last update time
sync();
// Sync the account's earnings
_syncEarnedInner(_account);
}
/// @notice Stake stakingToken for vault tokens
/// @param _amount The amount of stakingToken
function stake(uint256 _amount) public nonReentrant updateRewards(msg.sender) {
// Do checks
if (block.timestamp >= endingTimestamp) revert LockerHasEnded();
if (stakingPaused) revert StakingPaused();
if (stakesUnlocked) revert StakesAreUnlocked();
if (withdrawalOnlyShutdown) revert OnlyWithdrawalsAllowed();
if (_amount == 0) revert MustBeNonZero();
if ((totalSupply() + _amount) > cap) revert Capped();
// Pull the staking tokens from the msg.sender
TransferHelper.safeTransferFrom(address(stakingToken), msg.sender, address(this), _amount);
// Mint an equal amount of vault tokens to the staker
_mint(msg.sender, _amount);
// Update rewards
_updateRewards(msg.sender);
emit Stake(msg.sender, _amount, msg.sender);
}
/// @notice Withdraw stakingToken from vault tokens.
/// @param _vaultTknAmount Amount of vault tokens to use
/// @param _collectRewards Whether to also collect rewards
function withdraw(
uint256 _vaultTknAmount,
bool _collectRewards
) public nonReentrant returns (uint256[] memory _rtnRewards) {
if ((block.timestamp < endingTimestamp) && !(stakesUnlocked || withdrawalOnlyShutdown)) {
revert LockerStillActive();
}
if (withdrawalsPaused) revert WithdrawalsPaused();
// Burn the vault token from the sender
_burn(msg.sender, _vaultTknAmount);
// Give the stakingToken to the msg.sender
// Should throw if insufficient balance
TransferHelper.safeTransfer(address(stakingToken), msg.sender, _vaultTknAmount);
// Collect rewards
_rtnRewards = new uint256[](rewardTokens.length);
if (_collectRewards) _rtnRewards = getReward(msg.sender);
emit Withdrawal(msg.sender, _vaultTknAmount);
}
/// @notice Collect rewards
/// @param _destinationAddress Destination address for the rewards
/// @return _rtnRewards The amounts of collected reward tokens
function getReward(
address _destinationAddress
) public updateRewards(msg.sender) returns (uint256[] memory _rtnRewards) {
// Make sure you are not in shutdown
if (withdrawalOnlyShutdown) revert OnlyWithdrawalsAllowed();
// Make sure reward collections are not paused
if (rewardsCollectionPaused) revert RewardCollectionIsPaused();
// Prepare the return variable
_rtnRewards = new uint256[](rewardTokens.length);
// Loop through the rewards
for (uint256 i = 0; i < rewardTokens.length; ) {
_rtnRewards[i] = rewards[msg.sender][i];
// Do reward accounting
if (_rtnRewards[i] > 0) {
rewards[msg.sender][i] = 0;
TransferHelper.safeTransfer(rewardTokens[i], _destinationAddress, _rtnRewards[i]);
emit RewardPaid(msg.sender, _rtnRewards[i], rewardTokens[i], _destinationAddress);
}
unchecked {
++i;
}
}
// Update the last reward claim time
lastRewardClaimTime[msg.sender] = block.timestamp;
}
/// @notice Supply rewards. Only callable by whitelisted addresses.
/// @param _amounts Amount of each reward token to add
function notifyRewardAmounts(uint256[] memory _amounts) public {
// Only the owner and the whitelisted addresses can notify rewards
if (!((owner == msg.sender) || rewardNotifiers[msg.sender])) revert SenderNotOwnerOrRewarder();
// Make sure the locker has not ended
if (block.timestamp >= endingTimestamp) revert LockerHasEnded();
// Pull in the reward tokens from the sender
for (uint256 i = 0; i < rewardTokens.length; ) {
// Handle the transfer of emission tokens via `transferFrom` to reduce the number
// of transactions required and ensure correctness of the emission amount
TransferHelper.safeTransferFrom(rewardTokens[i], msg.sender, address(this), _amounts[i]);
unchecked {
++i;
}
}
// Update rewardsPerTokenStored and last update time
sync();
// Calculate the reward rate
for (uint256 i = 0; i < rewardTokens.length; ) {
// Account for unemitted tokens
uint256 remainingTime = periodFinish - block.timestamp;
uint256 leftoverRwd = remainingTime * rewardRates[i];
// Replace rewardsDuration with remainingTime here since we only have one big period
// rewardRates[i] = (_amounts[i] + leftoverRwd) / rewardsDuration;
rewardRates[i] = (_amounts[i] + leftoverRwd) / remainingTime;
emit RewardAdded(rewardTokens[i], _amounts[i], rewardRates[i]);
unchecked {
++i;
}
}
// Update rewardsPerTokenStored and last update time (again)
sync();
}
/* ========== RESTRICTED FUNCTIONS ========== */
/// @notice Only settable to true
function initiateWithdrawalOnlyShutdown() external onlyOwner {
withdrawalOnlyShutdown = true;
}
/// @notice Increase the staking token cap. Can be increased only if more reward tokens are simultaneously provided, to keep the new rewardPerSecondPerToken >= old rewardPerSecondPerToken.
/// @param _newCap The address of the token
/// @param _addlRewTknAmounts The amount(s) of reward tokens being supplied as part of this cap increase.
function increaseCapWithRewards(uint256 _newCap, uint256[] memory _addlRewTknAmounts) external onlyOwner {
// Cap can only increase
if (_newCap < cap) revert CapCanOnlyIncrease();
// Sync first
sync();
// Fetch the calculated new rewardRates as well as the amount of additional tokens needed
(uint256[] memory _minRewRates, uint256[] memory _minAddlTkns) = minAddlRewTknsForCapIncrease(_newCap);
// Make sure enough reward tokens were supplied
for (uint256 i = 0; i < rewardTokens.length; i++) {
if (_addlRewTknAmounts[i] < _minAddlTkns[i]) revert NotEnoughAddlRewTkns();
}
// Increase the cap
cap = _newCap;
// Add in the new rewards
notifyRewardAmounts(_addlRewTknAmounts);
// Compare the new rewardRate with the calculated minimum
// New must be >= old
for (uint256 i = 0; i < rewardTokens.length; i++) {
if (rewardRates[i] < _minRewRates[i]) {
revert NotEnoughAddlRewTkns();
}
}
}
/// @notice Added to support recovering LP Rewards and other mistaken tokens from other systems to be distributed to holders
/// @param _tokenAddress The address of the token
/// @param _tokenAmount The amount of the token
function recoverERC20(address _tokenAddress, uint256 _tokenAmount) external onlyOwner {
// Only the owner address can ever receive the recovery withdrawal
TransferHelper.safeTransfer(_tokenAddress, owner, _tokenAmount);
emit Recovered(_tokenAddress, _tokenAmount);
}
/// @notice Toggle the ability to syncEarned externally via bulkSyncEarnedUsers
function toggleExternalSyncEarning() external onlyOwner {
externalSyncEarningPaused = !externalSyncEarningPaused;
}
/// @notice Toggle the ability to stake
function toggleStaking() external onlyOwner {
stakingPaused = !stakingPaused;
}
/// @notice Toggle the ability to collect rewards
function toggleRewardsCollection() external onlyOwner {
rewardsCollectionPaused = !rewardsCollectionPaused;
}
/// @notice Toggle an address as being able to be a reward notifier
/// @param _notifierAddr The address to toggle
function toggleRewardNotifier(address _notifierAddr) external onlyOwner {
rewardNotifiers[_notifierAddr] = !rewardNotifiers[_notifierAddr];
}
/// @notice Toggle the ability to withdraw
function toggleWithdrawals() external onlyOwner {
withdrawalsPaused = !withdrawalsPaused;
}
/// @notice Unlock all stakes, in the case of an emergency
function unlockStakes() external onlyOwner {
stakesUnlocked = !stakesUnlocked;
}
/* ========== ERRORS ========== */
/// @notice When you are trying to lower the cap, which is not allowed
error CapCanOnlyIncrease();
/// @notice When you are trying to lock more tokens than are allowed
error Capped();
/// @notice If syncEarned should only be callable indirectly through methods or internally. Also occurs if in a withdrawal-only shutdown
error ExternalSyncEarningPaused();
/// @notice If the locker ending timestamp has passed
error LockerHasEnded();
/// @notice If the locker ending timestamp has not yet passed
error LockerStillActive();
/// @notice If an input value must be non-zero
error MustBeNonZero();
/// @notice If only withdrawals are allowed
error OnlyWithdrawalsAllowed();
/// @notice If reward collections are paused
error RewardCollectionIsPaused();
/// @notice When the cap is increased, the rewardPerSecondPerToken must either increase or stay the same
error NotEnoughAddlRewTkns();
/// @notice If the sender is not the owner or a rewarder
error SenderNotOwnerOrRewarder();
/// @notice If staking has been paused
error StakingPaused();
/// @notice If you are trying to stake after stakes have been unlock
error StakesAreUnlocked();
/// @notice If you didn't acknowledge the notifyRewardAmounts sync warning
error MustSyncAllUsersBeforeNotifying();
/// @notice If withdrawals have been paused
error WithdrawalsPaused();
/* ========== EVENTS ========== */
/// @notice When LP tokens are locked
/// @param user The staker
/// @param amount Amount of LP staked
/// @param source_address The origin address of the LP tokens. Usually the same as the user unless there is a migration in progress
event Stake(address indexed user, uint256 amount, address source_address);
/// @notice When LP tokens are withdrawn
/// @param user The staker
/// @param amount Amount of LP withdrawn
event Withdrawal(address indexed user, uint256 amount);
/// @notice When tokens are recovered, in the case of an emergency
/// @param token Address of the token
/// @param amount Amount of the recovered tokens
event Recovered(address token, uint256 amount);
/// @notice When a reward is deposited
/// @param reward_address The address of the reward token
/// @param reward Amount of tokens deposited
/// @param yieldRate The resultant yield/emission rate
event RewardAdded(address indexed reward_address, uint256 reward, uint256 yieldRate);
/// @notice When a staker collects rewards
/// @param user The staker
/// @param reward Amount of reward tokens
/// @param token_address Address of the reward token
/// @param destination_address Destination address of the reward tokens
event RewardPaid(address indexed user, uint256 reward, address token_address, address destination_address);
}
// src/contracts/Miscellany/FraxFarmQuitCreditor/L1QuitCreditorReceiverConverterTimedLocker.sol
// ====================================================================
// | ______ _______ |
// | / _____________ __ __ / ____(_____ ____ _____ ________ |
// | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
// | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
// | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
// | |
// ====================================================================
// ============ L1QuitCreditorReceiverConverterTimedLocker ============
// ====================================================================
// Accepts an L1 message from an Ethereum Mainnet FraxFarmQuitCreditor_XXX and converts the provided USD value to another token
// Further takes this token and puts it in a TimedLocker and returns the recipient the TimedLocker vault token
// Frax Finance: https://github.com/FraxFinance
// Primary Author(s)
// Travis Moore: https://github.com/FortisFortuna
// Reviewer(s) / Contributor(s)
// Dennis: https://github.com/denett
/// @notice Accepts an L1 message from an Ethereum Mainnet FraxFarmQuitCreditor_XXX and converts the provided USD value to another token
contract L1QuitCreditorReceiverConverterTimedLocker is ReentrancyGuard, OwnedV2 {
// STATE VARIABLES
// ===================================================
/// @notice Fraxtal CrossDomainMessenger
ICrossDomainMessenger public messenger = ICrossDomainMessenger(0x4200000000000000000000000000000000000007);
/// @notice Address of the L1 FraxFarmQuitCreditor_XXX
address public quitCreditorAddress;
/// @notice Token that the L1 USD credit is being exchanged for
IERC20 public conversionToken;
/// @notice Manually set conversion price (USDe18 per 1e18 conversion token)
uint256 public conversionPrice;
/// @notice TimedLocker where the converted token will be locked into
TimedLocker public timedLocker;
/// @notice Used for testing
mapping(address pinger => Ping lastPing) public lastPingReceived;
// STRUCTS
// ===================================================
/// @notice Ping used for testing purposes
/// @param sourceTs Timestamp the ping was triggered on Ethereum
/// @param fraxtalTs Timestamp the ping was received on this contract
struct Ping {
uint256 sourceTs;
uint256 fraxtalTs;
}
// MODIFIERS
// ===================================================
modifier correctSender() {
// Make sure the direct msg.sender is the messenger
if (msg.sender != address(messenger)) revert BadSender();
// Make sure that the caller on L1 was the FraxFarmQuitCreditor_XXX
if (messenger.xDomainMessageSender() != quitCreditorAddress) revert BadXDomainMessageSender();
_;
}
// CONSTRUCTOR
// ===================================================
/// @notice Constructor
/// @param _owner The owner of the contract
/// @param _quitCreditor Address of the L1 FraxFarmQuitCreditor_XXX
/// @param _conversionToken Token being converted to
/// @param _conversionPrice Price of the conversion token, in E18 USD
/// @param _timedLocker The destination TimedLocker
constructor(
address _owner,
address _quitCreditor,
address _conversionToken,
uint256 _conversionPrice,
address _timedLocker
) OwnedV2(_owner) {
quitCreditorAddress = _quitCreditor;
conversionToken = IERC20(_conversionToken);
conversionPrice = _conversionPrice;
timedLocker = TimedLocker(_timedLocker);
}
// PUBLIC FUNCTIONS
// ===================================================
/// @notice Used to test connectivity. Receives a dummy message from Ethereum
/// @param _pinger Original pinger on Ethereum
/// @param _sourceTs Time the ping was sent on Ethereum
function receivePing(address _pinger, uint256 _sourceTs) external nonReentrant correctSender {
// Mark when the last ping was received
lastPingReceived[_pinger] = Ping(_sourceTs, block.timestamp);
emit PingReceived(_pinger, _sourceTs, block.timestamp);
}
/// @notice Processes the L1-originating message from the FraxFarmQuitCreditor_XXX
/// @param _originalStaker Address of the original farmer who held the position
/// @param _recipient Recipient for the newly converted tokens
/// @param _usdCredit The USD value that should be converted into the conversion token
function processMessage(
address _originalStaker,
address _recipient,
uint256 _usdCredit
) external nonReentrant correctSender returns (uint256 _convTknOut) {
// Do the conversion
_convTknOut = (_usdCredit * 1e18) / conversionPrice;
// Lock in the TimedLocker
conversionToken.approve(address(timedLocker), _convTknOut);
timedLocker.stake(_convTknOut);
// Send out the TimedLocker vault tokens to the recipient
SafeERC20.safeTransfer(IERC20(timedLocker), _recipient, _convTknOut);
emit MessageProcessed(_originalStaker, _recipient, _usdCredit, _convTknOut);
}
// RESTRICTED FUNCTIONS
// ===================================================
/// @notice Allows the owner to recover any ERC20
/// @param tokenAddress The address of the token to recover
/// @param tokenAmount The amount of the token to recover
function recoverERC20(address tokenAddress, uint256 tokenAmount) external onlyOwner {
SafeERC20.safeTransfer(IERC20(tokenAddress), msg.sender, tokenAmount);
}
/// @notice Set the price of the conversion token, in E18 USD
/// @param _newConversionPrice The new conversion price
function setConversionPrice(uint256 _newConversionPrice) external onlyOwner {
conversionPrice = _newConversionPrice;
}
/// @notice Set the address for the L1 FraxFarmQuitCreditor_XXX
/// @param _newQuitCreditorAddress The new address for the L1 FraxFarmQuitCreditor_XXX
function setQuitCreditorAddress(address _newQuitCreditorAddress) external onlyOwner {
quitCreditorAddress = _newQuitCreditorAddress;
}
// ERRORS
// ===================================================
/// @notice Only the CrossDomainMessenger should be the sender
error BadSender();
/// @notice Only the FraxFarmQuitCreditor_XXX should be the messenger.xDomainMessageSender()
error BadXDomainMessageSender();
// EVENTS
// ===================================================
/// @notice When the ping from L1 was received
/// @param sender The msg.sender that triggered the ping on the FraxFarmQuitCreditor_XXX
/// @param sourceTs Ethereum time the ping was received
/// @param fraxtalTs Fraxtal time the ping was received
event PingReceived(address indexed sender, uint256 sourceTs, uint256 fraxtalTs);
/// @notice When the crediting message from the L1 FraxFarmQuitCreditor_XXX was processed
/// @param originalStaker Address of the original farmer who held the position
/// @param recipient Recipient for the newly converted tokens
/// @param usdCredit Amount of USD credit processed
/// @param convTknOut Conversion token output amount to the recipient
event MessageProcessed(
address indexed originalStaker,
address indexed recipient,
uint256 usdCredit,
uint256 convTknOut
);
/// @notice When ERC20 tokens were recovered
/// @param token Token address
/// @param amount Amount of tokens collected
event RecoveredERC20(address token, uint256 amount);
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_quitCreditor","type":"address"},{"internalType":"address","name":"_conversionToken","type":"address"},{"internalType":"uint256","name":"_conversionPrice","type":"uint256"},{"internalType":"address","name":"_timedLocker","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BadSender","type":"error"},{"inputs":[],"name":"BadXDomainMessageSender","type":"error"},{"inputs":[],"name":"InvalidOwnershipAcceptance","type":"error"},{"inputs":[],"name":"OnlyOwner","type":"error"},{"inputs":[],"name":"OwnerCannotBeZero","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"originalStaker","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"usdCredit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"convTknOut","type":"uint256"}],"name":"MessageProcessed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerNominated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"sourceTs","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fraxtalTs","type":"uint256"}],"name":"PingReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RecoveredERC20","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"conversionPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"conversionToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pinger","type":"address"}],"name":"lastPingReceived","outputs":[{"internalType":"uint256","name":"sourceTs","type":"uint256"},{"internalType":"uint256","name":"fraxtalTs","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"messenger","outputs":[{"internalType":"contract ICrossDomainMessenger","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"nominateNewOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nominatedOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_originalStaker","type":"address"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_usdCredit","type":"uint256"}],"name":"processMessage","outputs":[{"internalType":"uint256","name":"_convTknOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"quitCreditorAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_pinger","type":"address"},{"internalType":"uint256","name":"_sourceTs","type":"uint256"}],"name":"receivePing","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"recoverERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newConversionPrice","type":"uint256"}],"name":"setConversionPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newQuitCreditorAddress","type":"address"}],"name":"setQuitCreditorAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"timedLocker","outputs":[{"internalType":"contract TimedLocker","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
6080604052600380546001600160a01b031916734200000000000000000000000000000000000007179055348015610035575f80fd5b506040516112ba3803806112ba8339810160408190526100549161013d565b60015f55846001600160a01b03811661008057604051639b15e16f60e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b038316908117909155604080515f815260208101929092527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a150600480546001600160a01b039586166001600160a01b03199182161790915560058054948616948216949094179093556006919091556007805491909316911617905550610197565b80516001600160a01b0381168114610138575f80fd5b919050565b5f805f805f60a08688031215610151575f80fd5b61015a86610122565b945061016860208701610122565b935061017660408701610122565b92506060860151915061018b60808701610122565b90509295509295909350565b611116806101a45f395ff3fe608060405234801561000f575f80fd5b50600436106100f0575f3560e01c80638980f11f11610093578063a7a5324811610063578063a7a5324814610253578063ab219c4a14610266578063b7184b6814610279578063c6db2ee01461028c575f80fd5b80638980f11f146101ce5780638cda6c45146101e15780638da5cb5b146101f8578063a61721ac14610218575f80fd5b806353166ecf116100ce57806353166ecf1461016657806353a47bb71461018657806379ba5097146101a65780637ed2cb27146101ae575f80fd5b8063144911ad146100f45780631627540c146101095780633cb747bf1461011c575b5f80fd5b610107610102366004610f29565b6102ac565b005b610107610117366004610f29565b610344565b60035461013c9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b60055461013c9073ffffffffffffffffffffffffffffffffffffffff1681565b60025461013c9073ffffffffffffffffffffffffffffffffffffffff1681565b61010761040e565b60045461013c9073ffffffffffffffffffffffffffffffffffffffff1681565b6101076101dc366004610f44565b610503565b6101ea60065481565b60405190815260200161015d565b60015461013c9073ffffffffffffffffffffffffffffffffffffffff1681565b61023e610226366004610f29565b60086020525f90815260409020805460019091015482565b6040805192835260208301919091520161015d565b6101ea610261366004610f6e565b610563565b610107610274366004610f44565b6108ea565b610107610287366004610fac565b610b15565b60075461013c9073ffffffffffffffffffffffffffffffffffffffff1681565b60015473ffffffffffffffffffffffffffffffffffffffff1633146102fd576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60015473ffffffffffffffffffffffffffffffffffffffff163314610395576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229060200160405180910390a150565b60025473ffffffffffffffffffffffffffffffffffffffff16331461045f576040517fd74b334e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001546002546040805173ffffffffffffffffffffffffffffffffffffffff93841681529290911660208301527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a160028054600180547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff841617909155169055565b60015473ffffffffffffffffffffffffffffffffffffffff163314610554576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61055f823383610b6b565b5050565b5f60025f54036105d4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b60025f5560035473ffffffffffffffffffffffffffffffffffffffff163314610629576040517ff9b5d12d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60048054600354604080517f6e296e45000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff938416949390921692636e296e459282820192602092908290030181865afa15801561069c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106c09190610fc3565b73ffffffffffffffffffffffffffffffffffffffff161461070d576040517f3148944300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60065461072283670de0b6b3a7640000610fde565b61072c9190611020565b6005546007546040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff918216600482015260248101849052929350169063095ea7b3906044016020604051808303815f875af11580156107a6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107ca9190611058565b506007546040517fa694fc3a0000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff9091169063a694fc3a906024015f604051808303815f87803b158015610834575f80fd5b505af1158015610846573d5f803e3d5ffd5b505060075461086f925073ffffffffffffffffffffffffffffffffffffffff1690508483610b6b565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fd6d83c7e7e134e3b46a31613602e12af6a895cc707b1abd6f55f98dfc5ec7a2f84846040516108d7929190918252602082015260400190565b60405180910390a360015f559392505050565b60025f5403610955576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016105cb565b60025f5560035473ffffffffffffffffffffffffffffffffffffffff1633146109aa576040517ff9b5d12d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60048054600354604080517f6e296e45000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff938416949390921692636e296e459282820192602092908290030181865afa158015610a1d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a419190610fc3565b73ffffffffffffffffffffffffffffffffffffffff1614610a8e576040517f3148944300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051808201825282815242602080830182815273ffffffffffffffffffffffffffffffffffffffff87165f8181526008845286902094518555905160019094019390935583518581529081019190915290917f872ee393cb8a15e359df7de4088b3de854cb7aaeff6cdc4efd471f92e6bf8f34910160405180910390a2505060015f55565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b66576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600655565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610bf8908490610bfd565b505050565b5f610c5e826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610d089092919063ffffffff16565b805190915015610bf85780806020019051810190610c7c9190611058565b610bf8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016105cb565b6060610d1684845f85610d20565b90505b9392505050565b606082471015610db2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016105cb565b73ffffffffffffffffffffffffffffffffffffffff85163b610e30576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016105cb565b5f808673ffffffffffffffffffffffffffffffffffffffff168587604051610e589190611077565b5f6040518083038185875af1925050503d805f8114610e92576040519150601f19603f3d011682016040523d82523d5f602084013e610e97565b606091505b5091509150610ea7828286610eb2565b979650505050505050565b60608315610ec1575081610d19565b825115610ed15782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105cb919061108d565b73ffffffffffffffffffffffffffffffffffffffff81168114610f26575f80fd5b50565b5f60208284031215610f39575f80fd5b8135610d1981610f05565b5f8060408385031215610f55575f80fd5b8235610f6081610f05565b946020939093013593505050565b5f805f60608486031215610f80575f80fd5b8335610f8b81610f05565b92506020840135610f9b81610f05565b929592945050506040919091013590565b5f60208284031215610fbc575f80fd5b5035919050565b5f60208284031215610fd3575f80fd5b8151610d1981610f05565b808202811582820484141761101a577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b92915050565b5f82611053577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b5f60208284031215611068575f80fd5b81518015158114610d19575f80fd5b5f82518060208501845e5f920191825250919050565b602081525f82518060208401528060208501604085015e5f6040828501015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168401019150509291505056fea264697066735822122087cfcbfb22fcb02baf3b088d3f29d61a8c90f07773c6b21882b580e7c413d08e64736f6c634300081a0033000000000000000000000000625e700125ff054f75e5348497cbfab1ee4b7a4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006c9f4e6089c8890afee2bcba364c2712f88fa8180000000000000000000000000000000000000000000000000c4855c005f00400000000000000000000000000baf15fa061d83608b7f59226b8491c1eb9df48b2
Deployed Bytecode
0x608060405234801561000f575f80fd5b50600436106100f0575f3560e01c80638980f11f11610093578063a7a5324811610063578063a7a5324814610253578063ab219c4a14610266578063b7184b6814610279578063c6db2ee01461028c575f80fd5b80638980f11f146101ce5780638cda6c45146101e15780638da5cb5b146101f8578063a61721ac14610218575f80fd5b806353166ecf116100ce57806353166ecf1461016657806353a47bb71461018657806379ba5097146101a65780637ed2cb27146101ae575f80fd5b8063144911ad146100f45780631627540c146101095780633cb747bf1461011c575b5f80fd5b610107610102366004610f29565b6102ac565b005b610107610117366004610f29565b610344565b60035461013c9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b60055461013c9073ffffffffffffffffffffffffffffffffffffffff1681565b60025461013c9073ffffffffffffffffffffffffffffffffffffffff1681565b61010761040e565b60045461013c9073ffffffffffffffffffffffffffffffffffffffff1681565b6101076101dc366004610f44565b610503565b6101ea60065481565b60405190815260200161015d565b60015461013c9073ffffffffffffffffffffffffffffffffffffffff1681565b61023e610226366004610f29565b60086020525f90815260409020805460019091015482565b6040805192835260208301919091520161015d565b6101ea610261366004610f6e565b610563565b610107610274366004610f44565b6108ea565b610107610287366004610fac565b610b15565b60075461013c9073ffffffffffffffffffffffffffffffffffffffff1681565b60015473ffffffffffffffffffffffffffffffffffffffff1633146102fd576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60015473ffffffffffffffffffffffffffffffffffffffff163314610395576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229060200160405180910390a150565b60025473ffffffffffffffffffffffffffffffffffffffff16331461045f576040517fd74b334e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001546002546040805173ffffffffffffffffffffffffffffffffffffffff93841681529290911660208301527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a160028054600180547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff841617909155169055565b60015473ffffffffffffffffffffffffffffffffffffffff163314610554576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61055f823383610b6b565b5050565b5f60025f54036105d4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b60025f5560035473ffffffffffffffffffffffffffffffffffffffff163314610629576040517ff9b5d12d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60048054600354604080517f6e296e45000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff938416949390921692636e296e459282820192602092908290030181865afa15801561069c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106c09190610fc3565b73ffffffffffffffffffffffffffffffffffffffff161461070d576040517f3148944300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60065461072283670de0b6b3a7640000610fde565b61072c9190611020565b6005546007546040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff918216600482015260248101849052929350169063095ea7b3906044016020604051808303815f875af11580156107a6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107ca9190611058565b506007546040517fa694fc3a0000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff9091169063a694fc3a906024015f604051808303815f87803b158015610834575f80fd5b505af1158015610846573d5f803e3d5ffd5b505060075461086f925073ffffffffffffffffffffffffffffffffffffffff1690508483610b6b565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fd6d83c7e7e134e3b46a31613602e12af6a895cc707b1abd6f55f98dfc5ec7a2f84846040516108d7929190918252602082015260400190565b60405180910390a360015f559392505050565b60025f5403610955576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016105cb565b60025f5560035473ffffffffffffffffffffffffffffffffffffffff1633146109aa576040517ff9b5d12d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60048054600354604080517f6e296e45000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff938416949390921692636e296e459282820192602092908290030181865afa158015610a1d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a419190610fc3565b73ffffffffffffffffffffffffffffffffffffffff1614610a8e576040517f3148944300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051808201825282815242602080830182815273ffffffffffffffffffffffffffffffffffffffff87165f8181526008845286902094518555905160019094019390935583518581529081019190915290917f872ee393cb8a15e359df7de4088b3de854cb7aaeff6cdc4efd471f92e6bf8f34910160405180910390a2505060015f55565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b66576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600655565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610bf8908490610bfd565b505050565b5f610c5e826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610d089092919063ffffffff16565b805190915015610bf85780806020019051810190610c7c9190611058565b610bf8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016105cb565b6060610d1684845f85610d20565b90505b9392505050565b606082471015610db2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016105cb565b73ffffffffffffffffffffffffffffffffffffffff85163b610e30576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016105cb565b5f808673ffffffffffffffffffffffffffffffffffffffff168587604051610e589190611077565b5f6040518083038185875af1925050503d805f8114610e92576040519150601f19603f3d011682016040523d82523d5f602084013e610e97565b606091505b5091509150610ea7828286610eb2565b979650505050505050565b60608315610ec1575081610d19565b825115610ed15782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105cb919061108d565b73ffffffffffffffffffffffffffffffffffffffff81168114610f26575f80fd5b50565b5f60208284031215610f39575f80fd5b8135610d1981610f05565b5f8060408385031215610f55575f80fd5b8235610f6081610f05565b946020939093013593505050565b5f805f60608486031215610f80575f80fd5b8335610f8b81610f05565b92506020840135610f9b81610f05565b929592945050506040919091013590565b5f60208284031215610fbc575f80fd5b5035919050565b5f60208284031215610fd3575f80fd5b8151610d1981610f05565b808202811582820484141761101a577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b92915050565b5f82611053577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b5f60208284031215611068575f80fd5b81518015158114610d19575f80fd5b5f82518060208501845e5f920191825250919050565b602081525f82518060208401528060208501604085015e5f6040828501015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168401019150509291505056fea264697066735822122087cfcbfb22fcb02baf3b088d3f29d61a8c90f07773c6b21882b580e7c413d08e64736f6c634300081a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000625e700125ff054f75e5348497cbfab1ee4b7a4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006c9f4e6089c8890afee2bcba364c2712f88fa8180000000000000000000000000000000000000000000000000c4855c005f00400000000000000000000000000baf15fa061d83608b7f59226b8491c1eb9df48b2
-----Decoded View---------------
Arg [0] : _owner (address): 0x625e700125FF054f75e5348497cBFab1ee4b7A40
Arg [1] : _quitCreditor (address): 0x0000000000000000000000000000000000000000
Arg [2] : _conversionToken (address): 0x6c9f4E6089c8890AfEE2bcBA364C2712f88fA818
Arg [3] : _conversionPrice (uint256): 885051610000000000
Arg [4] : _timedLocker (address): 0xbAF15fA061d83608B7F59226b8491C1eb9DF48B2
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 000000000000000000000000625e700125ff054f75e5348497cbfab1ee4b7a40
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [2] : 0000000000000000000000006c9f4e6089c8890afee2bcba364c2712f88fa818
Arg [3] : 0000000000000000000000000000000000000000000000000c4855c005f00400
Arg [4] : 000000000000000000000000baf15fa061d83608b7f59226b8491c1eb9df48b2
Deployed Bytecode Sourcemap
79082:6627:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;84070:148;;;;;;:::i;:::-;;:::i;:::-;;29250:141;;;;;;:::i;:::-;;:::i;79301:106::-;;;;;;;;;;;;631:42:1;619:55;;;601:74;;589:2;574:18;79301:106:0;;;;;;;;79588:29;;;;;;;;;28960;;;;;;;;;29399:354;;;:::i;79476:34::-;;;;;;;;;83461:172;;;;;;:::i;:::-;;:::i;79708:30::-;;;;;;;;;1680:25:1;;;1668:2;1653:18;79708:30:0;1534:177:1;28933:20:0;;;;;;;;;79895:64;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;1890:25:1;;;1946:2;1931:18;;1924:34;;;;1863:18;79895:64:0;1716:248:1;82506:673:0;;;;;;:::i;:::-;;:::i;81877:288::-;;;;;;:::i;:::-;;:::i;83769:132::-;;;;;;:::i;:::-;;:::i;79822:30::-;;;;;;;;;84070:148;29904:5;;;;29890:10;:19;29886:43;;29918:11;;;;;;;;;;;;;;29886:43;84165:19:::1;:45:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;84070:148::o;29250:141::-;29904:5;;;;29890:10;:19;29886:43;;29918:11;;;;;;;;;;;;;;29886:43;29322:14:::1;:23:::0;;;::::1;;::::0;::::1;::::0;;::::1;::::0;;;29361:22:::1;::::0;601:74:1;;;29361:22:0::1;::::0;589:2:1;574:18;29361:22:0::1;;;;;;;29250:141:::0;:::o;29399:354::-;29572:14;;;;29558:10;:28;29554:69;;29595:28;;;;;;;;;;;;;;29554:69;29652:5;;29659:14;;29639:35;;;29652:5;;;;3138:74:1;;29659:14:0;;;;3243:2:1;3228:18;;3221:83;29639:35:0;;3111:18:1;29639:35:0;;;;;;;29693:14;;;;29685:22;;;;;;29693:14;;;29685:22;;;;29718:27;;;29399:354::o;83461:172::-;29904:5;;;;29890:10;:19;29886:43;;29918:11;;;;;;;;;;;;;;29886:43;83556:69:::1;83586:12;83601:10;83613:11;83556:22;:69::i;:::-;83461:172:::0;;:::o;82506:673::-;82674:19;1866:1;2464:7;;:19;2456:63;;;;;;;3517:2:1;2456:63:0;;;3499:21:1;3556:2;3536:18;;;3529:30;3595:33;3575:18;;;3568:61;3646:18;;2456:63:0;;;;;;;;;1866:1;2597:7;:18;80525:9:::1;::::0;::::1;;80503:10;:32;80499:56;;80544:11;;;;;;;;;;;;;;80499:56;80685:19;::::0;;80649:9:::1;::::0;:32:::1;::::0;;;;;;;80685:19:::1;::::0;;::::1;::::0;80649:9;;;::::1;::::0;:30:::1;::::0;:32;;::::1;::::0;::::1;::::0;;;;;;;:9;:32:::1;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:55;;;80645:93;;80713:25;;;;;;;;;;;;;;80645:93;82772:15:::2;::::0;82751:17:::2;:10:::0;82764:4:::2;82751:17;:::i;:::-;82750:37;;;;:::i;:::-;82836:15;::::0;82868:11:::2;::::0;82836:58:::2;::::0;;;;:15:::2;82868:11:::0;;::::2;82836:58;::::0;::::2;4711:74:1::0;4801:18;;;4794:34;;;82736:51:0;;-1:-1:-1;82836:15:0::2;::::0;:23:::2;::::0;4684:18:1;;82836:58:0::2;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;82905:11:0::2;::::0;:30:::2;::::0;;;;::::2;::::0;::::2;1680:25:1::0;;;82905:11:0::2;::::0;;::::2;::::0;:17:::2;::::0;1653:18:1;;82905:30:0::2;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;-1:-1:-1::0;;83045:11:0::2;::::0;83015:68:::2;::::0;-1:-1:-1;83045:11:0::2;;::::0;-1:-1:-1;83059:10:0;83071:11;83015:22:::2;:68::i;:::-;83135:10;83101:70;;83118:15;83101:70;;;83147:10;83159:11;83101:70;;;;;;1890:25:1::0;;;1946:2;1931:18;;1924:34;1878:2;1863:18;;1716:248;83101:70:0::2;;;;;;;;1822:1:::0;2776:7;:22;82506:673;;-1:-1:-1;;;82506:673:0:o;81877:288::-;1866:1;2464:7;;:19;2456:63;;;;;;;3517:2:1;2456:63:0;;;3499:21:1;3556:2;3536:18;;;3529:30;3595:33;3575:18;;;3568:61;3646:18;;2456:63:0;3315:355:1;2456:63:0;1866:1;2597:7;:18;80525:9:::1;::::0;::::1;;80503:10;:32;80499:56;;80544:11;;;;;;;;;;;;;;80499:56;80685:19;::::0;;80649:9:::1;::::0;:32:::1;::::0;;;;;;;80685:19:::1;::::0;;::::1;::::0;80649:9;;;::::1;::::0;:30:::1;::::0;:32;;::::1;::::0;::::1;::::0;;;;;;;:9;:32:::1;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:55;;;80645:93;;80713:25;;;;;;;;;;;;;;80645:93;82058:32:::2;::::0;;;;::::2;::::0;;;;;82074:15:::2;82058:32;::::0;;::::2;::::0;;;82030:25:::2;::::0;::::2;-1:-1:-1::0;82030:25:0;;;:16:::2;:25:::0;;;;;:60;;;;;;::::2;::::0;;::::2;::::0;;;;82108:49;;1890:25:1;;;1931:18;;;1924:34;;;;82030:25:0;;82108:49:::2;::::0;1863:18:1;82108:49:0::2;;;;;;;-1:-1:-1::0;;1822:1:0;2776:7;:22;81877:288::o;83769:132::-;29904:5;;;;29890:10;:19;29886:43;;29918:11;;;;;;;;;;;;;;29886:43;83856:15:::1;:37:::0;83769:132::o;46532:211::-;46676:58;;;4741:42:1;4729:55;;46676:58:0;;;4711:74:1;4801:18;;;;4794:34;;;46676:58:0;;;;;;;;;;4684:18:1;;;;46676:58:0;;;;;;;;;;46699:23;46676:58;;;46649:86;;46669:5;;46649:19;:86::i;:::-;46532:211;;;:::o;49599:716::-;50023:23;50049:69;50077:4;50049:69;;;;;;;;;;;;;;;;;50057:5;50049:27;;;;:69;;;;;:::i;:::-;50133:17;;50023:95;;-1:-1:-1;50133:21:0;50129:179;;50230:10;50219:30;;;;;;;;;;;;:::i;:::-;50211:85;;;;;;;5323:2:1;50211:85:0;;;5305:21:1;5362:2;5342:18;;;5335:30;5401:34;5381:18;;;5374:62;5472:12;5452:18;;;5445:40;5502:19;;50211:85:0;5121:406:1;11969:229:0;12106:12;12138:52;12160:6;12168:4;12174:1;12177:12;12138:21;:52::i;:::-;12131:59;;11969:229;;;;;;:::o;13089:510::-;13259:12;13317:5;13292:21;:30;;13284:81;;;;;;;5734:2:1;13284:81:0;;;5716:21:1;5773:2;5753:18;;;5746:30;5812:34;5792:18;;;5785:62;5883:8;5863:18;;;5856:36;5909:19;;13284:81:0;5532:402:1;13284:81:0;9519:19;;;;13376:60;;;;;;;6141:2:1;13376:60:0;;;6123:21:1;6180:2;6160:18;;;6153:30;6219:31;6199:18;;;6192:59;6268:18;;13376:60:0;5939:353:1;13376:60:0;13450:12;13464:23;13491:6;:11;;13510:5;13517:4;13491:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13449:73;;;;13540:51;13557:7;13566:10;13578:12;13540:16;:51::i;:::-;13533:58;13089:510;-1:-1:-1;;;;;;;13089:510:0:o;15775:762::-;15925:12;15954:7;15950:580;;;-1:-1:-1;15985:10:0;15978:17;;15950:580;16099:17;;:21;16095:424;;16347:10;16341:17;16408:15;16395:10;16391:2;16387:19;16380:44;16095:424;16490:12;16483:20;;;;;;;;;;;:::i;14:154:1:-;100:42;93:5;89:54;82:5;79:65;69:93;;158:1;155;148:12;69:93;14:154;:::o;173:247::-;232:6;285:2;273:9;264:7;260:23;256:32;253:52;;;301:1;298;291:12;253:52;340:9;327:23;359:31;384:5;359:31;:::i;1162:367::-;1230:6;1238;1291:2;1279:9;1270:7;1266:23;1262:32;1259:52;;;1307:1;1304;1297:12;1259:52;1346:9;1333:23;1365:31;1390:5;1365:31;:::i;:::-;1415:5;1493:2;1478:18;;;;1465:32;;-1:-1:-1;;;1162:367:1:o;1969:508::-;2046:6;2054;2062;2115:2;2103:9;2094:7;2090:23;2086:32;2083:52;;;2131:1;2128;2121:12;2083:52;2170:9;2157:23;2189:31;2214:5;2189:31;:::i;:::-;2239:5;-1:-1:-1;2296:2:1;2281:18;;2268:32;2309:33;2268:32;2309:33;:::i;:::-;1969:508;;2361:7;;-1:-1:-1;;;2441:2:1;2426:18;;;;2413:32;;1969:508::o;2482:226::-;2541:6;2594:2;2582:9;2573:7;2569:23;2565:32;2562:52;;;2610:1;2607;2600:12;2562:52;-1:-1:-1;2655:23:1;;2482:226;-1:-1:-1;2482:226:1:o;3675:251::-;3745:6;3798:2;3786:9;3777:7;3773:23;3769:32;3766:52;;;3814:1;3811;3804:12;3766:52;3846:9;3840:16;3865:31;3890:5;3865:31;:::i;3931:322::-;4004:9;;;4035;;4052:15;;;4046:22;;4032:37;4022:225;;4103:77;4100:1;4093:88;4204:4;4201:1;4194:15;4232:4;4229:1;4222:15;4022:225;3931:322;;;;:::o;4258:274::-;4298:1;4324;4314:189;;4359:77;4356:1;4349:88;4460:4;4457:1;4450:15;4488:4;4485:1;4478:15;4314:189;-1:-1:-1;4517:9:1;;4258:274::o;4839:277::-;4906:6;4959:2;4947:9;4938:7;4934:23;4930:32;4927:52;;;4975:1;4972;4965:12;4927:52;5007:9;5001:16;5060:5;5053:13;5046:21;5039:5;5036:32;5026:60;;5082:1;5079;5072:12;6297:301;6426:3;6464:6;6458:13;6510:6;6503:4;6495:6;6491:17;6486:3;6480:37;6572:1;6536:16;;6561:13;;;-1:-1:-1;6536:16:1;6297:301;-1:-1:-1;6297:301:1:o;6603:477::-;6752:2;6741:9;6734:21;6715:4;6784:6;6778:13;6827:6;6822:2;6811:9;6807:18;6800:34;6886:6;6881:2;6873:6;6869:15;6864:2;6853:9;6849:18;6843:50;6942:1;6937:2;6928:6;6917:9;6913:22;6909:31;6902:42;7071:2;7001:66;6996:2;6988:6;6984:15;6980:88;6969:9;6965:104;6961:113;6953:121;;;6603:477;;;;:::o
Swarm Source
ipfs://87cfcbfb22fcb02baf3b088d3f29d61a8c90f07773c6b21882b580e7c413d08e
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$347,917.42
Net Worth in FRAX
412,579.534517
Token Allocations
FXB20271231
99.95%
ETH
0.03%
FRXETH
0.03%
Multichain Portfolio | 35 Chains
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.