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

Add ERC20 and ERC777 fixed supply presets #2377 #2399

Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

* `BeaconProxy`: added new kind of proxy that allows simultaneous atomic upgrades. ([#2411](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2411))
* `EIP712`: added helpers to verify EIP712 typed data signatures on chain. ([#2418](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2418))
* Presets: added token presets with preminted fixed supply `ERC20PresetFixedSupply` and `ERC777PresetFixedSupply`. ([#2399](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2399))
* `Address`: added `functionDelegateCall`, similar to the existing `functionCall`. ([#2333](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2333))

## 3.3.0 (2020-11-26)
Expand Down
30 changes: 30 additions & 0 deletions contracts/presets/ERC20PresetFixedSupply.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.2;

import "../token/ERC20/ERC20Burnable.sol";

/**
* @dev {ERC20} token, including:
*
* - Preminted initial supply
* - Ability for holders to burn (destroy) their tokens
* - No access control mechanism (for minting/pausing) and hence no governance
*
* This contract uses {ERC20Burnable} to include burn capabilities - head to
* its documentation for details.
*/
contract ERC20PresetFixedSupply is ERC20Burnable {
/**
* @dev Mints `initialSupply` amount of token and transfers them to `owner`.
*
* See {ERC20-constructor}.
*/
constructor(
string memory name,
string memory symbol,
uint256 initialSupply,
address owner
) public ERC20(name, symbol) {
_mint(owner, initialSupply);
}
}
27 changes: 27 additions & 0 deletions contracts/presets/ERC777PresetFixedSupply.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.2;

import "../token/ERC777/ERC777.sol";

/**
* @dev {ERC777} token, including:
*
* - Preminted initial supply
* - No access control mechanism (for minting/pausing) and hence no governance
*/
contract ERC777PresetFixedSupply is ERC777 {
/**
* @dev Mints `initialSupply` amount of token and transfers them to `owner`.
*
* See {ERC777-constructor}.
*/
constructor(
string memory name,
string memory symbol,
address[] memory defaultOperators,
uint256 initialSupply,
address owner
) public ERC777(name, symbol, defaultOperators) {
_mint(owner, initialSupply, "", "");
}
}
4 changes: 4 additions & 0 deletions contracts/presets/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,7 @@ TIP: Intermediate and advanced users can use these as starting points when writi
{{ERC721PresetMinterPauserAutoId}}

{{ERC1155PresetMinterPauser}}

{{ERC20PresetFixedSupply}}

{{ERC777PresetFixedSupply}}
42 changes: 42 additions & 0 deletions test/presets/ERC20PresetFixedSupply.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
const { BN, constants, expectEvent } = require('@openzeppelin/test-helpers');
const { ZERO_ADDRESS } = constants;

const { expect } = require('chai');

const ERC20PresetFixedSupply = artifacts.require('ERC20PresetFixedSupply');

contract('ERC20PresetFixedSupply', function (accounts) {
const [deployer, owner] = accounts;

const name = 'PresetFixedSupply';
const symbol = 'PFS';

const initialSupply = new BN('50000');
const amount = new BN('10000');

before(async function () {
this.token = await ERC20PresetFixedSupply.new(name, symbol, initialSupply, owner, { from: deployer });
});

it('deployer has the balance equal to initial supply', async function () {
expect(await this.token.balanceOf(owner)).to.be.bignumber.equal(initialSupply);
});

it('total supply is equal to initial supply', async function () {
expect(await this.token.totalSupply()).to.be.bignumber.equal(initialSupply);
});

describe('burning', function () {
it('holders can burn their tokens', async function () {
const remainingBalance = initialSupply.sub(amount);
const receipt = await this.token.burn(amount, { from: owner });
expectEvent(receipt, 'Transfer', { from: owner, to: ZERO_ADDRESS, value: amount });
expect(await this.token.balanceOf(owner)).to.be.bignumber.equal(remainingBalance);
});

it('decrements totalSupply', async function () {
const expectedSupply = initialSupply.sub(amount);
expect(await this.token.totalSupply()).to.be.bignumber.equal(expectedSupply);
});
});
});
49 changes: 49 additions & 0 deletions test/presets/ERC777PresetFixedSupply.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
const { BN, singletons } = require('@openzeppelin/test-helpers');

const { expect } = require('chai');

const ERC777PresetFixedSupply = artifacts.require('ERC777PresetFixedSupply');

contract('ERC777PresetFixedSupply', function (accounts) {
const [registryFunder, owner, defaultOperatorA, defaultOperatorB, anyone] = accounts;

const initialSupply = new BN('10000');
const name = 'ERC777Preset';
const symbol = '777P';

const defaultOperators = [defaultOperatorA, defaultOperatorB];

before(async function () {
await singletons.ERC1820Registry(registryFunder);
});

beforeEach(async function () {
this.token = await ERC777PresetFixedSupply.new(name, symbol, defaultOperators, initialSupply, owner);
});

it('returns the name', async function () {
expect(await this.token.name()).to.equal(name);
});

it('returns the symbol', async function () {
expect(await this.token.symbol()).to.equal(symbol);
});

it('returns the default operators', async function () {
expect(await this.token.defaultOperators()).to.deep.equal(defaultOperators);
});

it('default operators are operators for all accounts', async function () {
for (const operator of defaultOperators) {
expect(await this.token.isOperatorFor(operator, anyone)).to.equal(true);
}
});

it('returns the total supply equal to initial supply', async function () {
expect(await this.token.totalSupply()).to.be.bignumber.equal(initialSupply);
});

it('returns the balance of owner equal to initial supply', async function () {
expect(await this.token.balanceOf(owner)).to.be.bignumber.equal(initialSupply);
});
});