Skip to content

Commit

Permalink
Implementation of the Aave NFTs template
Browse files Browse the repository at this point in the history
  • Loading branch information
aaitor committed Aug 31, 2021
1 parent 0f13917 commit 3f7e6c0
Show file tree
Hide file tree
Showing 8 changed files with 1,695 additions and 29 deletions.
105 changes: 105 additions & 0 deletions contracts/conditions/defi/aave/AaveBorrowCondition.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
pragma solidity 0.6.12;
// Copyright 2020 Keyko GmbH.
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
// Code is Apache-2.0 and docs are CC-BY-4.0

import "../../Condition.sol";
import "../../../registry/DIDRegistry.sol";
import "../../../Common.sol";
import "./AaveCreditVault.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";

/**
* @title Aave Borrow Credit Condition
* @author Keyko
*
* @dev Implementation of the Aave Borrow Credit Condition
*/
contract AaveBorrowCondition is Condition, Common {

DIDRegistry internal didRegistry;
AaveCreditVault internal aaveCreditVault;

bytes32 public constant CONDITION_TYPE = keccak256("AaveBorrowCondition");

event Fulfilled(
bytes32 indexed _agreementId,
bytes32 indexed _did,
bytes32 indexed _conditionId
);

/**
* @notice initialize init the contract with the following parameters
* @dev this function is called only once during the contract initialization.
* @param _owner contract's owner account address
* @param _conditionStoreManagerAddress condition store manager address
* @param _didRegistryAddress DID Registry address
*/
function initialize(
address _owner,
address _conditionStoreManagerAddress,
address _didRegistryAddress
)
external
initializer()
{
require(
_didRegistryAddress != address(0) &&
_conditionStoreManagerAddress != address(0),
"Invalid address"
);
OwnableUpgradeable.__Ownable_init();
transferOwnership(_owner);
conditionStoreManager = ConditionStoreManager(
_conditionStoreManagerAddress
);

didRegistry = DIDRegistry(_didRegistryAddress);
}

function hashValues(
bytes32 _did,
address _borrower,
address _assetToBorrow,
uint256 _amount
)
public
pure
returns (bytes32)
{
return
keccak256(
abi.encode(
_did,
_borrower,
_assetToBorrow,
_amount
)
);
}

function fulfill(
bytes32 _agreementId,
bytes32 _did,
address _vaultAddress,
address _assetToBorrow,
uint256 _amount
)
external
returns (ConditionStoreLibrary.ConditionState)
{
AaveCreditVault vault = AaveCreditVault(_vaultAddress);
vault.borrow(_assetToBorrow, _amount, msg.sender);

bytes32 _id =
generateId(
_agreementId,
hashValues(_did, msg.sender, _assetToBorrow, _amount)
);

ConditionStoreLibrary.ConditionState state =
super.fulfill(_id, ConditionStoreLibrary.ConditionState.Fulfilled);

return state;
}
}
135 changes: 135 additions & 0 deletions contracts/conditions/defi/aave/AaveCollateralDepositCondition.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
pragma solidity 0.6.12;
// Copyright 2020 Keyko GmbH.
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
// Code is Apache-2.0 and docs are CC-BY-4.0


import "../../Condition.sol";
import "../../../registry/DIDRegistry.sol";
import "./AaveCreditVault.sol";
import "../../../Common.sol";
import "../../../templates/AaveCreditTemplate.sol";
import '@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol';
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";

/**
* @title Aave Collateral Deposit Condition
* @author Keyko
*
* @dev Implementation of the Lock Payment Condition
* This condition allows to lock payment for multiple receivers taking
* into account the royalties to be paid to the original creators in a secondary market.
*/
contract AaveCollateralDepositCondition is Condition, Common, ReentrancyGuardUpgradeable {

DIDRegistry internal didRegistry;
AaveCreditVault internal aaveCreditVault;

bytes32 public constant CONDITION_TYPE = keccak256("AaveCollateralDepositCondition");

event Fulfilled(
bytes32 indexed _agreementId,
bytes32 indexed _did,
bytes32 indexed _conditionId
);

/**
* @notice initialize init the contract with the following parameters
* @dev this function is called only once during the contract initialization.
* @param _owner contract's owner account address
* @param _conditionStoreManagerAddress condition store manager address
* @param _didRegistryAddress DID Registry address
*/
function initialize(
address _owner,
address _conditionStoreManagerAddress,
address _didRegistryAddress
) external initializer() {

require(
_didRegistryAddress != address(0) &&
_conditionStoreManagerAddress != address(0),
"Invalid address"
);
OwnableUpgradeable.__Ownable_init();
transferOwnership(_owner);
conditionStoreManager = ConditionStoreManager(
_conditionStoreManagerAddress
);

didRegistry = DIDRegistry(_didRegistryAddress);
}

function hashValues(
bytes32 _did,
address _borrower,
address _collateralAsset,
uint256 _collateralAmount,
address _delegatedAsset,
uint256 _delegatedAmount
)
public
pure
returns (bytes32) {
return
keccak256(
abi.encode(
_did,
_borrower,
_collateralAsset,
_delegatedAsset,
_delegatedAmount,
_collateralAmount
)
);
}

function fulfill(
bytes32 _agreementId,
bytes32 _did,
address _vaultAddress,
address _borrower,
address _collateralAsset,
address _delegatedAsset,
uint256 _delegatedAmount,
uint256 _collateralAmount
)
external
payable
nonReentrant
returns (ConditionStoreLibrary.ConditionState) {
//Deposits the collateral in the Aave Lending pool contract

AaveCreditVault vault = AaveCreditVault(_vaultAddress);

if (msg.value == 0) {
IERC20Upgradeable token = ERC20Upgradeable(_collateralAsset);
token.transferFrom(
msg.sender,
address(vault),
_collateralAmount
);
}

vault.deposit{value: msg.value}(_collateralAsset, _collateralAmount);
vault.approveBorrower(_borrower, _delegatedAmount, _delegatedAsset);

bytes32 _id =
generateId(
_agreementId,
hashValues(
_did,
_borrower,
_collateralAsset,
_collateralAmount,
_delegatedAsset,
_delegatedAmount
)
);

ConditionStoreLibrary.ConditionState state =
super.fulfill(_id, ConditionStoreLibrary.ConditionState.Fulfilled);

return state;
}
}
152 changes: 152 additions & 0 deletions contracts/conditions/defi/aave/AaveCreditVault.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
pragma solidity 0.6.12;
// Copyright 2020 Keyko GmbH.
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
// Code is Apache-2.0 and docs are CC-BY-4.0


import {IERC20, ILendingPool, IProtocolDataProvider, IStableDebtToken} from '../../../interfaces/IAaveInterfaces.sol';
import {SafeERC20} from '../../../libraries/AaveLibrary.sol';
import '../../../interfaces/IWETHGateway.sol';
import '@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol';
import '@openzeppelin/contracts-upgradeable/token/ERC721/IERC721ReceiverUpgradeable.sol';
import '@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol';

contract AaveCreditVault is ReentrancyGuardUpgradeable, IERC721ReceiverUpgradeable {

using SafeERC20 for IERC20;

ILendingPool private lendingPool;
IProtocolDataProvider private dataProvider;
IWETHGateway private weth;

constructor(
address _lendingPool,
address _dataProvider,
address _weth
) public {
lendingPool = ILendingPool(_lendingPool);
dataProvider = IProtocolDataProvider(_dataProvider);
weth = IWETHGateway(_weth);
}

function deposit(
address _collateralAsset,
uint256 _amount
)
public
nonReentrant
payable
{
if (msg.value == 0) _transferERC20(_collateralAsset, _amount);
else {
weth.depositETH{value: msg.value}(address(lendingPool), address(this), 0);
}
}

function approveBorrower(
address borrower,
uint256 amount,
address asset
)
public
{
(, address stableDebtTokenAddress, ) = dataProvider
.getReserveTokensAddresses(asset);
IStableDebtToken(stableDebtTokenAddress).approveDelegation(
borrower,
amount
);
}

/**
* Return the actual delegated amount for the borrower in the specific asset
* @param borrower The borrower of the funds (i.e. delgatee)
* @param asset The asset they are allowed to borrow
*/
function delegatedAmount(
address borrower,
address asset
)
public
view
returns (uint256)
{
(, address stableDebtTokenAddress, ) = dataProvider
.getReserveTokensAddresses(asset);

return
IStableDebtToken(stableDebtTokenAddress).borrowAllowance(
address(this),
borrower
);
}

/**
* Borrower can call this function to borrow the delegated funds
* @param _assetToBorrow The asset they are allowed to borrow
* @param _amount Amount to borrow
* @param _delgatee Address where the funds will be transfered
*/
function borrow(
address _assetToBorrow,
uint256 _amount,
address _delgatee
)
public
{
lendingPool.borrow(_assetToBorrow, _amount, 1, 0, address(this));
IERC20(_assetToBorrow).transfer(_delgatee, _amount);
}

/**
* Repay an uncollaterised loan
* @param _amount The amount to repay
* @param _asset The asset to be repaid
*/
function repay(
uint256 _amount,
address _asset
)
public
{
IERC20(_asset).approve(address(lendingPool), _amount);
lendingPool.repay(_asset, _amount, 1, address(this));
}

/**
* Withdraw all of a collateral as the underlying asset, if no outstanding loans delegated
* @param _asset The underlying asset to withdraw
* @param _delegator Delegator address that deposited the collateral
*/
function withdrawCollateral(
address _asset,
address _delegator
)
public
{
(address aTokenAddress, , ) = dataProvider.getReserveTokensAddresses(
_asset
);
uint256 assetBalance = IERC20(aTokenAddress).balanceOf(address(this));
lendingPool.withdraw(_asset, assetBalance, _delegator);
}

function _transferERC20(
address _collateralAsset,
uint256 _amount
)
internal
{
IERC20Upgradeable token = ERC20Upgradeable(_collateralAsset);
token.approve(address(lendingPool), _amount);
lendingPool.deposit(_collateralAsset, _amount, address(this), 0);
}

/**
* Always returns `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(address, address, uint256, bytes memory) public virtual override returns (bytes4) {
return this.onERC721Received.selector;
}

}

0 comments on commit 3f7e6c0

Please sign in to comment.