Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add USDS-SUSDS token wrappers #13

Open
wants to merge 29 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
3fb0e1b
init
foodaka Sep 17, 2024
fb66cf8
fork execution
foodaka Sep 18, 2024
17ed1e5
cleanup
foodaka Sep 18, 2024
50f3eb7
test: Don't assume 0 ETH balance on wrapper contracts
CheyenneAtapour Sep 18, 2024
d3784d0
Fix TokenBorrow for SUSDS (#15)
CheyenneAtapour Sep 19, 2024
df5dd2b
feat: Move borrow logic to base wrapper
CheyenneAtapour Sep 20, 2024
0f69b1c
test: Add borrow test to SDAI wrapper. Lock blocknumbers
CheyenneAtapour Sep 20, 2024
e22cbd3
test: Add borrow token test for steth
CheyenneAtapour Sep 20, 2024
340414f
pr comments
foodaka Sep 24, 2024
a2dec9e
updated files
foodaka Sep 24, 2024
00b6ed4
move borrow as virtual on base
foodaka Sep 24, 2024
0163386
fix: Fuzz test, rename test, reorder fns per convention
CheyenneAtapour Sep 25, 2024
2cce3f7
borrow not permitted
foodaka Sep 25, 2024
0db3322
Merge branch 'feat/susds-wrappers' of github.com:aave/token-wrappers …
foodaka Sep 25, 2024
6915b96
borrow with sig
foodaka Sep 25, 2024
c24b358
fix: Move borrow logic to internal function
CheyenneAtapour Sep 25, 2024
1ab43a0
fix: Address pr comments
CheyenneAtapour Sep 26, 2024
4f5f382
fix: Move borrow logic to base wrapper
CheyenneAtapour Sep 27, 2024
1886062
fix: Move dependencies to V3 origin (#16)
miguelmtzinf Sep 30, 2024
9d654dd
fix: Remove unlimited allowance (#17)
miguelmtzinf Oct 1, 2024
253000b
feat: Generic ERC4626 <> ERC20 Token Wrapper (#20)
CheyenneAtapour Oct 3, 2024
53c52bd
fix: Remove unneccesary file
miguelmtzinf Oct 3, 2024
37e17c4
fix: Disables supply with permit for DAI because DAI permit is not st…
miguelmtzinf Oct 3, 2024
a10494c
fix: Re-order functions based on solidity guideliens
miguelmtzinf Oct 3, 2024
11c19c8
fix: Remove solc warnings
miguelmtzinf Oct 3, 2024
596d521
Refactors tests (#21)
miguelmtzinf Oct 3, 2024
86fb6e2
test: Add fuzz test for borrow
CheyenneAtapour Oct 4, 2024
9118be9
fix: Revert change test name
CheyenneAtapour Oct 4, 2024
13224ae
Add Additional BorrowToken Tests (#22)
CheyenneAtapour Oct 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@
src = "src"
out = "out"
libs = ["lib"]
solc = "0.8.20"
evm_version = "shanghai"

# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
27 changes: 26 additions & 1 deletion src/BaseTokenWrapper.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.10;

import {Ownable} from 'aave-v3-core/contracts/dependencies/openzeppelin/contracts/Ownable.sol';
import {IERC20} from 'aave-v3-core/contracts/dependencies/openzeppelin/contracts/IERC20.sol';
import {IERC20WithPermit} from 'aave-v3-core/contracts/interfaces/IERC20WithPermit.sol';
Expand All @@ -26,6 +25,14 @@ abstract contract BaseTokenWrapper is Ownable, IBaseTokenWrapper {
/// @inheritdoc IBaseTokenWrapper
IPool public immutable POOL;

/**
* @dev Throws if called by any token wrapper borrow function not permitted.
*/
modifier actionNotPermitted() {
miguelmtzinf marked this conversation as resolved.
Show resolved Hide resolved
require(false, 'INVALID_ACTION');
miguelmtzinf marked this conversation as resolved.
Show resolved Hide resolved
_;
}

/**
* @dev Constructor
* @param tokenIn ERC-20 token that will be wrapped in supply operations
Expand Down Expand Up @@ -103,6 +110,24 @@ abstract contract BaseTokenWrapper is Ownable, IBaseTokenWrapper {
return _withdrawToken(amount, to, aTokenOut);
}

/// @inheritdoc IBaseTokenWrapper
function borrowToken(
uint256 amount,
address to,
miguelmtzinf marked this conversation as resolved.
Show resolved Hide resolved
uint16 referralCode
) external virtual {}

/// @inheritdoc IBaseTokenWrapper
function borrowTokenWithPermit(
uint256 amount,
address to,
uint16 referralCode,
uint256 deadline,
miguelmtzinf marked this conversation as resolved.
Show resolved Hide resolved
uint8 permitV,
bytes32 permitR,
bytes32 permitS
) external virtual {}

/// @inheritdoc IBaseTokenWrapper
function rescueTokens(
IERC20 token,
Expand Down
108 changes: 108 additions & 0 deletions src/SavingUsdsTokenWrapper.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.10;
import 'forge-std/console2.sol';
miguelmtzinf marked this conversation as resolved.
Show resolved Hide resolved

import {IPool} from 'aave-v3-core/contracts/interfaces/IPool.sol';
import {ICreditDelegationToken} from 'aave-v3-core/contracts/interfaces/ICreditDelegationToken.sol';
import {IERC20} from 'aave-v3-core/contracts/dependencies/openzeppelin/contracts/IERC20.sol';
import {IUSDS} from './dependencies/IUSDS.sol';
import {BaseTokenWrapper} from './BaseTokenWrapper.sol';

/**
* @title SavingUsdsTokenWrapper
* @author Aave
* @notice Contract to wrap USDS to SuSDS on supply to Aave, or unwrap from SuSDS to USDS on withdrawal
*/
contract SavingUsdsTokenWrapper is BaseTokenWrapper {
/**
* @dev Constructor
* @param tokenIn Address for USDS
* @param tokenOut Address for SUSDS
* @param pool The address of the Aave Pool
* @param owner The address to transfer ownership to
*/
constructor(
address tokenIn,
address tokenOut,
address pool,
address owner
) BaseTokenWrapper(tokenIn, tokenOut, pool, owner) {
IERC20(tokenIn).approve(tokenOut, type(uint256).max);
}

/// @inheritdoc BaseTokenWrapper
function borrowToken(
uint256 amount,
address to,
uint16 referralCode
) external override {
_borrowToken(amount, to, referralCode);
}

/// @inheritdoc BaseTokenWrapper
function borrowTokenWithPermit(
uint256 amount,
address to,
uint16 referralCode,
uint256 deadline,
uint8 permitV,
bytes32 permitR,
bytes32 permitS
) external override {
if (deadline != 0) {
address debtToken = IPool(0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2)
.getReserveData(TOKEN_OUT)
.variableDebtTokenAddress;

ICreditDelegationToken(debtToken).delegationWithSig(
msg.sender,
address(this),
amount,
deadline,
permitV,
permitR,
permitS
);
}
_borrowToken(amount, to, referralCode);
}

/// @inheritdoc BaseTokenWrapper
function getTokenOutForTokenIn(
uint256 amount
) external view override returns (uint256) {
return IUSDS(TOKEN_OUT).previewDeposit(amount);
}

/// @inheritdoc BaseTokenWrapper
function getTokenInForTokenOut(
uint256 amount
) external view override returns (uint256) {
return IUSDS(TOKEN_OUT).previewRedeem(amount);
}

/// @inheritdoc BaseTokenWrapper
function _wrapTokenIn(uint256 amount) internal override returns (uint256) {
return IUSDS(TOKEN_OUT).deposit(amount, address(this));
}

/// @inheritdoc BaseTokenWrapper
function _unwrapTokenOut(uint256 amount) internal override returns (uint256) {
return IUSDS(TOKEN_OUT).redeem(amount, address(this), address(this));
}

function _borrowToken(
miguelmtzinf marked this conversation as resolved.
Show resolved Hide resolved
uint256 amount,
address to,
miguelmtzinf marked this conversation as resolved.
Show resolved Hide resolved
uint16 referralCode
) internal {
require(amount > 0, 'INSUFFICIENT_AMOUNT_TO_BORROW');
uint256 balanceBeforeBorrow = IERC20(TOKEN_OUT).balanceOf(address(this));
POOL.borrow(TOKEN_OUT, amount, 2, referralCode, address(to));
uint256 balanceAfterBorrow = IERC20(TOKEN_OUT).balanceOf(address(this));
uint256 amountIn = _unwrapTokenOut(
balanceAfterBorrow - balanceBeforeBorrow
);
IERC20(TOKEN_IN).transfer(to, amountIn);
}
}
18 changes: 18 additions & 0 deletions src/SavingsDaiTokenWrapper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,22 @@ contract SavingsDaiTokenWrapper is BaseTokenWrapper {
function _unwrapTokenOut(uint256 amount) internal override returns (uint256) {
return ISavingsDai(TOKEN_OUT).redeem(amount, address(this), address(this));
}

/// @inheritdoc BaseTokenWrapper
function borrowToken(
uint256 amount,
address to,
uint16 referralCode
) external override actionNotPermitted {}

/// @inheritdoc BaseTokenWrapper
function borrowTokenWithPermit(
uint256 amount,
address to,
uint16 referralCode,
uint256 deadline,
uint8 permitV,
bytes32 permitR,
bytes32 permitS
) external override actionNotPermitted {}
}
18 changes: 18 additions & 0 deletions src/StakedEthTokenWrapper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,22 @@ contract StakedEthTokenWrapper is BaseTokenWrapper {
function _unwrapTokenOut(uint256 amount) internal override returns (uint256) {
return IWstETH(TOKEN_OUT).unwrap(amount);
}

/// @inheritdoc BaseTokenWrapper
function borrowToken(
uint256 amount,
address to,
uint16 referralCode
) external override actionNotPermitted {}

/// @inheritdoc BaseTokenWrapper
function borrowTokenWithPermit(
uint256 amount,
address to,
uint16 referralCode,
uint256 deadline,
uint8 permitV,
bytes32 permitR,
bytes32 permitS
) external override actionNotPermitted {}
}
145 changes: 145 additions & 0 deletions src/dependencies/IUSDS.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity >=0.8.0;

interface IUSDS {
function DOMAIN_SEPARATOR() external view returns (bytes32);

function PERMIT_TYPEHASH() external view returns (bytes32);

function UPGRADE_INTERFACE_VERSION() external view returns (string memory);

function allowance(
address owner,
address spender
) external view returns (uint256);

function approve(address spender, uint256 value) external returns (bool);

function asset() external view returns (address);

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

function chi() external view returns (uint192);

function convertToAssets(uint256 shares) external view returns (uint256);

function convertToShares(uint256 assets) external view returns (uint256);

function decimals() external view returns (uint8);

function deny(address usr) external;

function deposit(uint256 assets, address receiver) external returns (uint256);

function deposit(
uint256 assets,
address receiver,
uint16 referral
) external returns (uint256);

function drip() external returns (uint256);

function file(bytes32 what, uint256 data) external;

function getImplementation() external view returns (address);

function initialize() external;

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

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

function maxRedeem(address owner) external view returns (uint256);

function maxWithdraw(address owner) external view returns (uint256);

function mint(
uint256 shares,
address receiver,
uint16 referral
) external returns (uint256);

function mint(uint256 shares, address receiver) external returns (uint256);

function name() external view returns (string memory);

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

function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
bytes memory signature
) external;

function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;

function previewDeposit(uint256 assets) external view returns (uint256);

function previewMint(uint256 shares) external view returns (uint256);

function previewRedeem(uint256 shares) external view returns (uint256);

function previewWithdraw(uint256 assets) external view returns (uint256);

function proxiableUUID() external view returns (bytes32);

function redeem(
uint256 shares,
address receiver,
address owner
) external returns (uint256);

function rely(address usr) external;

function rho() external view returns (uint64);

function ssr() external view returns (uint256);

function symbol() external view returns (string memory);

function totalAssets() external view returns (uint256);

function totalSupply() external view returns (uint256);

function transfer(address to, uint256 value) external returns (bool);

function transferFrom(
address from,
address to,
uint256 value
) external returns (bool);

function upgradeToAndCall(
address newImplementation,
bytes memory data
) external payable;

function usds() external view returns (address);

function usdsJoin() external view returns (address);

function vat() external view returns (address);

function version() external view returns (string memory);

function vow() external view returns (address);

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

function withdraw(
uint256 assets,
address receiver,
address owner
) external returns (uint256);
}
32 changes: 32 additions & 0 deletions src/interfaces/IBaseTokenWrapper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,38 @@ interface IBaseTokenWrapper {
PermitSignature calldata signature
) external returns (uint256);

/**
* @notice Borrows token from the Pool and unwraps it, sending to the recipient
* @param amount The amount of token to borrow
* @param to The address that will receive the unwrapped token
* @param referralCode Code used to register the integrator originating the operation, for potential rewards
*/
function borrowToken(
uint256 amount,
address to,
uint16 referralCode
) external;

/**
* @notice Borrows token from the Pool, unwraps it, and sends it to the recipient using EIP-2612 permit
* @param amount The amount of token to borrow
* @param to The address that will receive the unwrapped token
* @param referralCode Code used to register the integrator originating the operation, for potential rewards
* @param deadline The deadline timestamp for the permit signature to be valid
* @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 borrowTokenWithPermit(
uint256 amount,
address to,
uint16 referralCode,
uint256 deadline,
uint8 permitV,
bytes32 permitR,
bytes32 permitS
) external;

/**
* @notice Provides way for the contract owner to rescue ERC-20 tokens
* @param token The address of the token to withdraw from this contract
Expand Down
Loading