mirror of
				https://github.com/Instadapp/aave-protocol-v2.git
				synced 2024-07-29 21:47:30 +00:00 
			
		
		
		
	Added depositWithPermit, repayWithPermit test scenarios
This commit is contained in:
		
							parent
							
								
									6810940c9f
								
							
						
					
					
						commit
						3a6948ce2c
					
				| 
						 | 
					@ -8,14 +8,67 @@ import {ERC20} from '../../dependencies/openzeppelin/contracts/ERC20.sol';
 | 
				
			||||||
 * @dev ERC20 minting logic
 | 
					 * @dev ERC20 minting logic
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
contract MintableERC20 is ERC20 {
 | 
					contract MintableERC20 is ERC20 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  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_TYPEHASH =
 | 
				
			||||||
 | 
					    keccak256('Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mapping(address => uint256) public _nonces;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bytes32 public DOMAIN_SEPARATOR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  constructor(
 | 
					  constructor(
 | 
				
			||||||
    string memory name,
 | 
					    string memory name,
 | 
				
			||||||
    string memory symbol,
 | 
					    string memory symbol,
 | 
				
			||||||
    uint8 decimals
 | 
					    uint8 decimals
 | 
				
			||||||
  ) public ERC20(name, symbol) {
 | 
					  ) public ERC20(name, symbol) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint256 chainId;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assembly {
 | 
				
			||||||
 | 
					      chainId := chainid()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    DOMAIN_SEPARATOR = keccak256(
 | 
				
			||||||
 | 
					      abi.encode(
 | 
				
			||||||
 | 
					        EIP712_DOMAIN,
 | 
				
			||||||
 | 
					        keccak256(bytes(name)),
 | 
				
			||||||
 | 
					        keccak256(EIP712_REVISION),
 | 
				
			||||||
 | 
					        chainId,
 | 
				
			||||||
 | 
					        address(this)
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
    _setupDecimals(decimals);
 | 
					    _setupDecimals(decimals);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function permit(
 | 
				
			||||||
 | 
					    address owner,
 | 
				
			||||||
 | 
					    address spender,
 | 
				
			||||||
 | 
					    uint256 value,
 | 
				
			||||||
 | 
					    uint256 deadline,
 | 
				
			||||||
 | 
					    uint8 v,
 | 
				
			||||||
 | 
					    bytes32 r,
 | 
				
			||||||
 | 
					    bytes32 s
 | 
				
			||||||
 | 
					  ) external {
 | 
				
			||||||
 | 
					    require(owner != address(0), 'INVALID_OWNER');
 | 
				
			||||||
 | 
					    //solium-disable-next-line
 | 
				
			||||||
 | 
					    require(block.timestamp <= deadline, 'INVALID_EXPIRATION');
 | 
				
			||||||
 | 
					    uint256 currentValidNonce = _nonces[owner];
 | 
				
			||||||
 | 
					    bytes32 digest =
 | 
				
			||||||
 | 
					      keccak256(
 | 
				
			||||||
 | 
					        abi.encodePacked(
 | 
				
			||||||
 | 
					          '\x19\x01',
 | 
				
			||||||
 | 
					          DOMAIN_SEPARATOR,
 | 
				
			||||||
 | 
					          keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, currentValidNonce, deadline))
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    require(owner == ecrecover(digest, v, r, s), 'INVALID_SIGNATURE');
 | 
				
			||||||
 | 
					    _nonces[owner] = currentValidNonce.add(1);
 | 
				
			||||||
 | 
					    _approve(owner, spender, value);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * @dev Function to mint tokens
 | 
					   * @dev Function to mint tokens
 | 
				
			||||||
   * @param value The amount of tokens to mint.
 | 
					   * @param value The amount of tokens to mint.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -363,3 +363,5 @@ export const getFlashLiquidationAdapter = async (address?: tEthereumAddress) =>
 | 
				
			||||||
        .address,
 | 
					        .address,
 | 
				
			||||||
    await getFirstSigner()
 | 
					    await getFirstSigner()
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const getChainId = async () => (await DRE.ethers.provider.getNetwork()).chainId;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,7 +21,7 @@
 | 
				
			||||||
    "test": "TS_NODE_TRANSPILE_ONLY=1 hardhat test ./test-suites/test-aave/*.spec.ts",
 | 
					    "test": "TS_NODE_TRANSPILE_ONLY=1 hardhat test ./test-suites/test-aave/*.spec.ts",
 | 
				
			||||||
    "test-amm": "TS_NODE_TRANSPILE_ONLY=1 hardhat test ./test-suites/test-amm/*.spec.ts",
 | 
					    "test-amm": "TS_NODE_TRANSPILE_ONLY=1 hardhat test ./test-suites/test-amm/*.spec.ts",
 | 
				
			||||||
    "test-amm-scenarios": "TS_NODE_TRANSPILE_ONLY=1 hardhat test ./test-suites/test-amm/__setup.spec.ts test-suites/test-amm/scenario.spec.ts",
 | 
					    "test-amm-scenarios": "TS_NODE_TRANSPILE_ONLY=1 hardhat test ./test-suites/test-amm/__setup.spec.ts test-suites/test-amm/scenario.spec.ts",
 | 
				
			||||||
    "test-scenarios": "npx hardhat test test-suites/test-aave/__setup.spec.ts test-suites/test-aave/scenario.spec.ts",
 | 
					    "test-scenarios": "hardhat test test-suites/test-aave/__setup.spec.ts test-suites/test-aave/scenario.spec.ts",
 | 
				
			||||||
    "test-repay-with-collateral": "hardhat test test-suites/test-aave/__setup.spec.ts test-suites/test-aave/repay-with-collateral.spec.ts",
 | 
					    "test-repay-with-collateral": "hardhat test test-suites/test-aave/__setup.spec.ts test-suites/test-aave/repay-with-collateral.spec.ts",
 | 
				
			||||||
    "test-liquidate-with-collateral": "hardhat test test-suites/test-aave/__setup.spec.ts test-suites/test-aave/flash-liquidation-with-collateral.spec.ts",
 | 
					    "test-liquidate-with-collateral": "hardhat test test-suites/test-aave/__setup.spec.ts test-suites/test-aave/flash-liquidation-with-collateral.spec.ts",
 | 
				
			||||||
    "test-liquidate-underlying": "hardhat test test-suites/test-aave/__setup.spec.ts test-suites/test-aave/liquidation-underlying.spec.ts",
 | 
					    "test-liquidate-underlying": "hardhat test test-suites/test-aave/__setup.spec.ts test-suites/test-aave/liquidation-underlying.spec.ts",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,6 +16,7 @@ import {
 | 
				
			||||||
  calcExpectedUserDataAfterWithdraw,
 | 
					  calcExpectedUserDataAfterWithdraw,
 | 
				
			||||||
} from './utils/calculations';
 | 
					} from './utils/calculations';
 | 
				
			||||||
import { getReserveAddressFromSymbol, getReserveData, getUserData } from './utils/helpers';
 | 
					import { getReserveAddressFromSymbol, getReserveData, getUserData } from './utils/helpers';
 | 
				
			||||||
 | 
					import { buildPermitParams, getSignatureFromTypedData } from '../../../helpers/contracts-helpers';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { convertToCurrencyDecimals } from '../../../helpers/contracts-helpers';
 | 
					import { convertToCurrencyDecimals } from '../../../helpers/contracts-helpers';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
| 
						 | 
					@ -23,6 +24,7 @@ import {
 | 
				
			||||||
  getMintableERC20,
 | 
					  getMintableERC20,
 | 
				
			||||||
  getStableDebtToken,
 | 
					  getStableDebtToken,
 | 
				
			||||||
  getVariableDebtToken,
 | 
					  getVariableDebtToken,
 | 
				
			||||||
 | 
					  getChainId,
 | 
				
			||||||
} from '../../../helpers/contracts-getters';
 | 
					} from '../../../helpers/contracts-getters';
 | 
				
			||||||
import { MAX_UINT_AMOUNT, ONE_YEAR } from '../../../helpers/constants';
 | 
					import { MAX_UINT_AMOUNT, ONE_YEAR } from '../../../helpers/constants';
 | 
				
			||||||
import { SignerWithAddress, TestEnv } from './make-suite';
 | 
					import { SignerWithAddress, TestEnv } from './make-suite';
 | 
				
			||||||
| 
						 | 
					@ -30,9 +32,10 @@ import { advanceTimeAndBlock, DRE, timeLatest, waitForTx } from '../../../helper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import chai from 'chai';
 | 
					import chai from 'chai';
 | 
				
			||||||
import { ReserveData, UserReserveData } from './utils/interfaces';
 | 
					import { ReserveData, UserReserveData } from './utils/interfaces';
 | 
				
			||||||
import { ContractReceipt } from 'ethers';
 | 
					import { ContractReceipt, Wallet } from 'ethers';
 | 
				
			||||||
import { AToken } from '../../../types/AToken';
 | 
					import { AToken } from '../../../types/AToken';
 | 
				
			||||||
import { RateMode, tEthereumAddress } from '../../../helpers/types';
 | 
					import { RateMode, tEthereumAddress } from '../../../helpers/types';
 | 
				
			||||||
 | 
					import { MintableERC20Factory } from '../../../types';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const { expect } = chai;
 | 
					const { expect } = chai;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -515,6 +518,257 @@ export const repay = async (
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const depositWithPermit = async (
 | 
				
			||||||
 | 
					  reserveSymbol: string,
 | 
				
			||||||
 | 
					  amount: string,
 | 
				
			||||||
 | 
					  sender: SignerWithAddress,
 | 
				
			||||||
 | 
					  senderPk: string,
 | 
				
			||||||
 | 
					  onBehalfOf: tEthereumAddress,
 | 
				
			||||||
 | 
					  sendValue: string,
 | 
				
			||||||
 | 
					  expectedResult: string,
 | 
				
			||||||
 | 
					  testEnv: TestEnv,
 | 
				
			||||||
 | 
					  revertMessage?: string
 | 
				
			||||||
 | 
					) => {
 | 
				
			||||||
 | 
					  const { pool } = testEnv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const reserve = await getReserveAddressFromSymbol(reserveSymbol);
 | 
				
			||||||
 | 
					  const amountToDeposit = await convertToCurrencyDecimals(reserve, amount);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const chainId = await getChainId();
 | 
				
			||||||
 | 
					  const token = new MintableERC20Factory(sender.signer).attach(reserve);
 | 
				
			||||||
 | 
					  const highDeadline = '100000000000000000000000000';
 | 
				
			||||||
 | 
					  const nonce = await token._nonces(sender.address);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const msgParams = buildPermitParams(
 | 
				
			||||||
 | 
					    chainId,
 | 
				
			||||||
 | 
					    reserve,
 | 
				
			||||||
 | 
					    '1',
 | 
				
			||||||
 | 
					    reserveSymbol,
 | 
				
			||||||
 | 
					    sender.address,
 | 
				
			||||||
 | 
					    pool.address,
 | 
				
			||||||
 | 
					    nonce.toNumber(),
 | 
				
			||||||
 | 
					    highDeadline,
 | 
				
			||||||
 | 
					    amountToDeposit.toString()
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					  const { v, r, s } = getSignatureFromTypedData(senderPk, msgParams);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const txOptions: any = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const { reserveData: reserveDataBefore, userData: userDataBefore } = await getContractsData(
 | 
				
			||||||
 | 
					    reserve,
 | 
				
			||||||
 | 
					    onBehalfOf,
 | 
				
			||||||
 | 
					    testEnv,
 | 
				
			||||||
 | 
					    sender.address
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (sendValue) {
 | 
				
			||||||
 | 
					    txOptions.value = await convertToCurrencyDecimals(reserve, sendValue);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (expectedResult === 'success') {
 | 
				
			||||||
 | 
					    const txResult = await waitForTx(
 | 
				
			||||||
 | 
					      await pool
 | 
				
			||||||
 | 
					        .connect(sender.signer)
 | 
				
			||||||
 | 
					        .depositWithPermit(
 | 
				
			||||||
 | 
					          reserve,
 | 
				
			||||||
 | 
					          amountToDeposit,
 | 
				
			||||||
 | 
					          onBehalfOf,
 | 
				
			||||||
 | 
					          '0',
 | 
				
			||||||
 | 
					          highDeadline,
 | 
				
			||||||
 | 
					          v,
 | 
				
			||||||
 | 
					          r,
 | 
				
			||||||
 | 
					          s,
 | 
				
			||||||
 | 
					          txOptions
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const {
 | 
				
			||||||
 | 
					      reserveData: reserveDataAfter,
 | 
				
			||||||
 | 
					      userData: userDataAfter,
 | 
				
			||||||
 | 
					      timestamp,
 | 
				
			||||||
 | 
					    } = await getContractsData(reserve, onBehalfOf, testEnv, sender.address);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { txCost, txTimestamp } = await getTxCostAndTimestamp(txResult);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const expectedReserveData = calcExpectedReserveDataAfterDeposit(
 | 
				
			||||||
 | 
					      amountToDeposit.toString(),
 | 
				
			||||||
 | 
					      reserveDataBefore,
 | 
				
			||||||
 | 
					      txTimestamp
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const expectedUserReserveData = calcExpectedUserDataAfterDeposit(
 | 
				
			||||||
 | 
					      amountToDeposit.toString(),
 | 
				
			||||||
 | 
					      reserveDataBefore,
 | 
				
			||||||
 | 
					      expectedReserveData,
 | 
				
			||||||
 | 
					      userDataBefore,
 | 
				
			||||||
 | 
					      txTimestamp,
 | 
				
			||||||
 | 
					      timestamp,
 | 
				
			||||||
 | 
					      txCost
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expectEqual(reserveDataAfter, expectedReserveData);
 | 
				
			||||||
 | 
					    expectEqual(userDataAfter, expectedUserReserveData);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // truffleAssert.eventEmitted(txResult, "Deposit", (ev: any) => {
 | 
				
			||||||
 | 
					    //   const {_reserve, _user, _amount} = ev;
 | 
				
			||||||
 | 
					    //   return (
 | 
				
			||||||
 | 
					    //     _reserve === reserve &&
 | 
				
			||||||
 | 
					    //     _user === user &&
 | 
				
			||||||
 | 
					    //     new BigNumber(_amount).isEqualTo(new BigNumber(amountToDeposit))
 | 
				
			||||||
 | 
					    //   );
 | 
				
			||||||
 | 
					    // });
 | 
				
			||||||
 | 
					  } else if (expectedResult === 'revert') {
 | 
				
			||||||
 | 
					    await expect(
 | 
				
			||||||
 | 
					      pool
 | 
				
			||||||
 | 
					        .connect(sender.signer)
 | 
				
			||||||
 | 
					        .depositWithPermit(
 | 
				
			||||||
 | 
					          reserve,
 | 
				
			||||||
 | 
					          amountToDeposit,
 | 
				
			||||||
 | 
					          onBehalfOf,
 | 
				
			||||||
 | 
					          '0',
 | 
				
			||||||
 | 
					          highDeadline,
 | 
				
			||||||
 | 
					          v,
 | 
				
			||||||
 | 
					          r,
 | 
				
			||||||
 | 
					          s,
 | 
				
			||||||
 | 
					          txOptions
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      revertMessage
 | 
				
			||||||
 | 
					    ).to.be.reverted;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const repayWithPermit = async (
 | 
				
			||||||
 | 
					  reserveSymbol: string,
 | 
				
			||||||
 | 
					  amount: string,
 | 
				
			||||||
 | 
					  rateMode: string,
 | 
				
			||||||
 | 
					  user: SignerWithAddress,
 | 
				
			||||||
 | 
					  userPk: string,
 | 
				
			||||||
 | 
					  onBehalfOf: SignerWithAddress,
 | 
				
			||||||
 | 
					  sendValue: string,
 | 
				
			||||||
 | 
					  expectedResult: string,
 | 
				
			||||||
 | 
					  testEnv: TestEnv,
 | 
				
			||||||
 | 
					  revertMessage?: string
 | 
				
			||||||
 | 
					) => {
 | 
				
			||||||
 | 
					  const { pool } = testEnv;
 | 
				
			||||||
 | 
					  const reserve = await getReserveAddressFromSymbol(reserveSymbol);
 | 
				
			||||||
 | 
					  const highDeadline = '100000000000000000000000000';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const { reserveData: reserveDataBefore, userData: userDataBefore } = await getContractsData(
 | 
				
			||||||
 | 
					    reserve,
 | 
				
			||||||
 | 
					    onBehalfOf.address,
 | 
				
			||||||
 | 
					    testEnv
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let amountToRepay = '0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (amount !== '-1') {
 | 
				
			||||||
 | 
					    amountToRepay = (await convertToCurrencyDecimals(reserve, amount)).toString();
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    amountToRepay = MAX_UINT_AMOUNT;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  amountToRepay = '0x' + new BigNumber(amountToRepay).toString(16);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const chainId = await getChainId();
 | 
				
			||||||
 | 
					  const token = new MintableERC20Factory(user.signer).attach(reserve);
 | 
				
			||||||
 | 
					  const nonce = await token._nonces(user.address);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const msgParams = buildPermitParams(
 | 
				
			||||||
 | 
					    chainId,
 | 
				
			||||||
 | 
					    reserve,
 | 
				
			||||||
 | 
					    '1',
 | 
				
			||||||
 | 
					    reserveSymbol,
 | 
				
			||||||
 | 
					    user.address,
 | 
				
			||||||
 | 
					    pool.address,
 | 
				
			||||||
 | 
					    nonce.toNumber(),
 | 
				
			||||||
 | 
					    highDeadline,
 | 
				
			||||||
 | 
					    amountToRepay
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					  const { v, r, s } = getSignatureFromTypedData(userPk, msgParams);
 | 
				
			||||||
 | 
					  const txOptions: any = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (sendValue) {
 | 
				
			||||||
 | 
					    const valueToSend = await convertToCurrencyDecimals(reserve, sendValue);
 | 
				
			||||||
 | 
					    txOptions.value = '0x' + new BigNumber(valueToSend.toString()).toString(16);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (expectedResult === 'success') {
 | 
				
			||||||
 | 
					    const txResult = await waitForTx(
 | 
				
			||||||
 | 
					      await pool
 | 
				
			||||||
 | 
					        .connect(user.signer)
 | 
				
			||||||
 | 
					        .repayWithPermit(
 | 
				
			||||||
 | 
					          reserve,
 | 
				
			||||||
 | 
					          amountToRepay,
 | 
				
			||||||
 | 
					          rateMode,
 | 
				
			||||||
 | 
					          onBehalfOf.address,
 | 
				
			||||||
 | 
					          highDeadline,
 | 
				
			||||||
 | 
					          v,
 | 
				
			||||||
 | 
					          r,
 | 
				
			||||||
 | 
					          s,
 | 
				
			||||||
 | 
					          txOptions
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { txCost, txTimestamp } = await getTxCostAndTimestamp(txResult);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const {
 | 
				
			||||||
 | 
					      reserveData: reserveDataAfter,
 | 
				
			||||||
 | 
					      userData: userDataAfter,
 | 
				
			||||||
 | 
					      timestamp,
 | 
				
			||||||
 | 
					    } = await getContractsData(reserve, onBehalfOf.address, testEnv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const expectedReserveData = calcExpectedReserveDataAfterRepay(
 | 
				
			||||||
 | 
					      amountToRepay,
 | 
				
			||||||
 | 
					      <RateMode>rateMode,
 | 
				
			||||||
 | 
					      reserveDataBefore,
 | 
				
			||||||
 | 
					      userDataBefore,
 | 
				
			||||||
 | 
					      txTimestamp,
 | 
				
			||||||
 | 
					      timestamp
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const expectedUserData = calcExpectedUserDataAfterRepay(
 | 
				
			||||||
 | 
					      amountToRepay,
 | 
				
			||||||
 | 
					      <RateMode>rateMode,
 | 
				
			||||||
 | 
					      reserveDataBefore,
 | 
				
			||||||
 | 
					      expectedReserveData,
 | 
				
			||||||
 | 
					      userDataBefore,
 | 
				
			||||||
 | 
					      user.address,
 | 
				
			||||||
 | 
					      onBehalfOf.address,
 | 
				
			||||||
 | 
					      txTimestamp,
 | 
				
			||||||
 | 
					      timestamp
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expectEqual(reserveDataAfter, expectedReserveData);
 | 
				
			||||||
 | 
					    expectEqual(userDataAfter, expectedUserData);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // truffleAssert.eventEmitted(txResult, "Repay", (ev: any) => {
 | 
				
			||||||
 | 
					    //   const {_reserve, _user, _repayer} = ev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //   return (
 | 
				
			||||||
 | 
					    //     _reserve.toLowerCase() === reserve.toLowerCase() &&
 | 
				
			||||||
 | 
					    //     _user.toLowerCase() === onBehalfOf.toLowerCase() &&
 | 
				
			||||||
 | 
					    //     _repayer.toLowerCase() === user.toLowerCase()
 | 
				
			||||||
 | 
					    //   );
 | 
				
			||||||
 | 
					    // });
 | 
				
			||||||
 | 
					  } else if (expectedResult === 'revert') {
 | 
				
			||||||
 | 
					    await expect(
 | 
				
			||||||
 | 
					      pool
 | 
				
			||||||
 | 
					        .connect(user.signer)
 | 
				
			||||||
 | 
					        .repayWithPermit(
 | 
				
			||||||
 | 
					          reserve,
 | 
				
			||||||
 | 
					          amountToRepay,
 | 
				
			||||||
 | 
					          rateMode,
 | 
				
			||||||
 | 
					          onBehalfOf.address,
 | 
				
			||||||
 | 
					          highDeadline,
 | 
				
			||||||
 | 
					          v,
 | 
				
			||||||
 | 
					          r,
 | 
				
			||||||
 | 
					          s,
 | 
				
			||||||
 | 
					          txOptions
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      revertMessage
 | 
				
			||||||
 | 
					    ).to.be.reverted;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const setUseAsCollateral = async (
 | 
					export const setUseAsCollateral = async (
 | 
				
			||||||
  reserveSymbol: string,
 | 
					  reserveSymbol: string,
 | 
				
			||||||
  user: SignerWithAddress,
 | 
					  user: SignerWithAddress,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,8 +10,11 @@ import {
 | 
				
			||||||
  swapBorrowRateMode,
 | 
					  swapBorrowRateMode,
 | 
				
			||||||
  rebalanceStableBorrowRate,
 | 
					  rebalanceStableBorrowRate,
 | 
				
			||||||
  delegateBorrowAllowance,
 | 
					  delegateBorrowAllowance,
 | 
				
			||||||
 | 
					  repayWithPermit,
 | 
				
			||||||
 | 
					  depositWithPermit,
 | 
				
			||||||
} from './actions';
 | 
					} from './actions';
 | 
				
			||||||
import { RateMode } from '../../../helpers/types';
 | 
					import { RateMode } from '../../../helpers/types';
 | 
				
			||||||
 | 
					import { Wallet } from '@ethersproject/wallet';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface Action {
 | 
					export interface Action {
 | 
				
			||||||
  name: string;
 | 
					  name: string;
 | 
				
			||||||
| 
						 | 
					@ -73,6 +76,12 @@ const executeAction = async (action: Action, users: SignerWithAddress[], testEnv
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const user = users[parseInt(userIndex)];
 | 
					  const user = users[parseInt(userIndex)];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const userPrivateKey = require('../../../test-wallets.js').accounts[parseInt(userIndex) + 1]
 | 
				
			||||||
 | 
					    .secretKey;
 | 
				
			||||||
 | 
					  if (!userPrivateKey) {
 | 
				
			||||||
 | 
					    throw new Error('INVALID_OWNER_PK');
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  switch (name) {
 | 
					  switch (name) {
 | 
				
			||||||
    case 'mint':
 | 
					    case 'mint':
 | 
				
			||||||
      const { amount } = action.args;
 | 
					      const { amount } = action.args;
 | 
				
			||||||
| 
						 | 
					@ -111,6 +120,30 @@ const executeAction = async (action: Action, users: SignerWithAddress[], testEnv
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
 | 
					    case 'depositWithPermit':
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        const { amount, sendValue, onBehalfOf: onBehalfOfIndex } = action.args;
 | 
				
			||||||
 | 
					        const onBehalfOf = onBehalfOfIndex
 | 
				
			||||||
 | 
					          ? users[parseInt(onBehalfOfIndex)].address
 | 
				
			||||||
 | 
					          : user.address;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!amount || amount === '') {
 | 
				
			||||||
 | 
					          throw `Invalid amount to deposit into the ${reserve} reserve`;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        await depositWithPermit(
 | 
				
			||||||
 | 
					          reserve,
 | 
				
			||||||
 | 
					          amount,
 | 
				
			||||||
 | 
					          user,
 | 
				
			||||||
 | 
					          userPrivateKey,
 | 
				
			||||||
 | 
					          onBehalfOf,
 | 
				
			||||||
 | 
					          sendValue,
 | 
				
			||||||
 | 
					          expected,
 | 
				
			||||||
 | 
					          testEnv,
 | 
				
			||||||
 | 
					          revertMessage
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case 'delegateBorrowAllowance':
 | 
					    case 'delegateBorrowAllowance':
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
| 
						 | 
					@ -203,6 +236,40 @@ const executeAction = async (action: Action, users: SignerWithAddress[], testEnv
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case 'repayWithPermit':
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        const { amount, borrowRateMode, sendValue, deadline } = action.args;
 | 
				
			||||||
 | 
					        let { onBehalfOf: onBehalfOfIndex } = action.args;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!amount || amount === '') {
 | 
				
			||||||
 | 
					          throw `Invalid amount to repay into the ${reserve} reserve`;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let userToRepayOnBehalf: SignerWithAddress;
 | 
				
			||||||
 | 
					        if (!onBehalfOfIndex || onBehalfOfIndex === '') {
 | 
				
			||||||
 | 
					          console.log(
 | 
				
			||||||
 | 
					            'WARNING: No onBehalfOf specified for a repay action. Defaulting to the repayer address'
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					          userToRepayOnBehalf = user;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          userToRepayOnBehalf = users[parseInt(onBehalfOfIndex)];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        await repayWithPermit(
 | 
				
			||||||
 | 
					          reserve,
 | 
				
			||||||
 | 
					          amount,
 | 
				
			||||||
 | 
					          rateMode,
 | 
				
			||||||
 | 
					          user,
 | 
				
			||||||
 | 
					          userPrivateKey,
 | 
				
			||||||
 | 
					          userToRepayOnBehalf,
 | 
				
			||||||
 | 
					          sendValue,
 | 
				
			||||||
 | 
					          expected,
 | 
				
			||||||
 | 
					          testEnv,
 | 
				
			||||||
 | 
					          revertMessage
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case 'setUseAsCollateral':
 | 
					    case 'setUseAsCollateral':
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        const { useAsCollateral } = action.args;
 | 
					        const { useAsCollateral } = action.args;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,191 @@
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  "title": "LendingPool: Borrow/repay with permit with Permit (variable rate)",
 | 
				
			||||||
 | 
					  "description": "Test cases for the borrow function, variable mode.",
 | 
				
			||||||
 | 
					  "stories": [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "description": "User 2 deposits with permit 1 DAI to account for rounding errors",
 | 
				
			||||||
 | 
					      "actions": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "mint",
 | 
				
			||||||
 | 
					          "args": {
 | 
				
			||||||
 | 
					            "reserve": "DAI",
 | 
				
			||||||
 | 
					            "amount": "1",
 | 
				
			||||||
 | 
					            "user": "2"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "expected": "success"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "depositWithPermit",
 | 
				
			||||||
 | 
					          "args": {
 | 
				
			||||||
 | 
					            "reserve": "DAI",
 | 
				
			||||||
 | 
					            "amount": "1",
 | 
				
			||||||
 | 
					            "user": "2"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "expected": "success"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "description": "User 0 deposits with permit 1000 DAI, user 1 deposits 1 WETH as collateral and borrows 100 DAI at variable rate",
 | 
				
			||||||
 | 
					      "actions": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "mint",
 | 
				
			||||||
 | 
					          "args": {
 | 
				
			||||||
 | 
					            "reserve": "DAI",
 | 
				
			||||||
 | 
					            "amount": "1000",
 | 
				
			||||||
 | 
					            "user": "0"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "expected": "success"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "depositWithPermit",
 | 
				
			||||||
 | 
					          "args": {
 | 
				
			||||||
 | 
					            "reserve": "DAI",
 | 
				
			||||||
 | 
					            "amount": "1000",
 | 
				
			||||||
 | 
					            "user": "0"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "expected": "success"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "mint",
 | 
				
			||||||
 | 
					          "args": {
 | 
				
			||||||
 | 
					            "reserve": "WETH",
 | 
				
			||||||
 | 
					            "amount": "1",
 | 
				
			||||||
 | 
					            "user": "1"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "expected": "success"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "approve",
 | 
				
			||||||
 | 
					          "args": {
 | 
				
			||||||
 | 
					            "reserve": "WETH",
 | 
				
			||||||
 | 
					            "user": "1"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "expected": "success"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "deposit",
 | 
				
			||||||
 | 
					          "args": {
 | 
				
			||||||
 | 
					            "reserve": "WETH",
 | 
				
			||||||
 | 
					            "amount": "1",
 | 
				
			||||||
 | 
					            "user": "1"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "expected": "success"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "borrow",
 | 
				
			||||||
 | 
					          "args": {
 | 
				
			||||||
 | 
					            "reserve": "DAI",
 | 
				
			||||||
 | 
					            "amount": "100",
 | 
				
			||||||
 | 
					            "borrowRateMode": "variable",
 | 
				
			||||||
 | 
					            "user": "1",
 | 
				
			||||||
 | 
					            "timeTravel": "365"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "expected": "success"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "description": "User 1 tries to borrow the rest of the DAI liquidity (revert expected)",
 | 
				
			||||||
 | 
					      "actions": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "borrow",
 | 
				
			||||||
 | 
					          "args": {
 | 
				
			||||||
 | 
					            "reserve": "DAI",
 | 
				
			||||||
 | 
					            "amount": "900",
 | 
				
			||||||
 | 
					            "borrowRateMode": "variable",
 | 
				
			||||||
 | 
					            "user": "1"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "expected": "revert",
 | 
				
			||||||
 | 
					          "revertMessage": "There is not enough collateral to cover a new borrow"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "description": "User 1 tries to repay with permit 0 DAI (revert expected)",
 | 
				
			||||||
 | 
					      "actions": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "repayWithPermit",
 | 
				
			||||||
 | 
					          "args": {
 | 
				
			||||||
 | 
					            "reserve": "DAI",
 | 
				
			||||||
 | 
					            "amount": "0",
 | 
				
			||||||
 | 
					            "user": "1",
 | 
				
			||||||
 | 
					            "onBehalfOf": "1"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "expected": "revert",
 | 
				
			||||||
 | 
					          "revertMessage": "Amount must be greater than 0"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "description": "User 1 repays with permit a small amount of DAI, enough to cover a small part of the interest",
 | 
				
			||||||
 | 
					      "actions": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "repayWithPermit",
 | 
				
			||||||
 | 
					          "args": {
 | 
				
			||||||
 | 
					            "reserve": "DAI",
 | 
				
			||||||
 | 
					            "amount": "1.25",
 | 
				
			||||||
 | 
					            "user": "1",
 | 
				
			||||||
 | 
					            "onBehalfOf": "1",
 | 
				
			||||||
 | 
					            "borrowRateMode": "variable"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "expected": "success"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "description": "User 1 repays with permit the DAI borrow after one year",
 | 
				
			||||||
 | 
					      "actions": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "mint",
 | 
				
			||||||
 | 
					          "description": "Mint 10 DAI to cover the interest",
 | 
				
			||||||
 | 
					          "args": {
 | 
				
			||||||
 | 
					            "reserve": "DAI",
 | 
				
			||||||
 | 
					            "amount": "10",
 | 
				
			||||||
 | 
					            "user": "1"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "expected": "success"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "repayWithPermit",
 | 
				
			||||||
 | 
					          "args": {
 | 
				
			||||||
 | 
					            "reserve": "DAI",
 | 
				
			||||||
 | 
					            "amount": "-1",
 | 
				
			||||||
 | 
					            "user": "1",
 | 
				
			||||||
 | 
					            "onBehalfOf": "1",
 | 
				
			||||||
 | 
					            "borrowRateMode": "variable"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "expected": "success"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "description": "User 0 withdraws the deposited DAI plus interest",
 | 
				
			||||||
 | 
					      "actions": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "withdraw",
 | 
				
			||||||
 | 
					          "args": {
 | 
				
			||||||
 | 
					            "reserve": "DAI",
 | 
				
			||||||
 | 
					            "amount": "-1",
 | 
				
			||||||
 | 
					            "user": "0"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "expected": "success"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "description": "User 1 withdraws the collateral",
 | 
				
			||||||
 | 
					      "actions": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "withdraw",
 | 
				
			||||||
 | 
					          "args": {
 | 
				
			||||||
 | 
					            "reserve": "WETH",
 | 
				
			||||||
 | 
					            "amount": "-1",
 | 
				
			||||||
 | 
					            "user": "1"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "expected": "success"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user