├── .nvmrc
├── dist
├── .gitkeep
└── ServiceReceiver.dist.sol
├── analysis
├── .gitkeep
├── uml
│ ├── .gitkeep
│ ├── ServiceReceiver.svg
│ ├── StandardBEP20.svg
│ ├── SimpleBEP20.svg
│ └── BurnableBEP20.svg
├── control-flow
│ ├── .gitkeep
│ ├── CommonBEP20.png
│ ├── SimpleBEP20.png
│ ├── BurnableBEP20.png
│ ├── MintableBEP20.png
│ ├── StandardBEP20.png
│ └── ServiceReceiver.png
├── description-table
│ ├── .gitkeep
│ ├── ServiceReceiver.md
│ ├── StandardBEP20.md
│ ├── BurnableBEP20.md
│ ├── SimpleBEP20.md
│ ├── MintableBEP20.md
│ └── CommonBEP20.md
└── inheritance-tree
│ ├── .gitkeep
│ ├── CommonBEP20.png
│ ├── SimpleBEP20.png
│ ├── BurnableBEP20.png
│ ├── MintableBEP20.png
│ ├── StandardBEP20.png
│ └── ServiceReceiver.png
├── migrations
└── .gitkeep
├── .gitattributes
├── .eslintignore
├── scripts
├── coverage.sh
├── compile.sh
├── flat.sh
├── analyze.sh
└── test.sh
├── bs-config.json
├── .solcover.js
├── .editorconfig
├── web-console
├── package.json
├── index.html
└── js
│ └── app.js
├── contracts
├── mocks
│ ├── ServicePayerMock.sol
│ ├── BEP20Mock.sol
│ └── ERC20Mock.sol
├── service
│ ├── ServicePayer.sol
│ └── ServiceReceiver.sol
├── token
│ └── BEP20
│ │ ├── StandardBEP20.sol
│ │ ├── BurnableBEP20.sol
│ │ ├── SimpleBEP20.sol
│ │ ├── lib
│ │ ├── BEP20Capped.sol
│ │ ├── BEP20Burnable.sol
│ │ ├── BEP20Mintable.sol
│ │ ├── IBEP20.sol
│ │ └── BEP20.sol
│ │ ├── MintableBEP20.sol
│ │ └── CommonBEP20.sol
└── utils
│ └── GeneratorCopyright.sol
├── .solhint.json
├── hardhat.config.js
├── test
├── utils
│ └── GeneratorCopyright.behaviour.js
├── token
│ └── BEP20
│ │ ├── behaviours
│ │ ├── BEP20Capped.behaviour.js
│ │ ├── BEP20Mintable.behaviour.js
│ │ ├── BEP20Burnable.behaviour.js
│ │ └── BEP20.behaviour.js
│ │ ├── StandardBEP20.test.js
│ │ ├── SimpleBEP20.test.js
│ │ ├── BurnableBEP20.test.js
│ │ ├── MintableBEP20.test.js
│ │ └── CommonBEP20.test.js
├── access
│ └── Ownable.behavior.js
└── service
│ ├── ServicePayer.test.js
│ └── ServiceReceiver.test.js
├── .gitignore
├── truffle-config.js
├── LICENSE
├── .eslintrc
├── .github
└── workflows
│ └── ci.yml
├── package.json
└── README.md
/.nvmrc:
--------------------------------------------------------------------------------
1 | 14
2 |
--------------------------------------------------------------------------------
/dist/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/analysis/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/analysis/uml/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/migrations/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/analysis/control-flow/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/analysis/description-table/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/analysis/inheritance-tree/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.sol linguist-language=Solidity
2 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | coverage
2 | cache
3 | node_modules
4 | web-console
5 |
--------------------------------------------------------------------------------
/scripts/coverage.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | npm run hardhat:compile
4 | npm run hardhat:coverage
5 |
--------------------------------------------------------------------------------
/bs-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "server": {
3 | "baseDir": ["./web-console", "./build/contracts"]
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/analysis/control-flow/CommonBEP20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/markdgo/bep20-generator/HEAD/analysis/control-flow/CommonBEP20.png
--------------------------------------------------------------------------------
/analysis/control-flow/SimpleBEP20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/markdgo/bep20-generator/HEAD/analysis/control-flow/SimpleBEP20.png
--------------------------------------------------------------------------------
/analysis/control-flow/BurnableBEP20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/markdgo/bep20-generator/HEAD/analysis/control-flow/BurnableBEP20.png
--------------------------------------------------------------------------------
/analysis/control-flow/MintableBEP20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/markdgo/bep20-generator/HEAD/analysis/control-flow/MintableBEP20.png
--------------------------------------------------------------------------------
/analysis/control-flow/StandardBEP20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/markdgo/bep20-generator/HEAD/analysis/control-flow/StandardBEP20.png
--------------------------------------------------------------------------------
/analysis/control-flow/ServiceReceiver.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/markdgo/bep20-generator/HEAD/analysis/control-flow/ServiceReceiver.png
--------------------------------------------------------------------------------
/analysis/inheritance-tree/CommonBEP20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/markdgo/bep20-generator/HEAD/analysis/inheritance-tree/CommonBEP20.png
--------------------------------------------------------------------------------
/analysis/inheritance-tree/SimpleBEP20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/markdgo/bep20-generator/HEAD/analysis/inheritance-tree/SimpleBEP20.png
--------------------------------------------------------------------------------
/analysis/inheritance-tree/BurnableBEP20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/markdgo/bep20-generator/HEAD/analysis/inheritance-tree/BurnableBEP20.png
--------------------------------------------------------------------------------
/analysis/inheritance-tree/MintableBEP20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/markdgo/bep20-generator/HEAD/analysis/inheritance-tree/MintableBEP20.png
--------------------------------------------------------------------------------
/analysis/inheritance-tree/StandardBEP20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/markdgo/bep20-generator/HEAD/analysis/inheritance-tree/StandardBEP20.png
--------------------------------------------------------------------------------
/analysis/inheritance-tree/ServiceReceiver.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/markdgo/bep20-generator/HEAD/analysis/inheritance-tree/ServiceReceiver.png
--------------------------------------------------------------------------------
/scripts/compile.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | if [ "$SOLC_NIGHTLY" = true ]; then
4 | docker pull ethereum/solc:nightly
5 | fi
6 |
7 | npx truffle compile --all
8 |
--------------------------------------------------------------------------------
/.solcover.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | norpc: true,
3 | testCommand: 'npm run hardhat:test',
4 | compileCommand: 'npm run hardhat:compile',
5 | skipFiles: [
6 | 'mocks'
7 | ],
8 | };
9 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig is awesome: https://EditorConfig.org
2 |
3 | # top-most EditorConfig file
4 | root = true
5 |
6 | [*]
7 | charset = utf-8
8 | end_of_line = lf
9 | indent_size = 2
10 | indent_style = space
11 | insert_final_newline = true
12 | trim_trailing_whitespace = true
13 |
--------------------------------------------------------------------------------
/scripts/flat.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | for contract in "SimpleBEP20" "StandardBEP20" "BurnableBEP20" "MintableBEP20" "CommonBEP20"
4 | do
5 | npx truffle-flattener contracts/token/BEP20/$contract.sol > dist/$contract.dist.sol
6 | done
7 |
8 | npx truffle-flattener contracts/service/ServiceReceiver.sol > dist/ServiceReceiver.dist.sol
9 |
--------------------------------------------------------------------------------
/web-console/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dapp-src",
3 | "version": "1.0.0",
4 | "description": "",
5 | "scripts": {
6 | "test": "echo \"Error: no test specified\" && exit 1"
7 | },
8 | "author": "",
9 | "license": "MIT",
10 | "dependencies": {
11 | "truffle-contract": "3.0.7",
12 | "web3": "0.20.6"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/contracts/mocks/ServicePayerMock.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 |
3 | pragma solidity ^0.7.0;
4 |
5 | import "../service/ServicePayer.sol";
6 |
7 | // mock class using ServicePayer
8 | contract ServicePayerMock is ServicePayer {
9 |
10 | constructor (address payable feeReceiver) ServicePayer(feeReceiver, "ServicePayerMock") payable {}
11 | }
12 |
--------------------------------------------------------------------------------
/.solhint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "solhint:recommended",
3 | "rules": {
4 | "mark-callable-contracts": "off",
5 | "no-empty-blocks": "off",
6 | "compiler-version": ["error", "^0.7.0"],
7 | "private-vars-leading-underscore": "error",
8 | "reason-string": "off",
9 | "func-visibility": ["error", { "ignoreConstructors": true }]
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/contracts/service/ServicePayer.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 |
3 | pragma solidity ^0.7.0;
4 |
5 | import "./ServiceReceiver.sol";
6 |
7 | /**
8 | * @title ServicePayer
9 | * @dev Implementation of the ServicePayer
10 | */
11 | abstract contract ServicePayer {
12 |
13 | constructor (address payable receiver, string memory serviceName) payable {
14 | ServiceReceiver(receiver).pay{value: msg.value}(serviceName);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/contracts/mocks/BEP20Mock.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 |
3 | pragma solidity ^0.7.0;
4 |
5 | import "../token/BEP20/lib/BEP20.sol";
6 |
7 | // mock class using BEP20
8 | contract BEP20Mock is BEP20 {
9 |
10 | constructor (
11 | string memory name,
12 | string memory symbol,
13 | address initialAccount,
14 | uint256 initialBalance
15 | ) BEP20(name, symbol) {
16 | _mint(initialAccount, initialBalance);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/contracts/mocks/ERC20Mock.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 |
3 | pragma solidity ^0.7.0;
4 |
5 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
6 |
7 | // mock class using ERC20
8 | contract ERC20Mock is ERC20 {
9 |
10 | constructor (
11 | string memory name,
12 | string memory symbol,
13 | address initialAccount,
14 | uint256 initialBalance
15 | ) ERC20(name, symbol) {
16 | _mint(initialAccount, initialBalance);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/scripts/analyze.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | for contract in "SimpleBEP20" "StandardBEP20" "BurnableBEP20" "MintableBEP20" "CommonBEP20" "ServiceReceiver"
4 | do
5 | npx surya inheritance dist/$contract.dist.sol | dot -Tpng > analysis/inheritance-tree/$contract.png
6 |
7 | npx surya graph dist/$contract.dist.sol | dot -Tpng > analysis/control-flow/$contract.png
8 |
9 | npx surya mdreport analysis/description-table/$contract.md dist/$contract.dist.sol
10 |
11 | npx sol2uml dist/$contract.dist.sol -o analysis/uml/$contract.svg
12 | done
13 |
--------------------------------------------------------------------------------
/web-console/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Smart Contract - Console
8 |
9 |
10 | Smart Contract - Console
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/hardhat.config.js:
--------------------------------------------------------------------------------
1 | require('chai/register-should');
2 | require('@nomiclabs/hardhat-ganache');
3 | require('@nomiclabs/hardhat-truffle5');
4 | require('solidity-coverage');
5 |
6 | module.exports = {
7 | defaultNetwork: 'hardhat',
8 | networks: {
9 | coverage: {
10 | url: 'http://127.0.0.1:8555',
11 | gas: 0xfffffffffff,
12 | gasPrice: 0x01,
13 | },
14 | },
15 | solidity: {
16 | version: '0.7.6',
17 | settings: {
18 | optimizer: {
19 | enabled: true,
20 | runs: 200,
21 | },
22 | },
23 | },
24 | };
25 |
--------------------------------------------------------------------------------
/test/utils/GeneratorCopyright.behaviour.js:
--------------------------------------------------------------------------------
1 | function shouldBehaveLikeGeneratorCopyright (version) {
2 | describe('should have', function () {
3 | const _builtOn = {
4 | generator: 'https://hikecoder.github.io/bep20-generator',
5 | };
6 |
7 | it('a generator value', async function () {
8 | _builtOn.generator.should.be.equal(await this.instance.generator());
9 | });
10 |
11 | it('a version value', async function () {
12 | version.should.be.equal(await this.instance.version());
13 | });
14 | });
15 | }
16 |
17 | module.exports = {
18 | shouldBehaveLikeGeneratorCopyright,
19 | };
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.swp
2 | *.swo
3 |
4 | # Logs
5 | logs
6 | *.log
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | scTopics
13 |
14 | # Coverage directory used by tools like istanbul
15 | coverage
16 | coverage.json
17 | coverageEnv
18 |
19 | # temporary artifact from solidity-coverage
20 | allFiredEvents
21 | .coverage_artifacts
22 | .coverage_cache
23 | .coverage_contracts
24 |
25 | # node-waf configuration
26 | .lock-wscript
27 |
28 | # Dependency directory
29 | node_modules
30 |
31 | # Debug log from npm
32 | npm-debug.log
33 |
34 | # local env variables
35 | .env
36 |
37 | # truffle build directory
38 | /build
39 |
40 | # Hardhat files
41 | /artifacts
42 | /cache
43 |
44 | # macOS
45 | .DS_Store
46 |
47 | # truffle
48 | .node-xmlhttprequest-*
49 |
50 | # npm package
51 | package-lock.json
52 |
53 | # IntelliJ IDE
54 | .idea
55 |
--------------------------------------------------------------------------------
/contracts/token/BEP20/StandardBEP20.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 |
3 | pragma solidity ^0.7.0;
4 |
5 | import "./lib/BEP20.sol";
6 |
7 | import "../../service/ServicePayer.sol";
8 |
9 | /**
10 | * @title StandardBEP20
11 | * @dev Implementation of the StandardBEP20
12 | */
13 | contract StandardBEP20 is BEP20, ServicePayer {
14 |
15 | constructor (
16 | string memory name,
17 | string memory symbol,
18 | uint8 decimals,
19 | uint256 initialBalance,
20 | address payable feeReceiver
21 | )
22 | BEP20(name, symbol)
23 | ServicePayer(feeReceiver, "StandardBEP20")
24 | payable
25 | {
26 | require(initialBalance > 0, "StandardBEP20: supply cannot be zero");
27 |
28 | _setupDecimals(decimals);
29 | _mint(_msgSender(), initialBalance);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/contracts/token/BEP20/BurnableBEP20.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 |
3 | pragma solidity ^0.7.0;
4 |
5 | import "./lib/BEP20Burnable.sol";
6 |
7 | import "../../service/ServicePayer.sol";
8 |
9 | /**
10 | * @title BurnableBEP20
11 | * @dev Implementation of the BurnableBEP20
12 | */
13 | contract BurnableBEP20 is BEP20Burnable, ServicePayer {
14 |
15 | constructor (
16 | string memory name,
17 | string memory symbol,
18 | uint8 decimals,
19 | uint256 initialBalance,
20 | address payable feeReceiver
21 | )
22 | BEP20(name, symbol)
23 | ServicePayer(feeReceiver, "BurnableBEP20")
24 | payable
25 | {
26 | require(initialBalance > 0, "BurnableBEP20: supply cannot be zero");
27 |
28 | _setupDecimals(decimals);
29 | _mint(_msgSender(), initialBalance);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/truffle-config.js:
--------------------------------------------------------------------------------
1 | require('chai/register-should');
2 |
3 | const solcStable = {
4 | version: '0.7.6',
5 | settings: {
6 | optimizer: {
7 | enabled: true,
8 | runs: 200,
9 | },
10 | },
11 | };
12 |
13 | const solcNightly = {
14 | version: 'nightly',
15 | docker: true,
16 | };
17 |
18 | const useSolcNightly = process.env.SOLC_NIGHTLY === 'true';
19 |
20 | module.exports = {
21 | networks: {
22 | development: {
23 | host: 'localhost',
24 | port: 8545,
25 | network_id: '*', // eslint-disable-line camelcase
26 | },
27 | coverage: {
28 | host: 'localhost',
29 | network_id: '*', // eslint-disable-line camelcase
30 | port: 8555,
31 | gas: 0xfffffffffff,
32 | gasPrice: 0x01,
33 | },
34 | },
35 | compilers: {
36 | solc: useSolcNightly ? solcNightly : solcStable,
37 | },
38 | plugins: ['solidity-coverage'],
39 | };
40 |
--------------------------------------------------------------------------------
/contracts/utils/GeneratorCopyright.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 |
3 | pragma solidity ^0.7.0;
4 |
5 | /**
6 | * @title GeneratorCopyright
7 | * @author BEP20 Generator (https://hikecoder.github.io/bep20-generator)
8 | * @dev Implementation of the GeneratorCopyright
9 | */
10 | contract GeneratorCopyright {
11 |
12 | string private constant _GENERATOR = "https://hikecoder.github.io/bep20-generator";
13 | string private _version;
14 |
15 | constructor (string memory version_) {
16 | _version = version_;
17 | }
18 |
19 | /**
20 | * @dev Returns the token generator tool.
21 | */
22 | function generator() public pure returns (string memory) {
23 | return _GENERATOR;
24 | }
25 |
26 | /**
27 | * @dev Returns the token generator version.
28 | */
29 | function version() public view returns (string memory) {
30 | return _version;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/contracts/token/BEP20/SimpleBEP20.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 |
3 | pragma solidity ^0.7.0;
4 |
5 | import "./lib/BEP20.sol";
6 |
7 | import "../../service/ServicePayer.sol";
8 | import "../../utils/GeneratorCopyright.sol";
9 |
10 | /**
11 | * @title SimpleBEP20
12 | * @author BEP20 Generator (https://hikecoder.github.io/bep20-generator)
13 | * @dev Implementation of the SimpleBEP20
14 | */
15 | contract SimpleBEP20 is BEP20, ServicePayer, GeneratorCopyright("v1.0.0") {
16 |
17 | constructor (
18 | string memory name,
19 | string memory symbol,
20 | uint256 initialBalance,
21 | address payable feeReceiver
22 | )
23 | BEP20(name, symbol)
24 | ServicePayer(feeReceiver, "SimpleBEP20")
25 | payable
26 | {
27 | require(initialBalance > 0, "SimpleBEP20: supply cannot be zero");
28 |
29 | _mint(_msgSender(), initialBalance);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Vittorio Minacori (https://github.com/hikecoder)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/test/token/BEP20/behaviours/BEP20Capped.behaviour.js:
--------------------------------------------------------------------------------
1 | const { expectRevert } = require('@openzeppelin/test-helpers');
2 |
3 | const { expect } = require('chai');
4 |
5 | function shouldBehaveLikeBEP20Capped (cap, [minter, other]) {
6 | describe('totalSupply', function () {
7 | const from = minter;
8 |
9 | it('should start with the correct cap', async function () {
10 | expect(await this.token.cap()).to.be.bignumber.equal(cap);
11 | });
12 |
13 | it('should mint when amount is less than cap', async function () {
14 | await this.token.mint(other, cap.subn(1), { from });
15 | expect(await this.token.totalSupply()).to.be.bignumber.equal(cap.subn(1));
16 | });
17 |
18 | it('should fail to mint if the amount exceeds the cap', async function () {
19 | await this.token.mint(other, cap.subn(1), { from });
20 | await expectRevert(this.token.mint(other, 2, { from }), 'BEP20Capped: cap exceeded');
21 | });
22 |
23 | it('should fail to mint after cap is reached', async function () {
24 | await this.token.mint(other, cap, { from });
25 | await expectRevert(this.token.mint(other, 1, { from }), 'BEP20Capped: cap exceeded');
26 | });
27 | });
28 | }
29 |
30 | module.exports = {
31 | shouldBehaveLikeBEP20Capped,
32 | };
33 |
--------------------------------------------------------------------------------
/contracts/service/ServiceReceiver.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 |
3 | pragma solidity ^0.7.0;
4 |
5 | import "@openzeppelin/contracts/access/Ownable.sol";
6 |
7 | /**
8 | * @title ServiceReceiver
9 | * @dev Implementation of the ServiceReceiver
10 | */
11 | contract ServiceReceiver is Ownable {
12 |
13 | mapping (bytes32 => uint256) private _prices;
14 |
15 | event Created(string serviceName, address indexed serviceAddress);
16 |
17 | function pay(string memory serviceName) public payable {
18 | require(msg.value == _prices[_toBytes32(serviceName)], "ServiceReceiver: incorrect price");
19 |
20 | emit Created(serviceName, _msgSender());
21 | }
22 |
23 | function getPrice(string memory serviceName) public view returns (uint256) {
24 | return _prices[_toBytes32(serviceName)];
25 | }
26 |
27 | function setPrice(string memory serviceName, uint256 amount) public onlyOwner {
28 | _prices[_toBytes32(serviceName)] = amount;
29 | }
30 |
31 | function withdraw(uint256 amount) public onlyOwner {
32 | payable(owner()).transfer(amount);
33 | }
34 |
35 | function _toBytes32(string memory serviceName) private pure returns (bytes32) {
36 | return keccak256(abi.encode(serviceName));
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/contracts/token/BEP20/lib/BEP20Capped.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 |
3 | pragma solidity ^0.7.0;
4 |
5 | import "./BEP20.sol";
6 |
7 | /**
8 | * @dev Extension of {BEP20} that adds a cap to the supply of tokens.
9 | */
10 | abstract contract BEP20Capped is BEP20 {
11 | using SafeMath for uint256;
12 |
13 | uint256 private _cap;
14 |
15 | /**
16 | * @dev Sets the value of the `cap`. This value is immutable, it can only be
17 | * set once during construction.
18 | */
19 | constructor (uint256 cap_) {
20 | require(cap_ > 0, "BEP20Capped: cap is 0");
21 | _cap = cap_;
22 | }
23 |
24 | /**
25 | * @dev Returns the cap on the token's total supply.
26 | */
27 | function cap() public view returns (uint256) {
28 | return _cap;
29 | }
30 |
31 | /**
32 | * @dev See {BEP20-_beforeTokenTransfer}.
33 | *
34 | * Requirements:
35 | *
36 | * - minted tokens must not cause the total supply to go over the cap.
37 | */
38 | function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override {
39 | super._beforeTokenTransfer(from, to, amount);
40 |
41 | if (from == address(0)) { // When minting tokens
42 | require(totalSupply().add(amount) <= _cap, "BEP20Capped: cap exceeded");
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/contracts/token/BEP20/lib/BEP20Burnable.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 |
3 | pragma solidity ^0.7.0;
4 |
5 | import "@openzeppelin/contracts/GSN/Context.sol";
6 |
7 | import "./BEP20.sol";
8 |
9 | /**
10 | * @dev Extension of {BEP20} that allows token holders to destroy both their own
11 | * tokens and those that they have an allowance for, in a way that can be
12 | * recognized off-chain (via event analysis).
13 | */
14 | abstract contract BEP20Burnable is Context, BEP20 {
15 | using SafeMath for uint256;
16 |
17 | /**
18 | * @dev Destroys `amount` tokens from the caller.
19 | *
20 | * See {BEP20-_burn}.
21 | */
22 | function burn(uint256 amount) public virtual {
23 | _burn(_msgSender(), amount);
24 | }
25 |
26 | /**
27 | * @dev Destroys `amount` tokens from `account`, deducting from the caller's
28 | * allowance.
29 | *
30 | * See {BEP20-_burn} and {BEP20-allowance}.
31 | *
32 | * Requirements:
33 | *
34 | * - the caller must have allowance for ``accounts``'s tokens of at least
35 | * `amount`.
36 | */
37 | function burnFrom(address account, uint256 amount) public virtual {
38 | uint256 decreasedAllowance = allowance(account, _msgSender()).sub(amount, "BEP20: burn amount exceeds allowance");
39 |
40 | _approve(account, _msgSender(), decreasedAllowance);
41 | _burn(account, amount);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/analysis/description-table/ServiceReceiver.md:
--------------------------------------------------------------------------------
1 | ## Sūrya's Description Report
2 |
3 | ### Files Description Table
4 |
5 |
6 | | File Name | SHA-1 Hash |
7 | |-------------|--------------|
8 | | dist/ServiceReceiver.dist.sol | c82d86212412d090a68f0d78b2f291b5adb29e30 |
9 |
10 |
11 | ### Contracts Description Table
12 |
13 |
14 | | Contract | Type | Bases | | |
15 | |:----------:|:-------------------:|:----------------:|:----------------:|:---------------:|
16 | | └ | **Function Name** | **Visibility** | **Mutability** | **Modifiers** |
17 | ||||||
18 | | **Context** | Implementation | |||
19 | | └ | _msgSender | Internal 🔒 | | |
20 | | └ | _msgData | Internal 🔒 | | |
21 | ||||||
22 | | **Ownable** | Implementation | Context |||
23 | | └ | | Public ❗️ | 🛑 |NO❗️ |
24 | | └ | owner | Public ❗️ | |NO❗️ |
25 | | └ | renounceOwnership | Public ❗️ | 🛑 | onlyOwner |
26 | | └ | transferOwnership | Public ❗️ | 🛑 | onlyOwner |
27 | ||||||
28 | | **ServiceReceiver** | Implementation | Ownable |||
29 | | └ | pay | Public ❗️ | 💵 |NO❗️ |
30 | | └ | getPrice | Public ❗️ | |NO❗️ |
31 | | └ | setPrice | Public ❗️ | 🛑 | onlyOwner |
32 | | └ | withdraw | Public ❗️ | 🛑 | onlyOwner |
33 | | └ | _toBytes32 | Private 🔐 | | |
34 |
35 |
36 | ### Legend
37 |
38 | | Symbol | Meaning |
39 | |:--------:|-----------|
40 | | 🛑 | Function can modify state |
41 | | 💵 | Function is payable |
42 |
--------------------------------------------------------------------------------
/web-console/js/app.js:
--------------------------------------------------------------------------------
1 | /* global Web3, TruffleContract */
2 |
3 | const App = {
4 | web3Provider: null,
5 | contracts: [],
6 | sc: {},
7 | load: function (contracts) {
8 | this.contracts = contracts;
9 | return this.initWeb3();
10 | },
11 | initWeb3: async function () {
12 | if (typeof window.ethereum !== 'undefined') {
13 | console.log('injected web3');
14 | this.web3Provider = window.ethereum;
15 | await this.web3Provider.enable();
16 | } else if (typeof window.web3 !== 'undefined') {
17 | console.log('injected web3 (legacy');
18 | this.web3Provider = window.web3.currentProvider;
19 | } else {
20 | console.log('provided web3');
21 | this.web3Provider = new Web3.providers.HttpProvider('https://127.0.0.1:9545');
22 | window.web3 = new Web3(this.web3Provider);
23 | }
24 |
25 | return this.initContracts();
26 | },
27 | initContracts: function () {
28 | this.contracts.forEach((contractName) => {
29 | this.getContract(contractName);
30 | });
31 | },
32 | getContract: async function (contractName) {
33 | fetch(`${contractName}.json`)
34 | .then((response) => response.json())
35 | .then((contract) => {
36 | this.sc[contractName] = TruffleContract(contract);
37 | this.sc[contractName].setProvider(this.web3Provider);
38 | })
39 | .catch(error => console.log(error));
40 | },
41 | };
42 |
43 | App.load(['SimpleBEP20', 'StandardBEP20', 'ServiceReceiver']);
44 |
--------------------------------------------------------------------------------
/contracts/token/BEP20/MintableBEP20.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 |
3 | pragma solidity ^0.7.0;
4 |
5 | import "./lib/BEP20Mintable.sol";
6 |
7 | import "../../service/ServicePayer.sol";
8 |
9 | /**
10 | * @title MintableBEP20
11 | * @dev Implementation of the MintableBEP20
12 | */
13 | contract MintableBEP20 is BEP20Mintable, ServicePayer {
14 |
15 | constructor (
16 | string memory name,
17 | string memory symbol,
18 | uint8 decimals,
19 | uint256 initialBalance,
20 | address payable feeReceiver
21 | )
22 | BEP20(name, symbol)
23 | ServicePayer(feeReceiver, "MintableBEP20")
24 | payable
25 | {
26 | _setupDecimals(decimals);
27 | _mint(_msgSender(), initialBalance);
28 | }
29 |
30 | /**
31 | * @dev Function to mint tokens.
32 | *
33 | * NOTE: restricting access to owner only. See {BEP20Mintable-mint}.
34 | *
35 | * @param account The address that will receive the minted tokens
36 | * @param amount The amount of tokens to mint
37 | */
38 | function _mint(address account, uint256 amount) internal override onlyOwner {
39 | super._mint(account, amount);
40 | }
41 |
42 | /**
43 | * @dev Function to stop minting new tokens.
44 | *
45 | * NOTE: restricting access to owner only. See {BEP20Mintable-finishMinting}.
46 | */
47 | function _finishMinting() internal override onlyOwner {
48 | super._finishMinting();
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/test/access/Ownable.behavior.js:
--------------------------------------------------------------------------------
1 | const { constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers');
2 | const { ZERO_ADDRESS } = constants;
3 |
4 | function shouldBehaveLikeOwnable (owner, [other]) {
5 | describe('as an ownable', function () {
6 | it('should have an owner', async function () {
7 | expect(await this.ownable.owner()).to.equal(owner);
8 | });
9 |
10 | it('changes owner after transfer', async function () {
11 | const receipt = await this.ownable.transferOwnership(other, { from: owner });
12 | expectEvent(receipt, 'OwnershipTransferred');
13 |
14 | expect(await this.ownable.owner()).to.equal(other);
15 | });
16 |
17 | it('should prevent non-owners from transferring', async function () {
18 | await expectRevert(
19 | this.ownable.transferOwnership(other, { from: other }),
20 | 'Ownable: caller is not the owner',
21 | );
22 | });
23 |
24 | it('should guard access against stuck state', async function () {
25 | await expectRevert(
26 | this.ownable.transferOwnership(ZERO_ADDRESS, { from: owner }),
27 | 'Ownable: new owner is the zero address',
28 | );
29 | });
30 |
31 | it('loses owner after renouncement', async function () {
32 | const receipt = await this.ownable.renounceOwnership({ from: owner });
33 | expectEvent(receipt, 'OwnershipTransferred');
34 |
35 | expect(await this.ownable.owner()).to.equal(ZERO_ADDRESS);
36 | });
37 |
38 | it('should prevent non-owners from renouncement', async function () {
39 | await expectRevert(
40 | this.ownable.renounceOwnership({ from: other }),
41 | 'Ownable: caller is not the owner',
42 | );
43 | });
44 | });
45 | }
46 |
47 | module.exports = {
48 | shouldBehaveLikeOwnable,
49 | };
50 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends" : [
3 | "standard",
4 | "plugin:promise/recommended",
5 | ],
6 | "plugins": [
7 | "mocha-no-only",
8 | "promise",
9 | ],
10 | "env": {
11 | "browser" : true,
12 | "node" : true,
13 | "mocha" : true,
14 | "jest" : true,
15 | },
16 | "globals" : {
17 | "artifacts": false,
18 | "contract": false,
19 | "assert": false,
20 | "web3": false,
21 | },
22 | "rules": {
23 |
24 | // Strict mode
25 | "strict": ["error", "global"],
26 |
27 | // Code style
28 | "array-bracket-spacing": ["off"],
29 | "camelcase": ["error", {"properties": "always"}],
30 | "comma-dangle": ["error", "always-multiline"],
31 | "comma-spacing": ["error", {"before": false, "after": true}],
32 | "dot-notation": ["error", {"allowKeywords": true, "allowPattern": ""}],
33 | "eol-last": ["error", "always"],
34 | "eqeqeq": ["error", "smart"],
35 | "generator-star-spacing": ["error", "before"],
36 | "indent": ["error", 2],
37 | "linebreak-style": ["error", "unix"],
38 | "max-len": ["error", 120, 2],
39 | "no-debugger": "off",
40 | "no-dupe-args": "error",
41 | "no-dupe-keys": "error",
42 | "no-mixed-spaces-and-tabs": ["error", "smart-tabs"],
43 | "no-redeclare": ["error", {"builtinGlobals": true}],
44 | "no-trailing-spaces": ["error", { "skipBlankLines": false }],
45 | "no-undef": "error",
46 | "no-use-before-define": "off",
47 | "no-var": "error",
48 | "object-curly-spacing": ["error", "always"],
49 | "prefer-const": "error",
50 | "quotes": ["error", "single"],
51 | "semi": ["error", "always"],
52 | "space-before-function-paren": ["error", "always"],
53 |
54 | "mocha-no-only/mocha-no-only": ["error"],
55 |
56 | "promise/always-return": "off",
57 | "promise/avoid-new": "off",
58 | },
59 | "parserOptions": {
60 | "ecmaVersion": 2018
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/contracts/token/BEP20/lib/BEP20Mintable.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 |
3 | pragma solidity ^0.7.0;
4 |
5 | import "../lib/BEP20.sol";
6 |
7 | /**
8 | * @title BEP20Mintable
9 | * @dev Implementation of the BEP20Mintable. Extension of {BEP20} that adds a minting behaviour.
10 | */
11 | abstract contract BEP20Mintable is BEP20 {
12 |
13 | // indicates if minting is finished
14 | bool private _mintingFinished = false;
15 |
16 | /**
17 | * @dev Emitted during finish minting
18 | */
19 | event MintFinished();
20 |
21 | /**
22 | * @dev Tokens can be minted only before minting finished.
23 | */
24 | modifier canMint() {
25 | require(!_mintingFinished, "BEP20Mintable: minting is finished");
26 | _;
27 | }
28 |
29 | /**
30 | * @return if minting is finished or not.
31 | */
32 | function mintingFinished() public view returns (bool) {
33 | return _mintingFinished;
34 | }
35 |
36 | /**
37 | * @dev Function to mint tokens.
38 | *
39 | * WARNING: it allows everyone to mint new tokens. Access controls MUST be defined in derived contracts.
40 | *
41 | * @param account The address that will receive the minted tokens
42 | * @param amount The amount of tokens to mint
43 | */
44 | function mint(address account, uint256 amount) public canMint {
45 | _mint(account, amount);
46 | }
47 |
48 | /**
49 | * @dev Function to stop minting new tokens.
50 | *
51 | * WARNING: it allows everyone to finish minting. Access controls MUST be defined in derived contracts.
52 | */
53 | function finishMinting() public canMint {
54 | _finishMinting();
55 | }
56 |
57 | /**
58 | * @dev Function to stop minting new tokens.
59 | */
60 | function _finishMinting() internal virtual {
61 | _mintingFinished = true;
62 |
63 | emit MintFinished();
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/contracts/token/BEP20/CommonBEP20.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 |
3 | pragma solidity ^0.7.0;
4 |
5 | import "@openzeppelin/contracts/access/Ownable.sol";
6 | import "./lib/BEP20Capped.sol";
7 | import "./lib/BEP20Mintable.sol";
8 | import "./lib/BEP20Burnable.sol";
9 |
10 | import "../../service/ServicePayer.sol";
11 |
12 | /**
13 | * @title CommonBEP20
14 | * @dev Implementation of the CommonBEP20
15 | */
16 | contract CommonBEP20 is BEP20Capped, BEP20Mintable, BEP20Burnable, ServicePayer {
17 |
18 | constructor (
19 | string memory name,
20 | string memory symbol,
21 | uint8 decimals,
22 | uint256 cap,
23 | uint256 initialBalance,
24 | address payable feeReceiver
25 | )
26 | BEP20(name, symbol)
27 | BEP20Capped(cap)
28 | ServicePayer(feeReceiver, "CommonBEP20")
29 | payable
30 | {
31 | _setupDecimals(decimals);
32 | _mint(_msgSender(), initialBalance);
33 | }
34 |
35 | /**
36 | * @dev Function to mint tokens.
37 | *
38 | * NOTE: restricting access to owner only. See {BEP20Mintable-mint}.
39 | *
40 | * @param account The address that will receive the minted tokens
41 | * @param amount The amount of tokens to mint
42 | */
43 | function _mint(address account, uint256 amount) internal override onlyOwner {
44 | super._mint(account, amount);
45 | }
46 |
47 | /**
48 | * @dev Function to stop minting new tokens.
49 | *
50 | * NOTE: restricting access to owner only. See {BEP20Mintable-finishMinting}.
51 | */
52 | function _finishMinting() internal override onlyOwner {
53 | super._finishMinting();
54 | }
55 |
56 | /**
57 | * @dev See {BEP20-_beforeTokenTransfer}. See {BEP20Capped-_beforeTokenTransfer}.
58 | */
59 | function _beforeTokenTransfer(address from, address to, uint256 amount) internal override(BEP20, BEP20Capped) {
60 | super._beforeTokenTransfer(from, to, amount);
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push: {}
5 | pull_request: {}
6 | release:
7 | types:
8 | - created
9 |
10 | jobs:
11 | lint:
12 | name: Lint
13 | runs-on: ubuntu-latest
14 | steps:
15 | - name: Setup Code
16 | uses: actions/checkout@v2
17 |
18 | - name: Setup Node
19 | uses: actions/setup-node@v1
20 | with:
21 | node-version: '14.x'
22 |
23 | - name: Install dependencies
24 | run: npm install
25 |
26 | - name: Linter
27 | run: npm run lint
28 |
29 | test:
30 | name: Test
31 | runs-on: ubuntu-latest
32 | steps:
33 | - name: Setup Code
34 | uses: actions/checkout@v2
35 |
36 | - name: Setup Node
37 | uses: actions/setup-node@v1
38 | with:
39 | node-version: '14.x'
40 |
41 | - name: Install dependencies
42 | run: npm install
43 |
44 | - name: Test
45 | run: npm test
46 |
47 | coverage:
48 | name: Coverage
49 | runs-on: ubuntu-latest
50 | steps:
51 | - name: Setup Code
52 | uses: actions/checkout@v2
53 |
54 | - name: Setup Node
55 | uses: actions/setup-node@v1
56 | with:
57 | node-version: '14.x'
58 |
59 | - name: Install dependencies
60 | run: npm install
61 |
62 | - name: Coverage
63 | run: npm run coverage
64 |
65 | - name: Post to Coveralls
66 | uses: coverallsapp/github-action@master
67 | with:
68 | github-token: ${{ secrets.GITHUB_TOKEN }}
69 |
70 | nightly_build:
71 | name: Nightly Build
72 | runs-on: ubuntu-latest
73 |
74 | steps:
75 | - name: Setup Code
76 | uses: actions/checkout@v2
77 |
78 | - name: Setup Node
79 | uses: actions/setup-node@v1
80 | with:
81 | node-version: '14.x'
82 |
83 | - name: Install dependencies
84 | run: npm install
85 |
86 | - name: Nightly Build
87 | run: npm run truffle:test
88 | env:
89 | SOLC_NIGHTLY: true
90 |
--------------------------------------------------------------------------------
/test/service/ServicePayer.test.js:
--------------------------------------------------------------------------------
1 | const { balance, BN, constants, ether, expectRevert } = require('@openzeppelin/test-helpers');
2 | const { ZERO_ADDRESS } = constants;
3 |
4 | const { expect } = require('chai');
5 |
6 | const ServicePayer = artifacts.require('ServicePayerMock');
7 | const ServiceReceiver = artifacts.require('ServiceReceiver');
8 |
9 | contract('ServicePayer', function ([owner, thirdParty]) {
10 | const fee = ether('0.1');
11 |
12 | context('ServicePayer behaviours', function () {
13 | beforeEach(async function () {
14 | this.serviceReceiver = await ServiceReceiver.new({ from: owner });
15 |
16 | await this.serviceReceiver.setPrice('ServicePayerMock', fee);
17 | });
18 |
19 | it('requires a non-zero fee', async function () {
20 | await expectRevert(
21 | ServicePayer.new(
22 | this.serviceReceiver.address,
23 | {
24 | from: owner,
25 | value: new BN(0),
26 | },
27 | ),
28 | 'ServiceReceiver: incorrect price',
29 | );
30 | });
31 |
32 | it('requires a ServiceReceiver', async function () {
33 | await expectRevert.unspecified(
34 | ServicePayer.new(ZERO_ADDRESS, { from: owner, value: fee }),
35 | );
36 |
37 | await expectRevert.unspecified(
38 | ServicePayer.new(thirdParty, { from: owner, value: fee }),
39 | );
40 | });
41 |
42 | it('fail with incorrect price', async function () {
43 | await expectRevert(
44 | ServicePayer.new(
45 | this.serviceReceiver.address,
46 | {
47 | from: owner,
48 | value: fee.add(ether('1')),
49 | },
50 | ),
51 | 'ServiceReceiver: incorrect price',
52 | );
53 | });
54 |
55 | it('transfer fee to receiver', async function () {
56 | const initBalance = await balance.current(this.serviceReceiver.address);
57 |
58 | await ServicePayer.new(
59 | this.serviceReceiver.address,
60 | {
61 | from: owner,
62 | value: fee,
63 | },
64 | );
65 |
66 | const newBalance = (await balance.current(this.serviceReceiver.address));
67 |
68 | expect(newBalance).to.be.bignumber.equal(initBalance.add(fee));
69 | });
70 | });
71 | });
72 |
--------------------------------------------------------------------------------
/scripts/test.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Exit script as soon as a command fails.
4 | set -o errexit
5 |
6 | # Executes cleanup function at script exit.
7 | trap cleanup EXIT
8 |
9 | cleanup() {
10 | # Kill the ganache instance that we started (if we started one and if it's still running).
11 | if [ -n "$ganache_pid" ] && ps -p $ganache_pid > /dev/null; then
12 | kill -9 $ganache_pid
13 | fi
14 | }
15 |
16 | ganache_port=8545
17 |
18 | ganache_running() {
19 | nc -z localhost "$ganache_port"
20 | }
21 |
22 | start_ganache() {
23 | # We define 10 accounts with balance 1M ether, needed for high-value tests.
24 | local accounts=(
25 | --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501200,1000000000000000000000000"
26 | --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501201,1000000000000000000000000"
27 | --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501202,1000000000000000000000000"
28 | --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501203,1000000000000000000000000"
29 | --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501204,1000000000000000000000000"
30 | --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501205,1000000000000000000000000"
31 | --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501206,1000000000000000000000000"
32 | --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501207,1000000000000000000000000"
33 | --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501208,1000000000000000000000000"
34 | --account="0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501209,1000000000000000000000000"
35 | )
36 |
37 | npx ganache-cli --gasLimit 0xfffffffffff --port "$ganache_port" "${accounts[@]}" > /dev/null &
38 |
39 | ganache_pid=$!
40 |
41 | echo "Waiting for ganache to launch on port "$ganache_port"..."
42 |
43 | while ! ganache_running; do
44 | sleep 0.1 # wait for 1/10 of the second before check again
45 | done
46 |
47 | echo "Ganache launched!"
48 | }
49 |
50 | if ganache_running; then
51 | echo "Using existing ganache instance"
52 | else
53 | echo "Starting our own ganache instance"
54 | start_ganache
55 | fi
56 |
57 | npx truffle version
58 |
59 | npx truffle test "$@"
60 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bep20-generator",
3 | "version": "1.0.0",
4 | "description": "The new Smart Contract Generator for BEP20 Token.",
5 | "files": [
6 | "contracts",
7 | "test"
8 | ],
9 | "scripts": {
10 | "dev": "lite-server",
11 | "truffle:console": "truffle develop",
12 | "truffle:compile": "scripts/compile.sh",
13 | "truffle:test": "npm run truffle:compile && scripts/test.sh",
14 | "hardhat:console": "hardhat console",
15 | "hardhat:compile": "hardhat compile",
16 | "hardhat:test": "hardhat test",
17 | "hardhat:coverage": "hardhat coverage --network coverage",
18 | "test": "npm run hardhat:test",
19 | "coverage": "scripts/coverage.sh",
20 | "clean": "rm -rf coverage",
21 | "profile": "npm run clean && npm run coverage && open coverage/index.html",
22 | "lint": "npm run lint:js && npm run lint:sol",
23 | "lint:fix": "npm run lint:js:fix",
24 | "lint:js": "eslint .",
25 | "lint:js:fix": "eslint . --fix",
26 | "lint:sol": "solhint --max-warnings 0 \"contracts/**/*.sol\"",
27 | "flat": "scripts/flat.sh",
28 | "analyze": "scripts/analyze.sh"
29 | },
30 | "keywords": [
31 | "solidity",
32 | "bsc",
33 | "smart",
34 | "contracts",
35 | "token",
36 | "bep20"
37 | ],
38 | "repository": {
39 | "type": "git",
40 | "url": "https://github.com/hikecoder/bep20-generator.git"
41 | },
42 | "homepage": "https://hikecoder.github.io/bep20-generator",
43 | "bugs": {
44 | "url": "https://github.com/hikecoder/bep20-generator/issues"
45 | },
46 | "author": "Vittorio Minacori",
47 | "contributors": [
48 | {
49 | "name": "Vittorio Minacori",
50 | "url": "https://github.com/hikecoder"
51 | }
52 | ],
53 | "license": "MIT",
54 | "devDependencies": {
55 | "@nomiclabs/hardhat-ganache": "^2.0.0",
56 | "@nomiclabs/hardhat-truffle5": "^2.0.0",
57 | "@nomiclabs/hardhat-web3": "^2.0.0",
58 | "@openzeppelin/test-helpers": "^0.5.9",
59 | "chai": "^4.2.0",
60 | "eslint": "^7.16.0",
61 | "eslint-config-standard": "^16.0.2",
62 | "eslint-plugin-import": "^2.22.1",
63 | "eslint-plugin-mocha-no-only": "^1.1.1",
64 | "eslint-plugin-node": "^11.1.0",
65 | "eslint-plugin-promise": "^4.2.1",
66 | "eslint-plugin-standard": "^5.0.0",
67 | "ganache-cli": "^6.12.1",
68 | "hardhat": "^2.0.6",
69 | "lite-server": "^2.6.1",
70 | "sol2uml": "^1.1.21",
71 | "solhint": "^3.3.2",
72 | "solidity-coverage": "^0.7.13",
73 | "surya": "^0.4.1",
74 | "truffle": "5.1.49",
75 | "truffle-flattener": "^1.5.0"
76 | },
77 | "dependencies": {
78 | "@openzeppelin/contracts": "3.3.0-solc-0.7"
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/test/token/BEP20/StandardBEP20.test.js:
--------------------------------------------------------------------------------
1 | const { BN, ether, expectRevert } = require('@openzeppelin/test-helpers');
2 |
3 | const { shouldBehaveLikeBEP20 } = require('./behaviours/BEP20.behaviour');
4 |
5 | const StandardBEP20 = artifacts.require('StandardBEP20');
6 | const ServiceReceiver = artifacts.require('ServiceReceiver');
7 |
8 | contract('StandardBEP20', function ([owner, other, thirdParty]) {
9 | const _name = 'StandardBEP20';
10 | const _symbol = 'BEP20';
11 | const _decimals = new BN(8);
12 | const _initialSupply = new BN(100000000);
13 |
14 | const fee = ether('0.1');
15 |
16 | beforeEach(async function () {
17 | this.serviceReceiver = await ServiceReceiver.new({ from: owner });
18 | await this.serviceReceiver.setPrice('StandardBEP20', fee);
19 | });
20 |
21 | context('creating valid token', function () {
22 | describe('as a StandardBEP20', function () {
23 | describe('without initial supply', function () {
24 | it('should fail', async function () {
25 | await expectRevert(
26 | StandardBEP20.new(
27 | _name,
28 | _symbol,
29 | _decimals,
30 | 0,
31 | this.serviceReceiver.address,
32 | {
33 | from: owner,
34 | value: fee,
35 | },
36 | ),
37 | 'StandardBEP20: supply cannot be zero',
38 | );
39 | });
40 | });
41 |
42 | describe('with initial supply', function () {
43 | beforeEach(async function () {
44 | this.token = await StandardBEP20.new(
45 | _name,
46 | _symbol,
47 | _decimals,
48 | _initialSupply,
49 | this.serviceReceiver.address,
50 | {
51 | from: owner,
52 | value: fee,
53 | },
54 | );
55 | });
56 |
57 | describe('once deployed', function () {
58 | it('total supply should be equal to initial supply', async function () {
59 | (await this.token.totalSupply()).should.be.bignumber.equal(_initialSupply);
60 | });
61 |
62 | it('owner balance should be equal to initial supply', async function () {
63 | (await this.token.balanceOf(owner)).should.be.bignumber.equal(_initialSupply);
64 | });
65 | });
66 | });
67 | });
68 | });
69 |
70 | context('StandardBEP20 token behaviours', function () {
71 | beforeEach(async function () {
72 | this.token = await StandardBEP20.new(
73 | _name,
74 | _symbol,
75 | _decimals,
76 | _initialSupply,
77 | this.serviceReceiver.address,
78 | {
79 | from: owner,
80 | value: fee,
81 | },
82 | );
83 | });
84 |
85 | context('like a BEP20', function () {
86 | shouldBehaveLikeBEP20(_name, _symbol, _decimals, _initialSupply, [owner, other, thirdParty]);
87 | });
88 | });
89 | });
90 |
--------------------------------------------------------------------------------
/test/token/BEP20/SimpleBEP20.test.js:
--------------------------------------------------------------------------------
1 | const { BN, expectRevert } = require('@openzeppelin/test-helpers');
2 |
3 | const { shouldBehaveLikeBEP20 } = require('./behaviours/BEP20.behaviour');
4 |
5 | const { shouldBehaveLikeGeneratorCopyright } = require('../../utils/GeneratorCopyright.behaviour');
6 |
7 | const SimpleBEP20 = artifacts.require('SimpleBEP20');
8 | const ServiceReceiver = artifacts.require('ServiceReceiver');
9 |
10 | contract('SimpleBEP20', function ([owner, other, thirdParty]) {
11 | const _name = 'SimpleBEP20';
12 | const _symbol = 'BEP20';
13 | const _decimals = new BN(18);
14 | const _initialSupply = new BN(100000000);
15 |
16 | const fee = 0;
17 |
18 | const version = 'v1.0.0';
19 |
20 | beforeEach(async function () {
21 | this.serviceReceiver = await ServiceReceiver.new({ from: owner });
22 | // not to set any price means it doesn't require any fee
23 | // await this.serviceReceiver.setPrice('SimpleBEP20', fee);
24 | });
25 |
26 | context('creating valid token', function () {
27 | describe('without initial supply', function () {
28 | it('should fail', async function () {
29 | await expectRevert(
30 | SimpleBEP20.new(
31 | _name,
32 | _symbol,
33 | 0,
34 | this.serviceReceiver.address,
35 | {
36 | from: owner,
37 | value: fee,
38 | },
39 | ),
40 | 'SimpleBEP20: supply cannot be zero',
41 | );
42 | });
43 | });
44 |
45 | describe('with initial supply', function () {
46 | beforeEach(async function () {
47 | this.token = await SimpleBEP20.new(
48 | _name,
49 | _symbol,
50 | _initialSupply,
51 | this.serviceReceiver.address,
52 | {
53 | from: owner,
54 | value: fee,
55 | },
56 | );
57 | });
58 |
59 | describe('once deployed', function () {
60 | it('total supply should be equal to initial supply', async function () {
61 | (await this.token.totalSupply()).should.be.bignumber.equal(_initialSupply);
62 | });
63 |
64 | it('owner balance should be equal to initial supply', async function () {
65 | (await this.token.balanceOf(owner)).should.be.bignumber.equal(_initialSupply);
66 | });
67 | });
68 | });
69 | });
70 |
71 | context('SimpleBEP20 token behaviours', function () {
72 | beforeEach(async function () {
73 | this.token = await SimpleBEP20.new(
74 | _name,
75 | _symbol,
76 | _initialSupply,
77 | this.serviceReceiver.address,
78 | {
79 | from: owner,
80 | value: fee,
81 | },
82 | );
83 | });
84 |
85 | context('like a BEP20', function () {
86 | shouldBehaveLikeBEP20(_name, _symbol, _decimals, _initialSupply, [owner, other, thirdParty]);
87 | });
88 |
89 | context('like a GeneratorCopyright', function () {
90 | beforeEach(async function () {
91 | this.instance = this.token;
92 | });
93 |
94 | shouldBehaveLikeGeneratorCopyright(version);
95 | });
96 | });
97 | });
98 |
--------------------------------------------------------------------------------
/test/token/BEP20/BurnableBEP20.test.js:
--------------------------------------------------------------------------------
1 | const { BN, ether, expectRevert } = require('@openzeppelin/test-helpers');
2 |
3 | const { shouldBehaveLikeBEP20 } = require('./behaviours/BEP20.behaviour');
4 | const { shouldBehaveLikeBEP20Burnable } = require('./behaviours/BEP20Burnable.behaviour');
5 |
6 | const BurnableBEP20 = artifacts.require('BurnableBEP20');
7 | const ServiceReceiver = artifacts.require('ServiceReceiver');
8 |
9 | contract('BurnableBEP20', function ([owner, other, thirdParty]) {
10 | const _name = 'BurnableBEP20';
11 | const _symbol = 'BEP20';
12 | const _decimals = new BN(8);
13 | const _initialSupply = new BN(100000000);
14 |
15 | const fee = ether('0.1');
16 |
17 | beforeEach(async function () {
18 | this.serviceReceiver = await ServiceReceiver.new({ from: owner });
19 | await this.serviceReceiver.setPrice('BurnableBEP20', fee);
20 | });
21 |
22 | context('creating valid token', function () {
23 | describe('as a BurnableBEP20', function () {
24 | describe('without initial supply', function () {
25 | it('should fail', async function () {
26 | await expectRevert(
27 | BurnableBEP20.new(
28 | _name,
29 | _symbol,
30 | _decimals,
31 | 0,
32 | this.serviceReceiver.address,
33 | {
34 | from: owner,
35 | value: fee,
36 | },
37 | ),
38 | 'BurnableBEP20: supply cannot be zero',
39 | );
40 | });
41 | });
42 |
43 | describe('with initial supply', function () {
44 | beforeEach(async function () {
45 | this.token = await BurnableBEP20.new(
46 | _name,
47 | _symbol,
48 | _decimals,
49 | _initialSupply,
50 | this.serviceReceiver.address,
51 | {
52 | from: owner,
53 | value: fee,
54 | },
55 | );
56 | });
57 |
58 | describe('once deployed', function () {
59 | it('total supply should be equal to initial supply', async function () {
60 | (await this.token.totalSupply()).should.be.bignumber.equal(_initialSupply);
61 | });
62 |
63 | it('owner balance should be equal to initial supply', async function () {
64 | (await this.token.balanceOf(owner)).should.be.bignumber.equal(_initialSupply);
65 | });
66 | });
67 | });
68 | });
69 | });
70 |
71 | context('BurnableBEP20 token behaviours', function () {
72 | beforeEach(async function () {
73 | this.token = await BurnableBEP20.new(
74 | _name,
75 | _symbol,
76 | _decimals,
77 | _initialSupply,
78 | this.serviceReceiver.address,
79 | {
80 | from: owner,
81 | value: fee,
82 | },
83 | );
84 | });
85 |
86 | context('like a BEP20', function () {
87 | shouldBehaveLikeBEP20(_name, _symbol, _decimals, _initialSupply, [owner, other, thirdParty]);
88 | });
89 |
90 | context('like a BEP20Burnable', function () {
91 | shouldBehaveLikeBEP20Burnable(_initialSupply, [owner, thirdParty]);
92 | });
93 | });
94 | });
95 |
--------------------------------------------------------------------------------
/analysis/description-table/StandardBEP20.md:
--------------------------------------------------------------------------------
1 | ## Sūrya's Description Report
2 |
3 | ### Files Description Table
4 |
5 |
6 | | File Name | SHA-1 Hash |
7 | |-------------|--------------|
8 | | dist/StandardBEP20.dist.sol | 23219f5850842afedd8f7e908d03573fa9be6daa |
9 |
10 |
11 | ### Contracts Description Table
12 |
13 |
14 | | Contract | Type | Bases | | |
15 | |:----------:|:-------------------:|:----------------:|:----------------:|:---------------:|
16 | | └ | **Function Name** | **Visibility** | **Mutability** | **Modifiers** |
17 | ||||||
18 | | **Context** | Implementation | |||
19 | | └ | _msgSender | Internal 🔒 | | |
20 | | └ | _msgData | Internal 🔒 | | |
21 | ||||||
22 | | **Ownable** | Implementation | Context |||
23 | | └ | | Public ❗️ | 🛑 |NO❗️ |
24 | | └ | owner | Public ❗️ | |NO❗️ |
25 | | └ | renounceOwnership | Public ❗️ | 🛑 | onlyOwner |
26 | | └ | transferOwnership | Public ❗️ | 🛑 | onlyOwner |
27 | ||||||
28 | | **SafeMath** | Library | |||
29 | | └ | add | Internal 🔒 | | |
30 | | └ | sub | Internal 🔒 | | |
31 | | └ | sub | Internal 🔒 | | |
32 | | └ | mul | Internal 🔒 | | |
33 | | └ | div | Internal 🔒 | | |
34 | | └ | div | Internal 🔒 | | |
35 | | └ | mod | Internal 🔒 | | |
36 | | └ | mod | Internal 🔒 | | |
37 | ||||||
38 | | **IBEP20** | Interface | |||
39 | | └ | name | External ❗️ | |NO❗️ |
40 | | └ | symbol | External ❗️ | |NO❗️ |
41 | | └ | decimals | External ❗️ | |NO❗️ |
42 | | └ | totalSupply | External ❗️ | |NO❗️ |
43 | | └ | balanceOf | External ❗️ | |NO❗️ |
44 | | └ | getOwner | External ❗️ | |NO❗️ |
45 | | └ | transfer | External ❗️ | 🛑 |NO❗️ |
46 | | └ | transferFrom | External ❗️ | 🛑 |NO❗️ |
47 | | └ | approve | External ❗️ | 🛑 |NO❗️ |
48 | | └ | allowance | External ❗️ | |NO❗️ |
49 | ||||||
50 | | **BEP20** | Implementation | Ownable, IBEP20 |||
51 | | └ | | Public ❗️ | 🛑 |NO❗️ |
52 | | └ | name | Public ❗️ | |NO❗️ |
53 | | └ | symbol | Public ❗️ | |NO❗️ |
54 | | └ | decimals | Public ❗️ | |NO❗️ |
55 | | └ | totalSupply | Public ❗️ | |NO❗️ |
56 | | └ | balanceOf | Public ❗️ | |NO❗️ |
57 | | └ | getOwner | Public ❗️ | |NO❗️ |
58 | | └ | transfer | Public ❗️ | 🛑 |NO❗️ |
59 | | └ | transferFrom | Public ❗️ | 🛑 |NO❗️ |
60 | | └ | approve | Public ❗️ | 🛑 |NO❗️ |
61 | | └ | allowance | Public ❗️ | |NO❗️ |
62 | | └ | increaseAllowance | Public ❗️ | 🛑 |NO❗️ |
63 | | └ | decreaseAllowance | Public ❗️ | 🛑 |NO❗️ |
64 | | └ | _transfer | Internal 🔒 | 🛑 | |
65 | | └ | _mint | Internal 🔒 | 🛑 | |
66 | | └ | _burn | Internal 🔒 | 🛑 | |
67 | | └ | _approve | Internal 🔒 | 🛑 | |
68 | | └ | _setupDecimals | Internal 🔒 | 🛑 | |
69 | | └ | _beforeTokenTransfer | Internal 🔒 | 🛑 | |
70 | ||||||
71 | | **ServiceReceiver** | Implementation | Ownable |||
72 | | └ | pay | Public ❗️ | 💵 |NO❗️ |
73 | | └ | getPrice | Public ❗️ | |NO❗️ |
74 | | └ | setPrice | Public ❗️ | 🛑 | onlyOwner |
75 | | └ | withdraw | Public ❗️ | 🛑 | onlyOwner |
76 | | └ | _toBytes32 | Private 🔐 | | |
77 | ||||||
78 | | **ServicePayer** | Implementation | |||
79 | | └ | | Public ❗️ | 💵 |NO❗️ |
80 | ||||||
81 | | **StandardBEP20** | Implementation | BEP20, ServicePayer |||
82 | | └ | | Public ❗️ | 💵 | BEP20 ServicePayer |
83 |
84 |
85 | ### Legend
86 |
87 | | Symbol | Meaning |
88 | |:--------:|-----------|
89 | | 🛑 | Function can modify state |
90 | | 💵 | Function is payable |
91 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # BEP20 Token Generator
2 |
3 | [](https://github.com/defipro/bep20-generator/actions/)
4 | [](https://coveralls.io/github/defipro/bep20-generator?branch=master)
5 | [](https://github.com/defipro/bep20-generator/blob/master/LICENSE)
6 |
7 | The new Smart Contract Generator for BEP20 Token.
8 |
9 | ## Try it
10 |
11 | [https://defipro.github.io/bep20-generator](https://defipro.github.io/bep20-generator)
12 |
13 |
14 | ## Development
15 |
16 |
17 | ### Install dependencies
18 |
19 | ```bash
20 | npm install
21 | ```
22 |
23 |
24 | ### Usage (using Truffle)
25 |
26 | Open the Truffle console
27 |
28 | ```bash
29 | npm run truffle:console
30 | ```
31 |
32 |
33 | #### Compile
34 |
35 | ```bash
36 | npm run truffle:compile
37 | ```
38 |
39 |
40 | #### Test
41 |
42 | ```bash
43 | npm run truffle:test
44 | ```
45 |
46 |
47 | ### Usage (using Hardhat)
48 |
49 | Open the Hardhat console
50 |
51 | ```bash
52 | npm run hardhat:console
53 | ```
54 |
55 |
56 | #### Compile
57 |
58 | ```bash
59 | npm run hardhat:compile
60 | ```
61 |
62 |
63 | #### Test
64 |
65 | ```bash
66 | npm run hardhat:test
67 | ```
68 |
69 |
70 | ### Code Coverage
71 |
72 | ```bash
73 | npm run hardhat:coverage
74 | ```
75 |
76 |
77 | ## Linter
78 |
79 | Use Solhint
80 |
81 | ```bash
82 | npm run lint:sol
83 | ```
84 |
85 | Use ESLint
86 |
87 | ```bash
88 | npm run lint:js
89 | ```
90 |
91 | Use ESLint and fix
92 |
93 | ```bash
94 | npm run lint:fix
95 | ```
96 |
97 |
98 | ## Flattener
99 |
100 | This allow to flatten the code into a single file
101 |
102 | Edit `scripts/flat.sh` to add your contracts
103 |
104 | ```bash
105 | npm run flat
106 | ```
107 |
108 |
109 | ## Analysis
110 |
111 | Note: it is better to analyze the flattened code to have a bigger overview on the entire codebase. So run the flattener first.
112 |
113 | ### Describe
114 |
115 | The `describe` command shows a summary of the contracts and methods in the files provided
116 |
117 | ```bash
118 | npx surya describe dist/StandardBEP20.dist.sol
119 | ```
120 |
121 | ### Dependencies
122 |
123 | The `dependencies` command outputs the c3-linearization of a given contract's inheirtance graph. Contracts will be listed starting with most-derived, ie. if the same function is defined in more than one contract, the solidity compiler will use the definition in whichever contract is listed first.
124 |
125 | ```bash
126 | npx surya dependencies StandardBEP20 dist/StandardBEP20.dist.sol
127 | ```
128 | ### Generate Report
129 |
130 | Edit `scripts/analyze.sh` to add your contracts
131 |
132 | ```bash
133 | npm run analyze
134 | ```
135 |
136 | The `inheritance` command outputs a DOT-formatted graph of the inheritance tree.
137 |
138 | The `graph` command outputs a DOT-formatted graph of the control flow.
139 |
140 | The `mdreport` command creates a markdown description report with tables comprising information about the system's files, contracts and their functions.
141 |
142 | The `sol2uml` generates UML class diagram from Solidity contracts.
143 |
144 |
145 | ## License
146 |
147 | Code released under the [MIT License](https://github.com/defipro/bep20-generator/blob/master/LICENSE).
148 |
149 |
--------------------------------------------------------------------------------
/contracts/token/BEP20/lib/IBEP20.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 |
3 | pragma solidity ^0.7.0;
4 |
5 | /**
6 | * @dev Interface of the BEP standard.
7 | */
8 | interface IBEP20 {
9 |
10 | /**
11 | * @dev Returns the token name.
12 | */
13 | function name() external view returns (string memory);
14 |
15 | /**
16 | * @dev Returns the token symbol.
17 | */
18 | function symbol() external view returns (string memory);
19 |
20 | /**
21 | * @dev Returns the token decimals.
22 | */
23 | function decimals() external view returns (uint8);
24 |
25 | /**
26 | * @dev Returns the amount of tokens in existence.
27 | */
28 | function totalSupply() external view returns (uint256);
29 |
30 | /**
31 | * @dev Returns the amount of tokens owned by `account`.
32 | */
33 | function balanceOf(address account) external view returns (uint256);
34 |
35 | /**
36 | * @dev Returns the token owner.
37 | */
38 | function getOwner() external view returns (address);
39 |
40 | /**
41 | * @dev Moves `amount` tokens from the caller's account to `recipient`.
42 | *
43 | * Returns a boolean value indicating whether the operation succeeded.
44 | *
45 | * Emits a {Transfer} event.
46 | */
47 | function transfer(address recipient, uint256 amount) external returns (bool);
48 |
49 | /**
50 | * @dev Moves `amount` tokens from `sender` to `recipient` using the
51 | * allowance mechanism. `amount` is then deducted from the caller's
52 | * allowance.
53 | *
54 | * Returns a boolean value indicating whether the operation succeeded.
55 | *
56 | * Emits a {Transfer} event.
57 | */
58 | function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
59 |
60 | /**
61 | * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
62 | *
63 | * Returns a boolean value indicating whether the operation succeeded.
64 | *
65 | * IMPORTANT: Beware that changing an allowance with this method brings the risk
66 | * that someone may use both the old and the new allowance by unfortunate
67 | * transaction ordering. One possible solution to mitigate this race
68 | * condition is to first reduce the spender's allowance to 0 and set the
69 | * desired value afterwards:
70 | * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
71 | *
72 | * Emits an {Approval} event.
73 | */
74 | function approve(address spender, uint256 amount) external returns (bool);
75 |
76 | /**
77 | * @dev Returns the remaining number of tokens that `spender` will be
78 | * allowed to spend on behalf of `owner` through {transferFrom}. This is
79 | * zero by default.
80 | *
81 | * This value changes when {approve} or {transferFrom} are called.
82 | */
83 | function allowance(address _owner, address spender) external view returns (uint256);
84 |
85 | /**
86 | * @dev Emitted when `value` tokens are moved from one account (`from`) to
87 | * another (`to`).
88 | *
89 | * Note that `value` may be zero.
90 | */
91 | event Transfer(address indexed from, address indexed to, uint256 value);
92 |
93 | /**
94 | * @dev Emitted when the allowance of a `spender` for an `owner` is set by
95 | * a call to {approve}. `value` is the new allowance.
96 | */
97 | event Approval(address indexed owner, address indexed spender, uint256 value);
98 | }
99 |
--------------------------------------------------------------------------------
/analysis/description-table/BurnableBEP20.md:
--------------------------------------------------------------------------------
1 | ## Sūrya's Description Report
2 |
3 | ### Files Description Table
4 |
5 |
6 | | File Name | SHA-1 Hash |
7 | |-------------|--------------|
8 | | dist/BurnableBEP20.dist.sol | c6b9515f052b612a8cef28ce27d93603b37d7526 |
9 |
10 |
11 | ### Contracts Description Table
12 |
13 |
14 | | Contract | Type | Bases | | |
15 | |:----------:|:-------------------:|:----------------:|:----------------:|:---------------:|
16 | | └ | **Function Name** | **Visibility** | **Mutability** | **Modifiers** |
17 | ||||||
18 | | **Context** | Implementation | |||
19 | | └ | _msgSender | Internal 🔒 | | |
20 | | └ | _msgData | Internal 🔒 | | |
21 | ||||||
22 | | **Ownable** | Implementation | Context |||
23 | | └ | | Public ❗️ | 🛑 |NO❗️ |
24 | | └ | owner | Public ❗️ | |NO❗️ |
25 | | └ | renounceOwnership | Public ❗️ | 🛑 | onlyOwner |
26 | | └ | transferOwnership | Public ❗️ | 🛑 | onlyOwner |
27 | ||||||
28 | | **SafeMath** | Library | |||
29 | | └ | add | Internal 🔒 | | |
30 | | └ | sub | Internal 🔒 | | |
31 | | └ | sub | Internal 🔒 | | |
32 | | └ | mul | Internal 🔒 | | |
33 | | └ | div | Internal 🔒 | | |
34 | | └ | div | Internal 🔒 | | |
35 | | └ | mod | Internal 🔒 | | |
36 | | └ | mod | Internal 🔒 | | |
37 | ||||||
38 | | **IBEP20** | Interface | |||
39 | | └ | name | External ❗️ | |NO❗️ |
40 | | └ | symbol | External ❗️ | |NO❗️ |
41 | | └ | decimals | External ❗️ | |NO❗️ |
42 | | └ | totalSupply | External ❗️ | |NO❗️ |
43 | | └ | balanceOf | External ❗️ | |NO❗️ |
44 | | └ | getOwner | External ❗️ | |NO❗️ |
45 | | └ | transfer | External ❗️ | 🛑 |NO❗️ |
46 | | └ | transferFrom | External ❗️ | 🛑 |NO❗️ |
47 | | └ | approve | External ❗️ | 🛑 |NO❗️ |
48 | | └ | allowance | External ❗️ | |NO❗️ |
49 | ||||||
50 | | **BEP20** | Implementation | Ownable, IBEP20 |||
51 | | └ | | Public ❗️ | 🛑 |NO❗️ |
52 | | └ | name | Public ❗️ | |NO❗️ |
53 | | └ | symbol | Public ❗️ | |NO❗️ |
54 | | └ | decimals | Public ❗️ | |NO❗️ |
55 | | └ | totalSupply | Public ❗️ | |NO❗️ |
56 | | └ | balanceOf | Public ❗️ | |NO❗️ |
57 | | └ | getOwner | Public ❗️ | |NO❗️ |
58 | | └ | transfer | Public ❗️ | 🛑 |NO❗️ |
59 | | └ | transferFrom | Public ❗️ | 🛑 |NO❗️ |
60 | | └ | approve | Public ❗️ | 🛑 |NO❗️ |
61 | | └ | allowance | Public ❗️ | |NO❗️ |
62 | | └ | increaseAllowance | Public ❗️ | 🛑 |NO❗️ |
63 | | └ | decreaseAllowance | Public ❗️ | 🛑 |NO❗️ |
64 | | └ | _transfer | Internal 🔒 | 🛑 | |
65 | | └ | _mint | Internal 🔒 | 🛑 | |
66 | | └ | _burn | Internal 🔒 | 🛑 | |
67 | | └ | _approve | Internal 🔒 | 🛑 | |
68 | | └ | _setupDecimals | Internal 🔒 | 🛑 | |
69 | | └ | _beforeTokenTransfer | Internal 🔒 | 🛑 | |
70 | ||||||
71 | | **BEP20Burnable** | Implementation | Context, BEP20 |||
72 | | └ | burn | Public ❗️ | 🛑 |NO❗️ |
73 | | └ | burnFrom | Public ❗️ | 🛑 |NO❗️ |
74 | ||||||
75 | | **ServiceReceiver** | Implementation | Ownable |||
76 | | └ | pay | Public ❗️ | 💵 |NO❗️ |
77 | | └ | getPrice | Public ❗️ | |NO❗️ |
78 | | └ | setPrice | Public ❗️ | 🛑 | onlyOwner |
79 | | └ | withdraw | Public ❗️ | 🛑 | onlyOwner |
80 | | └ | _toBytes32 | Private 🔐 | | |
81 | ||||||
82 | | **ServicePayer** | Implementation | |||
83 | | └ | | Public ❗️ | 💵 |NO❗️ |
84 | ||||||
85 | | **BurnableBEP20** | Implementation | BEP20Burnable, ServicePayer |||
86 | | └ | | Public ❗️ | 💵 | BEP20 ServicePayer |
87 |
88 |
89 | ### Legend
90 |
91 | | Symbol | Meaning |
92 | |:--------:|-----------|
93 | | 🛑 | Function can modify state |
94 | | 💵 | Function is payable |
95 |
--------------------------------------------------------------------------------
/analysis/description-table/SimpleBEP20.md:
--------------------------------------------------------------------------------
1 | ## Sūrya's Description Report
2 |
3 | ### Files Description Table
4 |
5 |
6 | | File Name | SHA-1 Hash |
7 | |-------------|--------------|
8 | | dist/SimpleBEP20.dist.sol | 5cc3eb3c9ca4a92f761b3fdb28076859e60844e3 |
9 |
10 |
11 | ### Contracts Description Table
12 |
13 |
14 | | Contract | Type | Bases | | |
15 | |:----------:|:-------------------:|:----------------:|:----------------:|:---------------:|
16 | | └ | **Function Name** | **Visibility** | **Mutability** | **Modifiers** |
17 | ||||||
18 | | **Context** | Implementation | |||
19 | | └ | _msgSender | Internal 🔒 | | |
20 | | └ | _msgData | Internal 🔒 | | |
21 | ||||||
22 | | **Ownable** | Implementation | Context |||
23 | | └ | | Public ❗️ | 🛑 |NO❗️ |
24 | | └ | owner | Public ❗️ | |NO❗️ |
25 | | └ | renounceOwnership | Public ❗️ | 🛑 | onlyOwner |
26 | | └ | transferOwnership | Public ❗️ | 🛑 | onlyOwner |
27 | ||||||
28 | | **SafeMath** | Library | |||
29 | | └ | add | Internal 🔒 | | |
30 | | └ | sub | Internal 🔒 | | |
31 | | └ | sub | Internal 🔒 | | |
32 | | └ | mul | Internal 🔒 | | |
33 | | └ | div | Internal 🔒 | | |
34 | | └ | div | Internal 🔒 | | |
35 | | └ | mod | Internal 🔒 | | |
36 | | └ | mod | Internal 🔒 | | |
37 | ||||||
38 | | **IBEP20** | Interface | |||
39 | | └ | name | External ❗️ | |NO❗️ |
40 | | └ | symbol | External ❗️ | |NO❗️ |
41 | | └ | decimals | External ❗️ | |NO❗️ |
42 | | └ | totalSupply | External ❗️ | |NO❗️ |
43 | | └ | balanceOf | External ❗️ | |NO❗️ |
44 | | └ | getOwner | External ❗️ | |NO❗️ |
45 | | └ | transfer | External ❗️ | 🛑 |NO❗️ |
46 | | └ | transferFrom | External ❗️ | 🛑 |NO❗️ |
47 | | └ | approve | External ❗️ | 🛑 |NO❗️ |
48 | | └ | allowance | External ❗️ | |NO❗️ |
49 | ||||||
50 | | **BEP20** | Implementation | Ownable, IBEP20 |||
51 | | └ | | Public ❗️ | 🛑 |NO❗️ |
52 | | └ | name | Public ❗️ | |NO❗️ |
53 | | └ | symbol | Public ❗️ | |NO❗️ |
54 | | └ | decimals | Public ❗️ | |NO❗️ |
55 | | └ | totalSupply | Public ❗️ | |NO❗️ |
56 | | └ | balanceOf | Public ❗️ | |NO❗️ |
57 | | └ | getOwner | Public ❗️ | |NO❗️ |
58 | | └ | transfer | Public ❗️ | 🛑 |NO❗️ |
59 | | └ | transferFrom | Public ❗️ | 🛑 |NO❗️ |
60 | | └ | approve | Public ❗️ | 🛑 |NO❗️ |
61 | | └ | allowance | Public ❗️ | |NO❗️ |
62 | | └ | increaseAllowance | Public ❗️ | 🛑 |NO❗️ |
63 | | └ | decreaseAllowance | Public ❗️ | 🛑 |NO❗️ |
64 | | └ | _transfer | Internal 🔒 | 🛑 | |
65 | | └ | _mint | Internal 🔒 | 🛑 | |
66 | | └ | _burn | Internal 🔒 | 🛑 | |
67 | | └ | _approve | Internal 🔒 | 🛑 | |
68 | | └ | _setupDecimals | Internal 🔒 | 🛑 | |
69 | | └ | _beforeTokenTransfer | Internal 🔒 | 🛑 | |
70 | ||||||
71 | | **ServiceReceiver** | Implementation | Ownable |||
72 | | └ | pay | Public ❗️ | 💵 |NO❗️ |
73 | | └ | getPrice | Public ❗️ | |NO❗️ |
74 | | └ | setPrice | Public ❗️ | 🛑 | onlyOwner |
75 | | └ | withdraw | Public ❗️ | 🛑 | onlyOwner |
76 | | └ | _toBytes32 | Private 🔐 | | |
77 | ||||||
78 | | **ServicePayer** | Implementation | |||
79 | | └ | | Public ❗️ | 💵 |NO❗️ |
80 | ||||||
81 | | **GeneratorCopyright** | Implementation | |||
82 | | └ | | Public ❗️ | 🛑 |NO❗️ |
83 | | └ | generator | Public ❗️ | |NO❗️ |
84 | | └ | version | Public ❗️ | |NO❗️ |
85 | ||||||
86 | | **SimpleBEP20** | Implementation | BEP20, ServicePayer, GeneratorCopyright |||
87 | | └ | | Public ❗️ | 💵 | BEP20 ServicePayer |
88 |
89 |
90 | ### Legend
91 |
92 | | Symbol | Meaning |
93 | |:--------:|-----------|
94 | | 🛑 | Function can modify state |
95 | | 💵 | Function is payable |
96 |
--------------------------------------------------------------------------------
/analysis/description-table/MintableBEP20.md:
--------------------------------------------------------------------------------
1 | ## Sūrya's Description Report
2 |
3 | ### Files Description Table
4 |
5 |
6 | | File Name | SHA-1 Hash |
7 | |-------------|--------------|
8 | | dist/MintableBEP20.dist.sol | 4872a4fea53e96deb9c99b5a9d3c25b988c65220 |
9 |
10 |
11 | ### Contracts Description Table
12 |
13 |
14 | | Contract | Type | Bases | | |
15 | |:----------:|:-------------------:|:----------------:|:----------------:|:---------------:|
16 | | └ | **Function Name** | **Visibility** | **Mutability** | **Modifiers** |
17 | ||||||
18 | | **Context** | Implementation | |||
19 | | └ | _msgSender | Internal 🔒 | | |
20 | | └ | _msgData | Internal 🔒 | | |
21 | ||||||
22 | | **Ownable** | Implementation | Context |||
23 | | └ | | Public ❗️ | 🛑 |NO❗️ |
24 | | └ | owner | Public ❗️ | |NO❗️ |
25 | | └ | renounceOwnership | Public ❗️ | 🛑 | onlyOwner |
26 | | └ | transferOwnership | Public ❗️ | 🛑 | onlyOwner |
27 | ||||||
28 | | **SafeMath** | Library | |||
29 | | └ | add | Internal 🔒 | | |
30 | | └ | sub | Internal 🔒 | | |
31 | | └ | sub | Internal 🔒 | | |
32 | | └ | mul | Internal 🔒 | | |
33 | | └ | div | Internal 🔒 | | |
34 | | └ | div | Internal 🔒 | | |
35 | | └ | mod | Internal 🔒 | | |
36 | | └ | mod | Internal 🔒 | | |
37 | ||||||
38 | | **IBEP20** | Interface | |||
39 | | └ | name | External ❗️ | |NO❗️ |
40 | | └ | symbol | External ❗️ | |NO❗️ |
41 | | └ | decimals | External ❗️ | |NO❗️ |
42 | | └ | totalSupply | External ❗️ | |NO❗️ |
43 | | └ | balanceOf | External ❗️ | |NO❗️ |
44 | | └ | getOwner | External ❗️ | |NO❗️ |
45 | | └ | transfer | External ❗️ | 🛑 |NO❗️ |
46 | | └ | transferFrom | External ❗️ | 🛑 |NO❗️ |
47 | | └ | approve | External ❗️ | 🛑 |NO❗️ |
48 | | └ | allowance | External ❗️ | |NO❗️ |
49 | ||||||
50 | | **BEP20** | Implementation | Ownable, IBEP20 |||
51 | | └ | | Public ❗️ | 🛑 |NO❗️ |
52 | | └ | name | Public ❗️ | |NO❗️ |
53 | | └ | symbol | Public ❗️ | |NO❗️ |
54 | | └ | decimals | Public ❗️ | |NO❗️ |
55 | | └ | totalSupply | Public ❗️ | |NO❗️ |
56 | | └ | balanceOf | Public ❗️ | |NO❗️ |
57 | | └ | getOwner | Public ❗️ | |NO❗️ |
58 | | └ | transfer | Public ❗️ | 🛑 |NO❗️ |
59 | | └ | transferFrom | Public ❗️ | 🛑 |NO❗️ |
60 | | └ | approve | Public ❗️ | 🛑 |NO❗️ |
61 | | └ | allowance | Public ❗️ | |NO❗️ |
62 | | └ | increaseAllowance | Public ❗️ | 🛑 |NO❗️ |
63 | | └ | decreaseAllowance | Public ❗️ | 🛑 |NO❗️ |
64 | | └ | _transfer | Internal 🔒 | 🛑 | |
65 | | └ | _mint | Internal 🔒 | 🛑 | |
66 | | └ | _burn | Internal 🔒 | 🛑 | |
67 | | └ | _approve | Internal 🔒 | 🛑 | |
68 | | └ | _setupDecimals | Internal 🔒 | 🛑 | |
69 | | └ | _beforeTokenTransfer | Internal 🔒 | 🛑 | |
70 | ||||||
71 | | **BEP20Mintable** | Implementation | BEP20 |||
72 | | └ | mintingFinished | Public ❗️ | |NO❗️ |
73 | | └ | mint | Public ❗️ | 🛑 | canMint |
74 | | └ | finishMinting | Public ❗️ | 🛑 | canMint |
75 | | └ | _finishMinting | Internal 🔒 | 🛑 | |
76 | ||||||
77 | | **ServiceReceiver** | Implementation | Ownable |||
78 | | └ | pay | Public ❗️ | 💵 |NO❗️ |
79 | | └ | getPrice | Public ❗️ | |NO❗️ |
80 | | └ | setPrice | Public ❗️ | 🛑 | onlyOwner |
81 | | └ | withdraw | Public ❗️ | 🛑 | onlyOwner |
82 | | └ | _toBytes32 | Private 🔐 | | |
83 | ||||||
84 | | **ServicePayer** | Implementation | |||
85 | | └ | | Public ❗️ | 💵 |NO❗️ |
86 | ||||||
87 | | **MintableBEP20** | Implementation | BEP20Mintable, ServicePayer |||
88 | | └ | | Public ❗️ | 💵 | BEP20 ServicePayer |
89 | | └ | _mint | Internal 🔒 | 🛑 | onlyOwner |
90 | | └ | _finishMinting | Internal 🔒 | 🛑 | onlyOwner |
91 |
92 |
93 | ### Legend
94 |
95 | | Symbol | Meaning |
96 | |:--------:|-----------|
97 | | 🛑 | Function can modify state |
98 | | 💵 | Function is payable |
99 |
--------------------------------------------------------------------------------
/test/token/BEP20/behaviours/BEP20Mintable.behaviour.js:
--------------------------------------------------------------------------------
1 | const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers');
2 | const { ZERO_ADDRESS } = constants;
3 |
4 | function shouldBehaveLikeBEP20Mintable (initialBalance, [minter, thirdParty]) {
5 | describe('mint', function () {
6 | const initialSupply = new BN(initialBalance);
7 | const amount = new BN(50);
8 |
9 | const from = minter;
10 |
11 | context('behaviours', function () {
12 | it('rejects a null account', async function () {
13 | await expectRevert(
14 | this.token.mint(ZERO_ADDRESS, amount, { from: minter }),
15 | 'BEP20: mint to the zero address',
16 | );
17 | });
18 |
19 | describe('for a non null account', function () {
20 | beforeEach('minting', async function () {
21 | const { logs } = await this.token.mint(thirdParty, amount);
22 | this.logs = logs;
23 | });
24 |
25 | it('increments totalSupply', async function () {
26 | const expectedSupply = initialSupply.add(amount);
27 | (await this.token.totalSupply()).should.be.bignumber.equal(expectedSupply);
28 | });
29 |
30 | it('increments thirdParty balance', async function () {
31 | (await this.token.balanceOf(thirdParty)).should.be.bignumber.equal(amount);
32 | });
33 |
34 | it('emits Transfer event', async function () {
35 | const event = expectEvent.inLogs(this.logs, 'Transfer', {
36 | from: ZERO_ADDRESS,
37 | to: thirdParty,
38 | });
39 |
40 | event.args.value.should.be.bignumber.equal(amount);
41 | });
42 | });
43 |
44 | context('for a zero amount', function () {
45 | shouldMint(new BN(0));
46 | });
47 |
48 | context('for a non-zero amount', function () {
49 | shouldMint(amount);
50 | });
51 |
52 | function shouldMint (amount) {
53 | beforeEach(async function () {
54 | ({ logs: this.logs } = await this.token.mint(thirdParty, amount, { from }));
55 | });
56 |
57 | it('mints the requested amount', async function () {
58 | (await this.token.balanceOf(thirdParty)).should.be.bignumber.equal(amount);
59 | });
60 |
61 | it('emits a transfer event', async function () {
62 | expectEvent.inLogs(this.logs, 'Transfer', {
63 | from: ZERO_ADDRESS,
64 | to: thirdParty,
65 | value: amount,
66 | });
67 | });
68 | }
69 | });
70 |
71 | context('before finish minting', function () {
72 | it('mintingFinished should be false', async function () {
73 | (await this.token.mintingFinished()).should.be.equal(false);
74 | });
75 | });
76 |
77 | context('after finish minting', function () {
78 | beforeEach(async function () {
79 | ({ logs: this.logs } = await this.token.finishMinting({ from }));
80 | });
81 |
82 | it('should emit MintFinished', async function () {
83 | expectEvent.inLogs(this.logs, 'MintFinished');
84 | });
85 |
86 | it('mintingFinished should be true', async function () {
87 | (await this.token.mintingFinished()).should.be.equal(true);
88 | });
89 |
90 | it('cannot mint more tokens', async function () {
91 | await expectRevert(
92 | this.token.mint(thirdParty, 1, { from }),
93 | 'BEP20Mintable: minting is finished',
94 | );
95 | });
96 |
97 | it('cannot finish minting again', async function () {
98 | await expectRevert(
99 | this.token.finishMinting({ from }),
100 | 'BEP20Mintable: minting is finished',
101 | );
102 | });
103 | });
104 | });
105 | }
106 |
107 | module.exports = {
108 | shouldBehaveLikeBEP20Mintable,
109 | };
110 |
--------------------------------------------------------------------------------
/test/token/BEP20/behaviours/BEP20Burnable.behaviour.js:
--------------------------------------------------------------------------------
1 | const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers');
2 | const { ZERO_ADDRESS } = constants;
3 |
4 | const { expect } = require('chai');
5 |
6 | function shouldBehaveLikeBEP20Burnable (initialBalance, [burner, thirdParty]) {
7 | describe('burn', function () {
8 | describe('when the given amount is not greater than balance of the sender', function () {
9 | context('for a zero amount', function () {
10 | shouldBurn(new BN(0));
11 | });
12 |
13 | context('for a non-zero amount', function () {
14 | shouldBurn(new BN(100));
15 | });
16 |
17 | function shouldBurn (amount) {
18 | beforeEach(async function () {
19 | ({ logs: this.logs } = await this.token.burn(amount, { from: burner }));
20 | });
21 |
22 | it('burns the requested amount', async function () {
23 | expect(await this.token.balanceOf(burner)).to.be.bignumber.equal(initialBalance.sub(amount));
24 | });
25 |
26 | it('emits a transfer event', async function () {
27 | expectEvent.inLogs(this.logs, 'Transfer', {
28 | from: burner,
29 | to: ZERO_ADDRESS,
30 | value: amount,
31 | });
32 | });
33 | }
34 | });
35 |
36 | describe('when the given amount is greater than the balance of the sender', function () {
37 | const amount = initialBalance.addn(1);
38 |
39 | it('reverts', async function () {
40 | await expectRevert(this.token.burn(amount, { from: burner }),
41 | 'BEP20: burn amount exceeds balance',
42 | );
43 | });
44 | });
45 | });
46 |
47 | describe('burnFrom', function () {
48 | describe('on success', function () {
49 | context('for a zero amount', function () {
50 | shouldBurnFrom(new BN(0));
51 | });
52 |
53 | context('for a non-zero amount', function () {
54 | shouldBurnFrom(new BN(100));
55 | });
56 |
57 | function shouldBurnFrom (amount) {
58 | const originalAllowance = amount.muln(3);
59 |
60 | beforeEach(async function () {
61 | await this.token.approve(thirdParty, originalAllowance, { from: burner });
62 | const { logs } = await this.token.burnFrom(burner, amount, { from: thirdParty });
63 | this.logs = logs;
64 | });
65 |
66 | it('burns the requested amount', async function () {
67 | expect(await this.token.balanceOf(burner)).to.be.bignumber.equal(initialBalance.sub(amount));
68 | });
69 |
70 | it('decrements allowance', async function () {
71 | expect(await this.token.allowance(burner, thirdParty)).to.be.bignumber.equal(originalAllowance.sub(amount));
72 | });
73 |
74 | it('emits a transfer event', async function () {
75 | expectEvent.inLogs(this.logs, 'Transfer', {
76 | from: burner,
77 | to: ZERO_ADDRESS,
78 | value: amount,
79 | });
80 | });
81 | }
82 | });
83 |
84 | describe('when the given amount is greater than the balance of the sender', function () {
85 | const amount = initialBalance.addn(1);
86 |
87 | it('reverts', async function () {
88 | await this.token.approve(thirdParty, amount, { from: burner });
89 | await expectRevert(this.token.burnFrom(burner, amount, { from: thirdParty }),
90 | 'BEP20: burn amount exceeds balance',
91 | );
92 | });
93 | });
94 |
95 | describe('when the given amount is greater than the allowance', function () {
96 | const allowance = new BN(100);
97 |
98 | it('reverts', async function () {
99 | await this.token.approve(thirdParty, allowance, { from: burner });
100 | await expectRevert(this.token.burnFrom(burner, allowance.addn(1), { from: thirdParty }),
101 | 'BEP20: burn amount exceeds allowance',
102 | );
103 | });
104 | });
105 | });
106 | }
107 |
108 | module.exports = {
109 | shouldBehaveLikeBEP20Burnable,
110 | };
111 |
--------------------------------------------------------------------------------
/test/token/BEP20/MintableBEP20.test.js:
--------------------------------------------------------------------------------
1 | const { BN, ether, expectRevert } = require('@openzeppelin/test-helpers');
2 |
3 | const { shouldBehaveLikeBEP20 } = require('./behaviours/BEP20.behaviour');
4 | const { shouldBehaveLikeBEP20Mintable } = require('./behaviours/BEP20Mintable.behaviour');
5 |
6 | const MintableBEP20 = artifacts.require('MintableBEP20');
7 | const ServiceReceiver = artifacts.require('ServiceReceiver');
8 |
9 | contract('MintableBEP20', function ([owner, other, thirdParty]) {
10 | const _name = 'MintableBEP20';
11 | const _symbol = 'BEP20';
12 | const _decimals = new BN(8);
13 | const _initialSupply = new BN(100000000);
14 |
15 | const fee = ether('0.1');
16 |
17 | beforeEach(async function () {
18 | this.serviceReceiver = await ServiceReceiver.new({ from: owner });
19 | await this.serviceReceiver.setPrice('MintableBEP20', fee);
20 | });
21 |
22 | context('creating valid token', function () {
23 | describe('as a MintableBEP20', function () {
24 | describe('without initial supply', function () {
25 | beforeEach(async function () {
26 | this.token = await MintableBEP20.new(
27 | _name,
28 | _symbol,
29 | _decimals,
30 | 0,
31 | this.serviceReceiver.address,
32 | {
33 | from: owner,
34 | value: fee,
35 | },
36 | );
37 | });
38 |
39 | describe('once deployed', function () {
40 | it('total supply should be equal to zero', async function () {
41 | (await this.token.totalSupply()).should.be.bignumber.equal(new BN(0));
42 | });
43 |
44 | it('owner balance should be equal to zero', async function () {
45 | (await this.token.balanceOf(owner)).should.be.bignumber.equal(new BN(0));
46 | });
47 | });
48 | });
49 |
50 | describe('with initial supply', function () {
51 | beforeEach(async function () {
52 | this.token = await MintableBEP20.new(
53 | _name,
54 | _symbol,
55 | _decimals,
56 | _initialSupply,
57 | this.serviceReceiver.address,
58 | {
59 | from: owner,
60 | value: fee,
61 | },
62 | );
63 | });
64 |
65 | describe('once deployed', function () {
66 | it('total supply should be equal to initial supply', async function () {
67 | (await this.token.totalSupply()).should.be.bignumber.equal(_initialSupply);
68 | });
69 |
70 | it('owner balance should be equal to initial supply', async function () {
71 | (await this.token.balanceOf(owner)).should.be.bignumber.equal(_initialSupply);
72 | });
73 | });
74 | });
75 | });
76 | });
77 |
78 | context('MintableBEP20 token behaviours', function () {
79 | beforeEach(async function () {
80 | this.token = await MintableBEP20.new(
81 | _name,
82 | _symbol,
83 | _decimals,
84 | _initialSupply,
85 | this.serviceReceiver.address,
86 | {
87 | from: owner,
88 | value: fee,
89 | },
90 | );
91 | });
92 |
93 | context('like a BEP20', function () {
94 | shouldBehaveLikeBEP20(_name, _symbol, _decimals, _initialSupply, [owner, other, thirdParty]);
95 | });
96 |
97 | context('like a BEP20Mintable', function () {
98 | shouldBehaveLikeBEP20Mintable(_initialSupply, [owner, thirdParty]);
99 | });
100 |
101 | context('like a MintableBEP20', function () {
102 | describe('when the sender doesn\'t have minting permission', function () {
103 | const from = thirdParty;
104 |
105 | it('cannot mint', async function () {
106 | const amount = new BN(50);
107 |
108 | await expectRevert(
109 | this.token.mint(thirdParty, amount, { from }),
110 | 'Ownable: caller is not the owner',
111 | );
112 | });
113 |
114 | it('cannot finish minting', async function () {
115 | await expectRevert(
116 | this.token.finishMinting({ from }),
117 | 'Ownable: caller is not the owner',
118 | );
119 | });
120 | });
121 | });
122 | });
123 | });
124 |
--------------------------------------------------------------------------------
/analysis/description-table/CommonBEP20.md:
--------------------------------------------------------------------------------
1 | ## Sūrya's Description Report
2 |
3 | ### Files Description Table
4 |
5 |
6 | | File Name | SHA-1 Hash |
7 | |-------------|--------------|
8 | | dist/CommonBEP20.dist.sol | bdd3f4a8d6ccc008c46206ae1485e314ef06f6cb |
9 |
10 |
11 | ### Contracts Description Table
12 |
13 |
14 | | Contract | Type | Bases | | |
15 | |:----------:|:-------------------:|:----------------:|:----------------:|:---------------:|
16 | | └ | **Function Name** | **Visibility** | **Mutability** | **Modifiers** |
17 | ||||||
18 | | **Context** | Implementation | |||
19 | | └ | _msgSender | Internal 🔒 | | |
20 | | └ | _msgData | Internal 🔒 | | |
21 | ||||||
22 | | **Ownable** | Implementation | Context |||
23 | | └ | | Public ❗️ | 🛑 |NO❗️ |
24 | | └ | owner | Public ❗️ | |NO❗️ |
25 | | └ | renounceOwnership | Public ❗️ | 🛑 | onlyOwner |
26 | | └ | transferOwnership | Public ❗️ | 🛑 | onlyOwner |
27 | ||||||
28 | | **SafeMath** | Library | |||
29 | | └ | add | Internal 🔒 | | |
30 | | └ | sub | Internal 🔒 | | |
31 | | └ | sub | Internal 🔒 | | |
32 | | └ | mul | Internal 🔒 | | |
33 | | └ | div | Internal 🔒 | | |
34 | | └ | div | Internal 🔒 | | |
35 | | └ | mod | Internal 🔒 | | |
36 | | └ | mod | Internal 🔒 | | |
37 | ||||||
38 | | **IBEP20** | Interface | |||
39 | | └ | name | External ❗️ | |NO❗️ |
40 | | └ | symbol | External ❗️ | |NO❗️ |
41 | | └ | decimals | External ❗️ | |NO❗️ |
42 | | └ | totalSupply | External ❗️ | |NO❗️ |
43 | | └ | balanceOf | External ❗️ | |NO❗️ |
44 | | └ | getOwner | External ❗️ | |NO❗️ |
45 | | └ | transfer | External ❗️ | 🛑 |NO❗️ |
46 | | └ | transferFrom | External ❗️ | 🛑 |NO❗️ |
47 | | └ | approve | External ❗️ | 🛑 |NO❗️ |
48 | | └ | allowance | External ❗️ | |NO❗️ |
49 | ||||||
50 | | **BEP20** | Implementation | Ownable, IBEP20 |||
51 | | └ | | Public ❗️ | 🛑 |NO❗️ |
52 | | └ | name | Public ❗️ | |NO❗️ |
53 | | └ | symbol | Public ❗️ | |NO❗️ |
54 | | └ | decimals | Public ❗️ | |NO❗️ |
55 | | └ | totalSupply | Public ❗️ | |NO❗️ |
56 | | └ | balanceOf | Public ❗️ | |NO❗️ |
57 | | └ | getOwner | Public ❗️ | |NO❗️ |
58 | | └ | transfer | Public ❗️ | 🛑 |NO❗️ |
59 | | └ | transferFrom | Public ❗️ | 🛑 |NO❗️ |
60 | | └ | approve | Public ❗️ | 🛑 |NO❗️ |
61 | | └ | allowance | Public ❗️ | |NO❗️ |
62 | | └ | increaseAllowance | Public ❗️ | 🛑 |NO❗️ |
63 | | └ | decreaseAllowance | Public ❗️ | 🛑 |NO❗️ |
64 | | └ | _transfer | Internal 🔒 | 🛑 | |
65 | | └ | _mint | Internal 🔒 | 🛑 | |
66 | | └ | _burn | Internal 🔒 | 🛑 | |
67 | | └ | _approve | Internal 🔒 | 🛑 | |
68 | | └ | _setupDecimals | Internal 🔒 | 🛑 | |
69 | | └ | _beforeTokenTransfer | Internal 🔒 | 🛑 | |
70 | ||||||
71 | | **BEP20Capped** | Implementation | BEP20 |||
72 | | └ | | Public ❗️ | 🛑 |NO❗️ |
73 | | └ | cap | Public ❗️ | |NO❗️ |
74 | | └ | _beforeTokenTransfer | Internal 🔒 | 🛑 | |
75 | ||||||
76 | | **BEP20Mintable** | Implementation | BEP20 |||
77 | | └ | mintingFinished | Public ❗️ | |NO❗️ |
78 | | └ | mint | Public ❗️ | 🛑 | canMint |
79 | | └ | finishMinting | Public ❗️ | 🛑 | canMint |
80 | | └ | _finishMinting | Internal 🔒 | 🛑 | |
81 | ||||||
82 | | **BEP20Burnable** | Implementation | Context, BEP20 |||
83 | | └ | burn | Public ❗️ | 🛑 |NO❗️ |
84 | | └ | burnFrom | Public ❗️ | 🛑 |NO❗️ |
85 | ||||||
86 | | **ServiceReceiver** | Implementation | Ownable |||
87 | | └ | pay | Public ❗️ | 💵 |NO❗️ |
88 | | └ | getPrice | Public ❗️ | |NO❗️ |
89 | | └ | setPrice | Public ❗️ | 🛑 | onlyOwner |
90 | | └ | withdraw | Public ❗️ | 🛑 | onlyOwner |
91 | | └ | _toBytes32 | Private 🔐 | | |
92 | ||||||
93 | | **ServicePayer** | Implementation | |||
94 | | └ | | Public ❗️ | 💵 |NO❗️ |
95 | ||||||
96 | | **CommonBEP20** | Implementation | BEP20Capped, BEP20Mintable, BEP20Burnable, ServicePayer |||
97 | | └ | | Public ❗️ | 💵 | BEP20 BEP20Capped ServicePayer |
98 | | └ | _mint | Internal 🔒 | 🛑 | onlyOwner |
99 | | └ | _finishMinting | Internal 🔒 | 🛑 | onlyOwner |
100 | | └ | _beforeTokenTransfer | Internal 🔒 | 🛑 | |
101 |
102 |
103 | ### Legend
104 |
105 | | Symbol | Meaning |
106 | |:--------:|-----------|
107 | | 🛑 | Function can modify state |
108 | | 💵 | Function is payable |
109 |
--------------------------------------------------------------------------------
/test/service/ServiceReceiver.test.js:
--------------------------------------------------------------------------------
1 | const { balance, ether, expectEvent, expectRevert } = require('@openzeppelin/test-helpers');
2 |
3 | const { expect } = require('chai');
4 |
5 | const { shouldBehaveLikeOwnable } = require('../access/Ownable.behavior');
6 |
7 | const ServiceReceiver = artifacts.require('ServiceReceiver');
8 |
9 | contract('ServiceReceiver', function ([owner, thirdParty]) {
10 | const fee = ether('0.1');
11 |
12 | context('ServiceReceiver behaviours', function () {
13 | beforeEach(async function () {
14 | this.serviceReceiver = await ServiceReceiver.new({ from: owner });
15 | });
16 |
17 | describe('set price', function () {
18 | context('when the sender is owner', function () {
19 | it('should set price', async function () {
20 | await this.serviceReceiver.setPrice('ServiceMock', fee, { from: owner });
21 |
22 | (await this.serviceReceiver.getPrice('ServiceMock')).should.be.bignumber.equal(fee);
23 | });
24 | });
25 |
26 | context('when the sender is not owner', function () {
27 | it('reverts', async function () {
28 | await expectRevert(
29 | this.serviceReceiver.setPrice('ServiceMock', fee, { from: thirdParty }),
30 | 'Ownable: caller is not the owner',
31 | );
32 | });
33 | });
34 | });
35 |
36 | describe('pay', function () {
37 | context('with incorrect price', function () {
38 | it('reverts', async function () {
39 | await this.serviceReceiver.setPrice('ServiceMock', fee, { from: owner });
40 |
41 | await expectRevert(
42 | this.serviceReceiver.pay(
43 | 'ServiceMock',
44 | {
45 | from: thirdParty,
46 | value: fee.add(ether('1')),
47 | },
48 | ),
49 | 'ServiceReceiver: incorrect price',
50 | );
51 | });
52 | });
53 |
54 | context('with correct price', function () {
55 | beforeEach(async function () {
56 | await this.serviceReceiver.setPrice('ServiceMock', fee, { from: owner });
57 | });
58 |
59 | it('emits a Created event', async function () {
60 | const { logs } = await this.serviceReceiver.pay('ServiceMock', { value: fee, from: thirdParty });
61 |
62 | expectEvent.inLogs(logs, 'Created', {
63 | serviceName: 'ServiceMock',
64 | serviceAddress: thirdParty,
65 | });
66 | });
67 |
68 | it('transfer fee to receiver', async function () {
69 | const initBalance = await balance.current(this.serviceReceiver.address);
70 |
71 | await this.serviceReceiver.pay('ServiceMock', { value: fee, from: thirdParty });
72 |
73 | const newBalance = (await balance.current(this.serviceReceiver.address));
74 |
75 | expect(newBalance).to.be.bignumber.equal(initBalance.add(fee));
76 | });
77 | });
78 | });
79 |
80 | describe('withdraw', function () {
81 | beforeEach(async function () {
82 | await this.serviceReceiver.setPrice('ServiceMock', fee, { from: owner });
83 | await this.serviceReceiver.pay('ServiceMock', { value: fee, from: thirdParty });
84 | });
85 |
86 | context('when the sender is owner', function () {
87 | it('should withdraw', async function () {
88 | const amount = ether('0.05');
89 |
90 | const contractBalanceTracker = await balance.tracker(this.serviceReceiver.address);
91 | const ownerBalanceTracker = await balance.tracker(owner);
92 |
93 | await this.serviceReceiver.withdraw(amount, { from: owner, gasPrice: 0 });
94 |
95 | expect(await contractBalanceTracker.delta()).to.be.bignumber.equal(amount.neg());
96 | expect(await ownerBalanceTracker.delta()).to.be.bignumber.equal(amount);
97 | });
98 | });
99 |
100 | context('when the sender is not owner', function () {
101 | it('reverts', async function () {
102 | const amount = ether('0.05');
103 |
104 | await expectRevert(
105 | this.serviceReceiver.withdraw(amount, { from: thirdParty }),
106 | 'Ownable: caller is not the owner',
107 | );
108 | });
109 | });
110 | });
111 |
112 | context('like a Ownable', function () {
113 | beforeEach(async function () {
114 | this.ownable = this.serviceReceiver;
115 | });
116 |
117 | shouldBehaveLikeOwnable(owner, [thirdParty]);
118 | });
119 | });
120 | });
121 |
--------------------------------------------------------------------------------
/dist/ServiceReceiver.dist.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 |
3 | // File: @openzeppelin/contracts/GSN/Context.sol
4 |
5 | pragma solidity ^0.7.0;
6 |
7 | /*
8 | * @dev Provides information about the current execution context, including the
9 | * sender of the transaction and its data. While these are generally available
10 | * via msg.sender and msg.data, they should not be accessed in such a direct
11 | * manner, since when dealing with GSN meta-transactions the account sending and
12 | * paying for execution may not be the actual sender (as far as an application
13 | * is concerned).
14 | *
15 | * This contract is only required for intermediate, library-like contracts.
16 | */
17 | abstract contract Context {
18 | function _msgSender() internal view virtual returns (address payable) {
19 | return msg.sender;
20 | }
21 |
22 | function _msgData() internal view virtual returns (bytes memory) {
23 | this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
24 | return msg.data;
25 | }
26 | }
27 |
28 | // File: @openzeppelin/contracts/access/Ownable.sol
29 |
30 |
31 |
32 | pragma solidity ^0.7.0;
33 |
34 | /**
35 | * @dev Contract module which provides a basic access control mechanism, where
36 | * there is an account (an owner) that can be granted exclusive access to
37 | * specific functions.
38 | *
39 | * By default, the owner account will be the one that deploys the contract. This
40 | * can later be changed with {transferOwnership}.
41 | *
42 | * This module is used through inheritance. It will make available the modifier
43 | * `onlyOwner`, which can be applied to your functions to restrict their use to
44 | * the owner.
45 | */
46 | abstract contract Ownable is Context {
47 | address private _owner;
48 |
49 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
50 |
51 | /**
52 | * @dev Initializes the contract setting the deployer as the initial owner.
53 | */
54 | constructor () {
55 | address msgSender = _msgSender();
56 | _owner = msgSender;
57 | emit OwnershipTransferred(address(0), msgSender);
58 | }
59 |
60 | /**
61 | * @dev Returns the address of the current owner.
62 | */
63 | function owner() public view returns (address) {
64 | return _owner;
65 | }
66 |
67 | /**
68 | * @dev Throws if called by any account other than the owner.
69 | */
70 | modifier onlyOwner() {
71 | require(_owner == _msgSender(), "Ownable: caller is not the owner");
72 | _;
73 | }
74 |
75 | /**
76 | * @dev Leaves the contract without owner. It will not be possible to call
77 | * `onlyOwner` functions anymore. Can only be called by the current owner.
78 | *
79 | * NOTE: Renouncing ownership will leave the contract without an owner,
80 | * thereby removing any functionality that is only available to the owner.
81 | */
82 | function renounceOwnership() public virtual onlyOwner {
83 | emit OwnershipTransferred(_owner, address(0));
84 | _owner = address(0);
85 | }
86 |
87 | /**
88 | * @dev Transfers ownership of the contract to a new account (`newOwner`).
89 | * Can only be called by the current owner.
90 | */
91 | function transferOwnership(address newOwner) public virtual onlyOwner {
92 | require(newOwner != address(0), "Ownable: new owner is the zero address");
93 | emit OwnershipTransferred(_owner, newOwner);
94 | _owner = newOwner;
95 | }
96 | }
97 |
98 |
99 | // File: contracts/service/ServiceReceiver.sol
100 |
101 |
102 |
103 | pragma solidity ^0.7.0;
104 |
105 |
106 | /**
107 | * @title ServiceReceiver
108 | * @dev Implementation of the ServiceReceiver
109 | */
110 | contract ServiceReceiver is Ownable {
111 |
112 | mapping (bytes32 => uint256) private _prices;
113 |
114 | event Created(string serviceName, address indexed serviceAddress);
115 |
116 | function pay(string memory serviceName) public payable {
117 | require(msg.value == _prices[_toBytes32(serviceName)], "ServiceReceiver: incorrect price");
118 |
119 | emit Created(serviceName, _msgSender());
120 | }
121 |
122 | function getPrice(string memory serviceName) public view returns (uint256) {
123 | return _prices[_toBytes32(serviceName)];
124 | }
125 |
126 | function setPrice(string memory serviceName, uint256 amount) public onlyOwner {
127 | _prices[_toBytes32(serviceName)] = amount;
128 | }
129 |
130 | function withdraw(uint256 amount) public onlyOwner {
131 | payable(owner()).transfer(amount);
132 | }
133 |
134 | function _toBytes32(string memory serviceName) private pure returns (bytes32) {
135 | return keccak256(abi.encode(serviceName));
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/test/token/BEP20/CommonBEP20.test.js:
--------------------------------------------------------------------------------
1 | const { BN, ether, expectRevert } = require('@openzeppelin/test-helpers');
2 |
3 | const { shouldBehaveLikeBEP20 } = require('./behaviours/BEP20.behaviour');
4 | const { shouldBehaveLikeBEP20Burnable } = require('./behaviours/BEP20Burnable.behaviour');
5 | const { shouldBehaveLikeBEP20Capped } = require('./behaviours/BEP20Capped.behaviour');
6 | const { shouldBehaveLikeBEP20Mintable } = require('./behaviours/BEP20Mintable.behaviour');
7 |
8 | const CommonBEP20 = artifacts.require('CommonBEP20');
9 | const ServiceReceiver = artifacts.require('ServiceReceiver');
10 |
11 | contract('CommonBEP20', function ([owner, other, thirdParty]) {
12 | const _name = 'CommonBEP20';
13 | const _symbol = 'BEP20';
14 | const _decimals = new BN(8);
15 | const _cap = new BN(200000000);
16 | const _initialSupply = new BN(100000000);
17 |
18 | const fee = ether('0.1');
19 |
20 | beforeEach(async function () {
21 | this.serviceReceiver = await ServiceReceiver.new({ from: owner });
22 | await this.serviceReceiver.setPrice('CommonBEP20', fee);
23 | });
24 |
25 | context('creating valid token', function () {
26 | describe('as a BEP20Capped', function () {
27 | it('requires a non-zero cap', async function () {
28 | await expectRevert(
29 | CommonBEP20.new(
30 | _name,
31 | _symbol,
32 | _decimals,
33 | 0,
34 | _initialSupply,
35 | this.serviceReceiver.address,
36 | {
37 | from: owner,
38 | value: fee,
39 | },
40 | ),
41 | 'BEP20Capped: cap is 0',
42 | );
43 | });
44 | });
45 |
46 | describe('as a CommonBEP20', function () {
47 | describe('without initial supply', function () {
48 | beforeEach(async function () {
49 | this.token = await CommonBEP20.new(
50 | _name,
51 | _symbol,
52 | _decimals,
53 | _cap,
54 | 0,
55 | this.serviceReceiver.address,
56 | {
57 | from: owner,
58 | value: fee,
59 | },
60 | );
61 | });
62 |
63 | describe('once deployed', function () {
64 | it('total supply should be equal to zero', async function () {
65 | (await this.token.totalSupply()).should.be.bignumber.equal(new BN(0));
66 | });
67 |
68 | it('owner balance should be equal to zero', async function () {
69 | (await this.token.balanceOf(owner)).should.be.bignumber.equal(new BN(0));
70 | });
71 | });
72 | });
73 |
74 | describe('with initial supply', function () {
75 | beforeEach(async function () {
76 | this.token = await CommonBEP20.new(
77 | _name,
78 | _symbol,
79 | _decimals,
80 | _cap,
81 | _initialSupply,
82 | this.serviceReceiver.address,
83 | {
84 | from: owner,
85 | value: fee,
86 | },
87 | );
88 | });
89 |
90 | describe('once deployed', function () {
91 | it('total supply should be equal to initial supply', async function () {
92 | (await this.token.totalSupply()).should.be.bignumber.equal(_initialSupply);
93 | });
94 |
95 | it('owner balance should be equal to initial supply', async function () {
96 | (await this.token.balanceOf(owner)).should.be.bignumber.equal(_initialSupply);
97 | });
98 | });
99 | });
100 | });
101 | });
102 |
103 | context('CommonBEP20 token behaviours', function () {
104 | beforeEach(async function () {
105 | this.token = await CommonBEP20.new(
106 | _name,
107 | _symbol,
108 | _decimals,
109 | _cap,
110 | _initialSupply,
111 | this.serviceReceiver.address,
112 | {
113 | from: owner,
114 | value: fee,
115 | },
116 | );
117 | });
118 |
119 | context('like a BEP20', function () {
120 | shouldBehaveLikeBEP20(_name, _symbol, _decimals, _initialSupply, [owner, other, thirdParty]);
121 | });
122 |
123 | context('like a BEP20Capped', function () {
124 | beforeEach(async function () {
125 | // NOTE: burning initial supply to test cap
126 | await this.token.burn(_initialSupply, { from: owner });
127 | });
128 | shouldBehaveLikeBEP20Capped(_cap, [owner, other]);
129 | });
130 |
131 | context('like a BEP20Mintable', function () {
132 | shouldBehaveLikeBEP20Mintable(_initialSupply, [owner, thirdParty]);
133 | });
134 |
135 | context('like a BEP20Burnable', function () {
136 | shouldBehaveLikeBEP20Burnable(_initialSupply, [owner, thirdParty]);
137 | });
138 |
139 | context('like a CommonBEP20', function () {
140 | describe('when the sender doesn\'t have minting permission', function () {
141 | const from = thirdParty;
142 |
143 | it('cannot mint', async function () {
144 | const amount = new BN(50);
145 |
146 | await expectRevert(
147 | this.token.mint(thirdParty, amount, { from }),
148 | 'Ownable: caller is not the owner',
149 | );
150 | });
151 |
152 | it('cannot finish minting', async function () {
153 | await expectRevert(
154 | this.token.finishMinting({ from }),
155 | 'Ownable: caller is not the owner',
156 | );
157 | });
158 | });
159 | });
160 | });
161 | });
162 |
--------------------------------------------------------------------------------
/analysis/uml/ServiceReceiver.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
75 |
--------------------------------------------------------------------------------
/contracts/token/BEP20/lib/BEP20.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 |
3 | pragma solidity ^0.7.0;
4 |
5 | import "@openzeppelin/contracts/access/Ownable.sol";
6 | import "@openzeppelin/contracts/math/SafeMath.sol";
7 |
8 | import "./IBEP20.sol";
9 |
10 | /**
11 | * @dev Implementation of the {IBEP20} interface.
12 | *
13 | * This implementation is agnostic to the way tokens are created. This means
14 | * that a supply mechanism has to be added in a derived contract using {_mint}.
15 | *
16 | * We have followed general OpenZeppelin guidelines: functions revert instead
17 | * of returning `false` on failure. This behavior is nonetheless conventional
18 | * and does not conflict with the expectations of BEP20 applications.
19 | *
20 | * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
21 | * This allows applications to reconstruct the allowance for all accounts just
22 | * by listening to said events. Other implementations of the EIP may not emit
23 | * these events, as it isn't required by the specification.
24 | *
25 | * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
26 | * functions have been added to mitigate the well-known issues around setting
27 | * allowances. See {IBEP20-approve}.
28 | */
29 | contract BEP20 is Ownable, IBEP20 {
30 | using SafeMath for uint256;
31 |
32 | mapping (address => uint256) private _balances;
33 |
34 | mapping (address => mapping (address => uint256)) private _allowances;
35 |
36 | uint256 private _totalSupply;
37 |
38 | string private _name;
39 | string private _symbol;
40 | uint8 private _decimals;
41 |
42 | /**
43 | * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
44 | * a default value of 18.
45 | *
46 | * To select a different value for {decimals}, use {_setupDecimals}.
47 | *
48 | * All three of these values are immutable: they can only be set once during
49 | * construction.
50 | */
51 | constructor (string memory name_, string memory symbol_) {
52 | _name = name_;
53 | _symbol = symbol_;
54 | _decimals = 18;
55 | }
56 |
57 | /**
58 | * @dev Returns the name of the token.
59 | */
60 | function name() public view override returns (string memory) {
61 | return _name;
62 | }
63 |
64 | /**
65 | * @dev Returns the symbol of the token, usually a shorter version of the
66 | * name.
67 | */
68 | function symbol() public view override returns (string memory) {
69 | return _symbol;
70 | }
71 |
72 | /**
73 | * @dev Returns the number of decimals used to get its user representation.
74 | * For example, if `decimals` equals `2`, a balance of `505` tokens should
75 | * be displayed to a user as `5,05` (`505 / 10 ** 2`).
76 | *
77 | * Tokens usually opt for a value of 18, imitating the relationship between
78 | * Ether and Wei. This is the value {BEP20} uses, unless {_setupDecimals} is
79 | * called.
80 | *
81 | * NOTE: This information is only used for _display_ purposes: it in
82 | * no way affects any of the arithmetic of the contract, including
83 | * {IBEP20-balanceOf} and {IBEP20-transfer}.
84 | */
85 | function decimals() public view override returns (uint8) {
86 | return _decimals;
87 | }
88 |
89 | /**
90 | * @dev See {IBEP20-totalSupply}.
91 | */
92 | function totalSupply() public view override returns (uint256) {
93 | return _totalSupply;
94 | }
95 |
96 | /**
97 | * @dev See {IBEP20-balanceOf}.
98 | */
99 | function balanceOf(address account) public view override returns (uint256) {
100 | return _balances[account];
101 | }
102 |
103 | /**
104 | * @dev See {IBEP20-getOwner}.
105 | */
106 | function getOwner() public view override returns (address) {
107 | return owner();
108 | }
109 |
110 | /**
111 | * @dev See {IBEP20-transfer}.
112 | *
113 | * Requirements:
114 | *
115 | * - `recipient` cannot be the zero address.
116 | * - the caller must have a balance of at least `amount`.
117 | */
118 | function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
119 | _transfer(_msgSender(), recipient, amount);
120 | return true;
121 | }
122 |
123 | /**
124 | * @dev See {IBEP20-transferFrom}.
125 | *
126 | * Emits an {Approval} event indicating the updated allowance. This is not
127 | * required by the EIP. See the note at the beginning of {BEP20}.
128 | *
129 | * Requirements:
130 | *
131 | * - `sender` and `recipient` cannot be the zero address.
132 | * - `sender` must have a balance of at least `amount`.
133 | * - the caller must have allowance for ``sender``'s tokens of at least
134 | * `amount`.
135 | */
136 | function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
137 | _transfer(sender, recipient, amount);
138 | _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "BEP20: transfer amount exceeds allowance"));
139 | return true;
140 | }
141 |
142 | /**
143 | * @dev See {IBEP20-approve}.
144 | *
145 | * Requirements:
146 | *
147 | * - `spender` cannot be the zero address.
148 | */
149 | function approve(address spender, uint256 amount) public virtual override returns (bool) {
150 | _approve(_msgSender(), spender, amount);
151 | return true;
152 | }
153 |
154 | /**
155 | * @dev See {IBEP20-allowance}.
156 | */
157 | function allowance(address owner, address spender) public view virtual override returns (uint256) {
158 | return _allowances[owner][spender];
159 | }
160 |
161 | /**
162 | * @dev Atomically increases the allowance granted to `spender` by the caller.
163 | *
164 | * This is an alternative to {approve} that can be used as a mitigation for
165 | * problems described in {IBEP20-approve}.
166 | *
167 | * Emits an {Approval} event indicating the updated allowance.
168 | *
169 | * Requirements:
170 | *
171 | * - `spender` cannot be the zero address.
172 | */
173 | function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
174 | _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
175 | return true;
176 | }
177 |
178 | /**
179 | * @dev Atomically decreases the allowance granted to `spender` by the caller.
180 | *
181 | * This is an alternative to {approve} that can be used as a mitigation for
182 | * problems described in {IBEP20-approve}.
183 | *
184 | * Emits an {Approval} event indicating the updated allowance.
185 | *
186 | * Requirements:
187 | *
188 | * - `spender` cannot be the zero address.
189 | * - `spender` must have allowance for the caller of at least
190 | * `subtractedValue`.
191 | */
192 | function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
193 | _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "BEP20: decreased allowance below zero"));
194 | return true;
195 | }
196 |
197 | /**
198 | * @dev Moves tokens `amount` from `sender` to `recipient`.
199 | *
200 | * This is internal function is equivalent to {transfer}, and can be used to
201 | * e.g. implement automatic token fees, slashing mechanisms, etc.
202 | *
203 | * Emits a {Transfer} event.
204 | *
205 | * Requirements:
206 | *
207 | * - `sender` cannot be the zero address.
208 | * - `recipient` cannot be the zero address.
209 | * - `sender` must have a balance of at least `amount`.
210 | */
211 | function _transfer(address sender, address recipient, uint256 amount) internal virtual {
212 | require(sender != address(0), "BEP20: transfer from the zero address");
213 | require(recipient != address(0), "BEP20: transfer to the zero address");
214 |
215 | _beforeTokenTransfer(sender, recipient, amount);
216 |
217 | _balances[sender] = _balances[sender].sub(amount, "BEP20: transfer amount exceeds balance");
218 | _balances[recipient] = _balances[recipient].add(amount);
219 | emit Transfer(sender, recipient, amount);
220 | }
221 |
222 | /** @dev Creates `amount` tokens and assigns them to `account`, increasing
223 | * the total supply.
224 | *
225 | * Emits a {Transfer} event with `from` set to the zero address.
226 | *
227 | * Requirements:
228 | *
229 | * - `to` cannot be the zero address.
230 | */
231 | function _mint(address account, uint256 amount) internal virtual {
232 | require(account != address(0), "BEP20: mint to the zero address");
233 |
234 | _beforeTokenTransfer(address(0), account, amount);
235 |
236 | _totalSupply = _totalSupply.add(amount);
237 | _balances[account] = _balances[account].add(amount);
238 | emit Transfer(address(0), account, amount);
239 | }
240 |
241 | /**
242 | * @dev Destroys `amount` tokens from `account`, reducing the
243 | * total supply.
244 | *
245 | * Emits a {Transfer} event with `to` set to the zero address.
246 | *
247 | * Requirements:
248 | *
249 | * - `account` cannot be the zero address.
250 | * - `account` must have at least `amount` tokens.
251 | */
252 | function _burn(address account, uint256 amount) internal virtual {
253 | require(account != address(0), "BEP20: burn from the zero address");
254 |
255 | _beforeTokenTransfer(account, address(0), amount);
256 |
257 | _balances[account] = _balances[account].sub(amount, "BEP20: burn amount exceeds balance");
258 | _totalSupply = _totalSupply.sub(amount);
259 | emit Transfer(account, address(0), amount);
260 | }
261 |
262 | /**
263 | * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
264 | *
265 | * This internal function is equivalent to `approve`, and can be used to
266 | * e.g. set automatic allowances for certain subsystems, etc.
267 | *
268 | * Emits an {Approval} event.
269 | *
270 | * Requirements:
271 | *
272 | * - `owner` cannot be the zero address.
273 | * - `spender` cannot be the zero address.
274 | */
275 | function _approve(address owner, address spender, uint256 amount) internal virtual {
276 | require(owner != address(0), "BEP20: approve from the zero address");
277 | require(spender != address(0), "BEP20: approve to the zero address");
278 |
279 | _allowances[owner][spender] = amount;
280 | emit Approval(owner, spender, amount);
281 | }
282 |
283 | /**
284 | * @dev Sets {decimals} to a value other than the default one of 18.
285 | *
286 | * WARNING: This function should only be called from the constructor. Most
287 | * applications that interact with token contracts will not expect
288 | * {decimals} to ever change, and may work incorrectly if it does.
289 | */
290 | function _setupDecimals(uint8 decimals_) internal {
291 | _decimals = decimals_;
292 | }
293 |
294 | /**
295 | * @dev Hook that is called before any transfer of tokens. This includes
296 | * minting and burning.
297 | *
298 | * Calling conditions:
299 | *
300 | * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
301 | * will be to transferred to `to`.
302 | * - when `from` is zero, `amount` tokens will be minted for `to`.
303 | * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
304 | * - `from` and `to` are never both zero.
305 | *
306 | * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
307 | */
308 | function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
309 | }
310 |
--------------------------------------------------------------------------------
/test/token/BEP20/behaviours/BEP20.behaviour.js:
--------------------------------------------------------------------------------
1 | const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers');
2 | const { ZERO_ADDRESS } = constants;
3 |
4 | const { shouldBehaveLikeOwnable } = require('../../../access/Ownable.behavior');
5 |
6 | function shouldBehaveLikeBEP20 (name, symbol, decimals, initialBalance, [owner, other, thirdParty]) {
7 | it('has a name', async function () {
8 | (await this.token.name()).should.be.equal(name);
9 | });
10 |
11 | it('has a symbol', async function () {
12 | (await this.token.symbol()).should.be.equal(symbol);
13 | });
14 |
15 | it('has an amount of decimals', async function () {
16 | (await this.token.decimals()).should.be.bignumber.equal(decimals);
17 | });
18 |
19 | describe('total supply', function () {
20 | it('returns the total amount of tokens', async function () {
21 | (await this.token.totalSupply()).should.be.bignumber.equal(initialBalance);
22 | });
23 | });
24 |
25 | describe('balanceOf', function () {
26 | describe('when the requested account has no tokens', function () {
27 | it('returns zero', async function () {
28 | (await this.token.balanceOf(other)).should.be.bignumber.equal(new BN(0));
29 | });
30 | });
31 |
32 | describe('when the requested account has some tokens', function () {
33 | it('returns the total amount of tokens', async function () {
34 | (await this.token.balanceOf(owner)).should.be.bignumber.equal(initialBalance);
35 | });
36 | });
37 | });
38 |
39 | describe('getOwner', function () {
40 | it('returns the token owner', async function () {
41 | expect(await this.token.getOwner()).to.equal(owner);
42 | });
43 | });
44 |
45 | describe('transfer', function () {
46 | describe('when the recipient is not the zero address', function () {
47 | const to = thirdParty;
48 |
49 | describe('when the sender does not have enough balance', function () {
50 | const amount = initialBalance.addn(1);
51 |
52 | it('reverts', async function () {
53 | await expectRevert(
54 | this.token.transfer(to, amount, { from: owner }),
55 | 'BEP20: transfer amount exceeds balance',
56 | );
57 | });
58 | });
59 |
60 | describe('when the sender has enough balance', function () {
61 | const amount = initialBalance;
62 |
63 | it('transfers the requested amount', async function () {
64 | await this.token.transfer(to, amount, { from: owner });
65 |
66 | (await this.token.balanceOf(owner)).should.be.bignumber.equal(new BN(0));
67 |
68 | (await this.token.balanceOf(to)).should.be.bignumber.equal(amount);
69 | });
70 |
71 | it('emits a transfer event', async function () {
72 | const { logs } = await this.token.transfer(to, amount, { from: owner });
73 |
74 | expectEvent.inLogs(logs, 'Transfer', {
75 | from: owner,
76 | to: to,
77 | value: amount,
78 | });
79 | });
80 | });
81 | });
82 |
83 | describe('when the recipient is the zero address', function () {
84 | const to = ZERO_ADDRESS;
85 |
86 | it('reverts', async function () {
87 | await expectRevert(
88 | this.token.transfer(to, initialBalance, { from: owner }),
89 | 'BEP20: transfer to the zero address',
90 | );
91 | });
92 | });
93 | });
94 |
95 | describe('approve', function () {
96 | describe('when the spender is not the zero address', function () {
97 | const spender = thirdParty;
98 |
99 | describe('when the sender has enough balance', function () {
100 | const amount = initialBalance;
101 |
102 | it('emits an approval event', async function () {
103 | const { logs } = await this.token.approve(spender, amount, { from: owner });
104 |
105 | expectEvent.inLogs(logs, 'Approval', {
106 | owner: owner,
107 | spender: spender,
108 | value: amount,
109 | });
110 | });
111 |
112 | describe('when there was no approved amount before', function () {
113 | it('approves the requested amount', async function () {
114 | await this.token.approve(spender, amount, { from: owner });
115 |
116 | (await this.token.allowance(owner, spender)).should.be.bignumber.equal(amount);
117 | });
118 | });
119 |
120 | describe('when the spender had an approved amount', function () {
121 | beforeEach(async function () {
122 | await this.token.approve(spender, 1, { from: owner });
123 | });
124 |
125 | it('approves the requested amount and replaces the previous one', async function () {
126 | await this.token.approve(spender, amount, { from: owner });
127 |
128 | (await this.token.allowance(owner, spender)).should.be.bignumber.equal(amount);
129 | });
130 | });
131 | });
132 |
133 | describe('when the sender does not have enough balance', function () {
134 | const amount = initialBalance.addn(1);
135 |
136 | it('emits an approval event', async function () {
137 | const { logs } = await this.token.approve(spender, amount, { from: owner });
138 |
139 | expectEvent.inLogs(logs, 'Approval', {
140 | owner: owner,
141 | spender: spender,
142 | value: amount,
143 | });
144 | });
145 |
146 | describe('when there was no approved amount before', function () {
147 | it('approves the requested amount', async function () {
148 | await this.token.approve(spender, amount, { from: owner });
149 |
150 | (await this.token.allowance(owner, spender)).should.be.bignumber.equal(amount);
151 | });
152 | });
153 |
154 | describe('when the spender had an approved amount', function () {
155 | beforeEach(async function () {
156 | await this.token.approve(spender, 1, { from: owner });
157 | });
158 |
159 | it('approves the requested amount and replaces the previous one', async function () {
160 | await this.token.approve(spender, amount, { from: owner });
161 |
162 | (await this.token.allowance(owner, spender)).should.be.bignumber.equal(amount);
163 | });
164 | });
165 | });
166 | });
167 |
168 | describe('when the spender is the zero address', function () {
169 | const amount = initialBalance;
170 | const spender = ZERO_ADDRESS;
171 |
172 | it('reverts', async function () {
173 | await expectRevert(
174 | this.token.approve(spender, amount, { from: owner }),
175 | 'BEP20: approve to the zero address',
176 | );
177 | });
178 | });
179 | });
180 |
181 | describe('transfer from', function () {
182 | const spender = thirdParty;
183 |
184 | describe('when the recipient is not the zero address', function () {
185 | const to = other;
186 |
187 | describe('when the spender has enough approved balance', function () {
188 | beforeEach(async function () {
189 | await this.token.approve(spender, initialBalance, { from: owner });
190 | });
191 |
192 | describe('when the owner has enough balance', function () {
193 | const amount = initialBalance;
194 |
195 | it('transfers the requested amount', async function () {
196 | await this.token.transferFrom(owner, to, amount, { from: spender });
197 |
198 | (await this.token.balanceOf(owner)).should.be.bignumber.equal(new BN(0));
199 |
200 | (await this.token.balanceOf(to)).should.be.bignumber.equal(amount);
201 | });
202 |
203 | it('decreases the spender allowance', async function () {
204 | await this.token.transferFrom(owner, to, amount, { from: spender });
205 |
206 | (await this.token.allowance(owner, spender)).should.be.bignumber.equal(new BN(0));
207 | });
208 |
209 | it('emits a transfer event', async function () {
210 | const { logs } = await this.token.transferFrom(owner, to, amount, { from: spender });
211 |
212 | expectEvent.inLogs(logs, 'Transfer', {
213 | from: owner,
214 | to: to,
215 | value: amount,
216 | });
217 | });
218 | });
219 |
220 | describe('when the owner does not have enough balance', function () {
221 | const amount = initialBalance.addn(1);
222 |
223 | it('reverts', async function () {
224 | await expectRevert(
225 | this.token.transferFrom(owner, to, amount, { from: spender }),
226 | 'BEP20: transfer amount exceeds balance',
227 | );
228 | });
229 | });
230 | });
231 |
232 | describe('when the spender does not have enough approved balance', function () {
233 | beforeEach(async function () {
234 | await this.token.approve(spender, 99, { from: owner });
235 | });
236 |
237 | describe('when the owner has enough balance', function () {
238 | const amount = initialBalance;
239 |
240 | it('reverts', async function () {
241 | await expectRevert(
242 | this.token.transferFrom(owner, to, amount, { from: spender }),
243 | 'BEP20: transfer amount exceeds allowance',
244 | );
245 | });
246 | });
247 |
248 | describe('when the owner does not have enough balance', function () {
249 | const amount = initialBalance.addn(1);
250 |
251 | it('reverts', async function () {
252 | await expectRevert(
253 | this.token.transferFrom(owner, to, amount, { from: spender }),
254 | 'BEP20: transfer amount exceeds balance',
255 | );
256 | });
257 | });
258 | });
259 | });
260 |
261 | describe('when the recipient is the zero address', function () {
262 | const amount = initialBalance;
263 | const to = ZERO_ADDRESS;
264 |
265 | beforeEach(async function () {
266 | await this.token.approve(spender, amount, { from: owner });
267 | });
268 |
269 | it('reverts', async function () {
270 | await expectRevert(
271 | this.token.transferFrom(owner, to, amount, { from: spender }),
272 | 'BEP20: transfer to the zero address',
273 | );
274 | });
275 | });
276 | });
277 |
278 | describe('decrease allowance', function () {
279 | describe('when the spender is not the zero address', function () {
280 | const spender = thirdParty;
281 |
282 | function shouldDecreaseApproval (amount) {
283 | describe('when there was no approved amount before', function () {
284 | it('reverts', async function () {
285 | await expectRevert(
286 | this.token.decreaseAllowance(spender, amount, { from: owner }),
287 | 'BEP20: decreased allowance below zero',
288 | );
289 | });
290 | });
291 |
292 | describe('when the spender had an approved amount', function () {
293 | const approvedAmount = amount;
294 |
295 | beforeEach(async function () {
296 | ({ logs: this.logs } = await this.token.approve(spender, approvedAmount, { from: owner }));
297 | });
298 |
299 | it('emits an approval event', async function () {
300 | const { logs } = await this.token.decreaseAllowance(spender, approvedAmount, { from: owner });
301 |
302 | expectEvent.inLogs(logs, 'Approval', {
303 | owner: owner,
304 | spender: spender,
305 | value: new BN(0),
306 | });
307 | });
308 |
309 | it('decreases the spender allowance subtracting the requested amount', async function () {
310 | await this.token.decreaseAllowance(spender, approvedAmount.subn(1), { from: owner });
311 |
312 | (await this.token.allowance(owner, spender)).should.be.bignumber.equal(new BN(1));
313 | });
314 |
315 | it('sets the allowance to zero when all allowance is removed', async function () {
316 | await this.token.decreaseAllowance(spender, approvedAmount, { from: owner });
317 | (await this.token.allowance(owner, spender)).should.be.bignumber.equal(new BN(0));
318 | });
319 |
320 | it('reverts when more than the full allowance is removed', async function () {
321 | await expectRevert(
322 | this.token.decreaseAllowance(spender, approvedAmount.addn(1), { from: owner }),
323 | 'BEP20: decreased allowance below zero',
324 | );
325 | });
326 | });
327 | }
328 |
329 | describe('when the sender has enough balance', function () {
330 | const amount = initialBalance;
331 |
332 | shouldDecreaseApproval(amount);
333 | });
334 |
335 | describe('when the sender does not have enough balance', function () {
336 | const amount = initialBalance.addn(1);
337 |
338 | shouldDecreaseApproval(amount);
339 | });
340 | });
341 |
342 | describe('when the spender is the zero address', function () {
343 | const amount = initialBalance;
344 | const spender = ZERO_ADDRESS;
345 |
346 | it('reverts', async function () {
347 | await expectRevert(
348 | this.token.decreaseAllowance(spender, amount, { from: owner }),
349 | 'BEP20: decreased allowance below zero',
350 | );
351 | });
352 | });
353 | });
354 |
355 | describe('increase allowance', function () {
356 | const amount = initialBalance;
357 |
358 | describe('when the spender is not the zero address', function () {
359 | const spender = thirdParty;
360 |
361 | describe('when the sender has enough balance', function () {
362 | it('emits an approval event', async function () {
363 | const { logs } = await this.token.increaseAllowance(spender, amount, { from: owner });
364 |
365 | expectEvent.inLogs(logs, 'Approval', {
366 | owner: owner,
367 | spender: spender,
368 | value: amount,
369 | });
370 | });
371 |
372 | describe('when there was no approved amount before', function () {
373 | it('approves the requested amount', async function () {
374 | await this.token.increaseAllowance(spender, amount, { from: owner });
375 |
376 | (await this.token.allowance(owner, spender)).should.be.bignumber.equal(amount);
377 | });
378 | });
379 |
380 | describe('when the spender had an approved amount', function () {
381 | beforeEach(async function () {
382 | await this.token.approve(spender, 1, { from: owner });
383 | });
384 |
385 | it('increases the spender allowance adding the requested amount', async function () {
386 | await this.token.increaseAllowance(spender, amount, { from: owner });
387 |
388 | (await this.token.allowance(owner, spender)).should.be.bignumber.equal(amount.addn(1));
389 | });
390 | });
391 | });
392 |
393 | describe('when the sender does not have enough balance', function () {
394 | const amount = initialBalance.addn(1);
395 |
396 | it('emits an approval event', async function () {
397 | const { logs } = await this.token.increaseAllowance(spender, amount, { from: owner });
398 |
399 | expectEvent.inLogs(logs, 'Approval', {
400 | owner: owner,
401 | spender: spender,
402 | value: amount,
403 | });
404 | });
405 |
406 | describe('when there was no approved amount before', function () {
407 | it('approves the requested amount', async function () {
408 | await this.token.increaseAllowance(spender, amount, { from: owner });
409 |
410 | (await this.token.allowance(owner, spender)).should.be.bignumber.equal(amount);
411 | });
412 | });
413 |
414 | describe('when the spender had an approved amount', function () {
415 | beforeEach(async function () {
416 | await this.token.approve(spender, 1, { from: owner });
417 | });
418 |
419 | it('increases the spender allowance adding the requested amount', async function () {
420 | await this.token.increaseAllowance(spender, amount, { from: owner });
421 |
422 | (await this.token.allowance(owner, spender)).should.be.bignumber.equal(amount.addn(1));
423 | });
424 | });
425 | });
426 | });
427 |
428 | describe('when the spender is the zero address', function () {
429 | const spender = ZERO_ADDRESS;
430 |
431 | it('reverts', async function () {
432 | await expectRevert(
433 | this.token.increaseAllowance(spender, amount, { from: owner }),
434 | 'BEP20: approve to the zero address',
435 | );
436 | });
437 | });
438 | });
439 |
440 | context('like a Ownable', function () {
441 | beforeEach(async function () {
442 | this.ownable = this.token;
443 | });
444 |
445 | shouldBehaveLikeOwnable(owner, [thirdParty]);
446 | });
447 | }
448 |
449 | module.exports = {
450 | shouldBehaveLikeBEP20,
451 | };
452 |
--------------------------------------------------------------------------------
/analysis/uml/StandardBEP20.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
207 |
--------------------------------------------------------------------------------
/analysis/uml/SimpleBEP20.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
228 |
--------------------------------------------------------------------------------
/analysis/uml/BurnableBEP20.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
238 |
--------------------------------------------------------------------------------