From 3aacd06fff0b61509da3ddf8f55c9fd59da1fb41 Mon Sep 17 00:00:00 2001 From: Hadrien Charlanes Date: Mon, 5 Jul 2021 12:03:06 +0200 Subject: [PATCH] feat: added permitDelegation functions to stable and variable debt tokens --- contracts/interfaces/IStableDebtToken.sol | 20 +++++ contracts/interfaces/IVariableDebtToken.sol | 20 +++++ .../protocol/tokenization/StableDebtToken.sol | 73 +++++++++++++++++++ .../tokenization/VariableDebtToken.sol | 73 +++++++++++++++++++ 4 files changed, 186 insertions(+) diff --git a/contracts/interfaces/IStableDebtToken.sol b/contracts/interfaces/IStableDebtToken.sol index e39cf8b5..082a32db 100644 --- a/contracts/interfaces/IStableDebtToken.sol +++ b/contracts/interfaces/IStableDebtToken.sol @@ -69,6 +69,26 @@ interface IStableDebtToken is IInitializableDebtToken { uint256 rate ) external returns (bool); + /** + * @dev implements the credit delegation with 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 Signature param + * @param s Signature param + * @param r Signature param + */ + function permitDelegation( + address delegator, + address delegatee, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; + /** * @dev Burns debt of `user` * - The resulting rate is the weighted average between the rate of the new debt diff --git a/contracts/interfaces/IVariableDebtToken.sol b/contracts/interfaces/IVariableDebtToken.sol index d88c25fc..b839f8ee 100644 --- a/contracts/interfaces/IVariableDebtToken.sol +++ b/contracts/interfaces/IVariableDebtToken.sol @@ -36,6 +36,26 @@ interface IVariableDebtToken is IScaledBalanceToken, IInitializableDebtToken { uint256 index ) external returns (bool); + /** + * @dev implements the credit delegation with 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 Signature param + * @param s Signature param + * @param r Signature param + */ + function permitDelegation( + address delegator, + address delegatee, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; + /** * @dev Emitted when variable debt is burnt * @param user The user which debt has been burned diff --git a/contracts/protocol/tokenization/StableDebtToken.sol b/contracts/protocol/tokenization/StableDebtToken.sol index 2212e9cf..86f8607a 100644 --- a/contracts/protocol/tokenization/StableDebtToken.sol +++ b/contracts/protocol/tokenization/StableDebtToken.sol @@ -18,6 +18,14 @@ import {Errors} from '../libraries/helpers/Errors.sol'; contract StableDebtToken is IStableDebtToken, DebtTokenBase { using WadRayMath for uint256; + bytes public constant EIP712_REVISION = bytes('1'); + bytes32 internal constant EIP712_DOMAIN = + keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'); + bytes32 public constant PERMIT_DELEGATION_TYPEHASH = + keccak256( + 'PermitDelegation(address delegator,address delegatee,uint256 value,uint256 nonce,uint256 deadline)' + ); + uint256 public constant DEBT_TOKEN_REVISION = 0x1; uint256 internal _avgStableRate; @@ -29,6 +37,9 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase { address internal _underlyingAsset; IAaveIncentivesController internal _incentivesController; + mapping(address => uint256) public _nonces; + bytes32 public DOMAIN_SEPARATOR; + /** * @dev Initializes the debt token. * @param pool The address of the lending pool where this aToken will be used @@ -47,6 +58,13 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase { string memory debtTokenSymbol, bytes calldata params ) public override initializer { + uint256 chainId; + + //solium-disable-next-line + assembly { + chainId := chainid() + } + _setName(debtTokenName); _setSymbol(debtTokenSymbol); _setDecimals(debtTokenDecimals); @@ -55,6 +73,16 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase { _underlyingAsset = underlyingAsset; _incentivesController = incentivesController; + DOMAIN_SEPARATOR = keccak256( + abi.encode( + EIP712_DOMAIN, + keccak256(bytes(debtTokenName)), + keccak256(EIP712_REVISION), + chainId, + address(this) + ) + ); + emit Initialized( underlyingAsset, address(pool), @@ -256,6 +284,51 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase { emit Transfer(user, address(0), amount); } + /** + * @dev implements the credit delegation with 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 Signature param + * @param s Signature param + * @param r Signature param + */ + function permitDelegation( + address delegator, + address delegatee, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external override { + require(delegator != address(0), 'INVALID_DELEGATOR'); + //solium-disable-next-line + require(block.timestamp <= deadline, 'INVALID_EXPIRATION'); + uint256 currentValidNonce = _nonces[delegator]; + bytes32 digest = + keccak256( + abi.encodePacked( + '\x19\x01', + DOMAIN_SEPARATOR, + keccak256( + abi.encode( + PERMIT_DELEGATION_TYPEHASH, + delegator, + delegatee, + value, + currentValidNonce, + deadline + ) + ) + ) + ); + require(delegator == ecrecover(digest, v, r, s), 'INVALID_SIGNATURE'); + _nonces[delegator] = currentValidNonce.add(1); + _approveDelegation(delegator, delegatee, value); + } + /** * @dev Calculates the increase in balance since the last user interaction * @param user The address of the user for which the interest is being accumulated diff --git a/contracts/protocol/tokenization/VariableDebtToken.sol b/contracts/protocol/tokenization/VariableDebtToken.sol index a7a28176..f14a31fc 100644 --- a/contracts/protocol/tokenization/VariableDebtToken.sol +++ b/contracts/protocol/tokenization/VariableDebtToken.sol @@ -17,12 +17,23 @@ import {IAaveIncentivesController} from '../../interfaces/IAaveIncentivesControl contract VariableDebtToken is DebtTokenBase, IVariableDebtToken { using WadRayMath for uint256; + bytes public constant EIP712_REVISION = bytes('1'); + bytes32 internal constant EIP712_DOMAIN = + keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'); + bytes32 public constant PERMIT_DELEGATION_TYPEHASH = + keccak256( + 'PermitDelegation(address delegator,address delegatee,uint256 value,uint256 nonce,uint256 deadline)' + ); + uint256 public constant DEBT_TOKEN_REVISION = 0x1; ILendingPool internal _pool; address internal _underlyingAsset; IAaveIncentivesController internal _incentivesController; + mapping(address => uint256) public _nonces; + bytes32 public DOMAIN_SEPARATOR; + /** * @dev Initializes the debt token. * @param pool The address of the lending pool where this aToken will be used @@ -41,6 +52,13 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken { string memory debtTokenSymbol, bytes calldata params ) public override initializer { + uint256 chainId; + + //solium-disable-next-line + assembly { + chainId := chainid() + } + _setName(debtTokenName); _setSymbol(debtTokenSymbol); _setDecimals(debtTokenDecimals); @@ -49,6 +67,16 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken { _underlyingAsset = underlyingAsset; _incentivesController = incentivesController; + DOMAIN_SEPARATOR = keccak256( + abi.encode( + EIP712_DOMAIN, + keccak256(bytes(debtTokenName)), + keccak256(EIP712_REVISION), + chainId, + address(this) + ) + ); + emit Initialized( underlyingAsset, address(pool), @@ -135,6 +163,51 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken { emit Burn(user, amount, index); } + /** + * @dev implements the credit delegation with 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 Signature param + * @param s Signature param + * @param r Signature param + */ + function permitDelegation( + address delegator, + address delegatee, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external override { + require(delegator != address(0), 'INVALID_DELEGATOR'); + //solium-disable-next-line + require(block.timestamp <= deadline, 'INVALID_EXPIRATION'); + uint256 currentValidNonce = _nonces[delegator]; + bytes32 digest = + keccak256( + abi.encodePacked( + '\x19\x01', + DOMAIN_SEPARATOR, + keccak256( + abi.encode( + PERMIT_DELEGATION_TYPEHASH, + delegator, + delegatee, + value, + currentValidNonce, + deadline + ) + ) + ) + ); + require(delegator == ecrecover(digest, v, r, s), 'INVALID_SIGNATURE'); + _nonces[delegator] = currentValidNonce.add(1); + _approveDelegation(delegator, delegatee, value); + } + /** * @dev Returns the principal debt balance of the user from * @return The debt balance of the user since the last burn/mint action