You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

191 lines
6.7 KiB
JavaScript

1 year ago
const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers');
const { expect } = require('chai');
const { ZERO_ADDRESS, MAX_UINT256 } = constants;
const { shouldBehaveLikeERC20 } = require('../ERC20.behavior');
const NotAnERC20 = artifacts.require('CallReceiverMock');
const ERC20Decimals = artifacts.require('$ERC20DecimalsMock');
const ERC20Wrapper = artifacts.require('$ERC20Wrapper');
contract('ERC20', function (accounts) {
const [initialHolder, recipient, anotherAccount] = accounts;
const name = 'My Token';
const symbol = 'MTKN';
const initialSupply = new BN(100);
beforeEach(async function () {
this.underlying = await ERC20Decimals.new(name, symbol, 9);
await this.underlying.$_mint(initialHolder, initialSupply);
this.token = await ERC20Wrapper.new(`Wrapped ${name}`, `W${symbol}`, this.underlying.address);
});
afterEach(async function () {
expect(await this.underlying.balanceOf(this.token.address)).to.be.bignumber.equal(await this.token.totalSupply());
});
it('has a name', async function () {
expect(await this.token.name()).to.equal(`Wrapped ${name}`);
});
it('has a symbol', async function () {
expect(await this.token.symbol()).to.equal(`W${symbol}`);
});
it('has the same decimals as the underlying token', async function () {
expect(await this.token.decimals()).to.be.bignumber.equal('9');
});
it('decimals default back to 18 if token has no metadata', async function () {
const noDecimals = await NotAnERC20.new();
const otherToken = await ERC20Wrapper.new(`Wrapped ${name}`, `W${symbol}`, noDecimals.address);
expect(await otherToken.decimals()).to.be.bignumber.equal('18');
});
it('has underlying', async function () {
expect(await this.token.underlying()).to.be.bignumber.equal(this.underlying.address);
});
describe('deposit', function () {
it('valid', async function () {
await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder });
const { tx } = await this.token.depositFor(initialHolder, initialSupply, { from: initialHolder });
await expectEvent.inTransaction(tx, this.underlying, 'Transfer', {
from: initialHolder,
to: this.token.address,
value: initialSupply,
});
await expectEvent.inTransaction(tx, this.token, 'Transfer', {
from: ZERO_ADDRESS,
to: initialHolder,
value: initialSupply,
});
});
it('missing approval', async function () {
await expectRevert(
this.token.depositFor(initialHolder, initialSupply, { from: initialHolder }),
'ERC20: insufficient allowance',
);
});
it('missing balance', async function () {
await this.underlying.approve(this.token.address, MAX_UINT256, { from: initialHolder });
await expectRevert(
this.token.depositFor(initialHolder, MAX_UINT256, { from: initialHolder }),
'ERC20: transfer amount exceeds balance',
);
});
it('to other account', async function () {
await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder });
const { tx } = await this.token.depositFor(anotherAccount, initialSupply, { from: initialHolder });
await expectEvent.inTransaction(tx, this.underlying, 'Transfer', {
from: initialHolder,
to: this.token.address,
value: initialSupply,
});
await expectEvent.inTransaction(tx, this.token, 'Transfer', {
from: ZERO_ADDRESS,
to: anotherAccount,
value: initialSupply,
});
});
});
describe('withdraw', function () {
beforeEach(async function () {
await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder });
await this.token.depositFor(initialHolder, initialSupply, { from: initialHolder });
});
it('missing balance', async function () {
await expectRevert(
this.token.withdrawTo(initialHolder, MAX_UINT256, { from: initialHolder }),
'ERC20: burn amount exceeds balance',
);
});
it('valid', async function () {
const value = new BN(42);
const { tx } = await this.token.withdrawTo(initialHolder, value, { from: initialHolder });
await expectEvent.inTransaction(tx, this.underlying, 'Transfer', {
from: this.token.address,
to: initialHolder,
value: value,
});
await expectEvent.inTransaction(tx, this.token, 'Transfer', {
from: initialHolder,
to: ZERO_ADDRESS,
value: value,
});
});
it('entire balance', async function () {
const { tx } = await this.token.withdrawTo(initialHolder, initialSupply, { from: initialHolder });
await expectEvent.inTransaction(tx, this.underlying, 'Transfer', {
from: this.token.address,
to: initialHolder,
value: initialSupply,
});
await expectEvent.inTransaction(tx, this.token, 'Transfer', {
from: initialHolder,
to: ZERO_ADDRESS,
value: initialSupply,
});
});
it('to other account', async function () {
const { tx } = await this.token.withdrawTo(anotherAccount, initialSupply, { from: initialHolder });
await expectEvent.inTransaction(tx, this.underlying, 'Transfer', {
from: this.token.address,
to: anotherAccount,
value: initialSupply,
});
await expectEvent.inTransaction(tx, this.token, 'Transfer', {
from: initialHolder,
to: ZERO_ADDRESS,
value: initialSupply,
});
});
});
describe('recover', function () {
it('nothing to recover', async function () {
await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder });
await this.token.depositFor(initialHolder, initialSupply, { from: initialHolder });
const { tx } = await this.token.$_recover(anotherAccount);
await expectEvent.inTransaction(tx, this.token, 'Transfer', {
from: ZERO_ADDRESS,
to: anotherAccount,
value: '0',
});
});
it('something to recover', async function () {
await this.underlying.transfer(this.token.address, initialSupply, { from: initialHolder });
const { tx } = await this.token.$_recover(anotherAccount);
await expectEvent.inTransaction(tx, this.token, 'Transfer', {
from: ZERO_ADDRESS,
to: anotherAccount,
value: initialSupply,
});
});
});
describe('erc20 behaviour', function () {
beforeEach(async function () {
await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder });
await this.token.depositFor(initialHolder, initialSupply, { from: initialHolder });
});
shouldBehaveLikeERC20('ERC20', initialSupply, initialHolder, recipient, anotherAccount);
});
});