Skip to content

Commit

Permalink
Fix TokenBorrow for SUSDS (#15)
Browse files Browse the repository at this point in the history
* wip: borrowToken wrapper extension

* wip: Trying credit delegation

* testing

* updated fork

* fix: TokenBorrow working

---------

Co-authored-by: Mark Hinschberger <foodaka@users.noreply.github.com>
  • Loading branch information
CheyenneAtapour and foodaka authored Sep 19, 2024
1 parent 50f3eb7 commit d3784d0
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 2 deletions.
3 changes: 3 additions & 0 deletions src/BaseTokenWrapper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ abstract contract BaseTokenWrapper is Ownable, IBaseTokenWrapper {
return _withdrawToken(amount, to, aTokenOut);
}

/// @inheritdoc IBaseTokenWrapper
function borrowToken(uint256 amount, address to) external virtual {}

/// @inheritdoc IBaseTokenWrapper
function rescueTokens(
IERC20 token,
Expand Down
11 changes: 11 additions & 0 deletions src/SavingsSuSDSTokenWrapper.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.10;
import 'forge-std/console2.sol';

import {IERC20} from 'aave-v3-core/contracts/dependencies/openzeppelin/contracts/IERC20.sol';
import {IUSDS} from './interfaces/IUSDS.sol';
Expand Down Expand Up @@ -27,6 +28,16 @@ contract SavingsSuSDSTokenWrapper is BaseTokenWrapper {
IERC20(tokenIn).approve(tokenOut, type(uint256).max);
}

///@inheritdoc BaseTokenWrapper
function borrowToken(uint256 amount, address to) external override {
require(amount > 0, 'INSUFFICIENT_AMOUNT_TO_BORROW');

POOL.borrow(TOKEN_OUT, amount, 2, 0, address(to));

uint256 amountIn = _unwrapTokenOut(amount);
IERC20(TOKEN_IN).transfer(to, amountIn);
}

/// @inheritdoc BaseTokenWrapper
function getTokenOutForTokenIn(
uint256 amount
Expand Down
7 changes: 7 additions & 0 deletions src/interfaces/IBaseTokenWrapper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ 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
*/
function borrowToken(uint256 amount, address to) 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
49 changes: 49 additions & 0 deletions src/interfaces/ICreditDelegationToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
* @title ICreditDelegationToken
* @author Aave
* @notice Defines the basic interface for a token supporting credit delegation.
**/
interface ICreditDelegationToken {
/**
* @notice Delegates borrowing power to a user on the specific debt token.
* Delegation will still respect the liquidation constraints (even if delegated, a
* delegatee cannot force a delegator HF to go below 1)
* @param delegatee The address receiving the delegated borrowing power
* @param amount The maximum amount being delegated.
**/
function approveDelegation(address delegatee, uint256 amount) external;

/**
* @notice Returns the borrow allowance of the user
* @param fromUser The user to giving allowance
* @param toUser The user to give allowance to
* @return The current allowance of `toUser`
**/
function borrowAllowance(
address fromUser,
address toUser
) external view returns (uint256);

/**
* @notice Delegates borrowing power to a user on the specific debt token via ERC712 signature
* @param delegator The delegator of the credit
* @param delegatee The delegatee that can use the credit
* @param value The amount to be delegated
* @param deadline The deadline timestamp, type(uint256).max for max deadline
* @param v The V signature param
* @param s The S signature param
* @param r The R signature param
*/
function delegationWithSig(
address delegator,
address delegatee,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
}
83 changes: 81 additions & 2 deletions test/SavingsSuSDSTokenWrapper.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,26 @@
pragma solidity ^0.8.10;
import 'forge-std/console2.sol';

import {DataTypes} from 'aave-v3-core/contracts/protocol/libraries/types/DataTypes.sol';
import {IERC20} from 'aave-v3-core/contracts/dependencies/openzeppelin/contracts/IERC20.sol';
import {IPool} from 'aave-v3-core/contracts/interfaces/IPool.sol';
import {BaseTokenWrapperTest} from './BaseTokenWrapper.t.sol';
import {SavingsSuSDSTokenWrapper} from '../src/SavingsSuSDSTokenWrapper.sol';
import {ICreditDelegationToken} from '../src/interfaces/ICreditDelegationToken.sol';

// frontend deposits usds and automatically converted to susds on aave
contract SavingsSuSDSTokenWrapperTest is BaseTokenWrapperTest {
address constant USDS = 0xdC035D45d973E3EC169d2276DDab16f1e407384F;
address constant SUSDS = 0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD;
address constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;

// TODO Actual Address --> fork
address constant AUSDS = 0x5c647cE0Ae10658ec44FA4E11A51c96e94efd1Dd;
address constant AUSDS = 0x10Ac93971cdb1F5c778144084242374473c350Da;

function setUp() public {
// vm.createSelectFork(vm.envString('ETH_RPC_URL'));
vm.createSelectFork(
'https://rpc.tenderly.co/fork/26fdbc41-5ae7-4f5a-9b47-a4ae15e05ce0'
'https://rpc.tenderly.co/fork/881012fd-267f-41dc-93ba-8eb025b8bce2'
);
pool = 0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2;

Expand Down Expand Up @@ -49,4 +53,79 @@ contract SavingsSuSDSTokenWrapperTest is BaseTokenWrapperTest {
'Unexpected TOKEN_IN allowance'
);
}

// function testBorrow() public {
// address alice = makeAddr('ALICE');
// deal(USDS, alice, 1000e18);
// vm.startPrank(alice);
// IERC20(USDS).approve(address(pool), 1000e18);
// IPool(pool).supply(USDS, 1000e18, alice, 0);
// vm.stopPrank();

// // TODO: Instead of checking pool, need to check reserve contract
// /*
// assertEq(
// IERC20(SUSDS).balanceOf(address(pool)),
// 1e18,
// 'Unexpected post-deal pool USDS balance'
// );*/

// deal(WETH, address(this), 20 ether);
// IERC20(WETH).approve(pool, 20 ether);
// IPool(pool).supply(WETH, 20 ether, address(this), 0);

// deal(USDS, address(this), 1e18);
// IERC20(USDS).approve(address(pool), 1e18);
// IPool(pool).supply(USDS, 1e18, address(this), 0);
// deal(SUSDS, address(this), 1e18);
// IERC20(SUSDS).approve(address(pool), 1e18);
// IPool(pool).supply(SUSDS, 1e18, address(this), 0);

// uint256 amount = 1e18;
// uint256 amountOut = tokenWrapper.getTokenOutForTokenIn(amount);
// uint256 usdsBefore = IERC20(USDS).balanceOf(address(this));
// ICreditDelegationToken(SUSDS).approveDelegation(
// address(tokenWrapper),
// amountOut
// );
// tokenWrapper.borrowToken(amount, address(this));
// uint256 usdsAfter = IERC20(USDS).balanceOf(address(this));

// assertEq(
// usdsAfter,
// usdsBefore + amount,
// 'Unexpected USDS balance after borrow'
// );
// }

function testBorrow() public {
address debtToken = IPool(pool)
.getReserveData(SUSDS)
.variableDebtTokenAddress;

address alice = makeAddr('ALICE');
uint256 collateralAmount = 1000e18;

uint256 borrowAmount = 100e18;

deal(WETH, alice, collateralAmount);

vm.startPrank(alice);
IERC20(WETH).approve(address(pool), collateralAmount);
IPool(pool).supply(WETH, collateralAmount, alice, 0);

ICreditDelegationToken(debtToken).approveDelegation(
address(tokenWrapper),
borrowAmount
);

// IPool(pool).borrow(SUSDS, borrowAmount, 2, 0, alice);
// console2.log('Borrowing USDS', address(tokenWrapper));
tokenWrapper.borrowToken(borrowAmount, address(alice));

vm.stopPrank();

uint256 borrowedAmount = tokenWrapper.getTokenInForTokenOut(borrowAmount);
assertEq(IERC20(USDS).balanceOf(address(alice)), borrowedAmount);
}
}

0 comments on commit d3784d0

Please sign in to comment.