Feature Tip: Add private address tag to any address under My Name Tag !
Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00Latest 25 from a total of 100 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Supply As Collat... | 24778472 | 1 hr ago | IN | 0.00482205 ETH | 0.00008582 | ||||
| Supply As Collat... | 24778163 | 2 hrs ago | IN | 0.5 ETH | 0.00013585 | ||||
| Supply As Collat... | 24778066 | 2 hrs ago | IN | 0.001 ETH | 0.00028598 | ||||
| Supply As Collat... | 24777857 | 3 hrs ago | IN | 0.00111 ETH | 0.00027099 | ||||
| Supply Native | 24777571 | 4 hrs ago | IN | 0.05147931 ETH | 0.00011086 | ||||
| Supply As Collat... | 24777400 | 5 hrs ago | IN | 0.0001 ETH | 0.00005097 | ||||
| Supply As Collat... | 24777297 | 5 hrs ago | IN | 0.01 ETH | 0.0000328 | ||||
| Supply As Collat... | 24777260 | 5 hrs ago | IN | 0.01 ETH | 0.00041655 | ||||
| Withdraw Native | 24777017 | 6 hrs ago | IN | 0 ETH | 0.00060483 | ||||
| Supply As Collat... | 24776819 | 7 hrs ago | IN | 3 ETH | 0.00032599 | ||||
| Supply As Collat... | 24776745 | 7 hrs ago | IN | 0.0503 ETH | 0.00005131 | ||||
| Supply As Collat... | 24776598 | 7 hrs ago | IN | 0.01 ETH | 0.00005493 | ||||
| Supply As Collat... | 24776460 | 8 hrs ago | IN | 0.0016 ETH | 0.00012312 | ||||
| Supply As Collat... | 24776415 | 8 hrs ago | IN | 0.1 ETH | 0.00004868 | ||||
| Supply As Collat... | 24776344 | 8 hrs ago | IN | 0.01 ETH | 0.00004832 | ||||
| Supply As Collat... | 24776294 | 8 hrs ago | IN | 0.03 ETH | 0.00023931 | ||||
| Supply As Collat... | 24776125 | 9 hrs ago | IN | 0.03 ETH | 0.00010305 | ||||
| Supply As Collat... | 24775940 | 10 hrs ago | IN | 0.001 ETH | 0.00004255 | ||||
| Supply As Collat... | 24775799 | 10 hrs ago | IN | 0.05 ETH | 0.00040823 | ||||
| Supply As Collat... | 24775714 | 10 hrs ago | IN | 1 ETH | 0.0001191 | ||||
| Supply As Collat... | 24775683 | 10 hrs ago | IN | 0.01 ETH | 0.00017739 | ||||
| Supply Native | 24775511 | 11 hrs ago | IN | 0.00111 ETH | 0.00001937 | ||||
| Supply As Collat... | 24775405 | 11 hrs ago | IN | 0.002 ETH | 0.00011138 | ||||
| Supply As Collat... | 24775322 | 12 hrs ago | IN | 0.01 ETH | 0.00004184 | ||||
| Supply As Collat... | 24775299 | 12 hrs ago | IN | 0.015 ETH | 0.00004002 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| Deposit | 24778640 | 1 hr ago | 1.91911548 ETH | ||||
| Supply Native | 24778640 | 1 hr ago | 1.91911548 ETH | ||||
| Deposit | 24778472 | 1 hr ago | 0.00482205 ETH | ||||
| Deposit | 24778163 | 2 hrs ago | 0.5 ETH | ||||
| Deposit | 24778066 | 2 hrs ago | 0.001 ETH | ||||
| Deposit | 24777857 | 3 hrs ago | 0.00111 ETH | ||||
| Deposit | 24777755 | 3 hrs ago | 50 ETH | ||||
| Supply As Collat... | 24777755 | 3 hrs ago | 50 ETH | ||||
| Deposit | 24777571 | 4 hrs ago | 0.05147931 ETH | ||||
| Deposit | 24777400 | 5 hrs ago | 0.0001 ETH | ||||
| Deposit | 24777297 | 5 hrs ago | 0.01 ETH | ||||
| Deposit | 24777260 | 5 hrs ago | 0.01 ETH | ||||
| Transfer | 24777017 | 6 hrs ago | 3 ETH | ||||
| Transfer | 24777017 | 6 hrs ago | 3 ETH | ||||
| Deposit | 24776819 | 7 hrs ago | 3 ETH | ||||
| Deposit | 24776745 | 7 hrs ago | 0.0503 ETH | ||||
| Deposit | 24776598 | 7 hrs ago | 0.01 ETH | ||||
| Deposit | 24776460 | 8 hrs ago | 0.0016 ETH | ||||
| Deposit | 24776415 | 8 hrs ago | 0.1 ETH | ||||
| Deposit | 24776344 | 8 hrs ago | 0.01 ETH | ||||
| Deposit | 24776294 | 8 hrs ago | 0.03 ETH | ||||
| Deposit | 24776125 | 9 hrs ago | 0.03 ETH | ||||
| Deposit | 24775940 | 10 hrs ago | 0.001 ETH | ||||
| Deposit | 24775922 | 10 hrs ago | 150 ETH | ||||
| Supply As Collat... | 24775922 | 10 hrs ago | 150 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
NativeTokenGateway
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 44444444 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: LicenseRef-BUSL
pragma solidity 0.8.28;
import {ReentrancyGuardTransient} from 'src/dependencies/openzeppelin/ReentrancyGuardTransient.sol';
import {Address} from 'src/dependencies/openzeppelin/Address.sol';
import {SafeERC20, IERC20} from 'src/dependencies/openzeppelin/SafeERC20.sol';
import {ISpoke} from 'src/spoke/interfaces/ISpoke.sol';
import {INativeWrapper} from 'src/position-manager/interfaces/INativeWrapper.sol';
import {INativeTokenGateway} from 'src/position-manager/interfaces/INativeTokenGateway.sol';
import {PositionManagerBase} from 'src/position-manager/PositionManagerBase.sol';
/// @title NativeTokenGateway
/// @author Aave Labs
/// @notice Gateway to interact with a spoke using the native coin of a chain.
contract NativeTokenGateway is INativeTokenGateway, PositionManagerBase, ReentrancyGuardTransient {
using SafeERC20 for IERC20;
/// @inheritdoc INativeTokenGateway
address public immutable NATIVE_TOKEN_WRAPPER;
/// @dev Constructor.
/// @param nativeTokenWrapper_ The address of the native token wrapper contract.
/// @param initialOwner_ The address of the initial owner.
constructor(
address nativeTokenWrapper_,
address initialOwner_
) PositionManagerBase(initialOwner_) {
require(nativeTokenWrapper_ != address(0), InvalidAddress());
NATIVE_TOKEN_WRAPPER = nativeTokenWrapper_;
}
/// @dev Checks only 'nativeWrapper' can transfer native tokens.
receive() external payable {
require(msg.sender == NATIVE_TOKEN_WRAPPER, UnsupportedAction());
}
/// @dev Unsupported fallback function.
fallback() external payable {
revert UnsupportedAction();
}
/// @inheritdoc INativeTokenGateway
function supplyNative(
address spoke,
uint256 reserveId,
uint256 amount
) external payable nonReentrant onlyRegisteredSpoke(spoke) returns (uint256, uint256) {
require(msg.value == amount, NativeAmountMismatch());
return _supplyNative(spoke, reserveId, msg.sender, amount);
}
/// @inheritdoc INativeTokenGateway
function supplyAsCollateralNative(
address spoke,
uint256 reserveId,
uint256 amount
) external payable nonReentrant onlyRegisteredSpoke(spoke) returns (uint256, uint256) {
require(msg.value == amount, NativeAmountMismatch());
(uint256 suppliedShares, uint256 suppliedAmount) = _supplyNative(
spoke,
reserveId,
msg.sender,
amount
);
ISpoke(spoke).setUsingAsCollateral(reserveId, true, msg.sender);
return (suppliedShares, suppliedAmount);
}
/// @inheritdoc INativeTokenGateway
function withdrawNative(
address spoke,
uint256 reserveId,
uint256 amount
) external nonReentrant onlyRegisteredSpoke(spoke) returns (uint256, uint256) {
address underlying = _getReserveUnderlying(spoke, reserveId);
_validateParams(underlying, amount);
(uint256 withdrawnShares, uint256 withdrawnAmount) = ISpoke(spoke).withdraw(
reserveId,
amount,
msg.sender
);
INativeWrapper(NATIVE_TOKEN_WRAPPER).withdraw(withdrawnAmount);
Address.sendValue(payable(msg.sender), withdrawnAmount);
return (withdrawnShares, withdrawnAmount);
}
/// @inheritdoc INativeTokenGateway
function borrowNative(
address spoke,
uint256 reserveId,
uint256 amount
) external nonReentrant onlyRegisteredSpoke(spoke) returns (uint256, uint256) {
address underlying = _getReserveUnderlying(spoke, reserveId);
_validateParams(underlying, amount);
(uint256 borrowedShares, uint256 borrowedAmount) = ISpoke(spoke).borrow(
reserveId,
amount,
msg.sender
);
INativeWrapper(NATIVE_TOKEN_WRAPPER).withdraw(borrowedAmount);
Address.sendValue(payable(msg.sender), borrowedAmount);
return (borrowedShares, borrowedAmount);
}
/// @inheritdoc INativeTokenGateway
function repayNative(
address spoke,
uint256 reserveId,
uint256 amount
) external payable nonReentrant onlyRegisteredSpoke(spoke) returns (uint256, uint256) {
require(msg.value == amount, NativeAmountMismatch());
address underlying = _getReserveUnderlying(spoke, reserveId);
_validateParams(underlying, amount);
uint256 userTotalDebt = ISpoke(spoke).getUserTotalDebt(reserveId, msg.sender);
uint256 repayAmount = amount;
uint256 leftovers;
if (amount > userTotalDebt) {
leftovers = amount - userTotalDebt;
repayAmount = userTotalDebt;
}
INativeWrapper(NATIVE_TOKEN_WRAPPER).deposit{value: repayAmount}();
IERC20(NATIVE_TOKEN_WRAPPER).forceApprove(spoke, repayAmount);
(uint256 repaidShares, uint256 repaidAmount) = ISpoke(spoke).repay(
reserveId,
repayAmount,
msg.sender
);
if (leftovers > 0) {
Address.sendValue(payable(msg.sender), leftovers);
}
return (repaidShares, repaidAmount);
}
/// @dev `msg.value` verification must be done before calling this.
function _supplyNative(
address spoke,
uint256 reserveId,
address user,
uint256 amount
) internal returns (uint256, uint256) {
address underlying = _getReserveUnderlying(spoke, reserveId);
_validateParams(underlying, amount);
INativeWrapper(NATIVE_TOKEN_WRAPPER).deposit{value: amount}();
IERC20(NATIVE_TOKEN_WRAPPER).forceApprove(spoke, amount);
return ISpoke(spoke).supply(reserveId, amount, user);
}
function _validateParams(address underlying, uint256 amount) internal view {
require(NATIVE_TOKEN_WRAPPER == underlying, NotNativeWrappedAsset());
require(amount > 0, InvalidAmount());
}
/// @dev Multicall is disabled to prevent msg.value reuse across delegatecalls.
function _multicallEnabled() internal pure override returns (bool) {
return false;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.5.0) (utils/ReentrancyGuardTransient.sol)
pragma solidity ^0.8.24;
import {TransientSlot} from './TransientSlot.sol';
/**
* @dev Variant of {ReentrancyGuard} that uses transient storage.
*
* NOTE: This variant only works on networks where EIP-1153 is available.
*
* _Available since v5.1._
*
* @custom:stateless
*/
abstract contract ReentrancyGuardTransient {
using TransientSlot for *;
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant REENTRANCY_GUARD_STORAGE =
0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
/**
* @dev A `view` only version of {nonReentrant}. Use to block view functions
* from being called, preventing reading from inconsistent contract state.
*
* CAUTION: This is a "view" modifier and does not change the reentrancy
* status. Use it only on view functions. For payable or non-payable functions,
* use the standard {nonReentrant} modifier instead.
*/
modifier nonReentrantView() {
_nonReentrantBeforeView();
_;
}
function _nonReentrantBeforeView() private view {
if (_reentrancyGuardEntered()) {
revert ReentrancyGuardReentrantCall();
}
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, REENTRANCY_GUARD_STORAGE.asBoolean().tload() will be false
_nonReentrantBeforeView();
// Any calls to nonReentrant after this point will fail
_reentrancyGuardStorageSlot().asBoolean().tstore(true);
}
function _nonReentrantAfter() private {
_reentrancyGuardStorageSlot().asBoolean().tstore(false);
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _reentrancyGuardStorageSlot().asBoolean().tload();
}
function _reentrancyGuardStorageSlot() internal pure virtual returns (bytes32) {
return REENTRANCY_GUARD_STORAGE;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.5.0) (utils/Address.sol)
pragma solidity ^0.8.20;
import {Errors} from './Errors.sol';
import {LowLevelCall} from './LowLevelCall.sol';
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @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://consensys.net/diligence/blog/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.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert Errors.InsufficientBalance(address(this).balance, amount);
}
if (LowLevelCall.callNoReturn(recipient, amount, '')) {
// call successful, nothing to do
return;
} else if (LowLevelCall.returnDataSize() > 0) {
LowLevelCall.bubbleRevert();
} else {
revert Errors.FailedCall();
}
}
/**
* @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 or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {Errors.FailedCall} error.
*
* 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.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @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`.
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
if (address(this).balance < value) {
revert Errors.InsufficientBalance(address(this).balance, value);
}
bool success = LowLevelCall.callNoReturn(target, value, data);
if (success && (LowLevelCall.returnDataSize() > 0 || target.code.length > 0)) {
return LowLevelCall.returnData();
} else if (success) {
revert AddressEmptyCode(target);
} else if (LowLevelCall.returnDataSize() > 0) {
LowLevelCall.bubbleRevert();
} else {
revert Errors.FailedCall();
}
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(
address target,
bytes memory data
) internal view returns (bytes memory) {
bool success = LowLevelCall.staticcallNoReturn(target, data);
if (success && (LowLevelCall.returnDataSize() > 0 || target.code.length > 0)) {
return LowLevelCall.returnData();
} else if (success) {
revert AddressEmptyCode(target);
} else if (LowLevelCall.returnDataSize() > 0) {
LowLevelCall.bubbleRevert();
} else {
revert Errors.FailedCall();
}
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
bool success = LowLevelCall.delegatecallNoReturn(target, data);
if (success && (LowLevelCall.returnDataSize() > 0 || target.code.length > 0)) {
return LowLevelCall.returnData();
} else if (success) {
revert AddressEmptyCode(target);
} else if (LowLevelCall.returnDataSize() > 0) {
LowLevelCall.bubbleRevert();
} else {
revert Errors.FailedCall();
}
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case
* of an unsuccessful call.
*
* NOTE: This function is DEPRECATED and may be removed in the next major release.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (success && (returndata.length > 0 || target.code.length > 0)) {
return returndata;
} else if (success) {
revert AddressEmptyCode(target);
} else if (returndata.length > 0) {
LowLevelCall.bubbleRevert(returndata);
} else {
revert Errors.FailedCall();
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {Errors.FailedCall} error.
*/
function verifyCallResult(
bool success,
bytes memory returndata
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else if (returndata.length > 0) {
LowLevelCall.bubbleRevert(returndata);
} else {
revert Errors.FailedCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.5.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from './IERC20.sol';
import {IERC1363} from './IERC1363.sol';
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(
address spender,
uint256 currentAllowance,
uint256 requestedDecrease
);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
if (!_safeTransfer(token, to, value, true)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
if (!_safeTransferFrom(token, from, to, value, true)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
return _safeTransfer(token, to, value, false);
}
/**
* @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal returns (bool) {
return _safeTransferFrom(token, from, to, value, false);
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 requestedDecrease
) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
if (!_safeApprove(token, spender, value, false)) {
if (!_safeApprove(token, spender, 0, true)) revert SafeERC20FailedOperation(address(token));
if (!_safeApprove(token, spender, value, true))
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that relies on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(
IERC1363 token,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that relies on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Oppositely, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(
IERC1363 token,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity `token.transfer(to, value)` call, 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 to The recipient of the tokens
* @param value The amount of token to transfer
* @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.
*/
function _safeTransfer(
IERC20 token,
address to,
uint256 value,
bool bubble
) private returns (bool success) {
bytes4 selector = IERC20.transfer.selector;
assembly ('memory-safe') {
let fmp := mload(0x40)
mstore(0x00, selector)
mstore(0x04, and(to, shr(96, not(0))))
mstore(0x24, value)
success := call(gas(), token, 0, 0x00, 0x44, 0x00, 0x20)
// if call success and return is true, all is good.
// otherwise (not success or return is not true), we need to perform further checks
if iszero(and(success, eq(mload(0x00), 1))) {
// if the call was a failure and bubble is enabled, bubble the error
if and(iszero(success), bubble) {
returndatacopy(fmp, 0x00, returndatasize())
revert(fmp, returndatasize())
}
// if the return value is not true, then the call is only successful if:
// - the token address has code
// - the returndata is empty
success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))
}
mstore(0x40, fmp)
}
}
/**
* @dev Imitates a Solidity `token.transferFrom(from, to, value)` call, 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 from The sender of the tokens
* @param to The recipient of the tokens
* @param value The amount of token to transfer
* @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.
*/
function _safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value,
bool bubble
) private returns (bool success) {
bytes4 selector = IERC20.transferFrom.selector;
assembly ('memory-safe') {
let fmp := mload(0x40)
mstore(0x00, selector)
mstore(0x04, and(from, shr(96, not(0))))
mstore(0x24, and(to, shr(96, not(0))))
mstore(0x44, value)
success := call(gas(), token, 0, 0x00, 0x64, 0x00, 0x20)
// if call success and return is true, all is good.
// otherwise (not success or return is not true), we need to perform further checks
if iszero(and(success, eq(mload(0x00), 1))) {
// if the call was a failure and bubble is enabled, bubble the error
if and(iszero(success), bubble) {
returndatacopy(fmp, 0x00, returndatasize())
revert(fmp, returndatasize())
}
// if the return value is not true, then the call is only successful if:
// - the token address has code
// - the returndata is empty
success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))
}
mstore(0x40, fmp)
mstore(0x60, 0)
}
}
/**
* @dev Imitates a Solidity `token.approve(spender, value)` call, 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 spender The spender of the tokens
* @param value The amount of token to transfer
* @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.
*/
function _safeApprove(
IERC20 token,
address spender,
uint256 value,
bool bubble
) private returns (bool success) {
bytes4 selector = IERC20.approve.selector;
assembly ('memory-safe') {
let fmp := mload(0x40)
mstore(0x00, selector)
mstore(0x04, and(spender, shr(96, not(0))))
mstore(0x24, value)
success := call(gas(), token, 0, 0x00, 0x44, 0x00, 0x20)
// if call success and return is true, all is good.
// otherwise (not success or return is not true), we need to perform further checks
if iszero(and(success, eq(mload(0x00), 1))) {
// if the call was a failure and bubble is enabled, bubble the error
if and(iszero(success), bubble) {
returndatacopy(fmp, 0x00, returndatasize())
revert(fmp, returndatasize())
}
// if the return value is not true, then the call is only successful if:
// - the token address has code
// - the returndata is empty
success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))
}
mstore(0x40, fmp)
}
}
}// SPDX-License-Identifier: LicenseRef-BUSL
pragma solidity ^0.8.0;
import {IAccessManaged} from 'src/dependencies/openzeppelin/IAccessManaged.sol';
import {IIntentConsumer} from 'src/interfaces/IIntentConsumer.sol';
import {IMulticall} from 'src/interfaces/IMulticall.sol';
import {IHubBase} from 'src/hub/interfaces/IHubBase.sol';
import {IExtSload} from 'src/interfaces/IExtSload.sol';
type ReserveFlags is uint8;
/// @title ISpoke
/// @author Aave Labs
/// @notice Full interface for Spoke.
interface ISpoke is IAccessManaged, IIntentConsumer, IExtSload, IMulticall {
/// @notice Intent data to set user position managers with EIP712-typed signature.
/// @param onBehalfOf The address of the user on whose behalf position manager can act.
/// @param updates The array of position manager updates.
/// @param nonce The nonce for the signature.
/// @param deadline The deadline for the signature.
struct SetUserPositionManagers {
address onBehalfOf;
PositionManagerUpdate[] updates;
uint256 nonce;
uint256 deadline;
}
/// @notice Sub-Intent data to apply position manager update for user.
/// @param positionManager The address of the position manager.
/// @param approve True to approve the position manager, false to revoke approval.
struct PositionManagerUpdate {
address positionManager;
bool approve;
}
/// @notice Reserve level data.
/// @dev underlying The address of the underlying asset.
/// @dev hub The address of the associated Hub.
/// @dev assetId The identifier of the asset in the Hub.
/// @dev decimals The number of decimals of the underlying asset.
/// @dev collateralRisk The risk associated with a collateral asset, expressed in BPS.
/// @dev flags The packed boolean flags of the reserve (a wrapped uint8).
/// @dev dynamicConfigKey The key of the last reserve dynamic config.
struct Reserve {
address underlying;
//
IHubBase hub;
uint16 assetId;
uint8 decimals;
uint24 collateralRisk;
ReserveFlags flags;
uint32 dynamicConfigKey;
}
/// @notice Reserve configuration. Subset of the `Reserve` struct.
/// @dev collateralRisk The risk associated with a collateral asset, expressed in BPS.
/// @dev paused True if all actions are prevented for the reserve.
/// @dev frozen True if new activity is prevented for the reserve.
/// @dev borrowable True if the reserve is borrowable.
/// @dev receiveSharesEnabled True if the liquidator can receive collateral shares during liquidation.
struct ReserveConfig {
uint24 collateralRisk;
bool paused;
bool frozen;
bool borrowable;
bool receiveSharesEnabled;
}
/// @notice Dynamic reserve configuration data.
/// @dev collateralFactor The proportion of a reserve's value eligible to be used as collateral, expressed in BPS.
/// @dev maxLiquidationBonus The maximum extra amount of collateral given to the liquidator as bonus, expressed in BPS. 100_00 represents 0.00% bonus.
/// @dev liquidationFee The protocol fee charged on liquidations, taken from the collateral bonus given to the liquidator, expressed in BPS.
struct DynamicReserveConfig {
uint16 collateralFactor;
uint32 maxLiquidationBonus;
uint16 liquidationFee;
}
/// @notice Liquidation configuration data.
/// @dev targetHealthFactor The ideal health factor to restore a user position during liquidation, expressed in WAD.
/// @dev healthFactorForMaxBonus The health factor under which liquidation bonus is maximum, expressed in WAD.
/// @dev liquidationBonusFactor The value multiplied by `maxLiquidationBonus` to compute the minimum liquidation bonus, expressed in BPS.
struct LiquidationConfig {
uint128 targetHealthFactor;
uint64 healthFactorForMaxBonus;
uint16 liquidationBonusFactor;
}
/// @notice User position data per reserve.
/// @dev drawnShares The drawn shares of the user position.
/// @dev premiumShares The premium shares of the user position.
/// @dev premiumOffsetRay The premium offset of the user position, used to calculate the premium, expressed in asset units and scaled by RAY.
/// @dev suppliedShares The supplied shares of the user position.
/// @dev dynamicConfigKey The key of the user position dynamic config.
struct UserPosition {
uint120 drawnShares;
uint120 premiumShares;
//
int200 premiumOffsetRay;
//
uint120 suppliedShares;
uint32 dynamicConfigKey;
}
/// @notice Position manager configuration data.
/// @dev approval The mapping of position manager user approvals.
/// @dev active True if the position manager is active.
struct PositionManagerConfig {
mapping(address user => bool) approval;
bool active;
}
/// @notice User position status data.
/// @dev map The map of bitmap buckets for the position status.
/// @dev riskPremium The risk premium of the user position, expressed in BPS.
struct PositionStatus {
mapping(uint256 bucket => uint256) map;
uint24 riskPremium;
}
/// @notice User account data describing a user position and its health.
/// @dev riskPremium The risk premium of the user position, expressed in BPS.
/// @dev avgCollateralFactor The weighted average collateral factor of the user position, expressed in WAD.
/// @dev healthFactor The health factor of the user position, expressed in WAD. 1e18 represents a health factor of 1.00.
/// @dev totalCollateralValue The total collateral value of the user position, expressed in units of Value.
/// @dev totalDebtValueRay The total debt value of the user position, expressed in units of Value and scaled by RAY.
/// @dev activeCollateralCount The number of active collaterals, which includes reserves with `collateralFactor` > 0, `enabledAsCollateral` and `suppliedAmount` > 0.
/// @dev borrowCount The number of borrowed reserves of the user position.
struct UserAccountData {
uint256 riskPremium;
uint256 avgCollateralFactor;
uint256 healthFactor;
uint256 totalCollateralValue;
uint256 totalDebtValueRay;
uint256 activeCollateralCount;
uint256 borrowCount;
}
/// @notice Emitted when the immutable variables of the Spoke are set.
/// @param oracle The address of the oracle.
/// @param maxUserReservesLimit The max user reserves limit.
event SetSpokeImmutables(address indexed oracle, uint16 maxUserReservesLimit);
/// @notice Emitted when a liquidation config is updated.
/// @param config The new liquidation config.
event UpdateLiquidationConfig(LiquidationConfig config);
/// @notice Emitted when a reserve is added.
/// @param reserveId The identifier of the reserve.
/// @param assetId The identifier of the asset.
/// @param hub The address of the Hub where the asset is listed.
event AddReserve(uint256 indexed reserveId, uint256 indexed assetId, address indexed hub);
/// @notice Emitted when a reserve configuration is updated.
/// @param reserveId The identifier of the reserve.
/// @param config The reserve configuration.
event UpdateReserveConfig(uint256 indexed reserveId, ReserveConfig config);
/// @notice Emitted when the price source of a reserve is updated.
/// @param reserveId The identifier of the reserve.
/// @param priceSource The address of the new price source.
event UpdateReservePriceSource(uint256 indexed reserveId, address indexed priceSource);
/// @notice Emitted when a dynamic reserve config is added.
/// @dev The config key is the next available key for the reserve, which is now the latest config
/// key of the reserve.
/// @param reserveId The identifier of the reserve.
/// @param dynamicConfigKey The key of the added dynamic config.
/// @param config The dynamic reserve config.
event AddDynamicReserveConfig(
uint256 indexed reserveId,
uint32 indexed dynamicConfigKey,
DynamicReserveConfig config
);
/// @notice Emitted when a dynamic reserve config is updated.
/// @param reserveId The identifier of the reserve.
/// @param dynamicConfigKey The key of the updated dynamic config.
/// @param config The dynamic reserve config.
event UpdateDynamicReserveConfig(
uint256 indexed reserveId,
uint32 indexed dynamicConfigKey,
DynamicReserveConfig config
);
/// @notice Emitted on updatePositionManager action.
/// @param positionManager The address of the position manager.
/// @param active True if position manager has become active.
event UpdatePositionManager(address indexed positionManager, bool active);
/// @notice Emitted on the supply action.
/// @param reserveId The reserve identifier of the underlying asset.
/// @param caller The transaction initiator, and supplier of the underlying asset.
/// @param user The owner of the modified position.
/// @param suppliedShares The amount of supply shares minted.
/// @param suppliedAmount The amount of underlying asset supplied.
event Supply(
uint256 indexed reserveId,
address indexed caller,
address indexed user,
uint256 suppliedShares,
uint256 suppliedAmount
);
/// @notice Emitted on the withdraw action.
/// @param reserveId The reserve identifier of the underlying asset.
/// @param caller The transaction initiator, and recipient of the underlying asset being withdrawn.
/// @param user The owner of the modified position.
/// @param withdrawnShares The amount of supply shares burned.
/// @param withdrawnAmount The amount of underlying asset withdrawn.
event Withdraw(
uint256 indexed reserveId,
address indexed caller,
address indexed user,
uint256 withdrawnShares,
uint256 withdrawnAmount
);
/// @notice Emitted on the borrow action.
/// @param reserveId The reserve identifier of the underlying asset.
/// @param caller The transaction initiator, and recipient of the underlying asset being borrowed.
/// @param user The owner of the position on which debt is generated.
/// @param drawnShares The amount of debt shares minted.
/// @param drawnAmount The amount of underlying asset borrowed.
event Borrow(
uint256 indexed reserveId,
address indexed caller,
address indexed user,
uint256 drawnShares,
uint256 drawnAmount
);
/// @notice Emitted on the repay action.
/// @param reserveId The reserve identifier of the underlying asset.
/// @param caller The transaction initiator who is repaying the underlying asset.
/// @param user The owner of the position whose debt is being repaid.
/// @param drawnShares The amount of drawn shares burned.
/// @param totalAmountRepaid The amount of drawn and premium underlying assets repaid.
/// @param premiumDelta A struct representing the changes to premium debt after repayment.
event Repay(
uint256 indexed reserveId,
address indexed caller,
address indexed user,
uint256 drawnShares,
uint256 totalAmountRepaid,
IHubBase.PremiumDelta premiumDelta
);
/// @dev Emitted when a borrower is liquidated.
/// @param collateralReserveId The identifier of the reserve used as collateral, to receive as a result of the liquidation.
/// @param debtReserveId The identifier of the reserve to be repaid with the liquidation.
/// @param user The address of the borrower getting liquidated.
/// @param liquidator The address of the liquidator.
/// @param receiveShares True if the liquidator received collateral in supplied shares rather than underlying assets.
/// @param debtAmountRestored The amount of debt restored, expressed in asset units.
/// @param drawnSharesLiquidated The amount of drawn shares liquidated.
/// @param premiumDelta A struct representing the changes to premium debt after liquidation.
/// @param collateralAmountRemoved The amount of collateral removed, expressed in asset units.
/// @param collateralSharesLiquidated The total amount of collateral shares liquidated.
/// @param collateralSharesToLiquidator The amount of collateral shares that the liquidator received.
event LiquidationCall(
uint256 indexed collateralReserveId,
uint256 indexed debtReserveId,
address indexed user,
address liquidator,
bool receiveShares,
uint256 debtAmountRestored,
uint256 drawnSharesLiquidated,
IHubBase.PremiumDelta premiumDelta,
uint256 collateralAmountRemoved,
uint256 collateralSharesLiquidated,
uint256 collateralSharesToLiquidator
);
/// @notice Emitted when a reserve deficit is reported to the Hub.
/// @param reserveId The identifier of the reserve.
/// @param user The address of the user.
/// @param drawnShares The amount of drawn shares reported as deficit.
/// @param premiumDelta The premium delta data struct reported as deficit.
event ReportDeficit(
uint256 indexed reserveId,
address indexed user,
uint256 drawnShares,
IHubBase.PremiumDelta premiumDelta
);
/// @notice Emitted on setUsingAsCollateral action.
/// @param reserveId The reserve identifier of the underlying asset.
/// @param caller The transaction initiator.
/// @param user The owner of the position being modified.
/// @param usingAsCollateral Whether the reserve is enabled or disabled as collateral.
event SetUsingAsCollateral(
uint256 indexed reserveId,
address indexed caller,
address indexed user,
bool usingAsCollateral
);
/// @notice Emitted on updateUserRiskPremium action.
/// @param user The owner of the position being modified.
/// @param riskPremium The new risk premium (BPS) value of user.
event UpdateUserRiskPremium(address indexed user, uint256 riskPremium);
/// @notice Emitted when a user's dynamic config is refreshed for all reserves to their latest config key.
/// @param user The address of the user.
event RefreshAllUserDynamicConfig(address indexed user);
/// @notice Emitted when a user's dynamic config is refreshed for a single reserve to its latest config key.
/// @param user The address of the user.
/// @param reserveId The identifier of the reserve.
event RefreshSingleUserDynamicConfig(address indexed user, uint256 reserveId);
/// @notice Emitted on setUserPositionManager or renouncePositionManagerRole action.
/// @param user The address of the user on whose behalf position manager can act.
/// @param positionManager The address of the position manager.
/// @param approve True if position manager approval was granted, false if it was revoked.
event SetUserPositionManager(address indexed user, address indexed positionManager, bool approve);
/// @notice Emitted on refreshPremiumDebt action.
/// @param reserveId The identifier of the reserve.
/// @param user The address of the user.
/// @param premiumDelta The change in premium values.
event RefreshPremiumDebt(
uint256 indexed reserveId,
address indexed user,
IHubBase.PremiumDelta premiumDelta
);
/// @notice Thrown when an asset is not listed on the Hub when adding a reserve.
error AssetNotListed();
/// @notice Thrown when adding a new reserve if that reserve already exists for a given Hub/assetId pair.
error ReserveExists();
/// @notice Thrown when adding a new reserve if an asset id is invalid.
error InvalidAssetId();
/// @notice Thrown when adding a new reserve if the asset decimals are invalid.
error InvalidAssetDecimals();
/// @notice Thrown when updating a reserve if it is not listed.
error ReserveNotListed();
/// @notice Thrown when a reserve is not borrowable during a `borrow` action.
error ReserveNotBorrowable();
/// @notice Thrown when a reserve is paused during an attempted action.
error ReservePaused();
/// @notice Thrown when a reserve is frozen.
/// @dev Can only occur during an attempted `supply`, `borrow`, or `setUsingAsCollateral` action.
error ReserveFrozen();
/// @notice Thrown when an action causes a user's health factor to fall below the liquidation threshold.
error HealthFactorBelowThreshold();
/// @notice Thrown when reserve is not enabled as collateral during liquidation.
error ReserveNotEnabledAsCollateral();
/// @notice Thrown when a specified reserve is not supplied by the user during liquidation.
error ReserveNotSupplied();
/// @notice Thrown when a specified reserve is not borrowed by the user during liquidation.
error ReserveNotBorrowed();
/// @notice Thrown when an unauthorized caller attempts an action.
error Unauthorized();
/// @notice Thrown if a config key is uninitialized when updating a dynamic reserve config.
error DynamicConfigKeyUninitialized();
/// @notice Thrown for an invalid zero address.
error InvalidAddress();
/// @notice Thrown when the oracle decimals are not 8 in the constructor.
error InvalidOracleDecimals();
/// @notice Thrown when the maximum user reserves limit is zero in the constructor.
error InvalidMaxUserReservesLimit();
/// @notice Thrown when a collateral risk exceeds the maximum allowed.
error InvalidCollateralRisk();
/// @notice Thrown if a liquidation config is invalid when it is updated.
error InvalidLiquidationConfig();
/// @notice Thrown when a liquidation fee is invalid.
error InvalidLiquidationFee();
/// @notice Thrown when a collateral factor and max liquidation bonus are invalid.
error InvalidCollateralFactorAndMaxLiquidationBonus();
/// @notice Thrown when trying to set zero collateralFactor on historic dynamic configuration keys.
error InvalidCollateralFactor();
/// @notice Thrown when a self-liquidation is attempted.
error SelfLiquidation();
/// @notice Thrown during liquidation when a user's health factor is not below the liquidation threshold.
error HealthFactorNotBelowThreshold();
/// @notice Thrown when collateral or debt dust remains after a liquidation, and neither reserve is fully liquidated.
error MustNotLeaveDust();
/// @notice Thrown when a debt to cover input is zero.
error InvalidDebtToCover();
/// @notice Thrown when the liquidator tries to receive shares for a collateral reserve that is frozen or is not enabled to receive shares.
error CannotReceiveShares();
/// @notice Thrown when the maximum number of dynamic config keys is reached.
error MaximumDynamicConfigKeyReached();
/// @notice Thrown when user attempts to exceed either the maximum allowed collateral or borrowed reserves.
error MaximumUserReservesExceeded();
/// @notice Updates the liquidation config.
/// @param config The new liquidation config.
function updateLiquidationConfig(LiquidationConfig calldata config) external;
/// @notice Adds a new reserve to the Spoke.
/// @dev Allowed even if the Spoke has not yet been added to the Hub.
/// @dev Allowed even if the `active` flag is `false`.
/// @dev Allowed even if the Spoke has been added but the `addCap` is zero.
/// @param hub The address of the Hub where the asset is listed.
/// @param assetId The identifier of the asset in the Hub.
/// @param priceSource The address of the price source for the asset.
/// @param config The initial reserve configuration.
/// @param dynamicConfig The initial dynamic reserve configuration.
/// @return The identifier of the newly added reserve.
function addReserve(
address hub,
uint256 assetId,
address priceSource,
ReserveConfig calldata config,
DynamicReserveConfig calldata dynamicConfig
) external returns (uint256);
/// @notice Updates the reserve config for a given reserve.
/// @dev It reverts if the reserve associated with the given reserve identifier is not listed.
/// @param reserveId The identifier of the reserve.
/// @param params The new reserve config.
function updateReserveConfig(uint256 reserveId, ReserveConfig calldata params) external;
/// @notice Updates the price source of a reserve.
/// @param reserveId The identifier of the reserve.
/// @param priceSource The address of the price source.
function updateReservePriceSource(uint256 reserveId, address priceSource) external;
/// @notice Updates the dynamic reserve config for a given reserve.
/// @dev It reverts if the reserve associated with the given reserve identifier is not listed.
/// @dev Appends dynamic config to the next available key; reverts if `MAX_ALLOWED_DYNAMIC_CONFIG_KEY` is reached.
/// @param reserveId The identifier of the reserve.
/// @param dynamicConfig The new dynamic reserve config.
/// @return dynamicConfigKey The key of the added dynamic config.
function addDynamicReserveConfig(
uint256 reserveId,
DynamicReserveConfig calldata dynamicConfig
) external returns (uint32 dynamicConfigKey);
/// @notice Updates the dynamic reserve config for a given reserve at the specified key.
/// @dev It reverts if the reserve associated with the given reserve identifier is not listed.
/// @dev Reverts with `DynamicConfigKeyUninitialized` if the config key has not been initialized yet.
/// @dev Reverts with `InvalidCollateralFactor` if the collateral factor is 0.
/// @param reserveId The identifier of the reserve.
/// @param dynamicConfigKey The key of the config to update.
/// @param dynamicConfig The new dynamic reserve config.
function updateDynamicReserveConfig(
uint256 reserveId,
uint32 dynamicConfigKey,
DynamicReserveConfig calldata dynamicConfig
) external;
/// @notice Allows an approved caller (admin) to toggle the active status of position manager.
/// @param positionManager The address of the position manager.
/// @param active True if positionManager is to be set as active.
function updatePositionManager(address positionManager, bool active) external;
/// @notice Supplies an amount of underlying asset of the specified reserve.
/// @dev It reverts if the reserve associated with the given reserve identifier is not listed.
/// @dev The Spoke pulls the underlying asset from the caller, so prior token approval is required.
/// @dev Caller must be `onBehalfOf` or an authorized position manager for `onBehalfOf`.
/// @param reserveId The reserve identifier.
/// @param amount The amount of asset to supply.
/// @param onBehalfOf The owner of the position to add supply shares to.
/// @return The amount of shares supplied.
/// @return The amount of assets supplied.
function supply(
uint256 reserveId,
uint256 amount,
address onBehalfOf
) external returns (uint256, uint256);
/// @notice Withdraws a specified amount of underlying asset from the given reserve.
/// @dev It reverts if the reserve associated with the given reserve identifier is not listed.
/// @dev Providing an amount greater than the maximum withdrawable value signals a full withdrawal.
/// @dev Caller must be `onBehalfOf` or an authorized position manager for `onBehalfOf`.
/// @dev Caller receives the underlying asset withdrawn.
/// @param reserveId The identifier of the reserve.
/// @param amount The amount of asset to withdraw.
/// @param onBehalfOf The owner of position to remove supply shares from.
/// @return The amount of shares withdrawn.
/// @return The amount of assets withdrawn.
function withdraw(
uint256 reserveId,
uint256 amount,
address onBehalfOf
) external returns (uint256, uint256);
/// @notice Borrows a specified amount of underlying asset from the given reserve.
/// @dev It reverts if the reserve associated with the given reserve identifier is not listed.
/// @dev It reverts if the user would borrow more than the maximum allowed number of borrowed reserves.
/// @dev Caller must be `onBehalfOf` or an authorized position manager for `onBehalfOf`.
/// @dev Caller receives the underlying asset borrowed.
/// @param reserveId The identifier of the reserve.
/// @param amount The amount of asset to borrow.
/// @param onBehalfOf The owner of the position against which debt is generated.
/// @return The amount of shares borrowed.
/// @return The amount of assets borrowed.
function borrow(
uint256 reserveId,
uint256 amount,
address onBehalfOf
) external returns (uint256, uint256);
/// @notice Repays a specified amount of underlying asset to a given reserve.
/// @dev It reverts if the reserve associated with the given reserve identifier is not listed.
/// @dev The Spoke pulls the underlying asset from the caller, so prior approval is required.
/// @dev Caller must be `onBehalfOf` or an authorized position manager for `onBehalfOf`.
/// @param reserveId The identifier of the reserve.
/// @param amount The amount of asset to repay.
/// @param onBehalfOf The owner of the position whose debt is repaid.
/// @return The amount of shares repaid.
/// @return The amount of assets repaid.
function repay(
uint256 reserveId,
uint256 amount,
address onBehalfOf
) external returns (uint256, uint256);
/// @notice Liquidates a user position.
/// @dev It reverts if the reserves associated with any of the given reserve identifiers are not listed.
/// @dev The Spoke pulls underlying repaid debt assets from caller (Liquidator), hence it needs prior approval.
/// @param collateralReserveId The reserveId of the underlying asset used as collateral by the liquidated user.
/// @param debtReserveId The reserveId of the underlying asset borrowed by the liquidated user, to be repaid by Liquidator.
/// @param user The address of the user to liquidate.
/// @param debtToCover The desired amount of debt to cover.
/// @param receiveShares True to receive collateral in supplied shares, false to receive in underlying assets.
function liquidationCall(
uint256 collateralReserveId,
uint256 debtReserveId,
address user,
uint256 debtToCover,
bool receiveShares
) external;
/// @notice Allows suppliers to enable/disable a specific supplied reserve as collateral.
/// @dev It reverts if the reserve associated with the given reserve identifier is not listed.
/// @dev It reverts if the user exceeds the maximum allowed collateral reserves when enabling.
/// @dev Reserves with zero supplied or zero collateral factor count towards the max allowed collateral reserves.
/// @dev Caller must be `onBehalfOf` or an authorized position manager for `onBehalfOf`.
/// @param reserveId The reserve identifier of the underlying asset.
/// @param usingAsCollateral True if the user wants to use the supply as collateral.
/// @param onBehalfOf The owner of the position being modified.
function setUsingAsCollateral(
uint256 reserveId,
bool usingAsCollateral,
address onBehalfOf
) external;
/// @notice Allows updating the risk premium on onBehalfOf position.
/// @dev Caller must be `onBehalfOf`, an authorized position manager for `onBehalfOf`, or admin.
/// @param onBehalfOf The owner of the position being modified.
function updateUserRiskPremium(address onBehalfOf) external;
/// @notice Allows updating the dynamic configuration for all collateral reserves on onBehalfOf position.
/// @dev Caller must be `onBehalfOf`, an authorized position manager for `onBehalfOf`, or admin.
/// @param onBehalfOf The owner of the position being modified.
function updateUserDynamicConfig(address onBehalfOf) external;
/// @notice Enables a user to grant or revoke approval for a position manager.
/// @dev Allows approving inactive position managers.
/// @param positionManager The address of the position manager.
/// @param approve True to approve the position manager, false to revoke approval.
function setUserPositionManager(address positionManager, bool approve) external;
/// @notice Enables a user to grant or revoke approval for an array of position managers using an EIP712-typed intent.
/// @dev Uses keyed-nonces where for each key's namespace nonce is consumed sequentially.
/// @dev Allows duplicated updates and the last one is persisted. Allows approving inactive position managers.
/// @param params The structured setUserPositionManagers parameter.
/// @param signature The EIP712-compliant signature bytes.
function setUserPositionManagersWithSig(
SetUserPositionManagers calldata params,
bytes calldata signature
) external;
/// @notice Allows position manager (as caller) to renounce their approval given by the user.
/// @param user The address of the user.
function renouncePositionManagerRole(address user) external;
/// @notice Allows consuming a permit signature for the given reserve's underlying asset.
/// @dev It reverts if the reserve associated with the given reserve identifier is not listed.
/// @dev The Spoke must be configured as the spender.
/// @param reserveId The identifier of the reserve.
/// @param onBehalfOf The address of the user on whose behalf the permit is being used.
/// @param value The amount of the underlying asset to permit.
/// @param deadline The deadline for the permit.
/// @param permitV The v parameter of the permit signature.
/// @param permitR The r parameter of the permit signature.
/// @param permitS The s parameter of the permit signature.
function permitReserve(
uint256 reserveId,
address onBehalfOf,
uint256 value,
uint256 deadline,
uint8 permitV,
bytes32 permitR,
bytes32 permitS
) external;
/// @notice Returns the liquidation config struct.
function getLiquidationConfig() external view returns (LiquidationConfig memory);
/// @notice Returns the number of listed reserves on the Spoke.
/// @dev Count includes reserves that are not currently active.
function getReserveCount() external view returns (uint256);
/// @notice Returns the total amount of supplied assets of a given reserve.
/// @param reserveId The identifier of the reserve.
/// @return The amount of supplied assets.
function getReserveSuppliedAssets(uint256 reserveId) external view returns (uint256);
/// @notice Returns the total amount of supplied shares of a given reserve.
/// @dev It reverts if the reserve associated with the given reserve identifier is not listed.
/// @param reserveId The identifier of the reserve.
/// @return The amount of supplied shares.
function getReserveSuppliedShares(uint256 reserveId) external view returns (uint256);
/// @notice Returns the debt of a given reserve.
/// @dev It reverts if the reserve associated with the given reserve identifier is not listed.
/// @dev The total debt of the reserve is the sum of drawn debt and premium debt.
/// @param reserveId The identifier of the reserve.
/// @return The amount of drawn debt.
/// @return The amount of premium debt.
function getReserveDebt(uint256 reserveId) external view returns (uint256, uint256);
/// @notice Returns the total debt of a given reserve.
/// @dev It reverts if the reserve associated with the given reserve identifier is not listed.
/// @dev The total debt of the reserve is the sum of drawn debt and premium debt.
/// @param reserveId The identifier of the reserve.
/// @return The total debt amount.
function getReserveTotalDebt(uint256 reserveId) external view returns (uint256);
/// @notice Returns the reserve identifier for a given asset in a Hub.
/// @dev It reverts if no reserve is associated with the given asset identifier.
/// @param hub The address of the Hub.
/// @param assetId The identifier of the asset on the Hub.
/// @return The identifier of the reserve.
function getReserveId(address hub, uint256 assetId) external view returns (uint256);
/// @notice Returns the reserve struct data in storage.
/// @dev It reverts if the reserve associated with the given reserve identifier is not listed.
/// @param reserveId The identifier of the reserve.
/// @return The reserve struct.
function getReserve(uint256 reserveId) external view returns (Reserve memory);
/// @notice Returns the reserve configuration struct data in storage.
/// @dev It reverts if the reserve associated with the given reserve identifier is not listed.
/// @param reserveId The identifier of the reserve.
/// @return The reserve configuration struct.
function getReserveConfig(uint256 reserveId) external view returns (ReserveConfig memory);
/// @notice Returns the dynamic reserve configuration struct at the specified key.
/// @dev It reverts if the reserve associated with the given reserve identifier is not listed.
/// @dev Does not revert if `dynamicConfigKey` is unset.
/// @param reserveId The identifier of the reserve.
/// @param dynamicConfigKey The key of the dynamic config.
/// @return The dynamic reserve configuration struct.
function getDynamicReserveConfig(
uint256 reserveId,
uint32 dynamicConfigKey
) external view returns (DynamicReserveConfig memory);
/// @notice Returns two flags indicating whether the reserve is used as collateral and whether it is borrowed by the user.
/// @dev It reverts if the reserve associated with the given reserve identifier is not listed.
/// @dev Even if enabled as collateral, it will only count towards user position if the collateral factor is greater than 0.
/// @param reserveId The identifier of the reserve.
/// @param user The address of the user.
/// @return True if the reserve is enabled as collateral by the user.
/// @return True if the reserve is borrowed by the user.
function getUserReserveStatus(uint256 reserveId, address user) external view returns (bool, bool);
/// @notice Returns the amount of assets supplied by a specific user for a given reserve.
/// @dev It reverts if the reserve associated with the given reserve identifier is not listed.
/// @param reserveId The identifier of the reserve.
/// @param user The address of the user.
/// @return The amount of assets supplied by the user.
function getUserSuppliedAssets(uint256 reserveId, address user) external view returns (uint256);
/// @notice Returns the amount of shares supplied by a specific user for a given reserve.
/// @dev It reverts if the reserve associated with the given reserve identifier is not listed.
/// @param reserveId The identifier of the reserve.
/// @param user The address of the user.
/// @return The amount of shares supplied by the user.
function getUserSuppliedShares(uint256 reserveId, address user) external view returns (uint256);
/// @notice Returns the debt of a specific user for a given reserve.
/// @dev It reverts if the reserve associated with the given reserve identifier is not listed.
/// @dev The total debt of the user is the sum of drawn debt and premium debt.
/// @param reserveId The identifier of the reserve.
/// @param user The address of the user.
/// @return The amount of drawn debt.
/// @return The amount of premium debt.
function getUserDebt(uint256 reserveId, address user) external view returns (uint256, uint256);
/// @notice Returns the total debt of a specific user for a given reserve.
/// @dev It reverts if the reserve associated with the given reserve identifier is not listed.
/// @dev The total debt of the user is the sum of drawn debt and premium debt.
/// @param reserveId The identifier of the reserve.
/// @param user The address of the user.
/// @return The total debt amount.
function getUserTotalDebt(uint256 reserveId, address user) external view returns (uint256);
/// @notice Returns the full precision premium debt of a specific user for a given reserve.
/// @dev It reverts if the reserve associated with the given reserve identifier is not listed.
/// @param reserveId The identifier of the reserve.
/// @param user The address of the user.
/// @return The amount of premium debt, expressed in asset units and scaled by RAY.
function getUserPremiumDebtRay(uint256 reserveId, address user) external view returns (uint256);
/// @notice Returns the user position struct in storage.
/// @dev It reverts if the reserve associated with the given reserve identifier is not listed.
/// @param reserveId The identifier of the reserve.
/// @param user The address of the user.
/// @return The user position struct.
function getUserPosition(
uint256 reserveId,
address user
) external view returns (UserPosition memory);
/// @notice Returns the most up-to-date user account data information.
/// @dev Utilizes user's current dynamic configuration of user position.
/// @param user The address of the user.
/// @return The user account data struct.
function getUserAccountData(address user) external view returns (UserAccountData memory);
/// @notice Returns the risk premium from the user's last position update.
/// @param user The address of the user.
/// @return The risk premium of the user from the last position update, expressed in BPS.
function getUserLastRiskPremium(address user) external view returns (uint256);
/// @notice Returns the liquidation bonus for a given health factor, based on the user's current dynamic configuration.
/// @dev It reverts if the reserve associated with the given reserve identifier is not listed.
/// @param reserveId The identifier of the reserve.
/// @param user The address of the user.
/// @param healthFactor The health factor of the user, expressed in WAD.
/// @return The liquidation bonus for the user, expressed in BPS.
function getLiquidationBonus(
uint256 reserveId,
address user,
uint256 healthFactor
) external view returns (uint256);
/// @notice Returns whether positionManager is currently activated by governance.
/// @param positionManager The address of the position manager.
/// @return True if positionManager is currently active.
function isPositionManagerActive(address positionManager) external view returns (bool);
/// @notice Returns whether positionManager is active and approved by user.
/// @param user The address of the user.
/// @param positionManager The address of the position manager.
/// @return True if positionManager is active and approved by user.
function isPositionManager(address user, address positionManager) external view returns (bool);
/// @notice Returns the address of the external `LiquidationLogic` library.
function getLiquidationLogic() external pure returns (address);
/// @notice Returns the type hash for the SetUserPositionManagers intent.
/// @return The bytes-encoded EIP-712 struct hash representing the intent.
function SET_USER_POSITION_MANAGERS_TYPEHASH() external view returns (bytes32);
/// @notice Returns the address of the AaveOracle contract.
function ORACLE() external view returns (address);
/// @notice Returns the maximum allowed number of collateral and borrow reserves per user (each counted separately).
function MAX_USER_RESERVES_LIMIT() external view returns (uint16);
}// SPDX-License-Identifier: LicenseRef-BUSL
pragma solidity ^0.8.0;
import {IERC20} from 'src/dependencies/openzeppelin/IERC20.sol';
/// @title INativeWrapper interface
/// @author Aave Labs
/// @notice Minimal interface for interacting with a wrapped native token contract.
interface INativeWrapper is IERC20 {
/// @notice Deposit native currency and receive wrapped tokens.
function deposit() external payable;
/// @notice Withdraw native currency by burning wrapped tokens.
/// @param amount The amount of wrapped tokens to burn for native currency.
function withdraw(uint256 amount) external;
}// SPDX-License-Identifier: LicenseRef-BUSL
pragma solidity ^0.8.0;
import {IPositionManagerBase} from 'src/position-manager/interfaces/IPositionManagerBase.sol';
/// @title INativeTokenGateway
/// @author Aave Labs
/// @notice Abstracts actions to the protocol involving the native token.
/// @dev Must be set as `PositionManager` on the Spoke for the user.
interface INativeTokenGateway is IPositionManagerBase {
/// @notice Thrown when the underlying asset is not the wrapped native asset.
error NotNativeWrappedAsset();
/// @notice Thrown when the native amount sent does not match the given amount parameter.
error NativeAmountMismatch();
/// @notice Wraps the native asset and supplies to a specified registered Spoke.
/// @dev Contract must be an active and approved user position manager of the caller.
/// @param spoke The address of the registered Spoke.
/// @param reserveId The identifier of the reserve for the wrapped asset.
/// @param amount Amount to wrap and supply.
/// @return The amount of shares supplied.
/// @return The amount of assets supplied.
function supplyNative(
address spoke,
uint256 reserveId,
uint256 amount
) external payable returns (uint256, uint256);
/// @notice Wraps the native asset, supplies to a specified registered Spoke and sets it as collateral.
/// @dev Contract must be an active and approved user position manager of the caller.
/// @param spoke The address of the registered Spoke.
/// @param reserveId The identifier of the reserve for the wrapped asset.
/// @param amount Amount to wrap and supply.
/// @return The amount of shares supplied.
/// @return The amount of assets supplied.
function supplyAsCollateralNative(
address spoke,
uint256 reserveId,
uint256 amount
) external payable returns (uint256, uint256);
/// @notice Withdraws the wrapped asset from a specified registered Spoke and unwraps it back to the native asset.
/// @dev Contract must be an active and approved user position manager of the caller.
/// @dev The withdrawn amount may be lower than requested if the user has insufficient supplied assets.
/// @param spoke The address of the registered Spoke.
/// @param reserveId The identifier of the reserve for the wrapped asset.
/// @param amount Amount to withdraw and unwrap.
/// @return The amount of shares withdrawn.
/// @return The amount of assets withdrawn.
function withdrawNative(
address spoke,
uint256 reserveId,
uint256 amount
) external returns (uint256, uint256);
/// @notice Borrows the wrapped asset from a specified registered Spoke and unwraps it back to the native asset.
/// @dev Contract must be an active and approved user position manager of the caller.
/// @param spoke The address of the registered Spoke.
/// @param reserveId The identifier of the reserve for the wrapped asset.
/// @param amount Amount to borrow and unwrap.
/// @return The amount of shares borrowed.
/// @return The amount of assets borrowed.
function borrowNative(
address spoke,
uint256 reserveId,
uint256 amount
) external returns (uint256, uint256);
/// @notice Wraps the native asset and repays debt on a specified registered Spoke.
/// @dev It refunds any excess funds sent beyond the required debt repayment.
/// @dev Contract must be an active and approved user position manager of the caller.
/// @param spoke The address of the registered Spoke.
/// @param reserveId The identifier of the reserve for the wrapped asset.
/// @param amount Amount to wrap and repay.
/// @return The amount of shares repaid.
/// @return The amount of assets repaid.
function repayNative(
address spoke,
uint256 reserveId,
uint256 amount
) external payable returns (uint256, uint256);
/// @notice Returns the address of the Native Wrapper.
function NATIVE_TOKEN_WRAPPER() external view returns (address);
}// SPDX-License-Identifier: LicenseRef-BUSL
pragma solidity 0.8.28;
import {IERC20} from 'src/dependencies/openzeppelin/IERC20.sol';
import {IERC20Permit} from 'src/dependencies/openzeppelin/IERC20Permit.sol';
import {Ownable2Step, Ownable} from 'src/dependencies/openzeppelin/Ownable2Step.sol';
import {IMulticall, Multicall} from 'src/utils/Multicall.sol';
import {Rescuable} from 'src/utils/Rescuable.sol';
import {ISpoke} from 'src/spoke/interfaces/ISpoke.sol';
import {IPositionManagerBase} from 'src/position-manager/interfaces/IPositionManagerBase.sol';
/// @title PositionManagerBase
/// @author Aave Labs
/// @notice Base implementation for position manager common functionalities.
/// @dev This base contract is not mandatory for position managers, it only implements optional convenience methods for position managers.
/// @dev Contract must be an active and approved user position manager in order to execute spoke actions on a user's behalf.
/// @dev The `_multicallEnabled()` function must be implemented to specify whether multicall is enabled.
abstract contract PositionManagerBase is IPositionManagerBase, Ownable2Step, Rescuable, Multicall {
/// @dev Map of registered spokes.
mapping(address spoke => bool registered) internal _registeredSpokes;
/// @notice Modifier that checks if the specified spoke is registered.
modifier onlyRegisteredSpoke(address spoke) {
require(_isSpokeRegistered(spoke), SpokeNotRegistered());
_;
}
/// @dev Constructor.
/// @param initialOwner_ The address of the initial owner.
constructor(address initialOwner_) Ownable(initialOwner_) {}
/// @inheritdoc IPositionManagerBase
function registerSpoke(address spoke, bool registered) external onlyOwner {
require(spoke != address(0), InvalidAddress());
_registeredSpokes[spoke] = registered;
emit RegisterSpoke(spoke, registered);
}
/// @inheritdoc IPositionManagerBase
function setSelfAsUserPositionManagerWithSig(
address spoke,
address onBehalfOf,
bool approve,
uint256 nonce,
uint256 deadline,
bytes calldata signature
) external onlyRegisteredSpoke(spoke) {
ISpoke.PositionManagerUpdate[] memory updates = new ISpoke.PositionManagerUpdate[](1);
updates[0] = ISpoke.PositionManagerUpdate({positionManager: address(this), approve: approve});
try
ISpoke(spoke).setUserPositionManagersWithSig(
ISpoke.SetUserPositionManagers({
onBehalfOf: onBehalfOf,
updates: updates,
nonce: nonce,
deadline: deadline
}),
signature
)
{} catch {}
}
/// @inheritdoc IPositionManagerBase
function permitReserveUnderlying(
address spoke,
uint256 reserveId,
address onBehalfOf,
uint256 value,
uint256 deadline,
uint8 permitV,
bytes32 permitR,
bytes32 permitS
) external onlyRegisteredSpoke(spoke) {
address underlying = _getReserveUnderlying(spoke, reserveId);
try
IERC20Permit(underlying).permit({
owner: onBehalfOf,
spender: address(this),
value: value,
deadline: deadline,
v: permitV,
r: permitR,
s: permitS
})
{} catch {}
}
/// @inheritdoc IPositionManagerBase
function renouncePositionManagerRole(
address spoke,
address user
) external onlyOwner onlyRegisteredSpoke(spoke) {
ISpoke(spoke).renouncePositionManagerRole(user);
}
/// @inheritdoc IMulticall
function multicall(
bytes[] calldata data
) public override(Multicall, IMulticall) returns (bytes[] memory) {
require(_multicallEnabled(), UnsupportedAction());
return super.multicall(data);
}
/// @inheritdoc IPositionManagerBase
function isSpokeRegistered(address spoke) external view returns (bool) {
return _isSpokeRegistered(spoke);
}
/// @dev Verifies the specified spoke is registered.
function _isSpokeRegistered(address spoke) internal view returns (bool) {
return _registeredSpokes[spoke];
}
/// @return The underlying asset for `reserveId` on the specified spoke.
function _getReserveUnderlying(address spoke, uint256 reserveId) internal view returns (address) {
return ISpoke(spoke).getReserve(reserveId).underlying;
}
/// @dev Flag to enable multicall usage. Needs to be set by the inheriting contracts.
function _multicallEnabled() internal pure virtual returns (bool);
function _rescueGuardian() internal view override returns (address) {
return owner();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/TransientSlot.sol)
// This file was procedurally generated from scripts/generate/templates/TransientSlot.js.
pragma solidity ^0.8.24;
/**
* @dev Library for reading and writing value-types to specific transient storage slots.
*
* Transient slots are often used to store temporary values that are removed after the current transaction.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* * Example reading and writing values using transient storage:
* ```solidity
* contract Lock {
* using TransientSlot for *;
*
* // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
* bytes32 internal constant _LOCK_SLOT = 0xf4678858b2b588224636b8522b729e7722d32fc491da849ed75b3fdf3c84f542;
*
* modifier locked() {
* require(!_LOCK_SLOT.asBoolean().tload());
*
* _LOCK_SLOT.asBoolean().tstore(true);
* _;
* _LOCK_SLOT.asBoolean().tstore(false);
* }
* }
* ```
*
* TIP: Consider using this library along with {SlotDerivation}.
*/
library TransientSlot {
/**
* @dev UDVT that represents a slot holding an address.
*/
type AddressSlot is bytes32;
/**
* @dev Cast an arbitrary slot to a AddressSlot.
*/
function asAddress(bytes32 slot) internal pure returns (AddressSlot) {
return AddressSlot.wrap(slot);
}
/**
* @dev UDVT that represents a slot holding a bool.
*/
type BooleanSlot is bytes32;
/**
* @dev Cast an arbitrary slot to a BooleanSlot.
*/
function asBoolean(bytes32 slot) internal pure returns (BooleanSlot) {
return BooleanSlot.wrap(slot);
}
/**
* @dev UDVT that represents a slot holding a bytes32.
*/
type Bytes32Slot is bytes32;
/**
* @dev Cast an arbitrary slot to a Bytes32Slot.
*/
function asBytes32(bytes32 slot) internal pure returns (Bytes32Slot) {
return Bytes32Slot.wrap(slot);
}
/**
* @dev UDVT that represents a slot holding a uint256.
*/
type Uint256Slot is bytes32;
/**
* @dev Cast an arbitrary slot to a Uint256Slot.
*/
function asUint256(bytes32 slot) internal pure returns (Uint256Slot) {
return Uint256Slot.wrap(slot);
}
/**
* @dev UDVT that represents a slot holding a int256.
*/
type Int256Slot is bytes32;
/**
* @dev Cast an arbitrary slot to a Int256Slot.
*/
function asInt256(bytes32 slot) internal pure returns (Int256Slot) {
return Int256Slot.wrap(slot);
}
/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(AddressSlot slot) internal view returns (address value) {
assembly ('memory-safe') {
value := tload(slot)
}
}
/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(AddressSlot slot, address value) internal {
assembly ('memory-safe') {
tstore(slot, value)
}
}
/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(BooleanSlot slot) internal view returns (bool value) {
assembly ('memory-safe') {
value := tload(slot)
}
}
/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(BooleanSlot slot, bool value) internal {
assembly ('memory-safe') {
tstore(slot, value)
}
}
/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(Bytes32Slot slot) internal view returns (bytes32 value) {
assembly ('memory-safe') {
value := tload(slot)
}
}
/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(Bytes32Slot slot, bytes32 value) internal {
assembly ('memory-safe') {
tstore(slot, value)
}
}
/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(Uint256Slot slot) internal view returns (uint256 value) {
assembly ('memory-safe') {
value := tload(slot)
}
}
/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(Uint256Slot slot, uint256 value) internal {
assembly ('memory-safe') {
tstore(slot, value)
}
}
/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(Int256Slot slot) internal view returns (int256 value) {
assembly ('memory-safe') {
value := tload(slot)
}
}
/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(Int256Slot slot, int256 value) internal {
assembly ('memory-safe') {
tstore(slot, value)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of common custom errors used in multiple contracts
*
* IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
* It is recommended to avoid relying on the error API for critical functionality.
*
* _Available since v5.1._
*/
library Errors {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error InsufficientBalance(uint256 balance, uint256 needed);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedCall();
/**
* @dev The deployment failed.
*/
error FailedDeployment();
/**
* @dev A necessary precompile is missing.
*/
error MissingPrecompile(address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.5.0) (utils/LowLevelCall.sol)
pragma solidity ^0.8.20;
/**
* @dev Library of low level call functions that implement different calling strategies to deal with the return data.
*
* WARNING: Using this library requires an advanced understanding of Solidity and how the EVM works. It is recommended
* to use the {Address} library instead.
*/
library LowLevelCall {
/// @dev Performs a Solidity function call using a low level `call` and ignoring the return data.
function callNoReturn(address target, bytes memory data) internal returns (bool success) {
return callNoReturn(target, 0, data);
}
/// @dev Same as {callNoReturn}, but allows to specify the value to be sent in the call.
function callNoReturn(
address target,
uint256 value,
bytes memory data
) internal returns (bool success) {
assembly ('memory-safe') {
success := call(gas(), target, value, add(data, 0x20), mload(data), 0x00, 0x00)
}
}
/// @dev Performs a Solidity function call using a low level `call` and returns the first 64 bytes of the result
/// in the scratch space of memory. Useful for functions that return a tuple of single-word values.
///
/// WARNING: Do not assume that the results are zero if `success` is false. Memory can be already allocated
/// and this function doesn't zero it out.
function callReturn64Bytes(
address target,
bytes memory data
) internal returns (bool success, bytes32 result1, bytes32 result2) {
return callReturn64Bytes(target, 0, data);
}
/// @dev Same as {callReturnBytes32Pair}, but allows to specify the value to be sent in the call.
function callReturn64Bytes(
address target,
uint256 value,
bytes memory data
) internal returns (bool success, bytes32 result1, bytes32 result2) {
assembly ('memory-safe') {
success := call(gas(), target, value, add(data, 0x20), mload(data), 0x00, 0x40)
result1 := mload(0x00)
result2 := mload(0x20)
}
}
/// @dev Performs a Solidity function call using a low level `staticcall` and ignoring the return data.
function staticcallNoReturn(
address target,
bytes memory data
) internal view returns (bool success) {
assembly ('memory-safe') {
success := staticcall(gas(), target, add(data, 0x20), mload(data), 0x00, 0x00)
}
}
/// @dev Performs a Solidity function call using a low level `staticcall` and returns the first 64 bytes of the result
/// in the scratch space of memory. Useful for functions that return a tuple of single-word values.
///
/// WARNING: Do not assume that the results are zero if `success` is false. Memory can be already allocated
/// and this function doesn't zero it out.
function staticcallReturn64Bytes(
address target,
bytes memory data
) internal view returns (bool success, bytes32 result1, bytes32 result2) {
assembly ('memory-safe') {
success := staticcall(gas(), target, add(data, 0x20), mload(data), 0x00, 0x40)
result1 := mload(0x00)
result2 := mload(0x20)
}
}
/// @dev Performs a Solidity function call using a low level `delegatecall` and ignoring the return data.
function delegatecallNoReturn(address target, bytes memory data) internal returns (bool success) {
assembly ('memory-safe') {
success := delegatecall(gas(), target, add(data, 0x20), mload(data), 0x00, 0x00)
}
}
/// @dev Performs a Solidity function call using a low level `delegatecall` and returns the first 64 bytes of the result
/// in the scratch space of memory. Useful for functions that return a tuple of single-word values.
///
/// WARNING: Do not assume that the results are zero if `success` is false. Memory can be already allocated
/// and this function doesn't zero it out.
function delegatecallReturn64Bytes(
address target,
bytes memory data
) internal returns (bool success, bytes32 result1, bytes32 result2) {
assembly ('memory-safe') {
success := delegatecall(gas(), target, add(data, 0x20), mload(data), 0x00, 0x40)
result1 := mload(0x00)
result2 := mload(0x20)
}
}
/// @dev Returns the size of the return data buffer.
function returnDataSize() internal pure returns (uint256 size) {
assembly ('memory-safe') {
size := returndatasize()
}
}
/// @dev Returns a buffer containing the return data from the last call.
function returnData() internal pure returns (bytes memory result) {
assembly ('memory-safe') {
result := mload(0x40)
mstore(result, returndatasize())
returndatacopy(add(result, 0x20), 0x00, returndatasize())
mstore(0x40, add(result, add(0x20, returndatasize())))
}
}
/// @dev Revert with the return data from the last call.
function bubbleRevert() internal pure {
assembly ('memory-safe') {
let fmp := mload(0x40)
returndatacopy(fmp, 0x00, returndatasize())
revert(fmp, returndatasize())
}
}
function bubbleRevert(bytes memory returndata) internal pure {
assembly ('memory-safe') {
revert(add(returndata, 0x20), mload(returndata))
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol)
pragma solidity >=0.6.2;
import {IERC20} from './IERC20.sol';
import {IERC165} from './IERC165.sol';
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(
address from,
address to,
uint256 value,
bytes calldata data
) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(
address spender,
uint256 value,
bytes calldata data
) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (access/manager/IAccessManaged.sol)
pragma solidity >=0.8.4;
interface IAccessManaged {
/**
* @dev Authority that manages this contract was updated.
*/
event AuthorityUpdated(address authority);
error AccessManagedUnauthorized(address caller);
error AccessManagedRequiredDelay(address caller, uint32 delay);
error AccessManagedInvalidAuthority(address authority);
/**
* @dev Returns the current authority.
*/
function authority() external view returns (address);
/**
* @dev Transfers control to a new authority. The caller must be the current authority.
*/
function setAuthority(address) external;
/**
* @dev Returns true only in the context of a delayed restricted call, at the moment that the scheduled operation is
* being consumed. Prevents denial of service for delayed restricted calls in the case that the contract performs
* attacker controlled calls.
*/
function isConsumingScheduledOp() external view returns (bytes4);
}// SPDX-License-Identifier: LicenseRef-BUSL
pragma solidity ^0.8.0;
import {INoncesKeyed} from 'src/interfaces/INoncesKeyed.sol';
/// @title IIntentConsumer
/// @author Aave Labs
/// @notice Minimal interface for IntentConsumer.
interface IIntentConsumer is INoncesKeyed {
/// @notice Thrown when given signature is invalid.
error InvalidSignature();
/// @notice Returns the EIP-712 domain separator.
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: LicenseRef-BUSL
pragma solidity ^0.8.0;
/// @title IMulticall
/// @author Aave Labs
/// @notice Minimal interface for Multicall.
interface IMulticall {
/// @notice Call multiple functions in the current contract and return the data from each if they all succeed.
/// @param data The encoded function data for each of the calls to make to this contract.
/// @return results The results from each of the calls passed in via data.
function multicall(bytes[] calldata data) external returns (bytes[] memory);
}// SPDX-License-Identifier: LicenseRef-BUSL
pragma solidity ^0.8.0;
/// @title IHubBase
/// @author Aave Labs
/// @notice Minimal interface for Hub.
interface IHubBase {
/// @notice Changes to premium owed accounting.
/// @dev sharesDelta The change in premium shares.
/// @dev offsetRayDelta The change in premium offset, expressed in asset units and scaled by RAY.
/// @dev restoredPremiumRay The restored premium, expressed in asset units and scaled by RAY.
struct PremiumDelta {
int256 sharesDelta;
int256 offsetRayDelta;
uint256 restoredPremiumRay;
}
/// @notice Emitted on the `add` action.
/// @param assetId The identifier of the asset.
/// @param spoke The address of the Spoke.
/// @param shares The amount of shares added.
/// @param amount The amount of assets added.
event Add(uint256 indexed assetId, address indexed spoke, uint256 shares, uint256 amount);
/// @notice Emitted on the `remove` action.
/// @param assetId The identifier of the asset.
/// @param spoke The address of the Spoke.
/// @param shares The amount of shares removed.
/// @param amount The amount of assets removed.
event Remove(uint256 indexed assetId, address indexed spoke, uint256 shares, uint256 amount);
/// @notice Emitted on the `draw` action.
/// @param assetId The identifier of the asset.
/// @param spoke The address of the Spoke.
/// @param drawnShares The amount of drawn shares.
/// @param drawnAmount The amount of drawn assets.
event Draw(
uint256 indexed assetId,
address indexed spoke,
uint256 drawnShares,
uint256 drawnAmount
);
/// @notice Emitted on the `restore` action.
/// @param assetId The identifier of the asset.
/// @param spoke The address of the Spoke.
/// @param drawnShares The amount of drawn shares.
/// @param premiumDelta The premium delta data struct.
/// @param drawnAmount The amount of drawn assets restored.
/// @param premiumAmount The amount of premium assets restored.
event Restore(
uint256 indexed assetId,
address indexed spoke,
uint256 drawnShares,
PremiumDelta premiumDelta,
uint256 drawnAmount,
uint256 premiumAmount
);
/// @notice Emitted on the `refreshPremium` action.
/// @param assetId The identifier of the asset.
/// @param spoke The address of the Spoke.
/// @param premiumDelta The premium delta data struct.
event RefreshPremium(uint256 indexed assetId, address indexed spoke, PremiumDelta premiumDelta);
/// @notice Emitted on the `reportDeficit` action.
/// @param assetId The identifier of the asset.
/// @param spoke The address of the Spoke.
/// @param drawnShares The amount of drawn shares reported as deficit.
/// @param premiumDelta The premium delta data struct.
/// @param deficitAmountRay The amount of deficit reported, expressed in asset units and scaled by RAY.
event ReportDeficit(
uint256 indexed assetId,
address indexed spoke,
uint256 drawnShares,
PremiumDelta premiumDelta,
uint256 deficitAmountRay
);
/// @notice Emitted on the `transferShares` action.
/// @param assetId The identifier of the asset.
/// @param sender The address of the sender.
/// @param receiver The address of the receiver.
/// @param shares The amount of shares transferred.
event TransferShares(
uint256 indexed assetId,
address indexed sender,
address indexed receiver,
uint256 shares
);
/// @notice Adds assets on behalf of a user.
/// @dev Only callable by active spokes.
/// @dev Underlying assets must be transferred to the Hub before invocation.
/// @dev Extra untracked underlying liquidity in the Hub can be skimmed into the Hub's liquidity accounting through this action.
/// @param assetId The identifier of the asset.
/// @param amount The amount of asset liquidity to add.
/// @return The amount of shares added.
function add(uint256 assetId, uint256 amount) external returns (uint256);
/// @notice Removes assets on behalf of a user.
/// @dev Only callable by active spokes.
/// @param assetId The identifier of the asset.
/// @param amount The amount of asset liquidity to remove.
/// @param to The address to transfer the assets to.
/// @return The amount of shares removed.
function remove(uint256 assetId, uint256 amount, address to) external returns (uint256);
/// @notice Draws assets on behalf of a user.
/// @dev Only callable by active spokes.
/// @param assetId The identifier of the asset.
/// @param amount The amount of assets to draw.
/// @param to The address to transfer the underlying assets to.
/// @return The amount of drawn shares.
function draw(uint256 assetId, uint256 amount, address to) external returns (uint256);
/// @notice Restores assets on behalf of a user.
/// @dev Only callable by active spokes.
/// @dev Interest is always paid off first from premium, then from drawn.
/// @dev Underlying assets must be transferred to the Hub before invocation.
/// @dev Extra untracked underlying liquidity in the Hub can be skimmed into the Hub's liquidity accounting through this action.
/// @param assetId The identifier of the asset.
/// @param drawnAmount The drawn amount to restore.
/// @param premiumDelta The premium delta to apply which signals premium repayment.
/// @return The amount of drawn shares restored.
function restore(
uint256 assetId,
uint256 drawnAmount,
PremiumDelta calldata premiumDelta
) external returns (uint256);
/// @notice Reports an owed amount by the caller Spoke as a deficit.
/// @dev Only callable by active spokes.
/// @param assetId The identifier of the asset.
/// @param drawnAmount The drawn amount to report as deficit.
/// @param premiumDelta The premium delta to apply which signals premium deficit.
/// @return The amount of drawn shares reported as deficit.
/// @return The amount of deficit reported, expressed in asset units.
function reportDeficit(
uint256 assetId,
uint256 drawnAmount,
PremiumDelta calldata premiumDelta
) external returns (uint256, uint256);
/// @notice Refreshes premium accounting.
/// @dev Only callable by active spokes.
/// @dev Asset and spoke premium should not decrease.
/// @param assetId The identifier of the asset.
/// @param premiumDelta The change in premium.
function refreshPremium(uint256 assetId, PremiumDelta calldata premiumDelta) external;
/// @notice Transfers an amount of added shares of the caller Spoke to the fee receiver Spoke.
/// @dev It can be used to execute one-time payments to the fee receiver Spoke (e.g., liquidation fees).
/// @dev Only callable by active spokes.
/// @param assetId The identifier of the asset.
/// @param shares The amount of shares to pay to feeReceiver.
function payFeeShares(uint256 assetId, uint256 shares) external;
/// @notice Converts the specified amount of assets to shares upon an `add` action.
/// @dev Rounds down to the nearest shares amount.
/// @dev Defaults to a 1:1 exchange rate.
/// @param assetId The identifier of the asset.
/// @param assets The amount of assets to convert to shares amount.
/// @return The amount of shares converted from assets amount.
function previewAddByAssets(uint256 assetId, uint256 assets) external view returns (uint256);
/// @notice Converts the specified shares amount to assets amount added upon an `add` action.
/// @dev Rounds up to the nearest assets amount.
/// @dev Defaults to a 1:1 exchange rate.
/// @param assetId The identifier of the asset.
/// @param shares The amount of shares to convert to assets amount.
/// @return The amount of assets converted from shares amount.
function previewAddByShares(uint256 assetId, uint256 shares) external view returns (uint256);
/// @notice Converts the specified amount of assets to shares amount removed upon a `remove` action.
/// @dev Rounds up to the nearest shares amount.
/// @dev Defaults to a 1:1 exchange rate.
/// @param assetId The identifier of the asset.
/// @param assets The amount of assets to convert to shares amount.
/// @return The amount of shares converted from assets amount.
function previewRemoveByAssets(uint256 assetId, uint256 assets) external view returns (uint256);
/// @notice Converts the specified amount of shares to assets amount removed upon a `remove` action.
/// @dev Rounds down to the nearest assets amount.
/// @dev Defaults to a 1:1 exchange rate.
/// @param assetId The identifier of the asset.
/// @param shares The amount of shares to convert to assets amount.
/// @return The amount of assets converted from shares amount.
function previewRemoveByShares(uint256 assetId, uint256 shares) external view returns (uint256);
/// @notice Converts the specified amount of assets to shares amount drawn upon a `draw` action.
/// @dev Rounds up to the nearest shares amount.
/// @param assetId The identifier of the asset.
/// @param assets The amount of assets to convert to shares amount.
/// @return The amount of shares converted from assets amount.
function previewDrawByAssets(uint256 assetId, uint256 assets) external view returns (uint256);
/// @notice Converts the specified amount of shares to assets amount drawn upon a `draw` action.
/// @dev Rounds down to the nearest assets amount.
/// @param assetId The identifier of the asset.
/// @param shares The amount of shares to convert to assets amount.
/// @return The amount of assets converted from shares amount.
function previewDrawByShares(uint256 assetId, uint256 shares) external view returns (uint256);
/// @notice Converts the specified amount of assets to shares amount restored upon a `restore` action.
/// @dev Rounds down to the nearest shares amount.
/// @param assetId The identifier of the asset.
/// @param assets The amount of assets to convert to shares amount.
/// @return The amount of shares converted from assets amount.
function previewRestoreByAssets(uint256 assetId, uint256 assets) external view returns (uint256);
/// @notice Converts the specified amount of shares to assets amount restored upon a `restore` action.
/// @dev Rounds up to the nearest assets amount.
/// @param assetId The identifier of the asset.
/// @param shares The amount of drawn shares to convert to assets amount.
/// @return The amount of assets converted from shares amount.
function previewRestoreByShares(uint256 assetId, uint256 shares) external view returns (uint256);
/// @notice Returns the asset identifier for the specified underlying asset.
/// @dev Reverts with `AssetNotListed` if the underlying is not listed.
/// @param underlying The address of the underlying asset.
function getAssetId(address underlying) external view returns (uint256);
/// @notice Returns the underlying address and decimals of the specified asset.
/// @param assetId The identifier of the asset.
/// @return The underlying address of the asset.
/// @return The decimals of the asset.
function getAssetUnderlyingAndDecimals(uint256 assetId) external view returns (address, uint8);
/// @notice Calculates the current drawn index for the specified asset.
/// @param assetId The identifier of the asset.
/// @return The current drawn index of the asset.
function getAssetDrawnIndex(uint256 assetId) external view returns (uint256);
/// @notice Returns the total amount of the specified asset added to the Hub.
/// @param assetId The identifier of the asset.
/// @return The amount of the asset added.
function getAddedAssets(uint256 assetId) external view returns (uint256);
/// @notice Returns the total amount of shares of the specified asset added to the Hub.
/// @param assetId The identifier of the asset.
/// @return The amount of shares of the asset added.
function getAddedShares(uint256 assetId) external view returns (uint256);
/// @notice Returns the amount of owed drawn and premium assets for the specified asset.
/// @param assetId The identifier of the asset.
/// @return The amount of owed drawn assets.
/// @return The amount of owed premium assets.
function getAssetOwed(uint256 assetId) external view returns (uint256, uint256);
/// @notice Returns the total amount of assets owed to the Hub.
/// @param assetId The identifier of the asset.
/// @return The total amount of the assets owed.
function getAssetTotalOwed(uint256 assetId) external view returns (uint256);
/// @notice Returns the amount of owed premium with full precision for specified asset.
/// @param assetId The identifier of the asset.
/// @return The amount of premium owed, expressed in asset units and scaled by RAY.
function getAssetPremiumRay(uint256 assetId) external view returns (uint256);
/// @notice Returns the amount of drawn shares of the specified asset.
/// @param assetId The identifier of the asset.
/// @return The amount of drawn shares.
function getAssetDrawnShares(uint256 assetId) external view returns (uint256);
/// @notice Returns the information regarding premium shares of the specified asset.
/// @param assetId The identifier of the asset.
/// @return The amount of premium shares owed to the asset.
/// @return The premium offset of the asset, expressed in asset units and scaled by RAY.
function getAssetPremiumData(uint256 assetId) external view returns (uint256, int256);
/// @notice Returns the amount of available liquidity for the specified asset.
/// @param assetId The identifier of the asset.
/// @return The amount of available liquidity.
function getAssetLiquidity(uint256 assetId) external view returns (uint256);
/// @notice Returns the amount of deficit with full precision of the specified asset.
/// @param assetId The identifier of the asset.
/// @return The amount of deficit, expressed in asset units and scaled by RAY.
function getAssetDeficitRay(uint256 assetId) external view returns (uint256);
/// @notice Returns the total amount of the specified assets added to the Hub by the specified spoke.
/// @dev If spoke is `asset.feeReceiver`, includes converted `unrealizedFeeShares` in return value.
/// @param assetId The identifier of the asset.
/// @param spoke The address of the Spoke.
/// @return The amount of added assets.
function getSpokeAddedAssets(uint256 assetId, address spoke) external view returns (uint256);
/// @notice Returns the total amount of shares of the specified asset added to the Hub by the specified spoke.
/// @dev If spoke is `asset.feeReceiver`, includes `unrealizedFeeShares` in return value.
/// @param assetId The identifier of the asset.
/// @param spoke The address of the Spoke.
/// @return The amount of added shares.
function getSpokeAddedShares(uint256 assetId, address spoke) external view returns (uint256);
/// @notice Returns the amount of the specified assets owed to the Hub by the specified spoke.
/// @param assetId The identifier of the asset.
/// @param spoke The address of the Spoke.
/// @return The amount of owed drawn assets.
/// @return The amount of owed premium assets.
function getSpokeOwed(uint256 assetId, address spoke) external view returns (uint256, uint256);
/// @notice Returns the total amount of the specified asset owed to the Hub by the specified spoke.
/// @param assetId The identifier of the asset.
/// @param spoke The address of the Spoke.
/// @return The total amount of the asset owed.
function getSpokeTotalOwed(uint256 assetId, address spoke) external view returns (uint256);
/// @notice Returns the amount of owed premium with full precision for specified asset and spoke.
/// @param assetId The identifier of the asset.
/// @param spoke The address of the Spoke.
/// @return The amount of owed premium assets, expressed in asset units and scaled by RAY.
function getSpokePremiumRay(uint256 assetId, address spoke) external view returns (uint256);
/// @notice Returns the amount of drawn shares of the specified asset by the specified spoke.
/// @param assetId The identifier of the asset.
/// @param spoke The address of the Spoke.
/// @return The amount of drawn shares.
function getSpokeDrawnShares(uint256 assetId, address spoke) external view returns (uint256);
/// @notice Returns the information regarding premium shares of the specified asset for the specified spoke.
/// @param assetId The identifier of the asset.
/// @param spoke The address of the Spoke.
/// @return The amount of premium shares.
/// @return The premium offset, expressed in asset units and scaled by RAY.
function getSpokePremiumData(
uint256 assetId,
address spoke
) external view returns (uint256, int256);
/// @notice Returns the amount of a given spoke's deficit with full precision for the specified asset.
/// @param assetId The identifier of the asset.
/// @param spoke The address of the Spoke.
/// @return The amount of deficit, expressed in asset units and scaled by RAY.
function getSpokeDeficitRay(uint256 assetId, address spoke) external view returns (uint256);
}// SPDX-License-Identifier: LicenseRef-BUSL
pragma solidity ^0.8.0;
/// @title IExtSload
/// @author Aave Labs
/// @notice Minimal interface to easily access storage of source contract externally. See https://eips.ethereum.org/EIPS/eip-2330#rationale.
interface IExtSload {
/// @notice Returns the storage `value` of this contract at a given `slot`.
/// @param slot Slot to SLOAD from.
function extSload(bytes32 slot) external view returns (bytes32 value);
/// @notice Returns the storage `values` of this contract at the given `slots`.
/// @param slots Array of slots to SLOAD from.
function extSloads(bytes32[] calldata slots) external view returns (bytes32[] memory values);
}// SPDX-License-Identifier: LicenseRef-BUSL
pragma solidity ^0.8.0;
import {IMulticall} from 'src/interfaces/IMulticall.sol';
import {IRescuable} from 'src/interfaces/IRescuable.sol';
/// @title IPositionManagerBase
/// @author Aave Labs
/// @notice Base interface for position managers.
/// @dev This base interface is not mandatory for position managers, it only provides optional convenience methods.
interface IPositionManagerBase is IRescuable, IMulticall {
/// @notice Emitted when the Spoke's registration status is updated.
event RegisterSpoke(address indexed spoke, bool registered);
/// @notice Thrown when the specified address is invalid.
error InvalidAddress();
/// @notice Thrown when the specified amount is invalid.
error InvalidAmount();
/// @notice Thrown when trying to call an unsupported action on this position manager.
error UnsupportedAction();
/// @notice Thrown when the specified Spoke is not registered.
error SpokeNotRegistered();
/// @notice Facilitates setting this position manager as user position manager on the specified registered Spoke
/// with a typed signature from `onBehalfOf`.
/// @dev The signature is consumed on the specified registered Spoke.
/// @dev The given data is passed to the Spoke for the signature to be verified.
/// @dev Uses keyed-nonces where for each key's namespace nonce is consumed sequentially.
/// @param spoke The address of the registered spoke.
/// @param onBehalfOf The address of the user on whose behalf this position manager can act.
/// @param approve True to approve the position manager, false to revoke approval.
/// @param nonce The key-prefixed nonce for the signature.
/// @param deadline The deadline for the intent.
/// @param signature The EIP712-typed signed bytes for the intent.
function setSelfAsUserPositionManagerWithSig(
address spoke,
address onBehalfOf,
bool approve,
uint256 nonce,
uint256 deadline,
bytes calldata signature
) external;
/// @notice Facilitates consuming a permit for the given reserve's underlying asset on the specified registered Spoke.
/// @dev The given data is passed to the underlying asset for the signature to be verified.
/// @dev Uses keyed-nonces where for each key's namespace nonce is consumed sequentially.
/// @dev Spender is this position manager contract.
/// @param spoke The address of the Spoke.
/// @param reserveId The identifier of the reserve.
/// @param onBehalfOf The address of the user on whose behalf the permit is being used.
/// @param value The amount of the underlying asset to permit.
/// @param deadline The deadline for the permit.
function permitReserveUnderlying(
address spoke,
uint256 reserveId,
address onBehalfOf,
uint256 value,
uint256 deadline,
uint8 permitV,
bytes32 permitR,
bytes32 permitS
) external;
/// @notice Allows contract to renounce its position manager role for the specified user.
/// @param spoke The address of the registered Spoke.
/// @param user The address of the user to renounce the position manager role for.
function renouncePositionManagerRole(address spoke, address user) external;
/// @notice Registers or deregisters the Spoke.
/// @param spoke The address of the Spoke.
/// @param registered `true` to register, `false` to deregister.
function registerSpoke(address spoke, bool registered) external;
/// @notice Returns whether the specified Spoke is registered.
/// @param spoke The address of the Spoke.
/// @return `true` if the Spoke is registered, `false` otherwise.
function isSpokeRegistered(address spoke) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[ERC-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC-20 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.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
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].
*
* CAUTION: See Security Considerations above.
*/
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);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (access/Ownable2Step.sol)
pragma solidity ^0.8.20;
import {Ownable} from './Ownable.sol';
/**
* @dev Contract module which provides access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* This extension of the {Ownable} contract includes a two-step mechanism to transfer
* ownership, where the new owner must call {acceptOwnership} in order to replace the
* old one. This can help prevent common mistakes, such as transfers of ownership to
* incorrect accounts, or to contracts that are unable to interact with the
* permission system.
*
* The initial owner is specified at deployment time in the constructor for `Ownable`. This
* can later be changed with {transferOwnership} and {acceptOwnership}.
*
* This module is used through inheritance. It will make available all functions
* from parent (Ownable).
*/
abstract contract Ownable2Step is Ownable {
address private _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
/**
* @dev Returns the address of the pending owner.
*/
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
/**
* @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
* Can only be called by the current owner.
*
* Setting `newOwner` to the zero address is allowed; this can be used to cancel an initiated ownership transfer.
*/
function transferOwnership(address newOwner) public virtual override onlyOwner {
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
/**
* @dev The new owner accepts the ownership transfer.
*/
function acceptOwnership() public virtual {
address sender = _msgSender();
if (pendingOwner() != sender) {
revert OwnableUnauthorizedAccount(sender);
}
_transferOwnership(sender);
}
}// SPDX-License-Identifier: LicenseRef-BUSL
pragma solidity ^0.8.20;
import {IMulticall} from 'src/interfaces/IMulticall.sol';
/// @title Multicall
/// @author Aave Labs
/// @notice This contract allows for batching multiple calls into a single call.
/// @dev Inspired by the OpenZeppelin Multicall contract.
abstract contract Multicall is IMulticall {
/// @inheritdoc IMulticall
function multicall(bytes[] calldata data) public virtual returns (bytes[] memory) {
bytes[] memory results = new bytes[](data.length);
for (uint256 i; i < data.length; ++i) {
(bool ok, bytes memory res) = address(this).delegatecall(data[i]);
assembly ('memory-safe') {
if iszero(ok) {
revert(add(res, 32), mload(res)) // bubble up first revert
}
}
results[i] = res;
}
return results;
}
}// SPDX-License-Identifier: LicenseRef-BUSL
pragma solidity ^0.8.20;
import {SafeERC20, IERC20} from 'src/dependencies/openzeppelin/SafeERC20.sol';
import {Address} from 'src/dependencies/openzeppelin/Address.sol';
import {IRescuable} from 'src/interfaces/IRescuable.sol';
/// @title Rescuable
/// @author Aave Labs
/// @notice Contract that allows for the rescue of tokens and native assets.
abstract contract Rescuable is IRescuable {
using SafeERC20 for IERC20;
modifier onlyRescueGuardian() {
_checkRescueGuardian();
_;
}
/// @inheritdoc IRescuable
function rescueToken(address token, address to, uint256 amount) external onlyRescueGuardian {
IERC20(token).safeTransfer(to, amount);
}
/// @inheritdoc IRescuable
function rescueNative(address to, uint256 amount) external onlyRescueGuardian {
Address.sendValue(payable(to), amount);
}
/// @inheritdoc IRescuable
function rescueGuardian() external view returns (address) {
return _rescueGuardian();
}
function _rescueGuardian() internal view virtual returns (address);
function _checkRescueGuardian() internal view virtual {
require(_rescueGuardian() == msg.sender, OnlyRescueGuardian());
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: LicenseRef-BUSL
pragma solidity ^0.8.0;
interface INoncesKeyed {
/// @notice Thrown when nonce being consumed does not match `currentNonce` for `account`.
error InvalidAccountNonce(address account, uint256 currentNonce);
/// @notice Allows caller to revoke their next sequential nonce at specified `key`.
/// @dev This does not invalidate nonce at other `key`s namespace.
/// @param key The key which specifies namespace of the nonce.
/// @return keyNonce The revoked key-prefixed nonce.
function useNonce(uint192 key) external returns (uint256 keyNonce);
/// @notice Returns the next unused nonce for an address and key. Result contains the key prefix.
/// @param owner The address of the nonce owner.
/// @param key The key which specifies namespace of the nonce.
/// @return keyNonce The first 24 bytes are for the key, & the last 8 bytes for the nonce.
function nonces(address owner, uint192 key) external view returns (uint256 keyNonce);
}// SPDX-License-Identifier: LicenseRef-BUSL
pragma solidity ^0.8.0;
/// @title IRescuable
/// @author Aave Labs
/// @notice Interface for Rescuable.
interface IRescuable {
/// @notice Thrown when caller is not the rescue guardian.
error OnlyRescueGuardian();
/// @notice Recovers ERC20 tokens sent to this contract.
/// @param token The address of the ERC20 token to rescue.
/// @param to The address to send the rescued tokens to.
/// @param amount Amount of tokens to rescue.
function rescueToken(address token, address to, uint256 amount) external;
/// @notice Recovers native assets remaining in this contract.
/// @param to The address to send rescued native assets to.
/// @param amount Amount of native assets to rescue.
function rescueNative(address to, uint256 amount) external;
/// @notice Returns the rescue guardian address.
/// @return The address allowed to rescue funds.
function rescueGuardian() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from './Context.sol';
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @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;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}{
"remappings": [
"erc4626-tests/=lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/"
],
"optimizer": {
"enabled": true,
"runs": 44444444
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "none",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"nativeTokenWrapper_","type":"address"},{"internalType":"address","name":"initialOwner_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"FailedCall","type":"error"},{"inputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InvalidAddress","type":"error"},{"inputs":[],"name":"InvalidAmount","type":"error"},{"inputs":[],"name":"NativeAmountMismatch","type":"error"},{"inputs":[],"name":"NotNativeWrappedAsset","type":"error"},{"inputs":[],"name":"OnlyRescueGuardian","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SpokeNotRegistered","type":"error"},{"inputs":[],"name":"UnsupportedAction","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"spoke","type":"address"},{"indexed":false,"internalType":"bool","name":"registered","type":"bool"}],"name":"RegisterSpoke","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"NATIVE_TOKEN_WRAPPER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spoke","type":"address"},{"internalType":"uint256","name":"reserveId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"borrowNative","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spoke","type":"address"}],"name":"isSpokeRegistered","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spoke","type":"address"},{"internalType":"uint256","name":"reserveId","type":"uint256"},{"internalType":"address","name":"onBehalfOf","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"permitV","type":"uint8"},{"internalType":"bytes32","name":"permitR","type":"bytes32"},{"internalType":"bytes32","name":"permitS","type":"bytes32"}],"name":"permitReserveUnderlying","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spoke","type":"address"},{"internalType":"bool","name":"registered","type":"bool"}],"name":"registerSpoke","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spoke","type":"address"},{"internalType":"address","name":"user","type":"address"}],"name":"renouncePositionManagerRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spoke","type":"address"},{"internalType":"uint256","name":"reserveId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"repayNative","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"rescueGuardian","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"rescueNative","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"rescueToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spoke","type":"address"},{"internalType":"address","name":"onBehalfOf","type":"address"},{"internalType":"bool","name":"approve","type":"bool"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"setSelfAsUserPositionManagerWithSig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spoke","type":"address"},{"internalType":"uint256","name":"reserveId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"supplyAsCollateralNative","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"spoke","type":"address"},{"internalType":"uint256","name":"reserveId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"supplyNative","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spoke","type":"address"},{"internalType":"uint256","name":"reserveId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawNative","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60a060405234801561000f575f5ffd5b506040516123f43803806123f483398101604081905261002e91610127565b80806001600160a01b03811661005d57604051631e4fbdf760e01b81525f600482015260240160405180910390fd5b610066816100a1565b50506001600160a01b03821661008f5760405163e6c4247b60e01b815260040160405180910390fd5b506001600160a01b0316608052610158565b600180546001600160a01b03191690556100ba816100bd565b50565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b0381168114610122575f5ffd5b919050565b5f5f60408385031215610138575f5ffd5b6101418361010c565b915061014f6020840161010c565b90509250929050565b6080516122536101a15f395f818161017f0152818161021b01528181610735015281816110b401528181611148015281816114dd015281816115c7015261165b01526122535ff3fe608060405260043610610162575f3560e01c80638da5cb5b116100bf578063c504d66411610073578063e5711e8b11610058578063e5711e8b14610451578063f2f61d9414610470578063f2fde38b14610483576101d8565b8063c504d66414610414578063e30c397814610427576101d8565b8063a994a998116100a4578063a994a998146103aa578063ac9650d8146103c9578063c084998a146103f5576101d8565b80638da5cb5b1461038157806399aa728414610381576101d8565b80636d4f56c0116101165780637831a106116100fb5780637831a1061461032f578063792151ff1461034e57806379ba50971461036d576101d8565b80636d4f56c0146102ec578063715018a61461031b576101d8565b80633f345823116101475780633f345823146102865780634a32eaaf146102a5578063614b3341146102d9576101d8565b80630b1b9ebf1461020a5780631291f79d14610267576101d8565b366101d8573373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146101d6576040517f25e9714f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b005b6040517f25e9714f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b348015610215575f5ffd5b5061023d7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b348015610272575f5ffd5b506101d6610281366004611b68565b6104a2565b348015610291575f5ffd5b506101d66102a0366004611ba0565b6104b8565b3480156102b0575f5ffd5b506102c46102bf366004611c15565b6105dc565b6040805192835260208301919091520161025e565b6102c46102e7366004611c15565b6107c2565b3480156102f7575f5ffd5b5061030b610306366004611c47565b610914565b604051901515815260200161025e565b348015610326575f5ffd5b506101d6610943565b34801561033a575f5ffd5b506101d6610349366004611c62565b610956565b348015610359575f5ffd5b506101d6610368366004611cad565b610a44565b348015610378575f5ffd5b506101d6610bd4565b34801561038c575f5ffd5b505f5473ffffffffffffffffffffffffffffffffffffffff1661023d565b3480156103b5575f5ffd5b506102c46103c4366004611c15565b610c50565b3480156103d4575f5ffd5b506103e86103e3366004611d63565b610d3a565b60405161025e9190611dd4565b348015610400575f5ffd5b506101d661040f366004611e94565b610d75565b6102c4610422366004611c15565b610e53565b348015610432575f5ffd5b5060015473ffffffffffffffffffffffffffffffffffffffff1661023d565b34801561045c575f5ffd5b506101d661046b366004611ec7565b610f14565b6102c461047e366004611c15565b610f42565b34801561048e575f5ffd5b506101d661049d366004611c47565b611238565b6104aa6112e7565b6104b48282611353565b5050565b876104e78173ffffffffffffffffffffffffffffffffffffffff165f9081526002602052604090205460ff1690565b61051d576040517f9491872400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6105288a8a6113f8565b6040517fd505accf00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a81166004830152306024830152604482018a90526064820189905260ff8816608483015260a4820187905260c482018690529192509082169063d505accf9060e4015f604051808303815f87803b1580156105bd575f5ffd5b505af19250505080156105ce575060015b505b50505050505050505050565b5f5f6105e661148f565b846106158173ffffffffffffffffffffffffffffffffffffffff165f9081526002602052604090205460ff1690565b61064b576040517f9491872400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61065687876113f8565b905061066281866114c4565b6040517fd6bda0c000000000000000000000000000000000000000000000000000000000815260048101879052602481018690523360448201525f90819073ffffffffffffffffffffffffffffffffffffffff8a169063d6bda0c0906064015b60408051808303815f875af11580156106dd573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107019190611f05565b6040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081526004810182905291935091507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d906024015f604051808303815f87803b15801561078b575f5ffd5b505af115801561079d573d5f5f3e3d5ffd5b505050506107ab3382611353565b909450925050506107ba611582565b935093915050565b5f5f6107cc61148f565b846107fb8173ffffffffffffffffffffffffffffffffffffffff165f9081526002602052604090205460ff1690565b610831576040517f9491872400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83341461086a576040517f677606af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5f610878888833896115ac565b6040517f9e35c533000000000000000000000000000000000000000000000000000000008152600481018a905260016024820152336044820152919350915073ffffffffffffffffffffffffffffffffffffffff891690639e35c533906064015f604051808303815f87803b1580156108ef575f5ffd5b505af1158015610901573d5f5f3e3d5ffd5b50939650919450505050506107ba611582565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526002602052604081205460ff165b92915050565b61094b611730565b6109545f611782565b565b61095e611730565b8161098d8173ffffffffffffffffffffffffffffffffffffffff165f9081526002602052604090205460ff1690565b6109c3576040517f9491872400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517ffea149a600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff838116600483015284169063fea149a6906024015f604051808303815f87803b158015610a29575f5ffd5b505af1158015610a3b573d5f5f3e3d5ffd5b50505050505050565b86610a738173ffffffffffffffffffffffffffffffffffffffff165f9081526002602052604090205460ff1690565b610aa9576040517f9491872400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160018082528183019092525f91816020015b604080518082019091525f8082526020820152815260200190600190039081610abf57905050905060405180604001604052803073ffffffffffffffffffffffffffffffffffffffff168152602001881515815250815f81518110610b2657610b26611f27565b60200260200101819052508873ffffffffffffffffffffffffffffffffffffffff166303ed05c160405180608001604052808b73ffffffffffffffffffffffffffffffffffffffff1681526020018481526020018981526020018881525086866040518463ffffffff1660e01b8152600401610ba493929190611f9b565b5f604051808303815f87803b158015610bbb575f5ffd5b505af19250505080156105d05750505050505050505050565b600154339073ffffffffffffffffffffffffffffffffffffffff168114610c44576040517f118cdaa700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024015b60405180910390fd5b610c4d81611782565b50565b5f5f610c5a61148f565b84610c898173ffffffffffffffffffffffffffffffffffffffff165f9081526002602052604090205460ff1690565b610cbf576040517f9491872400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f610cca87876113f8565b9050610cd681866114c4565b6040517f0ad58d2f00000000000000000000000000000000000000000000000000000000815260048101879052602481018690523360448201525f90819073ffffffffffffffffffffffffffffffffffffffff8a1690630ad58d2f906064016106c2565b60606040517f25e9714f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b9392505050565b610d7d611730565b73ffffffffffffffffffffffffffffffffffffffff8216610dca576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82165f8181526002602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182527f9b8897e66a7714715dca5bcb7859e2c0bd6ec9348070d948c5b12222e71ad9ec910160405180910390a25050565b5f5f610e5d61148f565b84610e8c8173ffffffffffffffffffffffffffffffffffffffff165f9081526002602052604090205460ff1690565b610ec2576040517f9491872400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b833414610efb576040517f677606af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f07868633876115ac565b92509250506107ba611582565b610f1c6112e7565b610f3d73ffffffffffffffffffffffffffffffffffffffff84168383611888565b505050565b5f5f610f4c61148f565b84610f7b8173ffffffffffffffffffffffffffffffffffffffff165f9081526002602052604090205460ff1690565b610fb1576040517f9491872400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b833414610fea576040517f677606af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f610ff587876113f8565b905061100181866114c4565b6040517f9b7172a6000000000000000000000000000000000000000000000000000000008152600481018790523360248201525f9073ffffffffffffffffffffffffffffffffffffffff891690639b7172a690604401602060405180830381865afa158015611072573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611096919061205f565b9050855f828211156110b2576110ac8389612076565b90508291505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0836040518263ffffffff1660e01b81526004015f604051808303818588803b158015611118575f5ffd5b505af115801561112a573d5f5f3e3d5ffd5b5061117393505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001691508c9050846118e3565b6040517fb1e8f8ef000000000000000000000000000000000000000000000000000000008152600481018a9052602481018390523360448201525f90819073ffffffffffffffffffffffffffffffffffffffff8d169063b1e8f8ef9060640160408051808303815f875af11580156111ed573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112119190611f05565b90925090508215611226576112263384611353565b909750955050505050506107ba611582565b611240611730565b6001805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff000000000000000000000000000000000000000090911681179091556112a25f5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b336113065f5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614610954576040517f3a02626900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80471015611396576040517fcf47918100000000000000000000000000000000000000000000000000000000815247600482015260248101829052604401610c3b565b6113af828260405180602001604052805f81525061195b565b156113b8575050565b3d156113c6576104b4611970565b6040517fd6bda27500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f77778db3000000000000000000000000000000000000000000000000000000008152600481018290525f9073ffffffffffffffffffffffffffffffffffffffff8416906377778db39060240160e060405180830381865afa158015611463573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061148791906120fa565b519392505050565b61149761197b565b61095460017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005b906119d4565b8173ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1614611549576040517f7599646300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f81116104b4576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109545f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f006114be565b5f5f5f6115b987876113f8565b90506115c581856114c4565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0856040518263ffffffff1660e01b81526004015f604051808303818588803b15801561162b575f5ffd5b505af115801561163d573d5f5f3e3d5ffd5b5061168693505073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169150899050866118e3565b6040517f852a56a5000000000000000000000000000000000000000000000000000000008152600481018790526024810185905273ffffffffffffffffffffffffffffffffffffffff868116604483015288169063852a56a59060640160408051808303815f875af11580156116fe573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117229190611f05565b925092505094509492505050565b5f5473ffffffffffffffffffffffffffffffffffffffff163314610954576040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152602401610c3b565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055610c4d816119db565b60608152602001906001900390816117b35790505090505f5b83811015611880575f80308787858181106117e9576117e9611f27565b90506020028101906117fb91906121cf565b604051611809929190612237565b5f60405180830381855af49150503d805f8114611841576040519150601f19603f3d011682016040523d82523d5f602084013e611846565b606091505b50915091508161185857805160208201fd5b8084848151811061186b5761186b611f27565b602090810291909101015250506001016117cc565b509392505050565b6118958383836001611a4f565b610f3d576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610c3b565b6118ef8383835f611ad7565b610f3d5761190083835f6001611ad7565b61194e576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610c3b565b6118958383836001611ad7565b5f5f5f83516020850186885af1949350505050565b6040513d5f823e3d81fd5b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005c15610954576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80825d5050565b5f805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6040517fa9059cbb000000000000000000000000000000000000000000000000000000005f81815273ffffffffffffffffffffffffffffffffffffffff8616600452602485905291602083604481808b5af1925060015f51148316611acb578383151615611abf573d5f823e3d81fd5b5f873b113d1516831692505b60405250949350505050565b6040517f095ea7b3000000000000000000000000000000000000000000000000000000005f81815273ffffffffffffffffffffffffffffffffffffffff8616600452602485905291602083604481808b5af1925060015f51148316611acb578383151615611abf573d5f823e3d81fd5b73ffffffffffffffffffffffffffffffffffffffff81168114610c4d575f5ffd5b5f5f60408385031215611b79575f5ffd5b8235611b8481611b47565b946020939093013593505050565b60ff81168114610c4d575f5ffd5b5f5f5f5f5f5f5f5f610100898b031215611bb8575f5ffd5b8835611bc381611b47565b9750602089013596506040890135611bda81611b47565b9550606089013594506080890135935060a0890135611bf881611b92565b979a969950949793969295929450505060c08201359160e0013590565b5f5f5f60608486031215611c27575f5ffd5b8335611c3281611b47565b95602085013595506040909401359392505050565b5f60208284031215611c57575f5ffd5b8135610d6e81611b47565b5f5f60408385031215611c73575f5ffd5b8235611c7e81611b47565b91506020830135611c8e81611b47565b809150509250929050565b80358015158114611ca8575f5ffd5b919050565b5f5f5f5f5f5f5f60c0888a031215611cc3575f5ffd5b8735611cce81611b47565b96506020880135611cde81611b47565b9550611cec60408901611c99565b9450606088013593506080880135925060a088013567ffffffffffffffff811115611d15575f5ffd5b8801601f81018a13611d25575f5ffd5b803567ffffffffffffffff811115611d3b575f5ffd5b8a6020828401011115611d4c575f5ffd5b602082019350809250505092959891949750929550565b5f5f60208385031215611d74575f5ffd5b823567ffffffffffffffff811115611d8a575f5ffd5b8301601f81018513611d9a575f5ffd5b803567ffffffffffffffff811115611db0575f5ffd5b8560208260051b8401011115611dc4575f5ffd5b6020919091019590945092505050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b82811015611e88577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0878603018452815180518087528060208301602089015e5f6020828901015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011688010196505050602082019150602084019350600181019050611dfa565b50929695505050505050565b5f5f60408385031215611ea5575f5ffd5b8235611eb081611b47565b9150611ebe60208401611c99565b90509250929050565b5f5f5f60608486031215611ed9575f5ffd5b8335611ee481611b47565b92506020840135611ef481611b47565b929592945050506040919091013590565b5f5f60408385031215611f16575f5ffd5b505080516020909101519092909150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b604081525f60c0820173ffffffffffffffffffffffffffffffffffffffff865116604084015260208601516080606085015281815180845260e0860191506020830193505f92505b8083101561202b57835173ffffffffffffffffffffffffffffffffffffffff815116835260208101511515602084015250604082019150602084019350600183019250611fe3565b5060408801516080860152606088015160a08601528481036020860152612053818789611f54565b98975050505050505050565b5f6020828403121561206f575f5ffd5b5051919050565b8181038181111561093d577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8051611ca881611b47565b805161ffff81168114611ca8575f5ffd5b8051611ca881611b92565b805162ffffff81168114611ca8575f5ffd5b805163ffffffff81168114611ca8575f5ffd5b5f60e082840312801561210b575f5ffd5b5060405160e0810167ffffffffffffffff81118282101715612154577f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604052612160836120ae565b815261216e602084016120ae565b602082015261217f604084016120b9565b6040820152612190606084016120ca565b60608201526121a1608084016120d5565b60808201526121b260a084016120ca565b60a08201526121c360c084016120e7565b60c08201529392505050565b5f5f83357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612202575f5ffd5b83018035915067ffffffffffffffff82111561221c575f5ffd5b602001915036819003821315612230575f5ffd5b9250929050565b818382375f910190815291905056fea164736f6c634300081c000a000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000b00a89e5c8756ba8629846eef8a4a9c71ad1930a
Deployed Bytecode
0x608060405260043610610162575f3560e01c80638da5cb5b116100bf578063c504d66411610073578063e5711e8b11610058578063e5711e8b14610451578063f2f61d9414610470578063f2fde38b14610483576101d8565b8063c504d66414610414578063e30c397814610427576101d8565b8063a994a998116100a4578063a994a998146103aa578063ac9650d8146103c9578063c084998a146103f5576101d8565b80638da5cb5b1461038157806399aa728414610381576101d8565b80636d4f56c0116101165780637831a106116100fb5780637831a1061461032f578063792151ff1461034e57806379ba50971461036d576101d8565b80636d4f56c0146102ec578063715018a61461031b576101d8565b80633f345823116101475780633f345823146102865780634a32eaaf146102a5578063614b3341146102d9576101d8565b80630b1b9ebf1461020a5780631291f79d14610267576101d8565b366101d8573373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216146101d6576040517f25e9714f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b005b6040517f25e9714f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b348015610215575f5ffd5b5061023d7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b348015610272575f5ffd5b506101d6610281366004611b68565b6104a2565b348015610291575f5ffd5b506101d66102a0366004611ba0565b6104b8565b3480156102b0575f5ffd5b506102c46102bf366004611c15565b6105dc565b6040805192835260208301919091520161025e565b6102c46102e7366004611c15565b6107c2565b3480156102f7575f5ffd5b5061030b610306366004611c47565b610914565b604051901515815260200161025e565b348015610326575f5ffd5b506101d6610943565b34801561033a575f5ffd5b506101d6610349366004611c62565b610956565b348015610359575f5ffd5b506101d6610368366004611cad565b610a44565b348015610378575f5ffd5b506101d6610bd4565b34801561038c575f5ffd5b505f5473ffffffffffffffffffffffffffffffffffffffff1661023d565b3480156103b5575f5ffd5b506102c46103c4366004611c15565b610c50565b3480156103d4575f5ffd5b506103e86103e3366004611d63565b610d3a565b60405161025e9190611dd4565b348015610400575f5ffd5b506101d661040f366004611e94565b610d75565b6102c4610422366004611c15565b610e53565b348015610432575f5ffd5b5060015473ffffffffffffffffffffffffffffffffffffffff1661023d565b34801561045c575f5ffd5b506101d661046b366004611ec7565b610f14565b6102c461047e366004611c15565b610f42565b34801561048e575f5ffd5b506101d661049d366004611c47565b611238565b6104aa6112e7565b6104b48282611353565b5050565b876104e78173ffffffffffffffffffffffffffffffffffffffff165f9081526002602052604090205460ff1690565b61051d576040517f9491872400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6105288a8a6113f8565b6040517fd505accf00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a81166004830152306024830152604482018a90526064820189905260ff8816608483015260a4820187905260c482018690529192509082169063d505accf9060e4015f604051808303815f87803b1580156105bd575f5ffd5b505af19250505080156105ce575060015b505b50505050505050505050565b5f5f6105e661148f565b846106158173ffffffffffffffffffffffffffffffffffffffff165f9081526002602052604090205460ff1690565b61064b576040517f9491872400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61065687876113f8565b905061066281866114c4565b6040517fd6bda0c000000000000000000000000000000000000000000000000000000000815260048101879052602481018690523360448201525f90819073ffffffffffffffffffffffffffffffffffffffff8a169063d6bda0c0906064015b60408051808303815f875af11580156106dd573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107019190611f05565b6040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081526004810182905291935091507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d906024015f604051808303815f87803b15801561078b575f5ffd5b505af115801561079d573d5f5f3e3d5ffd5b505050506107ab3382611353565b909450925050506107ba611582565b935093915050565b5f5f6107cc61148f565b846107fb8173ffffffffffffffffffffffffffffffffffffffff165f9081526002602052604090205460ff1690565b610831576040517f9491872400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83341461086a576040517f677606af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5f610878888833896115ac565b6040517f9e35c533000000000000000000000000000000000000000000000000000000008152600481018a905260016024820152336044820152919350915073ffffffffffffffffffffffffffffffffffffffff891690639e35c533906064015f604051808303815f87803b1580156108ef575f5ffd5b505af1158015610901573d5f5f3e3d5ffd5b50939650919450505050506107ba611582565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526002602052604081205460ff165b92915050565b61094b611730565b6109545f611782565b565b61095e611730565b8161098d8173ffffffffffffffffffffffffffffffffffffffff165f9081526002602052604090205460ff1690565b6109c3576040517f9491872400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517ffea149a600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff838116600483015284169063fea149a6906024015f604051808303815f87803b158015610a29575f5ffd5b505af1158015610a3b573d5f5f3e3d5ffd5b50505050505050565b86610a738173ffffffffffffffffffffffffffffffffffffffff165f9081526002602052604090205460ff1690565b610aa9576040517f9491872400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160018082528183019092525f91816020015b604080518082019091525f8082526020820152815260200190600190039081610abf57905050905060405180604001604052803073ffffffffffffffffffffffffffffffffffffffff168152602001881515815250815f81518110610b2657610b26611f27565b60200260200101819052508873ffffffffffffffffffffffffffffffffffffffff166303ed05c160405180608001604052808b73ffffffffffffffffffffffffffffffffffffffff1681526020018481526020018981526020018881525086866040518463ffffffff1660e01b8152600401610ba493929190611f9b565b5f604051808303815f87803b158015610bbb575f5ffd5b505af19250505080156105d05750505050505050505050565b600154339073ffffffffffffffffffffffffffffffffffffffff168114610c44576040517f118cdaa700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024015b60405180910390fd5b610c4d81611782565b50565b5f5f610c5a61148f565b84610c898173ffffffffffffffffffffffffffffffffffffffff165f9081526002602052604090205460ff1690565b610cbf576040517f9491872400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f610cca87876113f8565b9050610cd681866114c4565b6040517f0ad58d2f00000000000000000000000000000000000000000000000000000000815260048101879052602481018690523360448201525f90819073ffffffffffffffffffffffffffffffffffffffff8a1690630ad58d2f906064016106c2565b60606040517f25e9714f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b9392505050565b610d7d611730565b73ffffffffffffffffffffffffffffffffffffffff8216610dca576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82165f8181526002602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182527f9b8897e66a7714715dca5bcb7859e2c0bd6ec9348070d948c5b12222e71ad9ec910160405180910390a25050565b5f5f610e5d61148f565b84610e8c8173ffffffffffffffffffffffffffffffffffffffff165f9081526002602052604090205460ff1690565b610ec2576040517f9491872400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b833414610efb576040517f677606af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f07868633876115ac565b92509250506107ba611582565b610f1c6112e7565b610f3d73ffffffffffffffffffffffffffffffffffffffff84168383611888565b505050565b5f5f610f4c61148f565b84610f7b8173ffffffffffffffffffffffffffffffffffffffff165f9081526002602052604090205460ff1690565b610fb1576040517f9491872400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b833414610fea576040517f677606af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f610ff587876113f8565b905061100181866114c4565b6040517f9b7172a6000000000000000000000000000000000000000000000000000000008152600481018790523360248201525f9073ffffffffffffffffffffffffffffffffffffffff891690639b7172a690604401602060405180830381865afa158015611072573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611096919061205f565b9050855f828211156110b2576110ac8389612076565b90508291505b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1663d0e30db0836040518263ffffffff1660e01b81526004015f604051808303818588803b158015611118575f5ffd5b505af115801561112a573d5f5f3e3d5ffd5b5061117393505073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21691508c9050846118e3565b6040517fb1e8f8ef000000000000000000000000000000000000000000000000000000008152600481018a9052602481018390523360448201525f90819073ffffffffffffffffffffffffffffffffffffffff8d169063b1e8f8ef9060640160408051808303815f875af11580156111ed573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112119190611f05565b90925090508215611226576112263384611353565b909750955050505050506107ba611582565b611240611730565b6001805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff000000000000000000000000000000000000000090911681179091556112a25f5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b336113065f5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614610954576040517f3a02626900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80471015611396576040517fcf47918100000000000000000000000000000000000000000000000000000000815247600482015260248101829052604401610c3b565b6113af828260405180602001604052805f81525061195b565b156113b8575050565b3d156113c6576104b4611970565b6040517fd6bda27500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f77778db3000000000000000000000000000000000000000000000000000000008152600481018290525f9073ffffffffffffffffffffffffffffffffffffffff8416906377778db39060240160e060405180830381865afa158015611463573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061148791906120fa565b519392505050565b61149761197b565b61095460017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005b906119d4565b8173ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1614611549576040517f7599646300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f81116104b4576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109545f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f006114be565b5f5f5f6115b987876113f8565b90506115c581856114c4565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1663d0e30db0856040518263ffffffff1660e01b81526004015f604051808303818588803b15801561162b575f5ffd5b505af115801561163d573d5f5f3e3d5ffd5b5061168693505073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2169150899050866118e3565b6040517f852a56a5000000000000000000000000000000000000000000000000000000008152600481018790526024810185905273ffffffffffffffffffffffffffffffffffffffff868116604483015288169063852a56a59060640160408051808303815f875af11580156116fe573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117229190611f05565b925092505094509492505050565b5f5473ffffffffffffffffffffffffffffffffffffffff163314610954576040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152602401610c3b565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055610c4d816119db565b60608152602001906001900390816117b35790505090505f5b83811015611880575f80308787858181106117e9576117e9611f27565b90506020028101906117fb91906121cf565b604051611809929190612237565b5f60405180830381855af49150503d805f8114611841576040519150601f19603f3d011682016040523d82523d5f602084013e611846565b606091505b50915091508161185857805160208201fd5b8084848151811061186b5761186b611f27565b602090810291909101015250506001016117cc565b509392505050565b6118958383836001611a4f565b610f3d576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610c3b565b6118ef8383835f611ad7565b610f3d5761190083835f6001611ad7565b61194e576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610c3b565b6118958383836001611ad7565b5f5f5f83516020850186885af1949350505050565b6040513d5f823e3d81fd5b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005c15610954576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80825d5050565b5f805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6040517fa9059cbb000000000000000000000000000000000000000000000000000000005f81815273ffffffffffffffffffffffffffffffffffffffff8616600452602485905291602083604481808b5af1925060015f51148316611acb578383151615611abf573d5f823e3d81fd5b5f873b113d1516831692505b60405250949350505050565b6040517f095ea7b3000000000000000000000000000000000000000000000000000000005f81815273ffffffffffffffffffffffffffffffffffffffff8616600452602485905291602083604481808b5af1925060015f51148316611acb578383151615611abf573d5f823e3d81fd5b73ffffffffffffffffffffffffffffffffffffffff81168114610c4d575f5ffd5b5f5f60408385031215611b79575f5ffd5b8235611b8481611b47565b946020939093013593505050565b60ff81168114610c4d575f5ffd5b5f5f5f5f5f5f5f5f610100898b031215611bb8575f5ffd5b8835611bc381611b47565b9750602089013596506040890135611bda81611b47565b9550606089013594506080890135935060a0890135611bf881611b92565b979a969950949793969295929450505060c08201359160e0013590565b5f5f5f60608486031215611c27575f5ffd5b8335611c3281611b47565b95602085013595506040909401359392505050565b5f60208284031215611c57575f5ffd5b8135610d6e81611b47565b5f5f60408385031215611c73575f5ffd5b8235611c7e81611b47565b91506020830135611c8e81611b47565b809150509250929050565b80358015158114611ca8575f5ffd5b919050565b5f5f5f5f5f5f5f60c0888a031215611cc3575f5ffd5b8735611cce81611b47565b96506020880135611cde81611b47565b9550611cec60408901611c99565b9450606088013593506080880135925060a088013567ffffffffffffffff811115611d15575f5ffd5b8801601f81018a13611d25575f5ffd5b803567ffffffffffffffff811115611d3b575f5ffd5b8a6020828401011115611d4c575f5ffd5b602082019350809250505092959891949750929550565b5f5f60208385031215611d74575f5ffd5b823567ffffffffffffffff811115611d8a575f5ffd5b8301601f81018513611d9a575f5ffd5b803567ffffffffffffffff811115611db0575f5ffd5b8560208260051b8401011115611dc4575f5ffd5b6020919091019590945092505050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b82811015611e88577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0878603018452815180518087528060208301602089015e5f6020828901015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011688010196505050602082019150602084019350600181019050611dfa565b50929695505050505050565b5f5f60408385031215611ea5575f5ffd5b8235611eb081611b47565b9150611ebe60208401611c99565b90509250929050565b5f5f5f60608486031215611ed9575f5ffd5b8335611ee481611b47565b92506020840135611ef481611b47565b929592945050506040919091013590565b5f5f60408385031215611f16575f5ffd5b505080516020909101519092909150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b604081525f60c0820173ffffffffffffffffffffffffffffffffffffffff865116604084015260208601516080606085015281815180845260e0860191506020830193505f92505b8083101561202b57835173ffffffffffffffffffffffffffffffffffffffff815116835260208101511515602084015250604082019150602084019350600183019250611fe3565b5060408801516080860152606088015160a08601528481036020860152612053818789611f54565b98975050505050505050565b5f6020828403121561206f575f5ffd5b5051919050565b8181038181111561093d577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8051611ca881611b47565b805161ffff81168114611ca8575f5ffd5b8051611ca881611b92565b805162ffffff81168114611ca8575f5ffd5b805163ffffffff81168114611ca8575f5ffd5b5f60e082840312801561210b575f5ffd5b5060405160e0810167ffffffffffffffff81118282101715612154577f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604052612160836120ae565b815261216e602084016120ae565b602082015261217f604084016120b9565b6040820152612190606084016120ca565b60608201526121a1608084016120d5565b60808201526121b260a084016120ca565b60a08201526121c360c084016120e7565b60c08201529392505050565b5f5f83357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612202575f5ffd5b83018035915067ffffffffffffffff82111561221c575f5ffd5b602001915036819003821315612230575f5ffd5b9250929050565b818382375f910190815291905056fea164736f6c634300081c000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000b00a89e5c8756ba8629846eef8a4a9c71ad1930a
-----Decoded View---------------
Arg [0] : nativeTokenWrapper_ (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [1] : initialOwner_ (address): 0xB00A89E5C8756bA8629846eEF8a4a9C71Ad1930A
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [1] : 000000000000000000000000b00a89e5c8756ba8629846eef8a4a9c71ad1930a
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
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.