mirror of
https://github.com/Instadapp/aave-protocol-v2.git
synced 2024-07-29 21:47:30 +00:00
- Added permit() to aToken.
This commit is contained in:
parent
f3856bac12
commit
748312cf20
|
@ -2,13 +2,13 @@ import {usePlugin, BuidlerConfig} from '@nomiclabs/buidler/config';
|
|||
// @ts-ignore
|
||||
import {accounts} from './test-wallets.js';
|
||||
import {eEthereumNetwork} from './helpers/types';
|
||||
import { BUIDLEREVM_CHAINID, COVERAGE_CHAINID } from './helpers/constants';
|
||||
|
||||
usePlugin('@nomiclabs/buidler-ethers');
|
||||
usePlugin('buidler-typechain');
|
||||
usePlugin('solidity-coverage');
|
||||
usePlugin('@nomiclabs/buidler-waffle');
|
||||
usePlugin('@nomiclabs/buidler-etherscan');
|
||||
usePlugin('buidler-gas-reporter');
|
||||
|
||||
const DEFAULT_BLOCK_GAS_LIMIT = 10000000;
|
||||
const DEFAULT_GAS_PRICE = 10;
|
||||
|
@ -59,6 +59,7 @@ const config: any = {
|
|||
networks: {
|
||||
coverage: {
|
||||
url: 'http://localhost:8555',
|
||||
chainId: COVERAGE_CHAINID,
|
||||
},
|
||||
kovan: getCommonNetworkConfig(eEthereumNetwork.kovan, 42),
|
||||
ropsten: getCommonNetworkConfig(eEthereumNetwork.ropsten, 3),
|
||||
|
@ -68,7 +69,7 @@ const config: any = {
|
|||
blockGasLimit: DEFAULT_BLOCK_GAS_LIMIT,
|
||||
gas: DEFAULT_BLOCK_GAS_LIMIT,
|
||||
gasPrice: 8000000000,
|
||||
chainId: 31337,
|
||||
chainId: BUIDLEREVM_CHAINID,
|
||||
throwOnTransactionFailures: true,
|
||||
throwOnCallFailures: true,
|
||||
accounts: accounts.map(({secretKey, balance}: {secretKey: string; balance: string}) => ({
|
||||
|
|
|
@ -29,8 +29,15 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
|
|||
|
||||
mapping(address => uint256) private _scaledRedirectedBalances;
|
||||
|
||||
/// @dev owner => next valid nonce to submit with permit()
|
||||
mapping (address => uint256) public _nonces;
|
||||
|
||||
uint256 public constant ATOKEN_REVISION = 0x1;
|
||||
|
||||
bytes32 public DOMAIN_SEPARATOR;
|
||||
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)");
|
||||
|
||||
modifier onlyLendingPool {
|
||||
require(msg.sender == address(POOL), Errors.CALLER_MUST_BE_LENDING_POOL);
|
||||
|
@ -56,6 +63,21 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
|
|||
string calldata tokenName,
|
||||
string calldata tokenSymbol
|
||||
) external virtual initializer {
|
||||
uint256 chainId;
|
||||
|
||||
//solium-disable-next-line
|
||||
assembly {
|
||||
chainId := chainid()
|
||||
}
|
||||
|
||||
DOMAIN_SEPARATOR = keccak256(abi.encode(
|
||||
EIP712_DOMAIN,
|
||||
keccak256(bytes(tokenName)),
|
||||
keccak256(EIP712_REVISION),
|
||||
chainId,
|
||||
address(this)
|
||||
));
|
||||
|
||||
_setName(tokenName);
|
||||
_setSymbol(tokenSymbol);
|
||||
_setDecimals(underlyingAssetDecimals);
|
||||
|
@ -187,6 +209,42 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
|
|||
return amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev implements the permit function as for https://github.com/ethereum/EIPs/blob/8a34d644aacf0f9f8f00815307fd7dd5da07655f/EIPS/eip-2612.md
|
||||
* @param owner the owner of the funds
|
||||
* @param spender the spender
|
||||
* @param value the amount
|
||||
* @param deadline the deadline timestamp, 0 for no deadline
|
||||
* @param v signature param
|
||||
* @param s signature param
|
||||
* @param r signature param
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
function _transfer(
|
||||
address from,
|
||||
address to,
|
||||
|
|
|
@ -8,12 +8,16 @@ import {
|
|||
IReserveParams,
|
||||
tEthereumAddress,
|
||||
iBasicDistributionParams,
|
||||
eEthereumNetwork,
|
||||
} from './types';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import {getParamPerPool} from './contracts-helpers';
|
||||
import {getParamPerPool, getParamPerNetwork} from './contracts-helpers';
|
||||
|
||||
export const TEST_SNAPSHOT_ID = '0x1';
|
||||
|
||||
export const BUIDLEREVM_CHAINID = 31337;
|
||||
export const COVERAGE_CHAINID = 1337;
|
||||
|
||||
// ----------------
|
||||
// MATH
|
||||
// ----------------
|
||||
|
@ -531,3 +535,18 @@ export const getFeeDistributionParamsCommon = (
|
|||
percentages,
|
||||
};
|
||||
};
|
||||
|
||||
export const getATokenDomainSeparatorPerNetwork = (
|
||||
network: eEthereumNetwork
|
||||
): tEthereumAddress =>
|
||||
getParamPerNetwork<tEthereumAddress>(
|
||||
{
|
||||
[eEthereumNetwork.coverage]: "0x95b73a72c6ecf4ccbbba5178800023260bad8e75cdccdb8e4827a2977a37c820",
|
||||
[eEthereumNetwork.buidlerevm]:
|
||||
"0x76cbbf8aa4b11a7c207dd79ccf8c394f59475301598c9a083f8258b4fafcfa86",
|
||||
[eEthereumNetwork.kovan]: "",
|
||||
[eEthereumNetwork.ropsten]: "",
|
||||
[eEthereumNetwork.main]: "",
|
||||
},
|
||||
network
|
||||
);
|
|
@ -32,6 +32,8 @@ import {Ierc20Detailed} from '../types/Ierc20Detailed';
|
|||
import {StableDebtToken} from '../types/StableDebtToken';
|
||||
import {VariableDebtToken} from '../types/VariableDebtToken';
|
||||
import {MockSwapAdapter} from '../types/MockSwapAdapter';
|
||||
import { signTypedData_v4, TypedData } from "eth-sig-util";
|
||||
import { fromRpcSig, ECDSASignature } from "ethereumjs-util";
|
||||
|
||||
export const registerContractInJsonDb = async (contractId: string, contractInstance: Contract) => {
|
||||
const currentNetwork = BRE.network.name;
|
||||
|
@ -431,10 +433,14 @@ const linkBytecode = (artifact: Artifact, libraries: any) => {
|
|||
};
|
||||
|
||||
export const getParamPerNetwork = <T>(
|
||||
{kovan, ropsten, main}: iParamsPerNetwork<T>,
|
||||
{kovan, ropsten, main, buidlerevm, coverage}: iParamsPerNetwork<T>,
|
||||
network: eEthereumNetwork
|
||||
) => {
|
||||
switch (network) {
|
||||
case eEthereumNetwork.coverage:
|
||||
return coverage;
|
||||
case eEthereumNetwork.buidlerevm:
|
||||
return buidlerevm;
|
||||
case eEthereumNetwork.kovan:
|
||||
return kovan;
|
||||
case eEthereumNetwork.ropsten:
|
||||
|
@ -471,3 +477,59 @@ export const convertToCurrencyUnits = async (tokenAddress: string, amount: strin
|
|||
const amountInCurrencyUnits = new BigNumber(amount).div(currencyUnit);
|
||||
return amountInCurrencyUnits.toFixed();
|
||||
};
|
||||
|
||||
export const buildPermitParams = (
|
||||
chainId: number,
|
||||
token: tEthereumAddress,
|
||||
revision: string,
|
||||
tokenName: string,
|
||||
owner: tEthereumAddress,
|
||||
spender: tEthereumAddress,
|
||||
nonce: number,
|
||||
deadline: string,
|
||||
value: tStringTokenSmallUnits
|
||||
) => ({
|
||||
types: {
|
||||
EIP712Domain: [
|
||||
{ name: "name", type: "string" },
|
||||
{ name: "version", type: "string" },
|
||||
{ name: "chainId", type: "uint256" },
|
||||
{ name: "verifyingContract", type: "address" },
|
||||
],
|
||||
Permit: [
|
||||
{ name: "owner", type: "address" },
|
||||
{ name: "spender", type: "address" },
|
||||
{ name: "value", type: "uint256" },
|
||||
{ name: "nonce", type: "uint256" },
|
||||
{ name: "deadline", type: "uint256" },
|
||||
],
|
||||
},
|
||||
primaryType: "Permit" as const,
|
||||
domain: {
|
||||
name: tokenName,
|
||||
version: revision,
|
||||
chainId: chainId,
|
||||
verifyingContract: token,
|
||||
},
|
||||
message: {
|
||||
owner,
|
||||
spender,
|
||||
value,
|
||||
nonce,
|
||||
deadline,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
export const getSignatureFromTypedData = (
|
||||
privateKey: string,
|
||||
typedData: any // TODO: should be TypedData, from eth-sig-utils, but TS doesn't accept it
|
||||
): ECDSASignature => {
|
||||
const signature = signTypedData_v4(
|
||||
Buffer.from(privateKey.substring(2, 66), "hex"),
|
||||
{
|
||||
data: typedData,
|
||||
}
|
||||
);
|
||||
return fromRpcSig(signature);
|
||||
};
|
|
@ -5,6 +5,7 @@ export enum eEthereumNetwork {
|
|||
kovan = 'kovan',
|
||||
ropsten = 'ropsten',
|
||||
main = 'main',
|
||||
coverage = 'coverage'
|
||||
}
|
||||
|
||||
export enum AavePools {
|
||||
|
@ -251,6 +252,8 @@ export interface IMarketRates {
|
|||
}
|
||||
|
||||
export interface iParamsPerNetwork<T> {
|
||||
[eEthereumNetwork.coverage]: T;
|
||||
[eEthereumNetwork.buidlerevm]: T;
|
||||
[eEthereumNetwork.kovan]: T;
|
||||
[eEthereumNetwork.ropsten]: T;
|
||||
[eEthereumNetwork.main]: T;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
"test-repay-with-collateral": "buidler test test/__setup.spec.ts test/repay-with-collateral.spec.ts",
|
||||
"test-liquidate-with-collateral": "buidler test test/__setup.spec.ts test/flash-liquidation-with-collateral.spec.ts",
|
||||
"test-flash": "buidler test test/__setup.spec.ts test/flashloan.spec.ts",
|
||||
"test-permit": "buidler test test/__setup.spec.ts test/atoken-permit.spec.ts",
|
||||
"dev:coverage": "buidler coverage --network coverage",
|
||||
"dev:deployment": "buidler dev-deployment",
|
||||
"dev:deployExample": "buidler deploy-Example",
|
||||
|
@ -58,7 +59,9 @@
|
|||
"tslint-config-prettier": "^1.18.0",
|
||||
"tslint-plugin-prettier": "^2.3.0",
|
||||
"typechain": "2.0.0",
|
||||
"typescript": "3.9.3"
|
||||
"typescript": "3.9.3",
|
||||
"eth-sig-util": "2.5.3",
|
||||
"ethereumjs-util": "7.0.2"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
|
|
312
test/atoken-permit.spec.ts
Normal file
312
test/atoken-permit.spec.ts
Normal file
|
@ -0,0 +1,312 @@
|
|||
import {
|
||||
MAX_UINT_AMOUNT,
|
||||
ZERO_ADDRESS,
|
||||
getATokenDomainSeparatorPerNetwork,
|
||||
BUIDLEREVM_CHAINID,
|
||||
} from '../helpers/constants';
|
||||
import {buildPermitParams, getSignatureFromTypedData} from '../helpers/contracts-helpers';
|
||||
import {expect} from 'chai';
|
||||
import {ethers} from 'ethers';
|
||||
import {eEthereumNetwork} from '../helpers/types';
|
||||
import {makeSuite, TestEnv} from './helpers/make-suite';
|
||||
import {BRE} from '../helpers/misc-utils';
|
||||
import {waitForTx} from './__setup.spec';
|
||||
|
||||
const {parseEther} = ethers.utils;
|
||||
|
||||
makeSuite('AToken: Permit', (testEnv: TestEnv) => {
|
||||
it('Checks the domain separator', async () => {
|
||||
const DOMAIN_SEPARATOR_ENCODED = getATokenDomainSeparatorPerNetwork(
|
||||
eEthereumNetwork.buidlerevm
|
||||
);
|
||||
|
||||
const {aDai} = testEnv;
|
||||
|
||||
const separator = await aDai.DOMAIN_SEPARATOR();
|
||||
|
||||
expect(separator).to.be.equal(DOMAIN_SEPARATOR_ENCODED, 'Invalid domain separator');
|
||||
});
|
||||
|
||||
it('Get aDAI for tests', async () => {
|
||||
const {dai, deployer, pool} = testEnv;
|
||||
|
||||
await dai.mint(parseEther('20000'));
|
||||
await dai.approve(pool.address, parseEther('20000'));
|
||||
await pool.deposit(dai.address, parseEther('20000'), deployer.address, 0);
|
||||
});
|
||||
|
||||
it('Reverts submitting a permit with 0 expiration', async () => {
|
||||
const {aDai, deployer, users} = testEnv;
|
||||
const owner = deployer;
|
||||
const spender = users[1];
|
||||
|
||||
const tokenName = await aDai.name();
|
||||
|
||||
const chainId = BRE.network.config.chainId || BUIDLEREVM_CHAINID;
|
||||
const expiration = 0;
|
||||
const nonce = (await aDai._nonces(owner.address)).toNumber();
|
||||
const permitAmount = ethers.utils.parseEther('2').toString();
|
||||
const msgParams = buildPermitParams(
|
||||
chainId,
|
||||
aDai.address,
|
||||
'1',
|
||||
tokenName,
|
||||
owner.address,
|
||||
spender.address,
|
||||
nonce,
|
||||
permitAmount,
|
||||
expiration.toFixed()
|
||||
);
|
||||
|
||||
const ownerPrivateKey = require('../test-wallets.js').accounts[0].secretKey;
|
||||
if (!ownerPrivateKey) {
|
||||
throw new Error('INVALID_OWNER_PK');
|
||||
}
|
||||
|
||||
expect((await aDai.allowance(owner.address, spender.address)).toString()).to.be.equal(
|
||||
'0',
|
||||
'INVALID_ALLOWANCE_BEFORE_PERMIT'
|
||||
);
|
||||
|
||||
const {v, r, s} = getSignatureFromTypedData(ownerPrivateKey, msgParams);
|
||||
|
||||
await expect(
|
||||
aDai
|
||||
.connect(spender.signer)
|
||||
.permit(owner.address, spender.address, permitAmount, expiration, v, r, s)
|
||||
).to.be.revertedWith('INVALID_EXPIRATION');
|
||||
|
||||
expect((await aDai.allowance(owner.address, spender.address)).toString()).to.be.equal(
|
||||
'0',
|
||||
'INVALID_ALLOWANCE_AFTER_PERMIT'
|
||||
);
|
||||
});
|
||||
|
||||
it('Submits a permit with maximum expiration length', async () => {
|
||||
const {aDai, deployer, users} = testEnv;
|
||||
const owner = deployer;
|
||||
const spender = users[1];
|
||||
|
||||
const chainId = BRE.network.config.chainId || BUIDLEREVM_CHAINID;
|
||||
const deadline = MAX_UINT_AMOUNT;
|
||||
const nonce = (await aDai._nonces(owner.address)).toNumber();
|
||||
const permitAmount = parseEther('2').toString();
|
||||
const msgParams = buildPermitParams(
|
||||
chainId,
|
||||
aDai.address,
|
||||
'1',
|
||||
await aDai.name(),
|
||||
owner.address,
|
||||
spender.address,
|
||||
nonce,
|
||||
deadline,
|
||||
permitAmount
|
||||
);
|
||||
|
||||
const ownerPrivateKey = require('../test-wallets.js').accounts[0].secretKey;
|
||||
if (!ownerPrivateKey) {
|
||||
throw new Error('INVALID_OWNER_PK');
|
||||
}
|
||||
|
||||
expect((await aDai.allowance(owner.address, spender.address)).toString()).to.be.equal(
|
||||
'0',
|
||||
'INVALID_ALLOWANCE_BEFORE_PERMIT'
|
||||
);
|
||||
|
||||
const {v, r, s} = getSignatureFromTypedData(ownerPrivateKey, msgParams);
|
||||
|
||||
await waitForTx(
|
||||
await aDai
|
||||
.connect(spender.signer)
|
||||
.permit(owner.address, spender.address, permitAmount, deadline, v, r, s)
|
||||
);
|
||||
|
||||
expect((await aDai._nonces(owner.address)).toNumber()).to.be.equal(1);
|
||||
});
|
||||
|
||||
it('Cancels the previous permit', async () => {
|
||||
const {aDai, deployer, users} = testEnv;
|
||||
const owner = deployer;
|
||||
const spender = users[1];
|
||||
|
||||
const chainId = BRE.network.config.chainId || BUIDLEREVM_CHAINID;
|
||||
const deadline = MAX_UINT_AMOUNT;
|
||||
const nonce = (await aDai._nonces(owner.address)).toNumber();
|
||||
const permitAmount = '0';
|
||||
const msgParams = buildPermitParams(
|
||||
chainId,
|
||||
aDai.address,
|
||||
'1',
|
||||
await aDai.name(),
|
||||
owner.address,
|
||||
spender.address,
|
||||
nonce,
|
||||
deadline,
|
||||
permitAmount
|
||||
);
|
||||
|
||||
const ownerPrivateKey = require('../test-wallets.js').accounts[0].secretKey;
|
||||
if (!ownerPrivateKey) {
|
||||
throw new Error('INVALID_OWNER_PK');
|
||||
}
|
||||
|
||||
const {v, r, s} = getSignatureFromTypedData(ownerPrivateKey, msgParams);
|
||||
|
||||
expect((await aDai.allowance(owner.address, spender.address)).toString()).to.be.equal(
|
||||
ethers.utils.parseEther('2'),
|
||||
'INVALID_ALLOWANCE_BEFORE_PERMIT'
|
||||
);
|
||||
|
||||
await waitForTx(
|
||||
await aDai
|
||||
.connect(spender.signer)
|
||||
.permit(owner.address, spender.address, permitAmount, deadline, v, r, s)
|
||||
);
|
||||
expect((await aDai.allowance(owner.address, spender.address)).toString()).to.be.equal(
|
||||
permitAmount,
|
||||
'INVALID_ALLOWANCE_AFTER_PERMIT'
|
||||
);
|
||||
|
||||
expect((await aDai._nonces(owner.address)).toNumber()).to.be.equal(2);
|
||||
});
|
||||
|
||||
it('Tries to submit a permit with invalid nonce', async () => {
|
||||
const {aDai, deployer, users} = testEnv;
|
||||
const owner = deployer;
|
||||
const spender = users[1];
|
||||
|
||||
const chainId = BRE.network.config.chainId || BUIDLEREVM_CHAINID;
|
||||
const deadline = MAX_UINT_AMOUNT;
|
||||
const nonce = 1000;
|
||||
const permitAmount = '0';
|
||||
const msgParams = buildPermitParams(
|
||||
chainId,
|
||||
aDai.address,
|
||||
'1',
|
||||
await aDai.name(),
|
||||
owner.address,
|
||||
spender.address,
|
||||
nonce,
|
||||
deadline,
|
||||
permitAmount
|
||||
);
|
||||
|
||||
const ownerPrivateKey = require('../test-wallets.js').accounts[0].secretKey;
|
||||
if (!ownerPrivateKey) {
|
||||
throw new Error('INVALID_OWNER_PK');
|
||||
}
|
||||
|
||||
const {v, r, s} = getSignatureFromTypedData(ownerPrivateKey, msgParams);
|
||||
|
||||
await expect(
|
||||
aDai
|
||||
.connect(spender.signer)
|
||||
.permit(owner.address, spender.address, permitAmount, deadline, v, r, s)
|
||||
).to.be.revertedWith('INVALID_SIGNATURE');
|
||||
});
|
||||
|
||||
it('Tries to submit a permit with invalid expiration (previous to the current block)', async () => {
|
||||
const {aDai, deployer, users} = testEnv;
|
||||
const owner = deployer;
|
||||
const spender = users[1];
|
||||
|
||||
const chainId = BRE.network.config.chainId || BUIDLEREVM_CHAINID;
|
||||
const expiration = '1';
|
||||
const nonce = (await aDai._nonces(owner.address)).toNumber();
|
||||
const permitAmount = '0';
|
||||
const msgParams = buildPermitParams(
|
||||
chainId,
|
||||
aDai.address,
|
||||
'1',
|
||||
await aDai.name(),
|
||||
owner.address,
|
||||
spender.address,
|
||||
nonce,
|
||||
expiration,
|
||||
permitAmount
|
||||
);
|
||||
|
||||
const ownerPrivateKey = require('../test-wallets.js').accounts[0].secretKey;
|
||||
if (!ownerPrivateKey) {
|
||||
throw new Error('INVALID_OWNER_PK');
|
||||
}
|
||||
|
||||
const {v, r, s} = getSignatureFromTypedData(ownerPrivateKey, msgParams);
|
||||
|
||||
await expect(
|
||||
aDai
|
||||
.connect(spender.signer)
|
||||
.permit(owner.address, spender.address, expiration, permitAmount, v, r, s)
|
||||
).to.be.revertedWith('INVALID_EXPIRATION');
|
||||
});
|
||||
|
||||
it('Tries to submit a permit with invalid signature', async () => {
|
||||
const {aDai, deployer, users} = testEnv;
|
||||
const owner = deployer;
|
||||
const spender = users[1];
|
||||
|
||||
const chainId = BRE.network.config.chainId || BUIDLEREVM_CHAINID;
|
||||
const deadline = MAX_UINT_AMOUNT;
|
||||
const nonce = (await aDai._nonces(owner.address)).toNumber();
|
||||
const permitAmount = '0';
|
||||
const msgParams = buildPermitParams(
|
||||
chainId,
|
||||
aDai.address,
|
||||
'1',
|
||||
await aDai.name(),
|
||||
owner.address,
|
||||
spender.address,
|
||||
nonce,
|
||||
deadline,
|
||||
permitAmount
|
||||
);
|
||||
|
||||
const ownerPrivateKey = require('../test-wallets.js').accounts[0].secretKey;
|
||||
if (!ownerPrivateKey) {
|
||||
throw new Error('INVALID_OWNER_PK');
|
||||
}
|
||||
|
||||
const {v, r, s} = getSignatureFromTypedData(ownerPrivateKey, msgParams);
|
||||
|
||||
await expect(
|
||||
aDai
|
||||
.connect(spender.signer)
|
||||
.permit(owner.address, ZERO_ADDRESS, permitAmount, deadline, v, r, s)
|
||||
).to.be.revertedWith('INVALID_SIGNATURE');
|
||||
});
|
||||
|
||||
it('Tries to submit a permit with invalid owner', async () => {
|
||||
const {aDai, deployer, users} = testEnv;
|
||||
const owner = deployer;
|
||||
const spender = users[1];
|
||||
|
||||
const chainId = BRE.network.config.chainId || BUIDLEREVM_CHAINID;
|
||||
const expiration = MAX_UINT_AMOUNT;
|
||||
const nonce = (await aDai._nonces(owner.address)).toNumber();
|
||||
const permitAmount = '0';
|
||||
const msgParams = buildPermitParams(
|
||||
chainId,
|
||||
aDai.address,
|
||||
'1',
|
||||
await aDai.name(),
|
||||
owner.address,
|
||||
spender.address,
|
||||
nonce,
|
||||
expiration,
|
||||
permitAmount
|
||||
);
|
||||
|
||||
const ownerPrivateKey = require('../test-wallets.js').accounts[0].secretKey;
|
||||
if (!ownerPrivateKey) {
|
||||
throw new Error('INVALID_OWNER_PK');
|
||||
}
|
||||
|
||||
const {v, r, s} = getSignatureFromTypedData(ownerPrivateKey, msgParams);
|
||||
|
||||
await expect(
|
||||
aDai
|
||||
.connect(spender.signer)
|
||||
.permit(ZERO_ADDRESS, spender.address, expiration, permitAmount, v, r, s)
|
||||
).to.be.revertedWith('INVALID_OWNER');
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user