Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inherit ERC20Wrapper decimals from the underlying #3259

Merged
merged 2 commits into from Mar 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions contracts/mocks/ERC20DecimalsMock.sol
Expand Up @@ -18,4 +18,12 @@ contract ERC20DecimalsMock is ERC20 {
function decimals() public view virtual override returns (uint8) {
return _decimals;
}

function mint(address account, uint256 amount) public {
_mint(account, amount);
}

function burn(address account, uint256 amount) public {
_burn(account, amount);
}
}
11 changes: 11 additions & 0 deletions contracts/token/ERC20/extensions/ERC20Wrapper.sol
Expand Up @@ -22,6 +22,17 @@ abstract contract ERC20Wrapper is ERC20 {
underlying = underlyingToken;
}

/**
* @dev See {ERC20-decimals}.
*/
function decimals() public view virtual override returns (uint8) {
try IERC20Metadata(address(underlying)).decimals() returns (uint8 value) {
return value;
} catch {
return super.decimals();
}
}

/**
* @dev Allow a user to deposit underlying tokens and mint the corresponding number of wrapped tokens.
*/
Expand Down
17 changes: 13 additions & 4 deletions test/token/ERC20/extensions/ERC20Wrapper.test.js
Expand Up @@ -4,7 +4,8 @@ const { ZERO_ADDRESS, MAX_UINT256 } = constants;

const { shouldBehaveLikeERC20 } = require('../ERC20.behavior');

const ERC20Mock = artifacts.require('ERC20Mock');
const NotAnERC20 = artifacts.require('CallReceiverMock');
const ERC20Mock = artifacts.require('ERC20DecimalsMock');
const ERC20WrapperMock = artifacts.require('ERC20WrapperMock');

contract('ERC20', function (accounts) {
Expand All @@ -16,8 +17,10 @@ contract('ERC20', function (accounts) {
const initialSupply = new BN(100);

beforeEach(async function () {
this.underlying = await ERC20Mock.new(name, symbol, initialHolder, initialSupply);
this.underlying = await ERC20Mock.new(name, symbol, 9);
this.token = await ERC20WrapperMock.new(this.underlying.address, `Wrapped ${name}`, `W${symbol}`);

await this.underlying.mint(initialHolder, initialSupply);
});

afterEach(async function () {
Expand All @@ -32,8 +35,14 @@ contract('ERC20', function (accounts) {
expect(await this.token.symbol()).to.equal(`W${symbol}`);
});

it('has 18 decimals', async function () {
expect(await this.token.decimals()).to.be.bignumber.equal('18');
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 ERC20WrapperMock.new(noDecimals.address, `Wrapped ${name}`, `W${symbol}`);
expect(await otherToken.decimals()).to.be.bignumber.equal('18');
});

it('has underlying', async function () {
Expand Down