2020-11-18 18:18:02 +00:00
|
|
|
import { MAX_UINT_AMOUNT, ZERO_ADDRESS } from '../helpers/constants';
|
|
|
|
import { BUIDLEREVM_CHAINID } from '../helpers/buidler-constants';
|
|
|
|
import { buildPermitParams, getSignatureFromTypedData } from '../helpers/contracts-helpers';
|
|
|
|
import { expect } from 'chai';
|
|
|
|
import { ethers } from 'ethers';
|
|
|
|
import { makeSuite, TestEnv } from './helpers/make-suite';
|
|
|
|
import { DRE } from '../helpers/misc-utils';
|
|
|
|
import { waitForTx } from '../helpers/misc-utils';
|
|
|
|
import { _TypedDataEncoder } from 'ethers/lib/utils';
|
|
|
|
|
|
|
|
const { parseEther } = ethers.utils;
|
2020-09-14 13:57:11 +00:00
|
|
|
|
|
|
|
makeSuite('AToken: Permit', (testEnv: TestEnv) => {
|
|
|
|
it('Checks the domain separator', async () => {
|
2020-11-18 18:18:02 +00:00
|
|
|
const { aDai } = testEnv;
|
2020-09-14 13:57:11 +00:00
|
|
|
const separator = await aDai.DOMAIN_SEPARATOR();
|
|
|
|
|
2020-11-18 18:18:02 +00:00
|
|
|
const domain = {
|
|
|
|
name: await aDai.name(),
|
|
|
|
version: '1',
|
|
|
|
chainId: DRE.network.config.chainId,
|
|
|
|
verifyingContract: aDai.address,
|
|
|
|
};
|
|
|
|
const domainSeparator = _TypedDataEncoder.hashDomain(domain);
|
|
|
|
|
|
|
|
expect(separator).to.be.equal(domainSeparator, 'Invalid domain separator');
|
2020-09-14 13:57:11 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
it('Get aDAI for tests', async () => {
|
2020-11-18 18:18:02 +00:00
|
|
|
const { dai, pool, deployer } = testEnv;
|
2020-09-14 13:57:11 +00:00
|
|
|
|
|
|
|
await dai.mint(parseEther('20000'));
|
|
|
|
await dai.approve(pool.address, parseEther('20000'));
|
2020-10-22 15:32:50 +00:00
|
|
|
|
2020-09-14 13:57:11 +00:00
|
|
|
await pool.deposit(dai.address, parseEther('20000'), deployer.address, 0);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('Reverts submitting a permit with 0 expiration', async () => {
|
2020-11-18 18:18:02 +00:00
|
|
|
const { aDai, deployer, users } = testEnv;
|
2020-09-14 13:57:11 +00:00
|
|
|
const owner = deployer;
|
|
|
|
const spender = users[1];
|
|
|
|
|
|
|
|
const tokenName = await aDai.name();
|
|
|
|
|
2020-11-05 12:44:20 +00:00
|
|
|
const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID;
|
2020-09-14 13:57:11 +00:00
|
|
|
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'
|
|
|
|
);
|
|
|
|
|
2020-11-18 18:18:02 +00:00
|
|
|
const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams);
|
2020-09-14 13:57:11 +00:00
|
|
|
|
|
|
|
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 () => {
|
2020-11-18 18:18:02 +00:00
|
|
|
const { aDai, deployer, users } = testEnv;
|
2020-09-14 13:57:11 +00:00
|
|
|
const owner = deployer;
|
|
|
|
const spender = users[1];
|
|
|
|
|
2020-11-05 12:44:20 +00:00
|
|
|
const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID;
|
2020-09-14 13:57:11 +00:00
|
|
|
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'
|
|
|
|
);
|
|
|
|
|
2020-11-18 18:18:02 +00:00
|
|
|
const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams);
|
2020-09-14 13:57:11 +00:00
|
|
|
|
|
|
|
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 () => {
|
2020-11-18 18:18:02 +00:00
|
|
|
const { aDai, deployer, users } = testEnv;
|
2020-09-14 13:57:11 +00:00
|
|
|
const owner = deployer;
|
|
|
|
const spender = users[1];
|
|
|
|
|
2020-11-05 12:44:20 +00:00
|
|
|
const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID;
|
2020-09-14 13:57:11 +00:00
|
|
|
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');
|
|
|
|
}
|
|
|
|
|
2020-11-18 18:18:02 +00:00
|
|
|
const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams);
|
2020-09-14 13:57:11 +00:00
|
|
|
|
|
|
|
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 () => {
|
2020-11-18 18:18:02 +00:00
|
|
|
const { aDai, deployer, users } = testEnv;
|
2020-09-14 13:57:11 +00:00
|
|
|
const owner = deployer;
|
|
|
|
const spender = users[1];
|
|
|
|
|
2020-11-05 12:44:20 +00:00
|
|
|
const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID;
|
2020-09-14 13:57:11 +00:00
|
|
|
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');
|
|
|
|
}
|
|
|
|
|
2020-11-18 18:18:02 +00:00
|
|
|
const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams);
|
2020-09-14 13:57:11 +00:00
|
|
|
|
|
|
|
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 () => {
|
2020-11-18 18:18:02 +00:00
|
|
|
const { aDai, deployer, users } = testEnv;
|
2020-09-14 13:57:11 +00:00
|
|
|
const owner = deployer;
|
|
|
|
const spender = users[1];
|
|
|
|
|
2020-11-05 12:44:20 +00:00
|
|
|
const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID;
|
2020-09-14 13:57:11 +00:00
|
|
|
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');
|
|
|
|
}
|
|
|
|
|
2020-11-18 18:18:02 +00:00
|
|
|
const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams);
|
2020-09-14 13:57:11 +00:00
|
|
|
|
|
|
|
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 () => {
|
2020-11-18 18:18:02 +00:00
|
|
|
const { aDai, deployer, users } = testEnv;
|
2020-09-14 13:57:11 +00:00
|
|
|
const owner = deployer;
|
|
|
|
const spender = users[1];
|
|
|
|
|
2020-11-05 12:44:20 +00:00
|
|
|
const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID;
|
2020-09-14 13:57:11 +00:00
|
|
|
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');
|
|
|
|
}
|
|
|
|
|
2020-11-18 18:18:02 +00:00
|
|
|
const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams);
|
2020-09-14 13:57:11 +00:00
|
|
|
|
|
|
|
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 () => {
|
2020-11-18 18:18:02 +00:00
|
|
|
const { aDai, deployer, users } = testEnv;
|
2020-09-14 13:57:11 +00:00
|
|
|
const owner = deployer;
|
|
|
|
const spender = users[1];
|
|
|
|
|
2020-11-05 12:44:20 +00:00
|
|
|
const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID;
|
2020-09-14 13:57:11 +00:00
|
|
|
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');
|
|
|
|
}
|
|
|
|
|
2020-11-18 18:18:02 +00:00
|
|
|
const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams);
|
2020-09-14 13:57:11 +00:00
|
|
|
|
|
|
|
await expect(
|
|
|
|
aDai
|
|
|
|
.connect(spender.signer)
|
|
|
|
.permit(ZERO_ADDRESS, spender.address, expiration, permitAmount, v, r, s)
|
|
|
|
).to.be.revertedWith('INVALID_OWNER');
|
|
|
|
});
|
|
|
|
});
|