├── .github └── FUNDING.yml ├── .gitignore ├── .infuraKey ├── .mnemonic ├── .travis.yml ├── README.md ├── README ├── Crowdsale │ ├── AllowanceCrowdsale.md │ ├── CappedCrowdsale.md │ ├── FinalizableCrowdsale.md │ ├── IndividuallyCappedCrowdsale.md │ ├── MintedCrowdsale.md │ ├── PausableCrowdsale.md │ ├── PostDeliveryCrowdsale.md │ ├── RefundableCrowdsale.md │ ├── TimedCrowdsale.md │ └── WhitelistCrowdsale.md ├── ERC20 │ ├── ERC20FixedSupply.md │ ├── ERC20WithBurnable.md │ ├── ERC20WithCapped.md │ ├── ERC20WithMintable.md │ ├── ERC20WithPausable.md │ ├── IssueTokenBeforeTimelock.md │ └── IssueTokenWithTimelock.md ├── ERC721 │ ├── ERC20Full.md │ ├── ERC721Burnable.md │ ├── ERC721Mintable.md │ └── ERC721Pausable.md ├── ERC777 │ └── ERC777Contract.md └── Multi │ ├── CrowdsalePaymentSplitter.md │ ├── ERC20Migrator.md │ ├── ERC20MultiFunction.md │ ├── ERC20WithSnapshot.md │ ├── ERC20WithTokenVesting.md │ └── MultiFunctionCrowdsale.md ├── contracts ├── Crowdsale │ ├── AllowanceCrowdsale.sol │ ├── CappedCrowdsale.sol │ ├── FinalizableCrowdsale.sol │ ├── IndividuallyCappedCrowdsale.sol │ ├── MintedCrowdsale.sol │ ├── PausableCrowdsale.sol │ ├── PostDeliveryCrowdsale.sol │ ├── RefundableCrowdsale.sol │ ├── TimedCrowdsale.sol │ └── WhitelistCrowdsale.sol ├── ERC20 │ ├── ERC20FixedSupply.sol │ ├── ERC20WithBurnable.sol │ ├── ERC20WithCapped.sol │ ├── ERC20WithMintable.sol │ ├── ERC20WithPausable.sol │ └── ERC20WithTokenTimelock.sol ├── ERC721 │ ├── ERC721Burnable.sol │ ├── ERC721Full.sol │ ├── ERC721Mintable.sol │ └── ERC721Pausable.sol ├── ERC777 │ ├── ERC777Contract.sol │ ├── TokensRecipient.sol │ └── TokensSender.sol ├── Migrations.sol └── Multi │ ├── CrowdsalePaymentSplitter.sol │ ├── ERC20Migrator.sol │ ├── ERC20MultiFunction.sol │ ├── ERC20WithSnapshot.sol │ ├── ERC20WithTokenVesting.sol │ └── MultiFunctionCrowdsale.sol ├── migrations ├── 10_deploy_MintedCrowdsale.js ├── 11_deploy_CappedCrowdsale.js ├── 12_deploy_IndividuallyCappedCrowdsale.js ├── 13_deploy_PausableCrowdsale.js ├── 14_deploy_TimedCrowdsale.js ├── 15_deploy_WhitelistCrowdsale.js ├── 16_deploy_FinalizableCrowdsale.js ├── 17_deploy_PostDeliveryCrowdsale.js ├── 18_deploy_RefundableCrowdsale.js ├── 19_deploy_ERC20MultiFunction.js ├── 1_initial_migration.js ├── 20_deploy_MultiFunctionCrowdsale.js ├── 21_deploy_ERC721Full.js ├── 22_deploy_ERC721Mintable.js ├── 23_deploy_ERC721Burnable.js ├── 24_deploy_ERC721Pausable.js ├── 25_deploy_ERC20Migrator.js ├── 26_deploy_ERC20WithSnapshot.js ├── 27_deploy_CrowdsalePaymentSplitter.js ├── 28_deploy_ERC20WithTokenVesting.js ├── 29_deploy_ERC777Contract.js ├── 2_deploy_ERC20FixedSupply.js ├── 3_deploy_ERC20WithBurnable.js ├── 4_deploy_ERC20WithMintable.js ├── 5_deploy_ERC20WithCapped.js ├── 6_deploy_ERC20WithPausable.js ├── 7_deploy_IssueTokenWithTimelock.js ├── 8_deploy_IssueTokenBeforeTimelock.js └── 9_deploy_AllowanceCrowdsale.js ├── package.json ├── script ├── migrate.js ├── network.js └── test.js ├── test-environment.config.js ├── test ├── Crowdsale │ ├── AllowanceCrowdsale.js │ ├── CappedCrowdsale.js │ ├── FinalizableCrowdsale.js │ ├── IndividuallyCappedCrowdsale.js │ ├── MintedCrowdsale.js │ ├── PausableCrowdsale.js │ ├── PostDeliveryCrowdsale.js │ ├── RefundableCrowdsaleNotReach.js │ ├── RefundableCrowdsaleReached.js │ ├── TimedCrowdsale.js │ └── WhitelistCrowdsale.js ├── ERC20 │ ├── ERC20FixedSupply.js │ ├── ERC20WithBurnable.js │ ├── ERC20WithCapped.js │ ├── ERC20WithMintable.js │ ├── ERC20WithPausable.js │ └── ERC20WithTokenTimelock.js ├── ERC721 │ ├── ERC721Burnable.js │ ├── ERC721Full.js │ ├── ERC721Mintable.js │ └── ERC721Pausable.js ├── ERC777 │ └── ERC777Contract.js ├── Multi │ ├── CrowdsalePaymentSplitter.js │ ├── ERC20Migrator.js │ ├── ERC20MultiFunction.js │ ├── ERC20WithSnapshot.js │ ├── ERC20WithTokenVesting.js │ └── MultiFunctionCrowdsale.js └── inc │ ├── Crowdsale.js │ ├── ERC20.js │ ├── ERC721.js │ └── ERC777.js ├── token.json └── truffle-config.js /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | build/ 3 | npm-debug.log 4 | yarn-error.log 5 | .DS_Store 6 | *.keystore 7 | !debug.keystore 8 | package-lock.json 9 | 10 | .vscode/ 11 | 12 | bin/ 13 | .infuraKey 14 | .mnemonic 15 | .openzeppelin 16 | -------------------------------------------------------------------------------- /.infuraKey: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.mnemonic: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: xenial 2 | language: node_js 3 | node_js: 4 | - "lts/dubnium" 5 | install: 6 | - npm install 7 | script: 8 | - npm run mocha -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MintCoin崔棉大师的花式发币法 2 | 3 | ### 发行ERC20代币 4 | - [固定总量代币](./README/ERC20/ERC20FixedSupply.md) 5 | - [可销毁代币](./README/ERC20/ERC20WithBurnable.md) 6 | - [可增发代币](./README/ERC20/ERC20WithMintable.md) 7 | - [有封顶代币](./README/ERC20/ERC20WithCapped.md) 8 | - [可暂停代币](./README/ERC20/ERC20WithPausable.md) 9 | ### 锁仓合约 10 | - [发行代币同时锁仓](./README/ERC20/IssueTokenWithTimelock.md) 11 | - [发行代币之后锁仓](./README/ERC20/IssueTokenBeforeTimelock.md) 12 | ### 发行众筹代币 13 | - [通用的众筹](./README/Crowdsale/AllowanceCrowdsale.md) 14 | - [可增发的众筹](./README/Crowdsale/MintedCrowdsale.md) 15 | - [有封顶的众筹](./README/Crowdsale/CappedCrowdsale.md) 16 | - [有配额的众筹](./README/Crowdsale/IndividuallyCappedCrowdsale.md) 17 | - [可暂停的众筹](./README/Crowdsale/PausableCrowdsale.md) 18 | - [有时限的众筹](./README/Crowdsale/TimedCrowdsale.md) 19 | - [白名单众筹](./README/Crowdsale/WhitelistCrowdsale.md) 20 | - [可终结的众筹](./README/Crowdsale/FinalizableCrowdsale.md) 21 | - [到期后交付的众筹](./README/Crowdsale/PostDeliveryCrowdsale.md) 22 | - [不成功退款的众筹](./README/Crowdsale/RefundableCrowdsale.md) 23 | 24 | ### 多功能代币 25 | - [多功能ERC20代币,可增发,可销毁,可暂停,有封顶](./README/Multi/ERC20MultiFunction.md) 26 | - [多功能众筹合约:可增发,可销毁,有封顶,有配额,可暂停,有时限,白名单,成功后交付,不成功退款](./README/Multi/MultiFunctionCrowdsale.md) 27 | - [股份制受益人合约](./README/Multi/CrowdsalePaymentSplitter.md) 28 | 29 | ### 发行ERC777代币 30 | - [ERC777代币](./README/ERC777/ERC777Contract.md) 31 | 32 | ### 发行ERC721代币 33 | - [全功能ERC721代币](./README/ERC721/ERC721Full.md) 34 | - [可销毁的ERC721代币](./README/Crowdsale/ERC721Burnable.md) 35 | - [可铸造ERC721代币](./README/Crowdsale/ERC721Mintable.md) 36 | - [可暂停的ERC721代币](./README/Crowdsale/ERC721Pausable.md) 37 | 38 | ### 草稿 39 | - [代币迁移合约](./README/Multi/ERC20Migrator.md) 40 | - [可快照的ERC20代币](./README/Multi/ERC20WithSnapshot.md) 41 | - [分期释放合约](./README/Multi/ERC20WithTokenVesting.md) 42 | 43 | --- 44 | ### 安装 45 | ```shell 46 | $ npm install //安装依赖包 47 | ``` 48 | ### 布署到测试节点 49 | ```shell 50 | $ npm run compile //编译合约 51 | $ npm run node //打开一个测试节点 52 | $ npm run test //测试合约 53 | $ npm run migrate //布署合约到测试节点 54 | ``` 55 | ### 布署合约到truffle 56 | ```shell 57 | $ truffle develop //打开truffle开发环境 58 | truffle(develop)> compile //编译合约 59 | truffle(develop)> test //测试合约 60 | truffle(develop)> migrate //布署合约 61 | ``` 62 | ### 布署到主网 63 | - [链接](https://github.com/Fankouzu/smart-contract/tree/master/Solidity%20Lesson%2003) 64 | - [视频课](https://www.bilibili.com/video/BV1vJ41117ck/) 65 | --- 66 | 67 | 68 | -------------------------------------------------------------------------------- /README/Crowdsale/AllowanceCrowdsale.md: -------------------------------------------------------------------------------- 1 | # MintCoin崔棉大师的花式发币法 2 | 3 | ## 通用的众筹 4 | > 众筹代币是指在代币发行后,任何一个地址都可以向众筹地址使用ETH购买代币. 5 | 6 | > 代币和ETH的兑换比例在合约布署同时设定. 7 | 8 | > 所有的众筹合约都要在一个ERC20代币布署成功后再布署众筹合约,布署脚本中已经设置了一个固定总量的ERC20合约 9 | 10 | [合约文件: AllowanceCrowdsale.sol](https://github.com/Fankouzu/MintCoin/blob/master/contracts/Crowdsale/AllowanceCrowdsale.sol) 11 | 12 | [测试脚本: AllowanceCrowdsale.js](https://github.com/Fankouzu/MintCoin/blob/master/test/Crowdsale/AllowanceCrowdsale.js) 13 | 14 | [布署脚本: 9_deploy_AllowanceCrowdsale.js](https://github.com/Fankouzu/MintCoin/blob/master/migrations/9_deploy_AllowanceCrowdsale.js) 15 | 16 | ### 在布署合约时定义以下变量 17 | ```javascript 18 | uint256 rate //兑换比例1ETH兑换多少ERC20代币 19 | address payable wallet //接收ETH受益人地址 20 | IERC20 token //代币地址 21 | address tokenWallet //代币从这个地址发送 22 | ``` 23 | ### 在布署众筹合约之后需要执行ERC20的方法 24 | ```javascript 25 | //在布署之后必须将发送者账户中的代币批准给众筹合约 26 | token.approve(crowdsale.address, SOME_TOKEN_AMOUNT); 27 | ``` 28 | ### 调用方法 29 | ```javascript 30 | //返回代币地址 31 | token() public view returns (IERC20) 32 | //返回受益人地址 33 | wallet() public view returns (address payable) 34 | //返回兑换比例 35 | rate() public view returns (uint256) 36 | //返回销售额 37 | weiRaised() public view returns (uint256) 38 | //购买代币,代币发送给指定地址 39 | buyTokens(address beneficiary) public nonReentrant payable 40 | //特殊方法 41 | //返回代币现存地址 42 | tokenWallet() public view returns (address) 43 | //检查配额中剩余的代币数量 44 | remainingTokens() public view returns (uint256) 45 | ``` 46 | -------------------------------------------------------------------------------- /README/Crowdsale/CappedCrowdsale.md: -------------------------------------------------------------------------------- 1 | # MintCoin崔棉大师的花式发币法 2 | 3 | ## 有封顶众筹 4 | > 众筹代币是指在代币发行后,任何一个地址都可以向众筹地址使用ETH购买代币. 5 | 6 | > 代币和ETH的兑换比例在合约布署同时设定. 7 | 8 | > 所有的众筹合约都要在一个ERC20代币布署成功后再布署众筹合约,布署脚本中已经设置了一个固定总量的ERC20合约 9 | 10 | [合约文件: CappedCrowdsale.sol](https://github.com/Fankouzu/MintCoin/blob/master/contracts/Crowdsale/CappedCrowdsale.sol) 11 | 12 | [测试脚本: CappedCrowdsale.js](https://github.com/Fankouzu/MintCoin/blob/master/test/Crowdsale/CappedCrowdsale.js) 13 | 14 | [布署脚本: 11_deploy_CappedCrowdsale.js](https://github.com/Fankouzu/MintCoin/blob/master/migrations/11_deploy_CappedCrowdsale.js) 15 | 16 | ### 在布署合约时定义以下变量 17 | ```javascript 18 | uint256 rate //兑换比例1ETH兑换多少ERC20代币 19 | address payable wallet //接收ETH受益人地址 20 | IERC20 token //代币地址 21 | address tokenWallet //代币从这个地址发送 22 | uint256 cap //众筹封顶数量,单位是wei 23 | ``` 24 | ### 在布署众筹合约之后需要执行ERC20的方法 25 | ```javascript 26 | //在布署之后必须将发送者账户中的代币批准给众筹合约 27 | token.approve(crowdsale.address, SOME_TOKEN_AMOUNT); 28 | ``` 29 | ### 调用方法 30 | ```javascript 31 | //返回代币地址 32 | token() public view returns (IERC20) 33 | //返回受益人地址 34 | wallet() public view returns (address payable) 35 | //返回兑换比例 36 | rate() public view returns (uint256) 37 | //返回销售额 38 | weiRaised() public view returns (uint256) 39 | //购买代币,代币发送给指定地址 40 | buyTokens(address beneficiary) public nonReentrant payable 41 | //特殊方法 42 | //返回代币现存地址 43 | tokenWallet() public view returns (address) 44 | //检查配额中剩余的代币数量 45 | remainingTokens() public view returns (uint256) 46 | //返回封顶的数量 47 | cap() public view returns (uint256) 48 | //返回当前是否达到封顶 49 | capReached() public view returns (bool) 50 | ``` 51 | -------------------------------------------------------------------------------- /README/Crowdsale/FinalizableCrowdsale.md: -------------------------------------------------------------------------------- 1 | # MintCoin崔棉大师的花式发币法 2 | 3 | ## 可终结的众筹 4 | > 众筹代币是指在代币发行后,任何一个地址都可以向众筹地址使用ETH购买代币. 5 | 6 | > 代币和ETH的兑换比例在合约布署同时设定. 7 | 8 | > 所有的众筹合约都要在一个ERC20代币布署成功后再布署众筹合约,布署脚本中已经设置了一个固定总量的ERC20合约 9 | 10 | > 可终结的众筹是指在有时限的众筹的基础上增加了结束众筹的方法 11 | 12 | [合约文件: FinalizableCrowdsale.sol](https://github.com/Fankouzu/MintCoin/blob/master/contracts/Crowdsale/FinalizableCrowdsale.sol) 13 | 14 | [测试脚本: FinalizableCrowdsale.js](https://github.com/Fankouzu/MintCoin/blob/master/test/Crowdsale/FinalizableCrowdsale.js) 15 | 16 | [布署脚本: 16_deploy_FinalizableCrowdsale.js](https://github.com/Fankouzu/MintCoin/blob/master/migrations/16_deploy_FinalizableCrowdsale.js) 17 | 18 | ### 额外增加 19 | > 在FinalizableCrowdsale.sol合约文件中可以设置一个结束众筹的方法,因为是内部函数,所以只能在合约文件中设置. 20 | ``` 21 | function _finalization() internal { 22 | // 写入众筹结束后的业务逻辑,当finalize()方法被调用时会执行这里 23 | super._finalization(); 24 | } 25 | ``` 26 | 27 | ### 在布署合约时定义以下变量 28 | ```javascript 29 | uint256 rate //兑换比例1ETH兑换多少ERC20代币 30 | address payable wallet //接收ETH受益人地址 31 | IERC20 token //代币地址 32 | address tokenWallet //代币从这个地址发送 33 | uint256 openingTime // 众筹开始时间 34 | uint256 closingTime // 众筹结束时间 35 | ``` 36 | ### 在布署众筹合约之后需要执行ERC20的方法 37 | ```javascript 38 | //在布署之后必须将发送者账户中的代币批准给众筹合约 39 | token.approve(crowdsale.address, SOME_TOKEN_AMOUNT); 40 | ``` 41 | ### 调用方法 42 | ```javascript 43 | //返回代币地址 44 | token() public view returns (IERC20) 45 | //返回受益人地址 46 | wallet() public view returns (address payable) 47 | //返回兑换比例 48 | rate() public view returns (uint256) 49 | //返回销售额 50 | weiRaised() public view returns (uint256) 51 | //购买代币,代币发送给指定地址 52 | buyTokens(address beneficiary) public nonReentrant payable 53 | //特殊方法 54 | //返回代币现存地址 55 | tokenWallet() public view returns (address) 56 | //检查配额中剩余的代币数量 57 | remainingTokens() public view returns (uint256) 58 | //返回众筹开始时间 59 | openingTime() public view returns (uint256) 60 | //返回众筹结束时间 61 | closingTime() public view returns (uint256) 62 | //返回众筹是否开始 63 | isOpen() public view returns (bool) 64 | //返回众筹是否结束 65 | hasClosed() public view returns (bool) 66 | //返回合约是否已经结束 67 | finalized() public view returns (bool) 68 | //触发合约结束方法 69 | finalize() public 70 | ``` 71 | -------------------------------------------------------------------------------- /README/Crowdsale/IndividuallyCappedCrowdsale.md: -------------------------------------------------------------------------------- 1 | # MintCoin崔棉大师的花式发币法 2 | 3 | ## 有配额的众筹 4 | > 众筹代币是指在代币发行后,任何一个地址都可以向众筹地址使用ETH购买代币. 5 | 6 | > 代币和ETH的兑换比例在合约布署同时设定. 7 | 8 | > 所有的众筹合约都要在一个ERC20代币布署成功后再布署众筹合约,布署脚本中已经设置了一个固定总量的ERC20合约 9 | 10 | > 有配额的众筹是指购买代币的账户必须在设置配额后才可以购买代币 11 | 12 | [合约文件: IndividuallyCappedCrowdsale.sol](https://github.com/Fankouzu/MintCoin/blob/master/contracts/Crowdsale/IndividuallyCappedCrowdsale.sol) 13 | 14 | [测试脚本: IndividuallyCappedCrowdsale.js](https://github.com/Fankouzu/MintCoin/blob/master/test/Crowdsale/IndividuallyCappedCrowdsale.js) 15 | 16 | [布署脚本: 12_deploy_IndividuallyCappedCrowdsale.js](https://github.com/Fankouzu/MintCoin/blob/master/migrations/12_deploy_IndividuallyCappedCrowdsale.js) 17 | 18 | ### 在布署合约时定义以下变量 19 | ```javascript 20 | uint256 rate //兑换比例1ETH兑换多少ERC20代币 21 | address payable wallet //接收ETH受益人地址 22 | IERC20 token //代币地址 23 | address tokenWallet //代币从这个地址发送 24 | ``` 25 | ### 在布署众筹合约之后需要执行ERC20的方法 26 | ```javascript 27 | //在布署之后必须将发送者账户中的代币批准给众筹合约 28 | token.approve(crowdsale.address, SOME_TOKEN_AMOUNT); 29 | ``` 30 | ### 调用方法 31 | ```javascript 32 | //返回代币地址 33 | token() public view returns (IERC20) 34 | //返回受益人地址 35 | wallet() public view returns (address payable) 36 | //返回兑换比例 37 | rate() public view returns (uint256) 38 | //返回销售额 39 | weiRaised() public view returns (uint256) 40 | //购买代币,代币发送给指定地址 41 | buyTokens(address beneficiary) public nonReentrant payable 42 | //特殊方法 43 | //返回代币现存地址 44 | tokenWallet() public view returns (address) 45 | //检查配额中剩余的代币数量 46 | remainingTokens() public view returns (uint256) 47 | //设置指定账户的封顶数量,单位是wei 48 | setCap(address beneficiary, uint256 cap) external onlyCapper 49 | //获取指定账户的封顶配额 50 | getCap(address beneficiary) public view returns (uint256) 51 | //获取指定账户提供的ETH数量 52 | getContribution(address beneficiary) public view returns (uint256) 53 | //返回指定账户是否拥有设置配额的权限 54 | isCapper(address account) public view returns (bool) 55 | //给指定账户添加设置配额的权限 56 | addCapper(address account) public onlyCapper 57 | //撤销当前账户的设置配额权限 58 | renounceCapper() public 59 | ``` 60 | -------------------------------------------------------------------------------- /README/Crowdsale/MintedCrowdsale.md: -------------------------------------------------------------------------------- 1 | # MintCoin崔棉大师的花式发币法 2 | 3 | ## 铸造式众筹 4 | 5 | > 代币发行时可以设置一个初始总量,也可以设置为0,当代币以指定的兑换比例销售时才铸造代币,销售多少铸造多少. 6 | 7 | > 代币和ETH的兑换比例在合约布署同时设定. 8 | 9 | > 所有的众筹合约都要在一个ERC20代币布署成功后再布署众筹合约,布署脚本中已经设置了一个可增发代币的ERC20合约 10 | 11 | 12 | [合约文件: MintedCrowdsale.sol](https://github.com/Fankouzu/MintCoin/blob/master/contracts/Crowdsale/MintedCrowdsale.sol) 13 | 14 | [测试脚本: MintedCrowdsale.js](https://github.com/Fankouzu/MintCoin/blob/master/test/Crowdsale/MintedCrowdsale.js) 15 | 16 | [布署脚本: 10_deploy_MintedCrowdsale.js](https://github.com/Fankouzu/MintCoin/blob/master/migrations/10_deploy_MintedCrowdsale.js) 17 | 18 | ### 在布署合约时定义以下变量 19 | ```javascript 20 | uint256 rate //兑换比例1ETH兑换多少ERC20代币 21 | address payable wallet //接收ETH受益人地址 22 | IERC20 token //代币地址 23 | ``` 24 | ### 在布署众筹合约之后需要执行ERC20的方法 25 | ```javascript 26 | //添加众筹合约的铸造权 27 | token.addMinter(crowdsale.address); 28 | //撤销当前账户的铸造权 29 | token.renounceMinter(); 30 | ``` 31 | ### 调用方法 32 | ```javascript 33 | //返回代币地址 34 | token() public view returns (IERC20) 35 | //返回受益人地址 36 | wallet() public view returns (address payable) 37 | //返回兑换比例 38 | rate() public view returns (uint256) 39 | //返回销售额 40 | weiRaised() public view returns (uint256) 41 | //购买代币,代币发送给指定地址 42 | buyTokens(address beneficiary) public nonReentrant payable 43 | ``` 44 | -------------------------------------------------------------------------------- /README/Crowdsale/PausableCrowdsale.md: -------------------------------------------------------------------------------- 1 | # MintCoin崔棉大师的花式发币法 2 | 3 | ## 可暂停的众筹 4 | > 众筹代币是指在代币发行后,任何一个地址都可以向众筹地址使用ETH购买代币. 5 | 6 | > 代币和ETH的兑换比例在合约布署同时设定. 7 | 8 | > 所有的众筹合约都要在一个ERC20代币布署成功后再布署众筹合约,布署脚本中已经设置了一个固定总量的ERC20合约 9 | 10 | [合约文件: PausableCrowdsale.sol](https://github.com/Fankouzu/MintCoin/blob/master/contracts/Crowdsale/PausableCrowdsale.sol) 11 | 12 | [测试脚本: PausableCrowdsale.js](https://github.com/Fankouzu/MintCoin/blob/master/test/Crowdsale/PausableCrowdsale.js) 13 | 14 | [布署脚本: 13_deploy_PausableCrowdsale.js](https://github.com/Fankouzu/MintCoin/blob/master/migrations/13_deploy_PausableCrowdsale.js) 15 | 16 | ### 在布署合约时定义以下变量 17 | ```javascript 18 | uint256 rate //兑换比例1ETH兑换多少ERC20代币 19 | address payable wallet //接收ETH受益人地址 20 | IERC20 token //代币地址 21 | address tokenWallet //代币从这个地址发送 22 | ``` 23 | ### 在布署众筹合约之后需要执行ERC20的方法 24 | ```javascript 25 | //在布署之后必须将发送者账户中的代币批准给众筹合约 26 | token.approve(crowdsale.address, SOME_TOKEN_AMOUNT); 27 | ``` 28 | ### 调用方法 29 | ```javascript 30 | //返回代币地址 31 | token() public view returns (IERC20) 32 | //返回受益人地址 33 | wallet() public view returns (address payable) 34 | //返回兑换比例 35 | rate() public view returns (uint256) 36 | //返回销售额 37 | weiRaised() public view returns (uint256) 38 | //购买代币,代币发送给指定地址 39 | buyTokens(address beneficiary) public nonReentrant payable 40 | //特殊方法 41 | //返回代币现存地址 42 | tokenWallet() public view returns (address) 43 | //检查配额中剩余的代币数量 44 | remainingTokens() public view returns (uint256) 45 | //返回指定地址是否拥有暂停权 46 | isPauser(address account) public view returns (bool) 47 | //给指定地址添加暂停权限,只有通过有暂停权的地址添加 48 | addPauser(address account) public onlyPauser 49 | //撤销当前发送账户的暂停权 50 | renouncePauser() public 51 | //返回合约当前是否已经暂停 52 | paused() public view returns (bool) 53 | //暂停合约 54 | pause() public onlyPauser whenNotPaused 55 | //恢复合约 56 | unpause() public onlyPauser whenPaused 57 | ``` 58 | -------------------------------------------------------------------------------- /README/Crowdsale/PostDeliveryCrowdsale.md: -------------------------------------------------------------------------------- 1 | # MintCoin崔棉大师的花式发币法 2 | 3 | ## 成功后交付的众筹 4 | > 众筹代币是指在代币发行后,任何一个地址都可以向众筹地址使用ETH购买代币. 5 | 6 | > 代币和ETH的兑换比例在合约布署同时设定. 7 | 8 | > 所有的众筹合约都要在一个ERC20代币布署成功后再布署众筹合约,布署脚本中已经设置了一个固定总量的ERC20合约 9 | 10 | > 成功后交付的众筹是指在有时限的众筹和可终结的众筹的基础上,只有当众筹时间到达后并且触发结束方法,购买者才可以通过withdrawTokens()方法提取到ERC20代币 11 | 12 | [合约文件: PostDeliveryCrowdsale.sol](https://github.com/Fankouzu/MintCoin/blob/master/contracts/Crowdsale/PostDeliveryCrowdsale.sol) 13 | 14 | [测试脚本: PostDeliveryCrowdsale.js](https://github.com/Fankouzu/MintCoin/blob/master/test/Crowdsale/PostDeliveryCrowdsale.js) 15 | 16 | [布署脚本: 17_deploy_PostDeliveryCrowdsale.js](https://github.com/Fankouzu/MintCoin/blob/master/migrations/17_deploy_PostDeliveryCrowdsale.js) 17 | 18 | ### 在布署合约时定义以下变量 19 | ```javascript 20 | uint256 rate //兑换比例1ETH兑换多少ERC20代币 21 | address payable wallet //接收ETH受益人地址 22 | IERC20 token //代币地址 23 | address tokenWallet //代币从这个地址发送 24 | uint256 openingTime // 众筹开始时间 25 | uint256 closingTime // 众筹结束时间 26 | ``` 27 | ### 在布署众筹合约之后需要执行ERC20的方法 28 | ```javascript 29 | //在布署之后必须将发送者账户中的代币批准给众筹合约 30 | token.approve(crowdsale.address, SOME_TOKEN_AMOUNT); 31 | ``` 32 | ### 调用方法 33 | ```javascript 34 | //返回代币地址 35 | token() public view returns (IERC20) 36 | //返回受益人地址 37 | wallet() public view returns (address payable) 38 | //返回兑换比例 39 | rate() public view returns (uint256) 40 | //返回销售额 41 | weiRaised() public view returns (uint256) 42 | //购买代币,代币发送给指定地址 43 | buyTokens(address beneficiary) public nonReentrant payable 44 | //特殊方法 45 | //返回代币现存地址 46 | tokenWallet() public view returns (address) 47 | //检查配额中剩余的代币数量 48 | remainingTokens() public view returns (uint256) 49 | //返回众筹开始时间 50 | openingTime() public view returns (uint256) 51 | //返回众筹结束时间 52 | closingTime() public view returns (uint256) 53 | //返回众筹是否开始 54 | isOpen() public view returns (bool) 55 | //返回众筹是否结束 56 | hasClosed() public view returns (bool) 57 | //返回合约是否已经结束 58 | finalized() public view returns (bool) 59 | //触发合约结束方法 60 | finalize() public 61 | //返回存储在合约上的ERC20数量 62 | balanceOf(address account) public view returns (uint256) 63 | //当众筹结束后可以提取ERC20 64 | withdrawTokens(address beneficiary) public 65 | ``` 66 | -------------------------------------------------------------------------------- /README/Crowdsale/RefundableCrowdsale.md: -------------------------------------------------------------------------------- 1 | # MintCoin崔棉大师的花式发币法 2 | 3 | ## 不成功退款的众筹 4 | > 众筹代币是指在代币发行后,任何一个地址都可以向众筹地址使用ETH购买代币. 5 | 6 | > 代币和ETH的兑换比例在合约布署同时设定. 7 | 8 | > 所有的众筹合约都要在一个ERC20代币布署成功后再布署众筹合约,布署脚本中已经设置了一个固定总量的ERC20合约 9 | 10 | > 不成功退款的众筹是指在成功后交付的众筹的基础上,设置了众筹目标(以ETH数量衡量). 11 | > 当众筹时间到达后,如果众筹目标没有到达,购买者可以通过claimRefund()方法退回ETH. 12 | > 当众筹时间到达后,如果到达了众筹目标,购买者才可以通过withdrawTokens()方法提取到ERC20代币. 13 | 14 | ### 众筹规则: 15 | 1. 兑换比例1ETH:100ERC20 16 | 2. 代币存于accounts[0]账户 17 | 3. 众筹获得的ETH交给accounts[1]账户 18 | 4. 众筹开始时间是当前时间 19 | 5. 众筹结束时间是5秒后 20 | 6. 众筹目标是2000个ERC20 21 | 7. 没达到众筹目标,在众筹结束后可以退款 22 | 8. 达到众筹目标,在众筹结束后提取代币 23 | 24 | [合约文件: RefundableCrowdsale.sol](https://github.com/Fankouzu/MintCoin/blob/master/contracts/Crowdsale/RefundableCrowdsale.sol) 25 | 26 | [测试脚本1(到达众筹目标): RefundableCrowdsaleReached.js](https://github.com/Fankouzu/MintCoin/blob/master/test/Crowdsale/RefundableCrowdsaleReached.js) 27 | 28 | [测试脚本2(没到达众筹目标): RefundableCrowdsaleNotReach.js](https://github.com/Fankouzu/MintCoin/blob/master/test/Crowdsale/RefundableCrowdsaleNotReach.js) 29 | 30 | [布署脚本: 18_deploy_RefundableCrowdsale.js](https://github.com/Fankouzu/MintCoin/blob/master/migrations/18_deploy_RefundableCrowdsale.js) 31 | 32 | ### 在布署合约时定义以下变量 33 | ```javascript 34 | uint256 rate //兑换比例1ETH兑换多少ERC20代币 35 | address payable wallet //接收ETH受益人地址 36 | IERC20 token //代币地址 37 | address tokenWallet //代币从这个地址发送 38 | uint256 openingTime //众筹开始时间 39 | uint256 closingTime //众筹结束时间 40 | uint256 goal //众筹目标 41 | ``` 42 | ### 在布署众筹合约之后需要执行ERC20的方法 43 | ```javascript 44 | //在布署之后必须将发送者账户中的代币批准给众筹合约 45 | token.approve(crowdsale.address, SOME_TOKEN_AMOUNT); 46 | ``` 47 | ### 调用方法 48 | ```javascript 49 | //返回代币地址 50 | token() public view returns (IERC20) 51 | //返回受益人地址 52 | wallet() public view returns (address payable) 53 | //返回兑换比例 54 | rate() public view returns (uint256) 55 | //返回销售额 56 | weiRaised() public view returns (uint256) 57 | //购买代币,代币发送给指定地址 58 | buyTokens(address beneficiary) public nonReentrant payable 59 | //特殊方法 60 | //返回代币现存地址 61 | tokenWallet() public view returns (address) 62 | //检查配额中剩余的代币数量 63 | remainingTokens() public view returns (uint256) 64 | //返回众筹开始时间 65 | openingTime() public view returns (uint256) 66 | //返回众筹结束时间 67 | closingTime() public view returns (uint256) 68 | //返回众筹是否开始 69 | isOpen() public view returns (bool) 70 | //返回众筹是否结束 71 | hasClosed() public view returns (bool) 72 | //返回合约是否已经结束 73 | finalized() public view returns (bool) 74 | //触发合约结束方法 75 | finalize() public 76 | //返回存储在合约上的ERC20数量 77 | balanceOf(address account) public view returns (uint256) 78 | //当众筹结束后,并且到达了众筹目标,触发可以提取ERC20 79 | withdrawTokens(address beneficiary) public 80 | //返回众筹目标,ETH的数量 81 | goal() public view returns (uint256) 82 | //当众筹结束后,并且没有达到目标时,触发这个方法可以给购买者退款 83 | claimRefund(address payable refundee) public 84 | //返回众筹目标是否到达 85 | goalReached() public view returns (bool) 86 | ``` 87 | -------------------------------------------------------------------------------- /README/Crowdsale/TimedCrowdsale.md: -------------------------------------------------------------------------------- 1 | # MintCoin崔棉大师的花式发币法 2 | 3 | ## 有时限的众筹 4 | > 众筹代币是指在代币发行后,任何一个地址都可以向众筹地址使用ETH购买代币. 5 | 6 | > 代币和ETH的兑换比例在合约布署同时设定. 7 | 8 | > 所有的众筹合约都要在一个ERC20代币布署成功后再布署众筹合约,布署脚本中已经设置了一个固定总量的ERC20合约 9 | 10 | > 有时限的众筹是指设置了众筹的开始时间和结束时间 11 | 12 | [合约文件: TimedCrowdsale.sol](https://github.com/Fankouzu/MintCoin/blob/master/contracts/Crowdsale/TimedCrowdsale.sol) 13 | 14 | [测试脚本: TimedCrowdsale.js](https://github.com/Fankouzu/MintCoin/blob/master/test/Crowdsale/TimedCrowdsale.js) 15 | 16 | [布署脚本: 14_deploy_TimedCrowdsale.js](https://github.com/Fankouzu/MintCoin/blob/master/migrations/14_deploy_TimedCrowdsale.js) 17 | 18 | ### 在布署合约时定义以下变量 19 | ```javascript 20 | uint256 rate //兑换比例1ETH兑换多少ERC20代币 21 | address payable wallet //接收ETH受益人地址 22 | IERC20 token //代币地址 23 | address tokenWallet //代币从这个地址发送 24 | uint256 openingTime // 众筹开始时间 25 | uint256 closingTime // 众筹结束时间 26 | ``` 27 | ### 在布署众筹合约之后需要执行ERC20的方法 28 | ```javascript 29 | //在布署之后必须将发送者账户中的代币批准给众筹合约 30 | token.approve(crowdsale.address, SOME_TOKEN_AMOUNT); 31 | ``` 32 | ### 调用方法 33 | ```javascript 34 | //返回代币地址 35 | token() public view returns (IERC20) 36 | //返回受益人地址 37 | wallet() public view returns (address payable) 38 | //返回兑换比例 39 | rate() public view returns (uint256) 40 | //返回销售额 41 | weiRaised() public view returns (uint256) 42 | //购买代币,代币发送给指定地址 43 | buyTokens(address beneficiary) public nonReentrant payable 44 | //特殊方法 45 | //返回代币现存地址 46 | tokenWallet() public view returns (address) 47 | //检查配额中剩余的代币数量 48 | remainingTokens() public view returns (uint256) 49 | //返回众筹开始时间 50 | openingTime() public view returns (uint256) 51 | //返回众筹结束时间 52 | closingTime() public view returns (uint256) 53 | //返回众筹是否开始 54 | isOpen() public view returns (bool) 55 | //返回众筹是否结束 56 | hasClosed() public view returns (bool) 57 | ``` 58 | -------------------------------------------------------------------------------- /README/Crowdsale/WhitelistCrowdsale.md: -------------------------------------------------------------------------------- 1 | # MintCoin崔棉大师的花式发币法 2 | 3 | ## 白名单众筹 4 | > 众筹代币是指在代币发行后,任何一个地址都可以向众筹地址使用ETH购买代币. 5 | 6 | > 代币和ETH的兑换比例在合约布署同时设定. 7 | 8 | > 所有的众筹合约都要在一个ERC20代币布署成功后再布署众筹合约,布署脚本中已经设置了一个固定总量的ERC20合约 9 | 10 | > 白名单众筹是指只能被加入到白名单的账户才可以参与购买代币的众筹 11 | 12 | [合约文件: WhitelistCrowdsale.sol](https://github.com/Fankouzu/MintCoin/blob/master/contracts/Crowdsale/WhitelistCrowdsale.sol) 13 | 14 | [测试脚本: WhitelistCrowdsale.js](https://github.com/Fankouzu/MintCoin/blob/master/test/Crowdsale/WhitelistCrowdsale.js) 15 | 16 | [布署脚本: 15_deploy_WhitelistCrowdsale.js](https://github.com/Fankouzu/MintCoin/blob/master/migrations/15_deploy_WhitelistCrowdsale.js) 17 | 18 | ### 在布署合约时定义以下变量 19 | ```javascript 20 | uint256 rate //兑换比例1ETH兑换多少ERC20代币 21 | address payable wallet //接收ETH受益人地址 22 | IERC20 token //代币地址 23 | address tokenWallet //代币从这个地址发送 24 | ``` 25 | ### 在布署众筹合约之后需要执行ERC20的方法 26 | ```javascript 27 | //在布署之后必须将发送者账户中的代币批准给众筹合约 28 | token.approve(crowdsale.address, SOME_TOKEN_AMOUNT); 29 | ``` 30 | ### 调用方法 31 | ```javascript 32 | //返回代币地址 33 | token() public view returns (IERC20) 34 | //返回受益人地址 35 | wallet() public view returns (address payable) 36 | //返回兑换比例 37 | rate() public view returns (uint256) 38 | //返回销售额 39 | weiRaised() public view returns (uint256) 40 | //购买代币,代币发送给指定地址 41 | buyTokens(address beneficiary) public nonReentrant payable 42 | //特殊方法 43 | //返回代币现存地址 44 | tokenWallet() public view returns (address) 45 | //检查配额中剩余的代币数量 46 | remainingTokens() public view returns (uint256) 47 | //返回指定账户是否在白名单 48 | isWhitelisted(address account) public view returns (bool) 49 | //添加指定账户到白名单 50 | addWhitelisted(address account) public onlyWhitelistAdmin 51 | //从白名单移除指定账户 52 | removeWhitelisted(address account) public onlyWhitelistAdmin 53 | //从白名单撤销自己的账户 54 | renounceWhitelisted() public 55 | //返回指定账户是否是白名单管理员 56 | isWhitelistAdmin(address account) public view returns (bool) 57 | //添加指定账户到白名单管理员 58 | addWhitelistAdmin(address account) public onlyWhitelistAdmin 59 | //从白名单管理员撤销自己的账户 60 | renounceWhitelistAdmin() public 61 | ``` 62 | -------------------------------------------------------------------------------- /README/ERC20/ERC20FixedSupply.md: -------------------------------------------------------------------------------- 1 | # MintCoin崔棉大师的花式发币法 2 | 3 | ## 固定总量代币 4 | > 固定总量代币是最基础的ERC20代币,包含了代币名称,代币缩写,精度和发型总量四个基本信息. 5 | 6 | [合约文件: ERC20FixedSupply.sol](https://github.com/Fankouzu/MintCoin/blob/master/contracts/ERC20/ERC20FixedSupply.sol) 7 | 8 | [测试脚本: ERC20FixedSupply.js](https://github.com/Fankouzu/MintCoin/blob/master/test/ERC20/ERC20FixedSupply.js) 9 | 10 | [布署脚本: 2_deploy_ERC20FixedSupply.js](https://github.com/Fankouzu/MintCoin/blob/master/migrations/2_deploy_ERC20FixedSupply.js) 11 | 12 | ### 在布署合约时定义以下变量 13 | ```javascript 14 | string memory name, //代币名称 15 | string memory symbol, //代币缩写 16 | uint8 decimals, //精度 17 | uint256 totalSupply //发行总量 18 | ``` 19 | ### 调用方法 20 | ```javascript 21 | //返回代币名称 22 | name() public view returns (string memory) 23 | //返回代币缩写 24 | symbol() public view returns (string memory) 25 | //返回代币精度 26 | decimals() public view returns (uint8) 27 | //返回发行总量 28 | totalSupply() external view returns (uint256) 29 | //返回指定地址的余额 30 | balanceOf(address account) external view returns (uint256) 31 | //发送代币,从当前账户发送到指定地址 32 | transfer(address recipient, uint256 amount) external returns (bool) 33 | //查询owner给予spender的配额 34 | allowance(address owner, address spender) external view returns (uint256) 35 | //批准spender代表发送者使用amount数量的代币 36 | approve(address spender, uint256 amount) external returns (bool) 37 | //spender调用这个函数发送sender账户中的amount数量的代币给recipient 38 | transferFrom(address sender, address recipient, uint256 amount) external returns (bool) 39 | //增加给予spender的配额 40 | increaseAllowance(address spender, uint256 addedValue) public returns (bool) 41 | //减少给予spender的配额 42 | decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) 43 | ``` 44 | -------------------------------------------------------------------------------- /README/ERC20/ERC20WithBurnable.md: -------------------------------------------------------------------------------- 1 | # MintCoin崔棉大师的花式发币法 2 | 3 | ## 可销毁代币 4 | > 可销毁的代币是指代币在发行之后,持有者可以销毁自己持有的代币,也可以通过批准方法让第三方负责销毁. 5 | 6 | [合约文件: ERC20WithBurnable.sol](https://github.com/Fankouzu/MintCoin/blob/master/contracts/ERC20/ERC20WithBurnable.sol) 7 | 8 | [测试脚本: ERC20WithBurnable.js](https://github.com/Fankouzu/MintCoin/blob/master/test/ERC20/ERC20WithBurnable.js) 9 | 10 | [布署脚本: 3_deploy_ERC20WithBurnable.js](https://github.com/Fankouzu/MintCoin/blob/master/migrations/3_deploy_ERC20WithBurnable.js) 11 | 12 | ### 在布署合约时定义以下变量 13 | ```javascript 14 | string memory name, //代币名称 15 | string memory symbol, //代币缩写 16 | uint8 decimals , //精度 17 | uint256 totalSupply //发行总量 18 | ``` 19 | ### 调用方法 20 | ```javascript 21 | //返回代币名称 22 | name() public view returns (string memory) 23 | //返回代币缩写 24 | symbol() public view returns (string memory) 25 | //返回代币精度 26 | decimals() public view returns (uint8) 27 | //返回发行总量 28 | totalSupply() external view returns (uint256) 29 | //返回指定地址的余额 30 | balanceOf(address account) external view returns (uint256) 31 | //发送代币,从当前账户发送到指定地址 32 | transfer(address recipient, uint256 amount) external returns (bool) 33 | //查询owner给予spender的配额 34 | allowance(address owner, address spender) external view returns (uint256) 35 | //批准spender代表发送者使用amount数量的代币 36 | approve(address spender, uint256 amount) external returns (bool) 37 | //spender调用这个函数发送sender账户中的amount数量的代币给recipient 38 | transferFrom(address sender, address recipient, uint256 amount) external returns (bool) 39 | //增加给予spender的配额 40 | increaseAllowance(address spender, uint256 addedValue) public returns (bool) 41 | //减少给予spender的配额 42 | decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) 43 | //特殊方法 44 | //调用此方法可以从调用者账户中销毁代币 45 | burn(uint256 amount) public 46 | //调用此方法可以从指定地址销毁代币,代币从发送者的批准中扣除 47 | burnFrom(address account, uint256 amount) public 48 | ``` 49 | -------------------------------------------------------------------------------- /README/ERC20/ERC20WithCapped.md: -------------------------------------------------------------------------------- 1 | # MintCoin崔棉大师的花式发币法 2 | 3 | ## 有封顶代币 4 | > 有封顶的代币指的是在可增发代币的基础上设置了铸造封顶数额,当铸造到达封顶数额时将抛出异常. 5 | 6 | [合约文件: ERC20WithCapped.sol](https://github.com/Fankouzu/MintCoin/blob/master/contracts/ERC20/ERC20WithCapped.sol) 7 | 8 | [测试脚本: ERC20WithCapped.js](https://github.com/Fankouzu/MintCoin/blob/master/test/ERC20/ERC20WithCapped.js) 9 | 10 | [布署脚本: 5_deploy_ERC20WithCapped.js](https://github.com/Fankouzu/MintCoin/blob/master/migrations/5_deploy_ERC20WithCapped.js) 11 | 12 | ### 在布署合约时定义以下变量 13 | ```javascript 14 | string memory name, //代币名称 15 | string memory symbol, //代币缩写 16 | uint8 decimals , //精度 17 | uint256 totalSupply //发行总量 18 | uint256 cap //封顶数量 19 | ``` 20 | ### 调用方法 21 | ```javascript 22 | //返回代币名称 23 | name() public view returns (string memory) 24 | //返回代币缩写 25 | symbol() public view returns (string memory) 26 | //返回代币精度 27 | decimals() public view returns (uint8) 28 | //返回发行总量 29 | totalSupply() external view returns (uint256) 30 | //返回指定地址的余额 31 | balanceOf(address account) external view returns (uint256) 32 | //发送代币,从当前账户发送到指定地址 33 | transfer(address recipient, uint256 amount) external returns (bool) 34 | //查询owner给予spender的配额 35 | allowance(address owner, address spender) external view returns (uint256) 36 | //批准spender代表发送者使用amount数量的代币 37 | approve(address spender, uint256 amount) external returns (bool) 38 | //spender调用这个函数发送sender账户中的amount数量的代币给recipient 39 | transferFrom(address sender, address recipient, uint256 amount) external returns (bool) 40 | //增加给予spender的配额 41 | increaseAllowance(address spender, uint256 addedValue) public returns (bool) 42 | //减少给予spender的配额 43 | decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) 44 | //特殊方法 45 | //返回封顶数量 46 | cap() public view returns (uint256) 47 | //查询指定地址是否拥有铸币权 48 | isMinter(address account) public view returns (bool) 49 | //给指定地址添加铸币权,只能通过有铸币权的地址添加 50 | addMinter(address account) public onlyMinter 51 | //撤销当前发送账户的铸币权 52 | renounceMinter() public 53 | //铸币 54 | mint(address account, uint256 amount) public onlyMinter returns (bool) 55 | ``` 56 | -------------------------------------------------------------------------------- /README/ERC20/ERC20WithMintable.md: -------------------------------------------------------------------------------- 1 | # MintCoin崔棉大师的花式发币法 2 | 3 | ## 可增发代币 4 | > 可增发代币是指在发行后,拥有铸造权的账户可以增发代币.也可以增加和撤销账户的铸造权. 5 | 6 | [合约文件: ERC20WithMintable.sol](https://github.com/Fankouzu/MintCoin/blob/master/contracts/ERC20/ERC20WithMintable.sol) 7 | 8 | [测试脚本: ERC20WithMintable.js](https://github.com/Fankouzu/MintCoin/blob/master/test/ERC20/ERC20WithMintable.js) 9 | 10 | [布署脚本: 4_deploy_ERC20WithMintable.js](https://github.com/Fankouzu/MintCoin/blob/master/migrations/4_deploy_ERC20WithMintable.js) 11 | 12 | ### 在布署合约时定义以下变量 13 | ```javascript 14 | string memory name, //代币名称 15 | string memory symbol, //代币缩写 16 | uint8 decimals , //精度 17 | uint256 totalSupply //发行总量 18 | ``` 19 | ### 调用方法 20 | ```javascript 21 | //返回代币名称 22 | name() public view returns (string memory) 23 | //返回代币缩写 24 | symbol() public view returns (string memory) 25 | //返回代币精度 26 | decimals() public view returns (uint8) 27 | //返回发行总量 28 | totalSupply() external view returns (uint256) 29 | //返回指定地址的余额 30 | balanceOf(address account) external view returns (uint256) 31 | //发送代币,从当前账户发送到指定地址 32 | transfer(address recipient, uint256 amount) external returns (bool) 33 | //查询owner给予spender的配额 34 | allowance(address owner, address spender) external view returns (uint256) 35 | //批准spender代表发送者使用amount数量的代币 36 | approve(address spender, uint256 amount) external returns (bool) 37 | //spender调用这个函数发送sender账户中的amount数量的代币给recipient 38 | transferFrom(address sender, address recipient, uint256 amount) external returns (bool) 39 | //增加给予spender的配额 40 | increaseAllowance(address spender, uint256 addedValue) public returns (bool) 41 | //减少给予spender的配额 42 | decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) 43 | //特殊方法 44 | //查询指定地址是否拥有铸币权 45 | isMinter(address account) public view returns (bool) 46 | //给指定地址添加铸币权,只能通过有铸币权的地址添加 47 | addMinter(address account) public onlyMinter 48 | //撤销当前发送账户的铸币权 49 | renounceMinter() public 50 | //铸币 51 | mint(address account, uint256 amount) public onlyMinter returns (bool) 52 | ``` 53 | -------------------------------------------------------------------------------- /README/ERC20/ERC20WithPausable.md: -------------------------------------------------------------------------------- 1 | # MintCoin崔棉大师的花式发币法 2 | 3 | ## 可暂停代币 4 | > 可暂停代币是指代币发行后,可以拥有权限的账户可以将代币所有功能暂停,当你的合约发生异常情况下将会有用 5 | [合约文件: ERC20WithPausable.sol](https://github.com/Fankouzu/MintCoin/blob/master/contracts/ERC20/ERC20WithPausable.sol) 6 | 7 | [测试脚本: ERC20WithPausable.js](https://github.com/Fankouzu/MintCoin/blob/master/test/ERC20/ERC20WithPausable.js) 8 | 9 | [布署脚本: 6_deploy_ERC20WithPausable.js](https://github.com/Fankouzu/MintCoin/blob/master/migrations/6_deploy_ERC20WithPausable.js) 10 | 11 | ### 在布署合约时定义以下变量 12 | ```javascript 13 | string memory name, //代币名称 14 | string memory symbol, //代币缩写 15 | uint8 decimals , //精度 16 | uint256 totalSupply //发行总量 17 | ``` 18 | ### 调用方法 19 | ```javascript 20 | //返回代币名称 21 | name() public view returns (string memory) 22 | //返回代币缩写 23 | symbol() public view returns (string memory) 24 | //返回代币精度 25 | decimals() public view returns (uint8) 26 | //返回发行总量 27 | totalSupply() external view returns (uint256) 28 | //返回指定地址的余额 29 | balanceOf(address account) external view returns (uint256) 30 | //发送代币,从当前账户发送到指定地址 31 | transfer(address recipient, uint256 amount) external returns (bool) 32 | //查询owner给予spender的配额 33 | allowance(address owner, address spender) external view returns (uint256) 34 | //批准spender代表发送者使用amount数量的代币 35 | approve(address spender, uint256 amount) external returns (bool) 36 | //spender调用这个函数发送sender账户中的amount数量的代币给recipient 37 | transferFrom(address sender, address recipient, uint256 amount) external returns (bool) 38 | //增加给予spender的配额 39 | increaseAllowance(address spender, uint256 addedValue) public returns (bool) 40 | //减少给予spender的配额 41 | decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) 42 | //特殊方法 43 | //返回指定地址是否拥有暂停权 44 | isPauser(address account) public view returns (bool) 45 | //给指定地址添加暂停权限,只有通过有暂停权的地址添加 46 | addPauser(address account) public onlyPauser 47 | //撤销当前发送账户的暂停权 48 | renouncePauser() public 49 | //返回合约当前是否已经暂停 50 | paused() public view returns (bool) 51 | //暂停合约 52 | pause() public onlyPauser whenNotPaused 53 | //恢复合约 54 | unpause() public onlyPauser whenPaused 55 | ``` 56 | -------------------------------------------------------------------------------- /README/ERC20/IssueTokenBeforeTimelock.md: -------------------------------------------------------------------------------- 1 | # MintCoin崔棉大师的花式发币法 2 | 3 | ## 发行代币之后锁仓 4 | ### 注意 5 | > 先按照发行ERC20代币的方法布署好合约,记录下合约地址,然后执行先发行后锁仓的布署脚本. 6 | 7 | > 而在实际情况中往往不能这么做,你可以将实例化合约的代码替换成合约地址,然后通过外部调用的方法将代币转移到锁仓合约的地址上. 8 | 9 | > 为了运行本示例,布署脚本中直接实例化了刚布署的ERC20合约. 10 | 11 | [合约文件: ERC20WithTokenTimelock.sol](https://github.com/Fankouzu/MintCoin/blob/master/contracts/ERC20/ERC20WithTokenTimelock.sol) 12 | 13 | [测试脚本: ERC20WithTokenTimelock.js](https://github.com/Fankouzu/MintCoin/blob/master/test/ERC20/ERC20WithTokenTimelock.js) 14 | 15 | [布署脚本: 8_deploy_IssueTokenBeforeTimelock.js](https://github.com/Fankouzu/MintCoin/blob/master/migrations/8_deploy_IssueTokenBeforeTimelock.js) 16 | 17 | ### 在布署合约时定义以下变量 18 | ```javascript 19 | IERC20 token //ERC20代币地址 20 | address beneficiary //受益人,可以是发送者以外的另一个账户 21 | uint256 releaseTime //解锁时间戳 22 | ``` 23 | ### 调用方法(已省略ERC20调用方法) 24 | ```javascript 25 | token() public view returns (IERC20) //返回ERC20合约 26 | beneficiary() public view returns (address) //返回受益人地址 27 | releaseTime() public view returns (uint256) //返回解锁时间 28 | release() public //触发解锁,任何人都可以调用,但是只能释放给受益人 29 | ``` 30 | -------------------------------------------------------------------------------- /README/ERC20/IssueTokenWithTimelock.md: -------------------------------------------------------------------------------- 1 | # MintCoin崔棉大师的花式发币法 2 | 3 | ## 发行代币同时锁仓 4 | ### 注意 5 | > 发行可锁仓的ERC20代币需要同时布署两个合约文件,其原理是首先将一个ERC20代币合约布署好之后,再将代币合约的地址作为参数传递给第二个锁仓的合约. 6 | 7 | > 在锁仓合约布署好之后还需要调用ERC20代币合约的tracsfer方法将所有代币从发送者账户传递到锁仓合约的账户中. 8 | 9 | >以上两点已经在布署脚本中设置好了 10 | 11 | [合约文件: ERC20WithTokenTimelock.sol](https://github.com/Fankouzu/MintCoin/blob/master/contracts/ERC20/ERC20WithTokenTimelock.sol) 12 | 13 | [测试脚本: ERC20WithTokenTimelock.js](https://github.com/Fankouzu/MintCoin/blob/master/test/ERC20/ERC20WithTokenTimelock.js) 14 | 15 | [布署脚本: 7_deploy_IssueTokenWithTimelock.js](https://github.com/Fankouzu/MintCoin/blob/master/migrations/7_deploy_IssueTokenWithTimelock.js) 16 | 17 | ### 在布署合约时定义以下变量 18 | ```javascript 19 | IERC20 token //ERC20代币地址 20 | address beneficiary //受益人,可以是发送者以外的另一个账户 21 | uint256 releaseTime //解锁时间戳 22 | ``` 23 | ### 调用方法(已省略ERC20调用方法) 24 | ```javascript 25 | token() public view returns (IERC20) //返回ERC20合约 26 | beneficiary() public view returns (address) //返回受益人地址 27 | releaseTime() public view returns (uint256) //返回解锁时间 28 | release() public //触发解锁,任何人都可以调用,但是只能释放给受益人 29 | ``` 30 | -------------------------------------------------------------------------------- /README/ERC721/ERC20Full.md: -------------------------------------------------------------------------------- 1 | # MintCoin崔棉大师的花式发币法 2 | 3 | ## 全功能ERC721代币 4 | > ERC721代币属于非同质化代币,全功能的ERC721代币包含ERC721的元数据和可枚举功能. 5 | 6 | [合约文件: ERC721Full.sol](https://github.com/Fankouzu/MintCoin/blob/master/contracts/ERC721/ERC721Full.sol) 7 | 8 | [测试脚本: ERC721Full.js](https://github.com/Fankouzu/MintCoin/blob/master/test/ERC721/ERC721Full.js) 9 | 10 | [布署脚本: 21_deploy_ERC721Full.js](https://github.com/Fankouzu/MintCoin/blob/master/migrations/21_deploy_ERC721Full.js) 11 | 12 | ### 在布署合约时定义以下变量 13 | ```javascript 14 | string memory name, //代币名称 15 | string memory symbol, //代币缩写 16 | string memory baseURI, //代币基础链接 17 | ``` 18 | ### 调用方法 19 | ```javascript 20 | //返回代币名称 21 | name() public view returns (string memory) 22 | //返回代币缩写 23 | symbol() public view returns (string memory) 24 | //token的基础链接地址 25 | baseURI() external view returns (string memory) 26 | //添加代币方法,传入所有者地址和Token的数据链接地址 27 | awardItem(address player, string memory tokenURI) public returns (uint256) 28 | //根据tokenid返回数据连接地址 29 | tokenURI(uint256 tokenId) external view returns (string memory) 30 | //返回指定账户拥有的代币数量 31 | balanceOf(address owner) public view returns (uint256) 32 | //根据tokenid返回拥有者 33 | ownerOf(uint256 tokenId) public view returns (address) 34 | //批准代币 35 | approve(address to, uint256 tokenId) public 36 | //获取令牌ID的批准地址;如果未设置地址或tokenID不存在,则返回零;。 37 | getApproved(uint256 tokenId) public view returns (address) 38 | //将拥有者的所有代币批准给指定地址 39 | setApprovalForAll(address to, bool approved) public 40 | //获取操作者是否将代币全部批准给指定地址 41 | isApprovedForAll(address owner, address operator) public view returns (bool) 42 | //发送批准 43 | transferFrom(address from, address to, uint256 tokenId) public 44 | //安全发送批准 45 | safeTransferFrom(address from, address to, uint256 tokenId) public 46 | //获取请求的所有者的令牌列表的给定索引处的令牌ID 47 | tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256) 48 | //获取合约的代币总量 49 | totalSupply() public view returns (uint256) 50 | //通过索引获取代币 51 | tokenByIndex(uint256 index) public view returns (uint256) 52 | ``` 53 | -------------------------------------------------------------------------------- /README/ERC721/ERC721Burnable.md: -------------------------------------------------------------------------------- 1 | # MintCoin崔棉大师的花式发币法 2 | 3 | ## 可销毁的ERC721代币 4 | > ERC721代币属于非同质化代币,全功能的ERC721代币包含ERC721的元数据和可枚举功能. 5 | > 可销毁的ERC721代币是指在全功能的ERC721代币基础上增加了销毁的逻辑,账户只能销毁自己持有的代币. 6 | 7 | [合约文件: ERC721Burnable.sol](https://github.com/Fankouzu/MintCoin/blob/master/contracts/ERC721/ERC721Burnable.sol) 8 | 9 | [测试脚本: ERC721Burnable.js](https://github.com/Fankouzu/MintCoin/blob/master/test/ERC721/ERC721Burnable.js) 10 | 11 | [布署脚本: 23_deploy_ERC721Burnable.js](https://github.com/Fankouzu/MintCoin/blob/master/migrations/23_deploy_ERC721Burnable.js) 12 | 13 | ### 在布署合约时定义以下变量 14 | ```javascript 15 | string memory name, //代币名称 16 | string memory symbol, //代币缩写 17 | string memory baseURI, //代币基础链接 18 | ``` 19 | ### 调用方法 20 | ```javascript 21 | //返回代币名称 22 | name() public view returns (string memory) 23 | //返回代币缩写 24 | symbol() public view returns (string memory) 25 | //token的基础链接地址 26 | baseURI() external view returns (string memory) 27 | //添加代币方法,传入所有者地址和Token的数据链接地址 28 | awardItem(address player, string memory tokenURI) public returns (uint256) 29 | //根据tokenid返回数据连接地址 30 | tokenURI(uint256 tokenId) external view returns (string memory) 31 | //返回指定账户拥有的代币数量 32 | balanceOf(address owner) public view returns (uint256) 33 | //根据tokenid返回拥有者 34 | ownerOf(uint256 tokenId) public view returns (address) 35 | //批准代币 36 | approve(address to, uint256 tokenId) public 37 | //获取令牌ID的批准地址;如果未设置地址或tokenID不存在,则返回零;。 38 | getApproved(uint256 tokenId) public view returns (address) 39 | //将拥有者的所有代币批准给指定地址 40 | setApprovalForAll(address to, bool approved) public 41 | //获取操作者是否将代币全部批准给指定地址 42 | isApprovedForAll(address owner, address operator) public view returns (bool) 43 | //发送批准 44 | transferFrom(address from, address to, uint256 tokenId) public 45 | //安全发送批准 46 | safeTransferFrom(address from, address to, uint256 tokenId) public 47 | //获取请求的所有者的令牌列表的给定索引处的令牌ID 48 | tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256) 49 | //获取合约的代币总量 50 | totalSupply() public view returns (uint256) 51 | //通过索引获取代币 52 | tokenByIndex(uint256 index) public view returns (uint256) 53 | //销毁代币方法 54 | burn(uint256 tokenId) public 55 | ``` 56 | -------------------------------------------------------------------------------- /README/ERC721/ERC721Mintable.md: -------------------------------------------------------------------------------- 1 | # MintCoin崔棉大师的花式发币法 2 | 3 | ## 可铸造ERC721代币 4 | > ERC721代币属于非同质化代币,全功能的ERC721代币包含ERC721的元数据和可枚举功能. 5 | > 可铸造的ERC721代币拥有一个公开的铸造方法,只有铸造管理员可以调用. 6 | 7 | [合约文件: ERC721Mintable.sol](https://github.com/Fankouzu/MintCoin/blob/master/contracts/ERC721/ERC721Mintable.sol) 8 | 9 | [测试脚本: ERC721Mintable.js](https://github.com/Fankouzu/MintCoin/blob/master/test/ERC721/ERC721Mintable.js) 10 | 11 | [布署脚本: 22_deploy_ERC721Mintable.js](https://github.com/Fankouzu/MintCoin/blob/master/migrations/22_deploy_ERC721Mintable.js) 12 | 13 | ### 在布署合约时定义以下变量 14 | ```javascript 15 | string memory name, //代币名称 16 | string memory symbol, //代币缩写 17 | string memory baseURI, //代币基础链接 18 | ``` 19 | ### 调用方法 20 | ```javascript 21 | //返回代币名称 22 | name() public view returns (string memory) 23 | //返回代币缩写 24 | symbol() public view returns (string memory) 25 | //token的基础链接地址 26 | baseURI() external view returns (string memory) 27 | //根据tokenid返回数据连接地址 28 | tokenURI(uint256 tokenId) external view returns (string memory) 29 | //返回指定账户拥有的代币数量 30 | balanceOf(address owner) public view returns (uint256) 31 | //根据tokenid返回拥有者 32 | ownerOf(uint256 tokenId) public view returns (address) 33 | //批准代币 34 | approve(address to, uint256 tokenId) public 35 | //获取令牌ID的批准地址;如果未设置地址或tokenID不存在,则返回零;。 36 | getApproved(uint256 tokenId) public view returns (address) 37 | //将拥有者的所有代币批准给指定地址 38 | setApprovalForAll(address to, bool approved) public 39 | //获取操作者是否将代币全部批准给指定地址 40 | isApprovedForAll(address owner, address operator) public view returns (bool) 41 | //发送批准 42 | transferFrom(address from, address to, uint256 tokenId) public 43 | //安全发送批准 44 | safeTransferFrom(address from, address to, uint256 tokenId) public 45 | //获取请求的所有者的令牌列表的给定索引处的令牌ID 46 | tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256) 47 | //获取合约的代币总量 48 | totalSupply() public view returns (uint256) 49 | //通过索引获取代币 50 | tokenByIndex(uint256 index) public view returns (uint256) 51 | //铸币方法 52 | mint(address to, uint256 tokenId) public onlyMinter returns (bool) 53 | //安全铸币方法 54 | safeMint(address to, uint256 tokenId) public onlyMinter returns (bool) 55 | //带URI铸币方法 56 | mintWithTokenURI(address to, uint256 tokenId, string memory tokenURI) public onlyMinter returns (bool) 57 | //查询指定地址是否拥有铸币权 58 | isMinter(address account) public view returns (bool) 59 | //给指定地址添加铸币权,只能通过有铸币权的地址添加 60 | addMinter(address account) public onlyMinter 61 | //撤销当前发送账户的铸币权 62 | renounceMinter() public 63 | ``` 64 | -------------------------------------------------------------------------------- /README/ERC721/ERC721Pausable.md: -------------------------------------------------------------------------------- 1 | # MintCoin崔棉大师的花式发币法 2 | 3 | ## 可暂停的ERC721代币 4 | > ERC721代币属于非同质化代币,全功能的ERC721代币包含ERC721的元数据和可枚举功能. 5 | 6 | [合约文件: ERC721Pausable.sol](https://github.com/Fankouzu/MintCoin/blob/master/contracts/ERC721/ERC721Pausable.sol) 7 | 8 | [测试脚本: ERC721Pausable.js](https://github.com/Fankouzu/MintCoin/blob/master/test/ERC721/ERC721Pausable.js) 9 | 10 | [布署脚本: 24_deploy_ERC721Pausable.js](https://github.com/Fankouzu/MintCoin/blob/master/migrations/24_deploy_ERC721Pausable.js) 11 | 12 | ### 在布署合约时定义以下变量 13 | ```javascript 14 | string memory name, //代币名称 15 | string memory symbol, //代币缩写 16 | string memory baseURI, //代币基础链接 17 | ``` 18 | ### 调用方法 19 | ```javascript 20 | //返回代币名称 21 | name() public view returns (string memory) 22 | //返回代币缩写 23 | symbol() public view returns (string memory) 24 | //token的基础链接地址 25 | baseURI() external view returns (string memory) 26 | //添加代币方法,传入所有者地址和Token的数据链接地址 27 | awardItem(address player, string memory tokenURI) public whenNotPaused() returns (uint256) 28 | //根据tokenid返回数据连接地址 29 | tokenURI(uint256 tokenId) external view returns (string memory) 30 | //返回指定账户拥有的代币数量 31 | balanceOf(address owner) public view returns (uint256) 32 | //根据tokenid返回拥有者 33 | ownerOf(uint256 tokenId) public view returns (address) 34 | //批准代币 35 | approve(address to, uint256 tokenId) public 36 | //获取令牌ID的批准地址;如果未设置地址或tokenID不存在,则返回零;。 37 | getApproved(uint256 tokenId) public view returns (address) 38 | //将拥有者的所有代币批准给指定地址 39 | setApprovalForAll(address to, bool approved) public 40 | //获取操作者是否将代币全部批准给指定地址 41 | isApprovedForAll(address owner, address operator) public view returns (bool) 42 | //发送批准 43 | transferFrom(address from, address to, uint256 tokenId) public 44 | //安全发送批准 45 | safeTransferFrom(address from, address to, uint256 tokenId) public 46 | //获取请求的所有者的令牌列表的给定索引处的令牌ID 47 | tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256) 48 | //获取合约的代币总量 49 | totalSupply() public view returns (uint256) 50 | //通过索引获取代币 51 | tokenByIndex(uint256 index) public view returns (uint256) 52 | //返回指定地址是否拥有暂停权 53 | isPauser(address account) public view returns (bool) 54 | //给指定地址添加暂停权限,只有通过有暂停权的地址添加 55 | addPauser(address account) public onlyPauser 56 | //撤销当前发送账户的暂停权 57 | renouncePauser() public 58 | //返回合约当前是否已经暂停 59 | paused() public view returns (bool) 60 | //暂停合约 61 | pause() public onlyPauser whenNotPaused 62 | //恢复合约 63 | unpause() public onlyPauser whenPaused 64 | ``` 65 | -------------------------------------------------------------------------------- /README/ERC777/ERC777Contract.md: -------------------------------------------------------------------------------- 1 | # MintCoin崔棉大师的花式发币法 2 | 3 | ## ERC777代币 4 | 5 | ### 介绍 6 | ERC777像ERC20一样,ERC777是可替代令牌的标准,并且专注于在交易令牌时允许更复杂的交互。该标准还带来了多种改进,例如消除了容易引起歧义的decimals,其杀手级功能是发送和接收的钩子。钩子方法是合约中的一个功能,当向其发送和接收代币时会被调用,这意味着账户和合约可以对发送和接收代币做出反应。 7 | ### 文件 8 | [合约文件: ERC777Contract.sol](https://github.com/Fankouzu/MintCoin/blob/master/contracts/ERC777/ERC777Contract.sol) 9 | 10 | [发送接口合约: TokensSender.sol](https://github.com/Fankouzu/MintCoin/blob/master/contracts/ERC777/TokensSender.sol) 11 | 12 | [接收接口合约: TokensRecipient.sol](https://github.com/Fankouzu/MintCoin/blob/master/contracts/ERC777/TokensRecipient.sol) 13 | 14 | [测试脚本: ERC777Contract.js](https://github.com/Fankouzu/MintCoin/blob/master/test/ERC777/ERC777Contract.js) 15 | 16 | [布署脚本: 29_deploy_ERC777Contract.js](https://github.com/Fankouzu/MintCoin/blob/master/migrations/29_deploy_ERC777Contract.js) 17 | ### 布署 18 | #### ERC777合约 19 | 在布署合约时定义以下变量 20 | ```javascript 21 | string memory name, //代币名称 22 | string memory symbol, //代币缩写 23 | uint256 initialSupply, //发行总量 24 | address[] memory defaultOperators //默认操作员数组 25 | ``` 26 | #### 发送接口合约 27 | 在调用ERC777合约的发送方法(transfer,send,burn,operatorSend,operatorBurn)时,合约都会到ERC1820注册表查询发送者的发送接口地址,如果发送者注册了发送接口合约地址,发送接口合约中的tokensToSend()方法就会被调用.以下就是发送接口合约的布署和注册方法. 28 | 在布署合约时定义以下变量 29 | ```javascript 30 | bool _setInterface //是否为合约自身注册接口 31 | ``` 32 | 在布署合约之后注册接口 33 | ```javascript 34 | await ERC1820Registry.setInterfaceImplementer( 35 | senderAddress,//发送代币的账户地址 36 | web3.utils.keccak256("ERC777TokensSender"),//ERC777TokensSender接口的keccak256哈希值 37 | TokensSender.address,//发送接口合约的地址 38 | ); 39 | ``` 40 | #### 接收接口合约 41 | 在调用ERC777合约的发送方法(transfer,send,burn,operatorSend,operatorBurn)时,合约都会到ERC1820注册表查询接收者的接收接口地址,如果接收者注册了接收接口合约地址,接收接口合约中的tokensReceived()方法就会被调用.以下就是接收接口合约的布署和注册方法. 42 | 在布署合约时定义以下变量 43 | ```javascript 44 | bool _setInterface //是否为合约自身注册接口 45 | ``` 46 | 在布署合约之后注册接口 47 | ```javascript 48 | await ERC1820Registry.setInterfaceImplementer( 49 | receiverAddress,//发送代币的账户地址 50 | web3.utils.keccak256("ERC777TokensRecipient"),//ERC777TokensRecipient接口的keccak256哈希值 51 | TokensRecipient.address,//接收接口合约的地址 52 | ); 53 | ``` 54 | ### ERC777调用方法 55 | #### 兼容ERC20的方法 56 | 57 | ```javascript 58 | //返回代币名称 59 | name() public view returns (string memory) 60 | //返回代币缩写 61 | symbol() public view returns (string memory) 62 | //返回代币精度 63 | decimals() public view returns (uint8) 64 | //返回发行总量 65 | totalSupply() external view returns (uint256) 66 | //返回指定地址的余额 67 | balanceOf(address account) external view returns (uint256) 68 | //发送代币,从当前账户发送到指定地址 69 | transfer(address recipient, uint256 amount) external returns (bool) 70 | //查询owner给予spender的配额 71 | allowance(address owner, address spender) external view returns (uint256) 72 | //批准spender代表发送者使用amount数量的代币 73 | approve(address spender, uint256 amount) external returns (bool) 74 | //spender调用这个函数发送sender账户中的amount数量的代币给recipient 75 | transferFrom(address sender, address recipient, uint256 amount) external returns (bool) 76 | //调用此方法可以从调用者账户中销毁代币 77 | burn(uint256 amount) public 78 | ``` 79 | #### ERC777新增方法 80 | ```javascript 81 | //返回代币的最小单位 82 | granularity() public view returns (uint256) 83 | //代替transfer的发送方法 84 | send(address recipient, uint256 amount, bytes memory data) public 85 | //验证指定地址的操作员地址 86 | isOperatorFor(address operator,address tokenHolder) public view returns (bool) 87 | //为当前账户设置操作员 88 | authorizeOperator(address operator) public 89 | //为当前账户撤销操作员 90 | revokeOperator(address operator) public 91 | //返回默认操作员数组 92 | defaultOperators() public view returns (address[] memory) 93 | //操作员发送方法 94 | operatorSend(address sender,address recipient,uint256 amount,bytes memory data,bytes memory operatorData) 95 | //操作员销毁方法 96 | operatorBurn(address account, uint256 amount, bytes memory data, bytes memory operatorData) public 97 | ``` 98 | #### 发送接口合约 99 | ```javascript 100 | //ERC777代币发送时通过ERC1820注册表查找到发送接口合约之后,调用这个接口 101 | tokensToSend(address _operator,address _from,address _to,uint _amount,bytes calldata _data,bytes calldata _operatorData)external 102 | //接受代币发送方法 103 | acceptTokensToSend() public onlyOwner 104 | //拒绝代币发送方法 105 | rejectTokensToSend() public onlyOwner 106 | ``` 107 | #### 接收接口合约 108 | ```javascript 109 | //ERC777代币发送时通过ERC1820注册表查找到接收接口合约之后,调用这个接口 110 | tokensReceived(address _operator,address _from,address _to,uint _amount,bytes calldata _data,bytes calldata _operatorData)external 111 | //接受接收代币方法 112 | acceptTokens() public onlyOwner 113 | //拒绝接收代币方法 114 | rejectTokens() public onlyOwner 115 | ``` -------------------------------------------------------------------------------- /README/Multi/CrowdsalePaymentSplitter.md: -------------------------------------------------------------------------------- 1 | # MintCoin崔棉大师的花式发币法 2 | 3 | ## 股份制受益人合约 4 | > 股份制受益人合约是指在众筹合约的基础上,将众筹受益人地址设置为股份制受益人的合约地址,这样当众筹获得收益后,ETH会被保存到股份制受益人合约.当合约设置的股东想要取回收益时,可以从股份制受益人合约按照布署时设定的股份比例取回收益. 5 | 6 | > 股东和股份比例在布署合约时设定,后期不能更改. 7 | 8 | [合约文件: CrowdsalePaymentSplitter.sol](https://github.com/Fankouzu/MintCoin/blob/master/contracts/Multi/CrowdsalePaymentSplitter.sol) 9 | 10 | [测试脚本: CrowdsalePaymentSplitter.js](https://github.com/Fankouzu/MintCoin/blob/master/test/Multi/CrowdsalePaymentSplitter.js) 11 | 12 | [布署脚本: 27_deploy_CrowdsalePaymentSplitter.js](https://github.com/Fankouzu/MintCoin/blob/master/migrations/27_deploy_CrowdsalePaymentSplitter.js) 13 | 14 | ### 在布署合约时定义以下变量 15 | ```javascript 16 | address[] memory payees, //股东数组 17 | uint256[] memory shares //股份比例 18 | ``` 19 | ### 调用方法 20 | ```javascript 21 | //返回股份比例的总和 22 | totalShares() public view returns (uint256) 23 | //返回总共释放的数额 24 | totalReleased() public view returns (uint256) 25 | //返回指定账户的股份数额 26 | shares(address account) public view returns (uint256) 27 | //释放指定账户已释放的数额 28 | released(address account) public view returns (uint256) 29 | //返回股东账户地址 30 | payee(uint256 index) public view returns (address) 31 | //释放方法 32 | release(address payable account) public 33 | ``` 34 | -------------------------------------------------------------------------------- /README/Multi/ERC20Migrator.md: -------------------------------------------------------------------------------- 1 | # MintCoin崔棉大师的花式发币法 2 | 3 | ## 代币迁移合约 4 | > 代币迁移合约是指在一个ERC20合约布署好之后,因为某种原因,需要放弃原有合约.每个ERC20代币持有者都必须选择参加迁移。要选择加入,用户必须为此合同批准他们要迁移的ERC20代币数量。设置批准后,任何人都可以触发向新代币合同的迁移。这样,代币持有者“上交”他们的旧余额,并将在新ERC20代币中铸造等量的ERC20代币。新的ERC20代币合约必须是可铸造的。旧ERC20代币的余额将遗留在迁移合约中,并永远的遗留在这里. 5 | 6 | 7 | [合约文件: ERC20Migrator.sol](https://github.com/Fankouzu/MintCoin/blob/master/contracts/Multi/ERC20Migrator.sol) 8 | 9 | [测试脚本: ERC20Migrator.js](https://github.com/Fankouzu/MintCoin/blob/master/test/Multi/ERC20Migrator.js) 10 | 11 | [布署脚本: 25_deploy_ERC20Migrator.js](https://github.com/Fankouzu/MintCoin/blob/master/migrations/25_deploy_ERC20Migrator.js) 12 | 13 | ### 在布署合约时定义以下变量 14 | ```javascript 15 | IERC20 legacyToken, //旧ERC20合约地址 16 | ``` 17 | ### 布署合约之后执行 18 | ```javascript 19 | //在布署之后所有旧合约的用户必须将账户中的代币批准给迁移合约 20 | token.approve(migrator.address, ALL_TOKEN_AMOUNT); 21 | //给新代币添加迁移合约的铸造权 22 | newTokentoken.addMinter(migrator.address); 23 | //撤销当前账户的铸造权 24 | newTokentoken.renounceMinter(); 25 | //设置新代币合约地址并开始迁移 26 | migrator.beginMigration(newToken.address); 27 | ``` 28 | ### 调用方法 29 | ```javascript 30 | //返回旧合约地址 31 | legacyToken() public view returns (IERC20) 32 | //返回新合约地址 33 | newToken() public view returns (IERC20) 34 | //设置新代币合约地址并开始迁移 35 | beginMigration(ERC20Mintable newToken_) public 36 | //迁移指定账户的指定数量代币到新合约 37 | migrate(address account, uint256 amount) public 38 | //迁移指定账户的所有代币到新合约 39 | migrateAll(address account) public 40 | ``` 41 | -------------------------------------------------------------------------------- /README/Multi/ERC20MultiFunction.md: -------------------------------------------------------------------------------- 1 | # MintCoin崔棉大师的花式发币法 2 | 3 | ## 多功能ERC20代币,可增发,可销毁,可暂停,有封顶 4 | 5 | 6 | [合约文件: ERC20MultiFunction.sol](https://github.com/Fankouzu/MintCoin/blob/master/contracts/Multi/ERC20FixedSupply.sol) 7 | 8 | [测试脚本: ERC20MultiFunction.js](https://github.com/Fankouzu/MintCoin/blob/master/test/Multi/ERC20FixedSupply.js) 9 | 10 | [布署脚本: 19_deploy_ERC20MultiFunction.js](https://github.com/Fankouzu/MintCoin/blob/master/migrations/19_deploy_ERC20MultiFunction.js) 11 | 12 | ### 在布署合约时定义以下变量 13 | ```javascript 14 | string memory name, //代币名称 15 | string memory symbol, //代币缩写 16 | uint8 decimals, //精度 17 | uint256 totalSupply, //发行总量 18 | uint256 cap //封顶数量 19 | ``` 20 | ### 调用方法 21 | ```javascript 22 | //返回代币名称 23 | name() public view returns (string memory) 24 | //返回代币缩写 25 | symbol() public view returns (string memory) 26 | //返回代币精度 27 | decimals() public view returns (uint8) 28 | //返回发行总量 29 | totalSupply() external view returns (uint256) 30 | //返回指定地址的余额 31 | balanceOf(address account) external view returns (uint256) 32 | //发送代币,从当前账户发送到指定地址 33 | transfer(address recipient, uint256 amount) external returns (bool) 34 | //查询owner给予spender的配额 35 | allowance(address owner, address spender) external view returns (uint256) 36 | //批准spender代表发送者使用amount数量的代币 37 | approve(address spender, uint256 amount) external returns (bool) 38 | //spender调用这个函数发送sender账户中的amount数量的代币给recipient 39 | transferFrom(address sender, address recipient, uint256 amount) external returns (bool) 40 | //增加给予spender的配额 41 | increaseAllowance(address spender, uint256 addedValue) public returns (bool) 42 | //减少给予spender的配额 43 | decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) 44 | //查询指定地址是否拥有铸币权 45 | isMinter(address account) public view returns (bool) 46 | //给指定地址添加铸币权,只能通过有铸币权的地址添加 47 | addMinter(address account) public onlyMinter 48 | //撤销当前发送账户的铸币权 49 | renounceMinter() public 50 | //铸币 51 | mint(address account, uint256 amount) public onlyMinter returns (bool) 52 | //调用此方法可以从调用者账户中销毁代币 53 | burn(uint256 amount) public 54 | //调用此方法可以从指定地址销毁代币,代币从发送者的批准中扣除 55 | burnFrom(address account, uint256 amount) public 56 | //返回指定地址是否拥有暂停权 57 | isPauser(address account) public view returns (bool) 58 | //给指定地址添加暂停权限,只有通过有暂停权的地址添加 59 | addPauser(address account) public onlyPauser 60 | //撤销当前发送账户的暂停权 61 | renouncePauser() public 62 | //返回合约当前是否已经暂停 63 | paused() public view returns (bool) 64 | //暂停合约 65 | pause() public onlyPauser whenNotPaused 66 | //恢复合约 67 | unpause() public onlyPauser whenPaused 68 | //返回封顶数量 69 | cap() public view returns (uint256) 70 | ``` 71 | -------------------------------------------------------------------------------- /README/Multi/ERC20WithSnapshot.md: -------------------------------------------------------------------------------- 1 | # MintCoin崔棉大师的花式发币法 2 | 3 | ## 可快照的ERC20代币 4 | > 可快照的ERC20代币使用快照机制扩展了ERC20代币。创建快照后,将记录当时的余额和总供应量,以供以后访问。 5 | 6 | > 快照由内部Snapshot函数创建,该内部函数将发出Snapshot事件并返回快照ID.要获取快照时的总供应量,请totalSupplyAt使用快照ID 调用该函数.要在快照时获取帐户余额,请balanceOfAt使用快照ID和帐户地址调用该函数. 7 | 8 | 9 | [合约文件: ERC20WithSnapshot.sol](https://github.com/Fankouzu/MintCoin/blob/master/contracts/Multi/ERC20WithSnapshot.sol) 10 | 11 | [测试脚本: ERC20WithSnapshot.js](https://github.com/Fankouzu/MintCoin/blob/master/test/Multi/ERC20WithSnapshot.js) 12 | 13 | [布署脚本: 26_deploy_ERC20WithSnapshot.js](https://github.com/Fankouzu/MintCoin/blob/master/migrations/26_deploy_ERC20WithSnapshot.js) 14 | 15 | ### 在布署合约时定义以下变量 16 | ```javascript 17 | string memory name, //代币名称 18 | string memory symbol, //代币缩写 19 | uint8 decimals, //精度 20 | uint256 totalSupply //发行总量 21 | ``` 22 | ### 调用方法 23 | ```javascript 24 | //返回代币名称 25 | name() public view returns (string memory) 26 | //返回代币缩写 27 | symbol() public view returns (string memory) 28 | //返回代币精度 29 | decimals() public view returns (uint8) 30 | //返回发行总量 31 | totalSupply() external view returns (uint256) 32 | //返回指定地址的余额 33 | balanceOf(address account) external view returns (uint256) 34 | //发送代币,从当前账户发送到指定地址 35 | transfer(address recipient, uint256 amount) external returns (bool) 36 | //查询owner给予spender的配额 37 | allowance(address owner, address spender) external view returns (uint256) 38 | //批准spender代表发送者使用amount数量的代币 39 | approve(address spender, uint256 amount) external returns (bool) 40 | //spender调用这个函数发送sender账户中的amount数量的代币给recipient 41 | transferFrom(address sender, address recipient, uint256 amount) external returns (bool) 42 | //增加给予spender的配额 43 | increaseAllowance(address spender, uint256 addedValue) public returns (bool) 44 | //减少给予spender的配额 45 | decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) 46 | //快照合约的特殊方法 47 | //创建快照 48 | snapshot() public returns (uint256) 49 | //根据快照ID查询指定地址的余额 50 | balanceOfAt(address account, uint256 snapshotId) public view returns (uint256) 51 | //根据快照ID查询发行总量 52 | totalSupplyAt(uint256 snapshotId) public view returns(uint256) 53 | // 54 | ``` 55 | -------------------------------------------------------------------------------- /README/Multi/ERC20WithTokenVesting.md: -------------------------------------------------------------------------------- 1 | # MintCoin崔棉大师的花式发币法 2 | 3 | ## 分期释放合约 4 | > 分期释放合约类似于锁仓合约,区别是被锁定的ERC20代币将按照合约布署时规定的时间周期逐步释放给受益人. 5 | > 释放周期的计算方法为:在`start`开始时间之后计算,以秒为单位,直到`cliffDuration`断崖时间之后可以释放,在`duration`持续时间到达之后结束. 6 | > 例如:锁仓4年,1年之后开始释放,这样就是start=now();cliffDuration=1 year;duration=4 year; 7 | > 在`cliffDuration`之后的任何时间都可以调用释放方法,释放数额的计算方法为: 锁仓总数额 * ((当前时间 - 开始时间) / 持续时间) - 已释放数 8 | 9 | 10 | [合约文件: ERC20WithTokenVesting.sol](https://github.com/Fankouzu/MintCoin/blob/master/contracts/Multi/ERC20WithTokenVesting.sol) 11 | 12 | [测试脚本: ERC20WithTokenVesting.js](https://github.com/Fankouzu/MintCoin/blob/master/test/Multi/ERC20WithTokenVesting.js) 13 | 14 | [布署脚本: 28_deploy_ERC20WithTokenVesting.js](https://github.com/Fankouzu/MintCoin/blob/master/migrations/28_deploy_ERC20WithTokenVesting.js) 15 | 16 | ### 在布署合约时定义以下变量 17 | ```javascript 18 | address beneficiary, //受益人 19 | uint256 start, //开始时间 20 | uint256 cliffDuration, //断崖时间 21 | uint256 duration, //持续时间 22 | bool revocable //是否可撤销 23 | ``` 24 | ### 布署合约之后执行 25 | ```javascript 26 | //在布署之后所有旧合约的用户必须将账户中的代币批准给迁移合约 27 | token.transfer(ERC20WithTokenVesting.address, SOME_TOKEN_AMOUNT); 28 | ``` 29 | ### 调用方法 30 | ```javascript 31 | //返回受益人地址 32 | beneficiary() public view returns (address) 33 | //返回开始时间 34 | start() public view returns (uint256) 35 | //返回断崖时间 36 | cliff() public view returns (uint256) 37 | //返回持续时间 38 | duration() public view returns (uint256) 39 | //返回能否撤销 40 | revocable() public view returns (bool) 41 | //返回已经释放数量 42 | released(address token) public view returns (uint256) 43 | //返回是否撤销 44 | revoked(address token) public view returns (bool) 45 | //释放方法 46 | release(IERC20 token) public 47 | //撤销方法 48 | revoke(IERC20 token) public onlyOwner 49 | ``` 50 | -------------------------------------------------------------------------------- /README/Multi/MultiFunctionCrowdsale.md: -------------------------------------------------------------------------------- 1 | # MintCoin崔棉大师的花式发币法 2 | 3 | ## 多功能众筹合约:可增发,可销毁,有封顶,有配额,可暂停,有时限,白名单,成功后交付,不成功退款 4 | 5 | [合约文件: MultiFunctionCrowdsale.sol](https://github.com/Fankouzu/MintCoin/blob/master/contracts/Multi/MultiFunctionCrowdsale.sol) 6 | 7 | [测试脚本: MultiFunctionCrowdsale.js](https://github.com/Fankouzu/MintCoin/blob/master/test/Multi/MultiFunctionCrowdsale.js) 8 | 9 | [布署脚本: 20_deploy_MultiFunctionCrowdsale.js](https://github.com/Fankouzu/MintCoin/blob/master/migrations/20_deploy_MultiFunctionCrowdsale.js) 10 | 11 | ### 在布署合约时定义以下变量 12 | ```javascript 13 | uint256 rate //兑换比例1ETH兑换多少ERC20代币 14 | address payable wallet //接收ETH受益人地址 15 | IERC20 token //代币地址 16 | address tokenWallet //代币从这个地址发送 17 | uint256 openingTime // 众筹开始时间 18 | uint256 closingTime // 众筹结束时间 19 | uint256 goal // 众筹目标 20 | uint256 cap // 封顶数量,单位是wei 21 | ``` 22 | ### 在布署众筹合约之后需要执行ERC20的方法 23 | ```javascript 24 | //在布署之后必须将发送者账户中的代币批准给众筹合约 25 | token.approve(crowdsale.address, SOME_TOKEN_AMOUNT); 26 | //添加众筹合约的铸造权 27 | token.addMinter(crowdsale.address); 28 | //撤销当前账户的铸造权 29 | token.renounceMinter(); 30 | ``` 31 | ### 调用方法 32 | ```javascript 33 | //返回代币地址 34 | token() public view returns (IERC20) 35 | //返回受益人地址 36 | wallet() public view returns (address payable) 37 | //返回兑换比例 38 | rate() public view returns (uint256) 39 | //返回销售额 40 | weiRaised() public view returns (uint256) 41 | //购买代币,代币发送给指定地址 42 | buyTokens(address beneficiary) public nonReentrant payable 43 | //特殊方法 44 | //返回代币现存地址 45 | tokenWallet() public view returns (address) 46 | //检查配额中剩余的代币数量 47 | remainingTokens() public view returns (uint256) 48 | //调用此方法可以从调用者账户中销毁代币 49 | burn(uint256 amount) public 50 | //调用此方法可以从指定地址销毁代币,代币从发送者的批准中扣除 51 | burnFrom(address account, uint256 amount) public 52 | //返回封顶数量 53 | cap() public view returns (uint256) 54 | //设置指定账户的封顶数量,单位是wei 55 | setCap(address beneficiary, uint256 cap) external onlyCapper 56 | //获取指定账户的封顶配额 57 | getCap(address beneficiary) public view returns (uint256) 58 | //获取指定账户提供的ETH数量 59 | getContribution(address beneficiary) public view returns (uint256) 60 | //返回指定账户是否拥有设置配额的权限 61 | isCapper(address account) public view returns (bool) 62 | //给指定账户添加设置配额的权限 63 | addCapper(address account) public onlyCapper 64 | //撤销当前账户的设置配额权限 65 | renounceCapper() public 66 | //返回指定地址是否拥有暂停权 67 | isPauser(address account) public view returns (bool) 68 | //给指定地址添加暂停权限,只有通过有暂停权的地址添加 69 | addPauser(address account) public onlyPauser 70 | //撤销当前发送账户的暂停权 71 | renouncePauser() public 72 | //返回合约当前是否已经暂停 73 | paused() public view returns (bool) 74 | //暂停合约 75 | pause() public onlyPauser whenNotPaused 76 | //恢复合约 77 | unpause() public onlyPauser whenPaused 78 | //返回众筹开始时间 79 | openingTime() public view returns (uint256) 80 | //返回众筹结束时间 81 | closingTime() public view returns (uint256) 82 | //返回众筹是否开始 83 | isOpen() public view returns (bool) 84 | //返回众筹是否结束 85 | hasClosed() public view returns (bool) 86 | //返回指定账户是否在白名单 87 | isWhitelisted(address account) public view returns (bool) 88 | //添加指定账户到白名单 89 | addWhitelisted(address account) public onlyWhitelistAdmin 90 | //从白名单移除指定账户 91 | removeWhitelisted(address account) public onlyWhitelistAdmin 92 | //从白名单撤销自己的账户 93 | renounceWhitelisted() public 94 | //返回指定账户是否是白名单管理员 95 | isWhitelistAdmin(address account) public view returns (bool) 96 | //添加指定账户到白名单管理员 97 | addWhitelistAdmin(address account) public onlyWhitelistAdmin 98 | //从白名单管理员撤销自己的账户 99 | renounceWhitelistAdmin() public 100 | //返回合约是否已经结束 101 | finalized() public view returns (bool) 102 | //触发合约结束方法 103 | finalize() public 104 | //返回存储在合约上的ERC20数量 105 | balanceOf(address account) public view returns (uint256) 106 | //当众筹结束后,并且到达了众筹目标,触发可以提取ERC20 107 | withdrawTokens(address beneficiary) public 108 | //返回众筹目标,ETH的数量 109 | goal() public view returns (uint256) 110 | //当众筹结束后,并且没有达到目标时,触发这个方法可以给购买者退款 111 | claimRefund(address payable refundee) public 112 | //返回众筹目标是否到达 113 | goalReached() public view returns (bool) 114 | ``` 115 | -------------------------------------------------------------------------------- /contracts/Crowdsale/AllowanceCrowdsale.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "@openzeppelin/contracts/crowdsale/Crowdsale.sol"; 4 | import "@openzeppelin/contracts/crowdsale/emission/AllowanceCrowdsale.sol"; 5 | 6 | //普通的众筹 7 | contract AllowanceCrowdsaleContract is Crowdsale, AllowanceCrowdsale { 8 | constructor( 9 | uint256 rate, // 兑换比例 10 | address payable wallet, // 接收ETH受益人地址 11 | IERC20 token, // 代币地址 12 | address tokenWallet // 代币从这个地址发送 13 | ) 14 | AllowanceCrowdsale(tokenWallet) 15 | Crowdsale(rate, wallet, token) 16 | public 17 | { 18 | 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /contracts/Crowdsale/CappedCrowdsale.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "@openzeppelin/contracts/crowdsale/Crowdsale.sol"; 4 | import "@openzeppelin/contracts/crowdsale/emission/AllowanceCrowdsale.sol"; 5 | import "@openzeppelin/contracts/crowdsale/validation/CappedCrowdsale.sol"; 6 | 7 | //有封顶的众筹 8 | contract CappedCrowdsaleContract is Crowdsale, AllowanceCrowdsale, CappedCrowdsale { 9 | constructor( 10 | uint256 rate, // 兑换比例 11 | address payable wallet, // 接收ETH受益人地址 12 | IERC20 token, // 代币地址 13 | address tokenWallet, // 代币从这个地址发送 14 | uint256 cap // 封顶数量,单位是wei 15 | ) 16 | AllowanceCrowdsale(tokenWallet) 17 | CappedCrowdsale(cap) 18 | Crowdsale(rate, wallet, token) 19 | public 20 | { 21 | 22 | } 23 | } -------------------------------------------------------------------------------- /contracts/Crowdsale/FinalizableCrowdsale.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "@openzeppelin/contracts/crowdsale/Crowdsale.sol"; 4 | import "@openzeppelin/contracts/crowdsale/emission/AllowanceCrowdsale.sol"; 5 | import "@openzeppelin/contracts/crowdsale/distribution/FinalizableCrowdsale.sol"; 6 | import "@openzeppelin/contracts/crowdsale/validation/TimedCrowdsale.sol"; 7 | 8 | 9 | //可终结的众筹 10 | contract FinalizableCrowdsaleContract is 11 | Crowdsale, 12 | AllowanceCrowdsale, 13 | TimedCrowdsale, 14 | FinalizableCrowdsale 15 | { 16 | constructor( 17 | uint256 rate, // 兑换比例 18 | address payable wallet, // 接收ETH受益人地址 19 | IERC20 token, // 代币地址 20 | address tokenWallet, // 代币从这个地址发送 21 | uint256 openingTime, // 众筹开始时间 22 | uint256 closingTime // 众筹结束时间 23 | ) 24 | public 25 | AllowanceCrowdsale(tokenWallet) 26 | TimedCrowdsale(openingTime, closingTime) 27 | FinalizableCrowdsale() 28 | Crowdsale(rate, wallet, token) 29 | {} 30 | 31 | function _finalization() internal { 32 | // 写入众筹结束后的业务逻辑,当finalize()方法被调用时会执行这里 33 | super._finalization(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /contracts/Crowdsale/IndividuallyCappedCrowdsale.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "@openzeppelin/contracts/crowdsale/Crowdsale.sol"; 4 | import "@openzeppelin/contracts/crowdsale/emission/AllowanceCrowdsale.sol"; 5 | import "@openzeppelin/contracts/crowdsale/validation/IndividuallyCappedCrowdsale.sol"; 6 | 7 | //有配额的众筹 8 | contract IndividuallyCappedCrowdsaleContract is Crowdsale, AllowanceCrowdsale, IndividuallyCappedCrowdsale { 9 | constructor( 10 | uint256 rate, // 兑换比例 11 | address payable wallet, // 接收ETH受益人地址 12 | IERC20 token, // 代币地址 13 | address tokenWallet // 代币从这个地址发送 14 | ) 15 | AllowanceCrowdsale(tokenWallet) 16 | Crowdsale(rate, wallet, token) 17 | public 18 | { 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /contracts/Crowdsale/MintedCrowdsale.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "@openzeppelin/contracts/crowdsale/Crowdsale.sol"; 4 | import "@openzeppelin/contracts/crowdsale/emission/MintedCrowdsale.sol"; 5 | 6 | //可增发的众筹 7 | contract MintedCrowdsaleContract is Crowdsale, MintedCrowdsale { 8 | constructor( 9 | uint256 rate, // 兑换比例 10 | address payable wallet, // 接收ETH受益人地址 11 | IERC20 token // 代币地址 12 | ) 13 | Crowdsale(rate, wallet, token) 14 | public 15 | { 16 | 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /contracts/Crowdsale/PausableCrowdsale.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "@openzeppelin/contracts/crowdsale/Crowdsale.sol"; 4 | import "@openzeppelin/contracts/crowdsale/emission/AllowanceCrowdsale.sol"; 5 | import "@openzeppelin/contracts/crowdsale/validation/PausableCrowdsale.sol"; 6 | 7 | //可暂停的众筹 8 | contract PausableCrowdsaleContract is Crowdsale, AllowanceCrowdsale, PausableCrowdsale { 9 | constructor( 10 | uint256 rate, // 兑换比例 11 | address payable wallet, // 接收ETH受益人地址 12 | IERC20 token, // 代币地址 13 | address tokenWallet // 代币从这个地址发送 14 | ) 15 | AllowanceCrowdsale(tokenWallet) 16 | Crowdsale(rate, wallet, token) 17 | public 18 | { 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /contracts/Crowdsale/PostDeliveryCrowdsale.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "@openzeppelin/contracts/crowdsale/Crowdsale.sol"; 4 | import "@openzeppelin/contracts/crowdsale/emission/AllowanceCrowdsale.sol"; 5 | import "@openzeppelin/contracts/crowdsale/distribution/PostDeliveryCrowdsale.sol"; 6 | import "@openzeppelin/contracts/crowdsale/validation/TimedCrowdsale.sol"; 7 | 8 | 9 | //到期后交付的众筹 10 | contract PostDeliveryCrowdsaleContract is 11 | Crowdsale, 12 | AllowanceCrowdsale, 13 | TimedCrowdsale, 14 | PostDeliveryCrowdsale 15 | { 16 | constructor( 17 | uint256 rate, // 兑换比例 18 | address payable wallet, // 接收ETH受益人地址 19 | IERC20 token, // 代币地址 20 | address tokenWallet, // 代币从这个地址发送 21 | uint256 openingTime, // 众筹开始时间 22 | uint256 closingTime // 众筹结束时间 23 | ) 24 | public 25 | AllowanceCrowdsale(tokenWallet) 26 | TimedCrowdsale(openingTime, closingTime) 27 | PostDeliveryCrowdsale() 28 | Crowdsale(rate, wallet, token) 29 | {} 30 | } 31 | -------------------------------------------------------------------------------- /contracts/Crowdsale/RefundableCrowdsale.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "@openzeppelin/contracts/crowdsale/Crowdsale.sol"; 4 | import "@openzeppelin/contracts/crowdsale/emission/AllowanceCrowdsale.sol"; 5 | import "@openzeppelin/contracts/crowdsale/distribution/RefundableCrowdsale.sol"; 6 | import "@openzeppelin/contracts/crowdsale/distribution/RefundablePostDeliveryCrowdsale.sol"; 7 | 8 | 9 | //不成功退款的众筹 10 | contract RefundableCrowdsaleContract is 11 | Crowdsale, 12 | AllowanceCrowdsale, 13 | RefundablePostDeliveryCrowdsale 14 | { 15 | constructor( 16 | uint256 rate, // 兑换比例 17 | address payable wallet, // 接收ETH受益人地址 18 | IERC20 token, // 代币地址 19 | address tokenWallet, // 代币从这个地址发送 20 | uint256 openingTime, // 众筹开始时间 21 | uint256 closingTime, // 众筹结束时间 22 | uint256 goal // 众筹目标 23 | ) 24 | public 25 | Crowdsale(rate, wallet, token) 26 | AllowanceCrowdsale(tokenWallet) 27 | TimedCrowdsale(openingTime, closingTime) 28 | RefundableCrowdsale(goal) 29 | RefundablePostDeliveryCrowdsale() 30 | {} 31 | 32 | function _finalization() internal { 33 | // 写入众筹结束后的业务逻辑,当finalize()方法被调用时会执行这里 34 | super._finalization(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /contracts/Crowdsale/TimedCrowdsale.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "@openzeppelin/contracts/crowdsale/Crowdsale.sol"; 4 | import "@openzeppelin/contracts/crowdsale/emission/AllowanceCrowdsale.sol"; 5 | import "@openzeppelin/contracts/crowdsale/validation/TimedCrowdsale.sol"; 6 | 7 | //有时限的众筹 8 | contract TimedCrowdsaleContract is Crowdsale, AllowanceCrowdsale, TimedCrowdsale { 9 | constructor( 10 | uint256 rate, // 兑换比例 11 | address payable wallet, // 接收ETH受益人地址 12 | IERC20 token, // 代币地址 13 | address tokenWallet, // 代币从这个地址发送 14 | uint256 openingTime, // 众筹开始时间 15 | uint256 closingTime // 众筹结束时间 16 | ) 17 | AllowanceCrowdsale(tokenWallet) 18 | TimedCrowdsale(openingTime, closingTime) 19 | Crowdsale(rate, wallet, token) 20 | public 21 | { 22 | 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /contracts/Crowdsale/WhitelistCrowdsale.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "@openzeppelin/contracts/crowdsale/Crowdsale.sol"; 4 | import "@openzeppelin/contracts/crowdsale/emission/AllowanceCrowdsale.sol"; 5 | import "@openzeppelin/contracts/crowdsale/validation/WhitelistCrowdsale.sol"; 6 | 7 | //白名单众筹 8 | contract WhitelistCrowdsaleContract is Crowdsale, AllowanceCrowdsale, WhitelistCrowdsale { 9 | constructor( 10 | uint256 rate, // 兑换比例 11 | address payable wallet, // 接收ETH受益人地址 12 | IERC20 token, // 代币地址 13 | address tokenWallet // 代币从这个地址发送 14 | ) 15 | AllowanceCrowdsale(tokenWallet) 16 | Crowdsale(rate, wallet, token) 17 | public 18 | { 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /contracts/ERC20/ERC20FixedSupply.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.7.0; 2 | 3 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 4 | import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; 5 | 6 | 7 | //固定总量代币 8 | contract ERC20FixedSupply is ERC20, ERC20Detailed { 9 | constructor( 10 | string memory name, //代币名称 11 | string memory symbol, //代币缩写 12 | uint8 decimals, //精度 13 | uint256 totalSupply //发行总量 14 | ) public ERC20Detailed(name, symbol, decimals) { 15 | _mint(msg.sender, totalSupply * (10**uint256(decimals))); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /contracts/ERC20/ERC20WithBurnable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.7.0; 2 | 3 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 4 | import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; 5 | import "@openzeppelin/contracts/token/ERC20/ERC20Burnable.sol"; 6 | 7 | 8 | //可销毁代币 9 | contract ERC20WithBurnable is ERC20, ERC20Detailed, ERC20Burnable { 10 | constructor( 11 | string memory name, //代币名称 12 | string memory symbol, //代币缩写 13 | uint8 decimals, //精度 14 | uint256 totalSupply //发行总量 15 | ) public ERC20Detailed(name, symbol, decimals) { 16 | _mint(msg.sender, totalSupply * (10**uint256(decimals))); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /contracts/ERC20/ERC20WithCapped.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.7.0; 2 | 3 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 4 | import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; 5 | import "@openzeppelin/contracts/token/ERC20/ERC20Capped.sol"; 6 | 7 | 8 | //有封顶代币 9 | contract ERC20WithCapped is ERC20, ERC20Detailed, ERC20Capped { 10 | constructor( 11 | string memory name, //代币名称 12 | string memory symbol, //代币缩写 13 | uint8 decimals, //精度 14 | uint256 initalSupply, //初始总量 15 | uint256 cap //封顶数量 16 | ) public ERC20Detailed(name, symbol, decimals) ERC20Capped(cap * (10**uint256(decimals))){ 17 | _mint(msg.sender, initalSupply * (10**uint256(decimals))); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /contracts/ERC20/ERC20WithMintable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.7.0; 2 | 3 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 4 | import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; 5 | import "@openzeppelin/contracts/token/ERC20/ERC20Mintable.sol"; 6 | 7 | 8 | //可增发代币 9 | contract ERC20WithMintable is ERC20, ERC20Detailed, ERC20Mintable { 10 | constructor( 11 | string memory name, //代币名称 12 | string memory symbol, //代币缩写 13 | uint8 decimals, //精度 14 | uint256 totalSupply //发行总量 15 | ) public ERC20Detailed(name, symbol, decimals) { 16 | _mint(msg.sender, totalSupply * (10**uint256(decimals))); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /contracts/ERC20/ERC20WithPausable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.7.0; 2 | 3 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 4 | import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; 5 | import "@openzeppelin/contracts/token/ERC20/ERC20Pausable.sol"; 6 | 7 | 8 | //可暂停代币 9 | contract ERC20WithPausable is ERC20, ERC20Detailed, ERC20Pausable { 10 | constructor( 11 | string memory name, //代币名称 12 | string memory symbol, //代币缩写 13 | uint8 decimals, //精度 14 | uint256 totalSupply //发行总量 15 | ) public ERC20Detailed(name, symbol, decimals) { 16 | _mint(msg.sender, totalSupply * (10**uint256(decimals))); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /contracts/ERC20/ERC20WithTokenTimelock.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.7.0; 2 | 3 | import "@openzeppelin/contracts/token/ERC20/TokenTimelock.sol"; 4 | 5 | 6 | //锁仓合约 7 | contract ERC20WithTokenTimelock is TokenTimelock { 8 | constructor( 9 | IERC20 token, //ERC20代币合约地址 10 | address beneficiary, //受益人 11 | uint256 releaseTime //解锁时间戳 12 | ) public TokenTimelock(token, beneficiary, releaseTime) {} 13 | } 14 | -------------------------------------------------------------------------------- /contracts/ERC721/ERC721Burnable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "@openzeppelin/contracts/token/ERC721/ERC721Full.sol"; 4 | import "@openzeppelin/contracts/token/ERC721/ERC721Burnable.sol"; 5 | import "@openzeppelin/contracts/token/ERC721/ERC721Holder.sol"; 6 | import "@openzeppelin/contracts/drafts/Counters.sol"; 7 | //可销毁的ERC721代币 8 | contract ERC721BurnableContract is ERC721Full, ERC721Burnable, ERC721Holder{ 9 | using Counters for Counters.Counter; 10 | Counters.Counter private _tokenIds; 11 | 12 | constructor( 13 | string memory name, //代币名称 14 | string memory symbol,//代币缩写 15 | string memory baseURI//代币基本地址 16 | ) ERC721Full(name, symbol) public { 17 | _setBaseURI(baseURI); 18 | } 19 | 20 | function awardItem(address player, string memory tokenURI) public returns (uint256) { 21 | _tokenIds.increment(); 22 | 23 | uint256 newItemId = _tokenIds.current(); 24 | _mint(player, newItemId); 25 | _setTokenURI(newItemId, tokenURI); 26 | 27 | return newItemId; 28 | } 29 | } -------------------------------------------------------------------------------- /contracts/ERC721/ERC721Full.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "@openzeppelin/contracts/token/ERC721/ERC721Full.sol"; 4 | import "@openzeppelin/contracts/token/ERC721/ERC721Holder.sol"; 5 | import "@openzeppelin/contracts/drafts/Counters.sol"; 6 | //全功能ERC721代币 7 | contract ERC721FullContract is ERC721Full, ERC721Holder { 8 | using Counters for Counters.Counter; 9 | Counters.Counter private _tokenIds; 10 | 11 | constructor( 12 | string memory name, //代币名称 13 | string memory symbol,//代币缩写 14 | string memory baseURI//代币基本地址 15 | ) ERC721Full(name, symbol) public { 16 | _setBaseURI(baseURI); 17 | } 18 | 19 | function awardItem(address player, string memory tokenURI) public returns (uint256) { 20 | _tokenIds.increment(); 21 | 22 | uint256 newItemId = _tokenIds.current(); 23 | _mint(player, newItemId); 24 | _setTokenURI(newItemId, tokenURI); 25 | 26 | return newItemId; 27 | } 28 | } -------------------------------------------------------------------------------- /contracts/ERC721/ERC721Mintable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "@openzeppelin/contracts/token/ERC721/ERC721Full.sol"; 4 | import "@openzeppelin/contracts/token/ERC721/ERC721Mintable.sol"; 5 | import "@openzeppelin/contracts/token/ERC721/ERC721MetadataMintable.sol"; 6 | import "@openzeppelin/contracts/token/ERC721/ERC721Holder.sol"; 7 | //可铸造的ERC721代币 8 | contract ERC721MintableContract is ERC721Full, ERC721Mintable, ERC721MetadataMintable, ERC721Holder{ 9 | constructor( 10 | string memory name, //代币名称 11 | string memory symbol,//代币缩写 12 | string memory baseURI//代币基本地址 13 | ) 14 | ERC721Full(name, symbol) 15 | public { 16 | _setBaseURI(baseURI); 17 | } 18 | } -------------------------------------------------------------------------------- /contracts/ERC721/ERC721Pausable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "@openzeppelin/contracts/token/ERC721/ERC721Full.sol"; 4 | import "@openzeppelin/contracts/token/ERC721/ERC721Pausable.sol"; 5 | import "@openzeppelin/contracts/token/ERC721/ERC721Holder.sol"; 6 | import "@openzeppelin/contracts/drafts/Counters.sol"; 7 | //可暂停的ERC721代币 8 | contract ERC721PausableContract is ERC721Full, ERC721Pausable, ERC721Holder{ 9 | using Counters for Counters.Counter; 10 | Counters.Counter private _tokenIds; 11 | 12 | constructor( 13 | string memory name, //代币名称 14 | string memory symbol,//代币缩写 15 | string memory baseURI//代币基本地址 16 | ) ERC721Full(name, symbol) public { 17 | _setBaseURI(baseURI); 18 | } 19 | 20 | function awardItem(address player, string memory tokenURI) public whenNotPaused() returns (uint256) { 21 | _tokenIds.increment(); 22 | 23 | uint256 newItemId = _tokenIds.current(); 24 | _mint(player, newItemId); 25 | _setTokenURI(newItemId, tokenURI); 26 | 27 | return newItemId; 28 | } 29 | } -------------------------------------------------------------------------------- /contracts/ERC777/ERC777Contract.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "@openzeppelin/contracts/token/ERC777/ERC777.sol"; 4 | 5 | contract ERC777Contract is ERC777{ 6 | constructor( 7 | string memory name, //代币名称 8 | string memory symbol, //代币缩写 9 | uint256 initialSupply, //发行总量 10 | address[] memory defaultOperators //默认操作员数组 11 | ) public ERC777(name, symbol, defaultOperators) { 12 | _mint(msg.sender, msg.sender, initialSupply, "", ""); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /contracts/ERC777/TokensRecipient.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "@openzeppelin/contracts/ownership/Ownable.sol"; 4 | import "@openzeppelin/contracts/token/ERC777/IERC777Recipient.sol"; 5 | import "@openzeppelin/contracts/introspection/ERC1820Implementer.sol"; 6 | import "@openzeppelin/contracts/introspection/IERC1820Registry.sol"; 7 | import "@openzeppelin/contracts/token/ERC777/IERC777.sol"; 8 | import "@openzeppelin/contracts/math/SafeMath.sol"; 9 | 10 | 11 | contract TokensRecipient is ERC1820Implementer, IERC777Recipient, Ownable { 12 | bool private allowTokensReceived; 13 | using SafeMath for uint256; 14 | // keccak256("ERC777TokensRecipient") 15 | bytes32 private constant TOKENS_RECIPIENT_INTERFACE_HASH = 0xb281fc8c12954d22544db45de3159a39272895b169a852b314f9cc762e44c53b; 16 | 17 | mapping(address => address) public token; 18 | mapping(address => address) public operator; 19 | mapping(address => address) public from; 20 | mapping(address => address) public to; 21 | mapping(address => uint256) public amount; 22 | mapping(address => bytes) public data; 23 | mapping(address => bytes) public operatorData; 24 | mapping(address => uint256) public balanceOf; 25 | 26 | IERC1820Registry internal constant ERC1820_REGISTRY = IERC1820Registry( 27 | 0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24 28 | ); 29 | 30 | constructor(bool _setInterface) public { 31 | if (_setInterface) { 32 | ERC1820_REGISTRY.setInterfaceImplementer( 33 | address(this), 34 | TOKENS_RECIPIENT_INTERFACE_HASH, 35 | address(this) 36 | ); 37 | } 38 | _registerInterfaceForAddress(TOKENS_RECIPIENT_INTERFACE_HASH, msg.sender); 39 | allowTokensReceived = true; 40 | } 41 | 42 | function tokensReceived( 43 | address _operator, 44 | address _from, 45 | address _to, 46 | uint256 _amount, 47 | bytes calldata _data, 48 | bytes calldata _operatorData 49 | ) external { 50 | require(allowTokensReceived, "Receive not allowed"); 51 | token[_from] = msg.sender; 52 | operator[_from] = _operator; 53 | from[_from] = _from; 54 | to[_from] = _to; 55 | amount[_from] = amount[_from].add(_amount); 56 | data[_from] = _data; 57 | operatorData[_from] = _operatorData; 58 | balanceOf[_from] = IERC777(msg.sender).balanceOf(_from); 59 | balanceOf[_to] = IERC777(msg.sender).balanceOf(_to); 60 | } 61 | 62 | function acceptTokens() public onlyOwner { 63 | allowTokensReceived = true; 64 | } 65 | 66 | function rejectTokens() public onlyOwner { 67 | allowTokensReceived = false; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /contracts/ERC777/TokensSender.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "@openzeppelin/contracts/ownership/Ownable.sol"; 4 | import "@openzeppelin/contracts/token/ERC777/IERC777Sender.sol"; 5 | import "@openzeppelin/contracts/introspection/ERC1820Implementer.sol"; 6 | import "@openzeppelin/contracts/introspection/IERC1820Registry.sol"; 7 | import "@openzeppelin/contracts/token/ERC777/IERC777.sol"; 8 | import "@openzeppelin/contracts/math/SafeMath.sol"; 9 | 10 | 11 | contract TokensSender is ERC1820Implementer, IERC777Sender, Ownable { 12 | bool private allowTokensToSend; 13 | using SafeMath for uint256; 14 | // keccak256("ERC777TokensSender") 15 | bytes32 private constant TOKENS_SENDER_INTERFACE_HASH = 0x29ddb589b1fb5fc7cf394961c1adf5f8c6454761adf795e67fe149f658abe895; 16 | 17 | mapping(address => address) public token; 18 | mapping(address => address) public operator; 19 | mapping(address => address) public from; 20 | mapping(address => address) public to; 21 | mapping(address => uint256) public amount; 22 | mapping(address => bytes) public data; 23 | mapping(address => bytes) public operatorData; 24 | mapping(address => uint256) public balanceOf; 25 | 26 | IERC1820Registry internal constant ERC1820_REGISTRY = IERC1820Registry( 27 | 0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24 28 | ); 29 | 30 | constructor(bool _setInterface) public { 31 | if (_setInterface) { 32 | ERC1820_REGISTRY.setInterfaceImplementer( 33 | address(this), 34 | TOKENS_SENDER_INTERFACE_HASH, 35 | address(this) 36 | ); 37 | } 38 | _registerInterfaceForAddress(TOKENS_SENDER_INTERFACE_HASH, msg.sender); 39 | allowTokensToSend = true; 40 | } 41 | 42 | function tokensToSend( 43 | address _operator, 44 | address _from, 45 | address _to, 46 | uint256 _amount, 47 | bytes calldata _data, 48 | bytes calldata _operatorData 49 | ) external { 50 | require(allowTokensToSend, "Send not allowed"); 51 | token[_to] = msg.sender; 52 | operator[_to] = _operator; 53 | from[_to] = _from; 54 | to[_to] = _to; 55 | amount[_to] = amount[_to].add(_amount); 56 | data[_to] = _data; 57 | operatorData[_to] = _operatorData; 58 | balanceOf[_from] = IERC777(msg.sender).balanceOf(_from); 59 | balanceOf[_to] = IERC777(msg.sender).balanceOf(_to); 60 | } 61 | 62 | function acceptTokensToSend() public onlyOwner { 63 | allowTokensToSend = true; 64 | } 65 | 66 | function rejectTokensToSend() public onlyOwner { 67 | allowTokensToSend = false; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.7.0; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | constructor() public { 8 | owner = msg.sender; 9 | } 10 | 11 | modifier restricted() { 12 | if (msg.sender == owner) _; 13 | } 14 | 15 | function setCompleted(uint completed) public restricted { 16 | last_completed_migration = completed; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /contracts/Multi/CrowdsalePaymentSplitter.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | import "@openzeppelin/contracts/payment/PaymentSplitter.sol"; 3 | 4 | //股份制受益人合约 5 | contract CrowdsalePaymentSplitter is PaymentSplitter { 6 | constructor( 7 | address[] memory payees, //受益人数组 8 | uint256[] memory shares //受益人股份比例 9 | ) 10 | PaymentSplitter(payees,shares) 11 | public payable 12 | { 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /contracts/Multi/ERC20Migrator.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | import "@openzeppelin/contracts/drafts/ERC20Migrator.sol"; 3 | 4 | //代币迁移合约 5 | contract ERC20MigratorContract is ERC20Migrator { 6 | constructor( 7 | IERC20 legacyToken //旧代币合约 8 | ) 9 | ERC20Migrator(legacyToken) 10 | public 11 | { 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /contracts/Multi/ERC20MultiFunction.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.7.0; 2 | 3 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 4 | import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; 5 | import "@openzeppelin/contracts/token/ERC20/ERC20Burnable.sol"; 6 | import "@openzeppelin/contracts/token/ERC20/ERC20Capped.sol"; 7 | import "@openzeppelin/contracts/token/ERC20/ERC20Pausable.sol"; 8 | 9 | 10 | //多功能ERC20代币,可增发,可销毁,可暂停,有封顶 11 | contract ERC20MultiFunction is 12 | ERC20, 13 | ERC20Detailed, 14 | ERC20Burnable, 15 | ERC20Capped, 16 | ERC20Pausable 17 | { 18 | constructor( 19 | string memory name, //代币名称 20 | string memory symbol, //代币缩写 21 | uint8 decimals, //精度 22 | uint256 totalSupply, //发行总量 23 | uint256 cap //封顶数量 24 | ) public ERC20Detailed(name, symbol, decimals) ERC20Capped(cap * (10**uint256(decimals))){ 25 | _mint(msg.sender, totalSupply * (10**uint256(decimals))); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /contracts/Multi/ERC20WithSnapshot.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.7.0; 2 | 3 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 4 | import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; 5 | import "@openzeppelin/contracts/drafts/ERC20Snapshot.sol"; 6 | 7 | 8 | //可快照的ERC20代币 9 | contract ERC20WithSnapshot is ERC20, ERC20Detailed, ERC20Snapshot { 10 | constructor( 11 | string memory name, //代币名称 12 | string memory symbol, //代币缩写 13 | uint8 decimals, //精度 14 | uint256 totalSupply //发行总量 15 | ) public ERC20Detailed(name, symbol, decimals) { 16 | _mint(msg.sender, totalSupply * (10**uint256(decimals))); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /contracts/Multi/ERC20WithTokenVesting.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.7.0; 2 | 3 | import "@openzeppelin/contracts/drafts/TokenVesting.sol"; 4 | 5 | //分期释放合约 6 | contract ERC20WithTokenVesting is TokenVesting { 7 | constructor( 8 | address beneficiary, //受益人 9 | uint256 start, //开始时间 10 | uint256 cliffDuration, //断崖时间 11 | uint256 duration, //持续时间 12 | bool revocable //是否可撤销 13 | ) public TokenVesting(beneficiary, start, cliffDuration, duration, revocable) {} 14 | } 15 | -------------------------------------------------------------------------------- /contracts/Multi/MultiFunctionCrowdsale.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 4 | import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; 5 | import "@openzeppelin/contracts/token/ERC20/ERC20Mintable.sol"; 6 | import "@openzeppelin/contracts/token/ERC20/ERC20Burnable.sol"; 7 | import "@openzeppelin/contracts/crowdsale/Crowdsale.sol"; 8 | import "@openzeppelin/contracts/crowdsale/distribution/RefundablePostDeliveryCrowdsale.sol"; 9 | import "@openzeppelin/contracts/crowdsale/emission/MintedCrowdsale.sol"; 10 | import "@openzeppelin/contracts/crowdsale/validation/CappedCrowdsale.sol"; 11 | import "@openzeppelin/contracts/crowdsale/validation/IndividuallyCappedCrowdsale.sol"; 12 | import "@openzeppelin/contracts/crowdsale/validation/PausableCrowdsale.sol"; 13 | import "@openzeppelin/contracts/crowdsale/validation/WhitelistCrowdsale.sol"; 14 | 15 | //多功能众筹合约:可增发,可销毁,有封顶,有配额,可暂停,有时限,白名单,成功后交付,不成功退款 16 | contract MultiFunctionCrowdsaleERC20 is 17 | ERC20, 18 | ERC20Detailed, 19 | ERC20Mintable, 20 | ERC20Burnable 21 | { 22 | constructor( 23 | string memory name, //代币名称 24 | string memory symbol, //代币缩写 25 | uint8 decimals, //精度 26 | uint256 totalSupply //发行总量 27 | ) public ERC20Detailed(name, symbol, decimals) { 28 | _mint(msg.sender, totalSupply * (10**uint256(decimals))); 29 | } 30 | } 31 | 32 | 33 | contract MultiFunctionCrowdsale is 34 | Crowdsale, 35 | CappedCrowdsale, 36 | IndividuallyCappedCrowdsale, 37 | MintedCrowdsale, 38 | PausableCrowdsale, 39 | RefundablePostDeliveryCrowdsale, 40 | WhitelistCrowdsale 41 | { 42 | constructor( 43 | uint256 rate, // 兑换比例 44 | address payable wallet, // 接收ETH受益人地址 45 | IERC20 token, // 代币地址 46 | address tokenWallet, // 代币从这个地址发送 47 | uint256 openingTime, // 众筹开始时间 48 | uint256 closingTime, // 众筹结束时间 49 | uint256 goal, // 众筹目标 50 | uint256 cap // 封顶数量,单位是wei 51 | ) 52 | public 53 | CappedCrowdsale(cap) 54 | Crowdsale(rate, wallet, token) 55 | TimedCrowdsale(openingTime, closingTime) 56 | RefundableCrowdsale(goal) 57 | RefundablePostDeliveryCrowdsale() 58 | {} 59 | 60 | function _finalization() internal { 61 | // 写入众筹结束后的业务逻辑,当finalize()方法被调用时会执行这里 62 | super._finalization(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /migrations/10_deploy_MintedCrowdsale.js: -------------------------------------------------------------------------------- 1 | //增发式众筹合约必须在可增发代币基础上构建 2 | const ERC20WithMintable = artifacts.require("ERC20WithMintable"); 3 | const MintedCrowdsaleContract = artifacts.require("MintedCrowdsaleContract"); 4 | 5 | module.exports = function (deployer, network, accounts) { 6 | deployer.deploy(ERC20WithMintable, 7 | "My Golden Coin", //代币名称 8 | "MGC", //代币缩写 9 | 18, //精度 10 | 1000000000 //初始发行量 11 | ).then((ERC20WithMintableInstance) => { 12 | return deployer.deploy(MintedCrowdsaleContract, 13 | 100, //兑换比例 14 | accounts[0], //接收ETH受益人地址 15 | ERC20WithMintable.address //代币地址 16 | ).then(() => { 17 | ERC20WithMintableInstance.addMinter(MintedCrowdsaleContract.address); 18 | ERC20WithMintableInstance.renounceMinter(); 19 | }); 20 | }) 21 | }; 22 | -------------------------------------------------------------------------------- /migrations/11_deploy_CappedCrowdsale.js: -------------------------------------------------------------------------------- 1 | //可以将ERC20FixedSupply替换成自己想要布署的合约名称 2 | const ERC20FixedSupply = artifacts.require("ERC20FixedSupply"); 3 | const CappedCrowdsaleContract = artifacts.require("CappedCrowdsaleContract"); 4 | 5 | module.exports = function (deployer, network, accounts) { 6 | const totalSupply = 1000000000; //发行量 7 | const cap = web3.utils.toWei('2000000000','ether'); //众筹封顶数量 8 | deployer.deploy(ERC20FixedSupply, 9 | "My Golden Coin", //代币名称 10 | "MGC", //代币缩写 11 | 18, //精度 12 | totalSupply //发行量 13 | ).then((ERC20FixedSupplyInstance) => { 14 | return deployer.deploy(CappedCrowdsaleContract, 15 | 100, //兑换比例1ETH:100ERC20 16 | accounts[1], //接收ETH受益人地址 17 | ERC20FixedSupply.address, //代币地址 18 | accounts[0], //代币从这个地址发送 19 | cap //众筹封顶数量 20 | ).then(() => { 21 | //在布署之后必须将发送者账户中的代币批准给众筹合约 22 | //totalSupply 是批准数量,默认是全部代币数量,你可以调整成自己需要的 23 | ERC20FixedSupplyInstance.approve(CappedCrowdsaleContract.address, cap); 24 | }); 25 | }) 26 | }; 27 | -------------------------------------------------------------------------------- /migrations/12_deploy_IndividuallyCappedCrowdsale.js: -------------------------------------------------------------------------------- 1 | //可以将ERC20FixedSupply替换成自己想要布署的合约名称 2 | const ERC20FixedSupply = artifacts.require("ERC20FixedSupply"); 3 | const IndividuallyCappedCrowdsaleContract = artifacts.require("IndividuallyCappedCrowdsaleContract"); 4 | 5 | module.exports = function (deployer, network, accounts) { 6 | const totalSupply = 1000000000; //发行量 7 | deployer.deploy(ERC20FixedSupply, 8 | "My Golden Coin", //代币名称 9 | "MGC", //代币缩写 10 | 18, //精度 11 | totalSupply //发行量 12 | ).then((ERC20FixedSupplyInstance) => { 13 | return deployer.deploy(IndividuallyCappedCrowdsaleContract, 14 | 100, //兑换比例1ETH:100ERC20 15 | accounts[1], //接收ETH受益人地址 16 | ERC20FixedSupply.address, //代币地址 17 | accounts[0] //代币从这个地址发送 18 | ).then(() => { 19 | //在布署之后必须将发送者账户中的代币批准给众筹合约 20 | //totalSupply 是批准数量,默认是全部代币数量,你可以调整成自己需要的 21 | ERC20FixedSupplyInstance.approve(IndividuallyCappedCrowdsaleContract.address, web3.utils.toWei(totalSupply.toString(),'ether')); 22 | }); 23 | }) 24 | }; 25 | -------------------------------------------------------------------------------- /migrations/13_deploy_PausableCrowdsale.js: -------------------------------------------------------------------------------- 1 | //可以将ERC20FixedSupply替换成自己想要布署的合约名称 2 | const ERC20FixedSupply = artifacts.require("ERC20FixedSupply"); 3 | const PausableCrowdsaleContract = artifacts.require("PausableCrowdsaleContract"); 4 | 5 | module.exports = function (deployer, network, accounts) { 6 | const totalSupply = 1000000000; //发行量 7 | deployer.deploy(ERC20FixedSupply, 8 | "My Golden Coin", //代币名称 9 | "MGC", //代币缩写 10 | 18, //精度 11 | totalSupply //发行量 12 | ).then((ERC20FixedSupplyInstance) => { 13 | return deployer.deploy(PausableCrowdsaleContract, 14 | 100, //兑换比例1ETH:100ERC20 15 | accounts[1], //接收ETH受益人地址 16 | ERC20FixedSupply.address, //代币地址 17 | accounts[0] //代币从这个地址发送 18 | ).then(() => { 19 | //在布署之后必须将发送者账户中的代币批准给众筹合约 20 | //totalSupply 是批准数量,默认是全部代币数量,你可以调整成自己需要的 21 | ERC20FixedSupplyInstance.approve(PausableCrowdsaleContract.address, web3.utils.toWei(totalSupply.toString(),'ether')); 22 | }); 23 | }) 24 | }; 25 | -------------------------------------------------------------------------------- /migrations/14_deploy_TimedCrowdsale.js: -------------------------------------------------------------------------------- 1 | //可以将ERC20FixedSupply替换成自己想要布署的合约名称 2 | const ERC20FixedSupply = artifacts.require("ERC20FixedSupply"); 3 | const TimedCrowdsaleContract = artifacts.require("TimedCrowdsaleContract"); 4 | 5 | module.exports = function (deployer, network, accounts) { 6 | const totalSupply = 1000000000; //发行量 7 | deployer.deploy(ERC20FixedSupply, 8 | "My Golden Coin", //代币名称 9 | "MGC", //代币缩写 10 | 18, //精度 11 | totalSupply //发行量 12 | ).then((ERC20FixedSupplyInstance) => { 13 | return deployer.deploy(TimedCrowdsaleContract, 14 | 100, //兑换比例1ETH:100ERC20 15 | accounts[1], //接收ETH受益人地址 16 | ERC20FixedSupply.address, //代币地址 17 | accounts[0], //代币从这个地址发送 18 | Math.ceil(new Date().getTime() / 1000) + 60, //众筹开始时间 19 | Math.ceil(new Date().getTime() / 1000) + 600 //众筹结束时间 20 | ).then(() => { 21 | //在布署之后必须将发送者账户中的代币批准给众筹合约 22 | //totalSupply 是批准数量,默认是全部代币数量,你可以调整成自己需要的 23 | ERC20FixedSupplyInstance.approve(TimedCrowdsaleContract.address, web3.utils.toWei(totalSupply.toString(),'ether')); 24 | }); 25 | }) 26 | }; 27 | -------------------------------------------------------------------------------- /migrations/15_deploy_WhitelistCrowdsale.js: -------------------------------------------------------------------------------- 1 | //可以将ERC20FixedSupply替换成自己想要布署的合约名称 2 | const ERC20FixedSupply = artifacts.require("ERC20FixedSupply"); 3 | const WhitelistCrowdsaleContract = artifacts.require("WhitelistCrowdsaleContract"); 4 | 5 | module.exports = function (deployer, network, accounts) { 6 | const totalSupply = 1000000000; //发行量 7 | deployer.deploy(ERC20FixedSupply, 8 | "My Golden Coin", //代币名称 9 | "MGC", //代币缩写 10 | 18, //精度 11 | totalSupply //发行量 12 | ).then((ERC20FixedSupplyInstance) => { 13 | return deployer.deploy(WhitelistCrowdsaleContract, 14 | 100, //兑换比例1ETH:100ERC20 15 | accounts[1], //接收ETH受益人地址 16 | ERC20FixedSupply.address, //代币地址 17 | accounts[0] //代币从这个地址发送 18 | ).then(() => { 19 | //在布署之后必须将发送者账户中的代币批准给众筹合约 20 | //totalSupply 是批准数量,默认是全部代币数量,你可以调整成自己需要的 21 | ERC20FixedSupplyInstance.approve(WhitelistCrowdsaleContract.address, web3.utils.toWei(totalSupply.toString(),'ether')); 22 | }); 23 | }) 24 | }; 25 | -------------------------------------------------------------------------------- /migrations/16_deploy_FinalizableCrowdsale.js: -------------------------------------------------------------------------------- 1 | //可以将ERC20FixedSupply替换成自己想要布署的合约名称 2 | const ERC20FixedSupply = artifacts.require("ERC20FixedSupply"); 3 | const FinalizableCrowdsaleContract = artifacts.require("FinalizableCrowdsaleContract"); 4 | 5 | module.exports = function (deployer, network, accounts) { 6 | const totalSupply = 1000000000; //发行量 7 | deployer.deploy(ERC20FixedSupply, 8 | "My Golden Coin", //代币名称 9 | "MGC", //代币缩写 10 | 18, //精度 11 | totalSupply //发行量 12 | ).then((ERC20FixedSupplyInstance) => { 13 | return deployer.deploy(FinalizableCrowdsaleContract, 14 | 100, //兑换比例1ETH:100ERC20 15 | accounts[1], //接收ETH受益人地址 16 | ERC20FixedSupply.address, //代币地址 17 | accounts[0], //代币从这个地址发送 18 | Math.ceil(new Date().getTime() / 1000) + 60, //众筹开始时间 19 | Math.ceil(new Date().getTime() / 1000) + 600 //众筹结束时间 20 | ).then(() => { 21 | //在布署之后必须将发送者账户中的代币批准给众筹合约 22 | //totalSupply 是批准数量,默认是全部代币数量,你可以调整成自己需要的 23 | ERC20FixedSupplyInstance.approve(FinalizableCrowdsaleContract.address, web3.utils.toWei(totalSupply.toString(), 'ether')); 24 | }); 25 | }) 26 | }; 27 | -------------------------------------------------------------------------------- /migrations/17_deploy_PostDeliveryCrowdsale.js: -------------------------------------------------------------------------------- 1 | //可以将ERC20FixedSupply替换成自己想要布署的合约名称 2 | const ERC20FixedSupply = artifacts.require("ERC20FixedSupply"); 3 | const PostDeliveryCrowdsaleContract = artifacts.require("PostDeliveryCrowdsaleContract"); 4 | 5 | module.exports = function (deployer, network, accounts) { 6 | const totalSupply = 1000000000; //发行量 7 | deployer.deploy(ERC20FixedSupply, 8 | "My Golden Coin", //代币名称 9 | "MGC", //代币缩写 10 | 18, //精度 11 | totalSupply //发行量 12 | ).then((ERC20FixedSupplyInstance) => { 13 | return deployer.deploy(PostDeliveryCrowdsaleContract, 14 | 100, //兑换比例1ETH:100ERC20 15 | accounts[1], //接收ETH受益人地址 16 | ERC20FixedSupply.address, //代币地址 17 | accounts[0], //代币从这个地址发送 18 | Math.ceil(new Date().getTime() / 1000) + 60, //众筹开始时间 19 | Math.ceil(new Date().getTime() / 1000) + 600 //众筹结束时间 20 | ).then(() => { 21 | //在布署之后必须将发送者账户中的代币批准给众筹合约 22 | //totalSupply 是批准数量,默认是全部代币数量,你可以调整成自己需要的 23 | ERC20FixedSupplyInstance.approve(PostDeliveryCrowdsaleContract.address, web3.utils.toWei(totalSupply.toString(), 'ether')); 24 | }); 25 | }) 26 | }; 27 | -------------------------------------------------------------------------------- /migrations/18_deploy_RefundableCrowdsale.js: -------------------------------------------------------------------------------- 1 | //可以将ERC20FixedSupply替换成自己想要布署的合约名称 2 | const ERC20FixedSupply = artifacts.require("ERC20FixedSupply"); 3 | const RefundableCrowdsaleContract = artifacts.require("RefundableCrowdsaleContract"); 4 | 5 | module.exports = function (deployer, network, accounts) { 6 | const totalSupply = 1000000000; //发行量 7 | deployer.deploy(ERC20FixedSupply, 8 | "My Golden Coin", //代币名称 9 | "MGC", //代币缩写 10 | 18, //精度 11 | totalSupply //发行量 12 | ).then((ERC20FixedSupplyInstance) => { 13 | return deployer.deploy(RefundableCrowdsaleContract, 14 | 100, //兑换比例1ETH:100ERC20 15 | accounts[1], //接收ETH受益人地址 16 | ERC20FixedSupply.address, //代币地址 17 | accounts[0], //代币从这个地址发送 18 | Math.ceil(new Date().getTime() / 1000) + 60, //众筹开始时间 19 | Math.ceil(new Date().getTime() / 1000) + 600, //众筹结束时间 20 | web3.utils.toWei('20', 'ether') //众筹目标 21 | ).then(() => { 22 | //在布署之后必须将发送者账户中的代币批准给众筹合约 23 | //totalSupply 是批准数量,默认是全部代币数量,你可以调整成自己需要的 24 | ERC20FixedSupplyInstance.approve(RefundableCrowdsaleContract.address, web3.utils.toWei(totalSupply.toString(), 'ether')); 25 | }); 26 | }) 27 | }; 28 | -------------------------------------------------------------------------------- /migrations/19_deploy_ERC20MultiFunction.js: -------------------------------------------------------------------------------- 1 | //固定总量代币 2 | const ERC20MultiFunction = artifacts.require("ERC20MultiFunction"); 3 | 4 | module.exports = function(deployer) { 5 | deployer.deploy(ERC20MultiFunction, 6 | //构造函数的参数 7 | "My Golden Coin","MGC",18,1000,1000000000); 8 | }; -------------------------------------------------------------------------------- /migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | const Migrations = artifacts.require("Migrations"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /migrations/20_deploy_MultiFunctionCrowdsale.js: -------------------------------------------------------------------------------- 1 | const MultiFunctionCrowdsaleERC20 = artifacts.require("MultiFunctionCrowdsaleERC20"); 2 | const MultiFunctionCrowdsale = artifacts.require("MultiFunctionCrowdsale"); 3 | 4 | module.exports = function (deployer, network, accounts) { 5 | const totalSupply = 1000000000; //发行量 6 | const cap = web3.utils.toWei('10000', 'ether'); //众筹封顶数量 7 | const rate = 100; // 兑换比例 8 | const goal = web3.utils.toWei('200', 'ether'); //众筹目标 9 | deployer.deploy(MultiFunctionCrowdsaleERC20, 10 | "My Golden Coin", //代币名称 11 | "MGC", //代币缩写 12 | 18, //精度 13 | totalSupply //初始发行量 14 | ).then((MultiFunctionCrowdsaleERC20Instance) => { 15 | return deployer.deploy(MultiFunctionCrowdsale, 16 | rate, // 兑换比例 17 | accounts[0], // 接收ETH受益人地址 18 | MultiFunctionCrowdsaleERC20.address, // 代币地址 19 | accounts[0], // 代币从这个地址发送 20 | Math.ceil(new Date().getTime() / 1000) + 60, //众筹开始时间 21 | Math.ceil(new Date().getTime() / 1000) + 600, //众筹结束时间 22 | goal, //众筹目标 23 | cap //众筹封顶数量 24 | ).then(() => { 25 | MultiFunctionCrowdsaleERC20Instance.addMinter(MultiFunctionCrowdsale.address); 26 | MultiFunctionCrowdsaleERC20Instance.renounceMinter(); 27 | MultiFunctionCrowdsaleERC20Instance.approve(MultiFunctionCrowdsale.address, web3.utils.toWei(totalSupply.toString(), 'ether')); 28 | }); 29 | }) 30 | }; 31 | -------------------------------------------------------------------------------- /migrations/21_deploy_ERC721Full.js: -------------------------------------------------------------------------------- 1 | //固定总量代币 2 | const ERC721FullContract = artifacts.require("ERC721FullContract"); 3 | 4 | module.exports = function(deployer) { 5 | deployer.deploy(ERC721FullContract, 6 | //构造函数的参数 7 | "My Game Token","MGT",'https://github.com/Fankouzu/MintCoin/blob/master/'); 8 | }; -------------------------------------------------------------------------------- /migrations/22_deploy_ERC721Mintable.js: -------------------------------------------------------------------------------- 1 | const ERC721MintableContract = artifacts.require("ERC721MintableContract"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(ERC721MintableContract, 5 | //构造函数的参数 6 | "My Game Token","MGT",'https://github.com/Fankouzu/MintCoin/blob/master/'); 7 | }; -------------------------------------------------------------------------------- /migrations/23_deploy_ERC721Burnable.js: -------------------------------------------------------------------------------- 1 | const ERC721BurnableContract = artifacts.require("ERC721BurnableContract"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(ERC721BurnableContract, 5 | //构造函数的参数 6 | "My Game Token","MGT",'https://github.com/Fankouzu/MintCoin/blob/master/'); 7 | }; -------------------------------------------------------------------------------- /migrations/24_deploy_ERC721Pausable.js: -------------------------------------------------------------------------------- 1 | const ERC721PausableContract = artifacts.require("ERC721PausableContract"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(ERC721PausableContract, 5 | //构造函数的参数 6 | "My Game Token","MGT",'https://github.com/Fankouzu/MintCoin/blob/master/'); 7 | }; -------------------------------------------------------------------------------- /migrations/25_deploy_ERC20Migrator.js: -------------------------------------------------------------------------------- 1 | const ERC20FixedSupply = artifacts.require("ERC20FixedSupply"); 2 | const ERC20Migrator = artifacts.require("ERC20MigratorContract"); 3 | 4 | module.exports = (deployer) => { 5 | //发行总量 6 | const totalSupply = 1000000000; 7 | deployer.deploy(ERC20FixedSupply, 8 | //构造函数的参数 9 | "My Golden Coin", //代币名称 10 | "MGC", //代币缩写 11 | 18, //精度 12 | totalSupply //发行总量 13 | ) 14 | .then((ERC20FixedSupplyInstance) => { 15 | return deployer.deploy(ERC20Migrator, 16 | ERC20FixedSupplyInstance.address, //ERC20代币合约地址 17 | ) 18 | }); 19 | }; -------------------------------------------------------------------------------- /migrations/26_deploy_ERC20WithSnapshot.js: -------------------------------------------------------------------------------- 1 | const ERC20WithSnapshot = artifacts.require("ERC20WithSnapshot"); 2 | module.exports = (deployer) => { 3 | //发行总量 4 | const totalSupply = 1000000000; 5 | deployer.deploy(ERC20WithSnapshot, 6 | //构造函数的参数 7 | "My Golden Coin", //代币名称 8 | "MGC", //代币缩写 9 | 18, //精度 10 | totalSupply //发行总量 11 | ) 12 | }; -------------------------------------------------------------------------------- /migrations/27_deploy_CrowdsalePaymentSplitter.js: -------------------------------------------------------------------------------- 1 | const CrowdsalePaymentSplitter = artifacts.require("CrowdsalePaymentSplitter"); 2 | //股份制受益人合约 3 | module.exports = (deployer,network,accounts) => { 4 | deployer.deploy(CrowdsalePaymentSplitter, 5 | [accounts[0],accounts[1],accounts[2],accounts[3]], //股东账户 6 | ['10','20','30','40'] //股份比例 7 | ) 8 | }; -------------------------------------------------------------------------------- /migrations/28_deploy_ERC20WithTokenVesting.js: -------------------------------------------------------------------------------- 1 | //可以将ERC20FixedSupply替换成自己想要布署的合约名称 2 | const ERC20FixedSupply = artifacts.require("ERC20FixedSupply"); 3 | const ERC20WithTokenVesting = artifacts.require("ERC20WithTokenVesting"); 4 | 5 | module.exports = (deployer, network, accounts) => { 6 | //发行总量 7 | const totalSupply = 1000000000; 8 | //锁仓总量 9 | const amount = 24000; 10 | deployer.deploy(ERC20FixedSupply, 11 | //构造函数的参数 12 | "My Golden Coin", //代币名称 13 | "MGC", //代币缩写 14 | 18, //精度 15 | totalSupply //发行总量 16 | ) 17 | .then((ERC20FixedSupplyInstance) => { 18 | return deployer.deploy(ERC20WithTokenVesting, 19 | accounts[1], //受益人账户 20 | parseInt(new Date().getTime() / 1000) + 10, //开始时间 21 | '3600', //断崖时间 22 | '86400', //持续时间 23 | true //可以撤销 24 | ).then((ERC20WithTokenVestingInstance) => { 25 | //将代币转移到锁仓合约的账户中 26 | ERC20FixedSupplyInstance.transfer(ERC20WithTokenVestingInstance.address, web3.utils.toWei(amount.toString(),'ether')); 27 | }) 28 | }); 29 | }; -------------------------------------------------------------------------------- /migrations/29_deploy_ERC777Contract.js: -------------------------------------------------------------------------------- 1 | const ERC777Contract = artifacts.require("ERC777Contract"); 2 | const TokensSender = artifacts.require("TokensSender"); 3 | const TokensRecipient = artifacts.require("TokensRecipient"); 4 | const { singletons } = require('@openzeppelin/test-helpers'); 5 | 6 | module.exports = async (deployer, network, accounts) => { 7 | await singletons.ERC1820Registry(accounts[0]); 8 | const initialSupply = web3.utils.toWei('1000000000'); 9 | const defaultOperators = accounts[1]; 10 | const param = [ 11 | //构造函数的参数 12 | "My Golden Coin", //代币名称 13 | "MGC", //代币缩写 14 | initialSupply, //发行总量 15 | [defaultOperators] //默认操作员 16 | ] 17 | await deployer.deploy(ERC777Contract, ...param); 18 | await deployer.deploy(TokensSender, true); 19 | await deployer.deploy(TokensRecipient, true); 20 | }; -------------------------------------------------------------------------------- /migrations/2_deploy_ERC20FixedSupply.js: -------------------------------------------------------------------------------- 1 | //固定总量代币 2 | const ERC20FixedSupply = artifacts.require("ERC20FixedSupply"); 3 | 4 | module.exports = function(deployer) { 5 | deployer.deploy(ERC20FixedSupply, 6 | //构造函数的参数 7 | "My Golden Coin","MGC",18,1000000000); 8 | }; -------------------------------------------------------------------------------- /migrations/3_deploy_ERC20WithBurnable.js: -------------------------------------------------------------------------------- 1 | //可销毁代币 2 | const ERC20WithBurnable = artifacts.require("ERC20WithBurnable"); 3 | 4 | module.exports = function(deployer) { 5 | deployer.deploy(ERC20WithBurnable, 6 | //构造函数的参数 7 | "My Golden Coin","MGC",18,1000000000); 8 | }; -------------------------------------------------------------------------------- /migrations/4_deploy_ERC20WithMintable.js: -------------------------------------------------------------------------------- 1 | //可增发代币 2 | const ERC20WithMintable = artifacts.require("ERC20WithMintable"); 3 | 4 | module.exports = function(deployer) { 5 | deployer.deploy(ERC20WithMintable, 6 | //构造函数的参数 7 | "My Golden Coin","MGC",18,1000000000); 8 | }; -------------------------------------------------------------------------------- /migrations/5_deploy_ERC20WithCapped.js: -------------------------------------------------------------------------------- 1 | //有封顶代币 2 | const ERC20WithCapped = artifacts.require("ERC20WithCapped"); 3 | 4 | module.exports = function(deployer) { 5 | deployer.deploy(ERC20WithCapped, 6 | //构造函数的参数 7 | "My Golden Coin","MGC",18,1000,1000000000); 8 | }; -------------------------------------------------------------------------------- /migrations/6_deploy_ERC20WithPausable.js: -------------------------------------------------------------------------------- 1 | //可暂停代币 2 | const ERC20WithPausable = artifacts.require("ERC20WithPausable"); 3 | 4 | module.exports = function(deployer) { 5 | deployer.deploy(ERC20WithPausable, 6 | //构造函数的参数 7 | "My Golden Coin","MGC",18,1000000000); 8 | }; -------------------------------------------------------------------------------- /migrations/7_deploy_IssueTokenWithTimelock.js: -------------------------------------------------------------------------------- 1 | //可以将ERC20FixedSupply替换成自己想要布署的合约名称 2 | const ERC20FixedSupply = artifacts.require("ERC20FixedSupply"); 3 | const IssueTokenWithTimelock = artifacts.require("ERC20WithTokenTimelock"); 4 | 5 | module.exports = (deployer, network, accounts) => { 6 | //发行总量 7 | const totalSupply = 1000000000; 8 | //锁仓总量 9 | const amount = 1000; 10 | deployer.deploy(ERC20FixedSupply, 11 | //构造函数的参数 12 | "My Golden Coin", //代币名称 13 | "MGC", //代币缩写 14 | 18, //精度 15 | totalSupply //发行总量 16 | ) 17 | .then((ERC20FixedSupplyInstance) => { 18 | return deployer.deploy(IssueTokenWithTimelock, 19 | ERC20FixedSupplyInstance.address, //ERC20代币合约地址 20 | accounts[0], //受益人为当前账户 21 | parseInt(new Date().getTime() / 1000 + 10) //解锁时间戳 22 | ).then((IssueTokenWithTimelockInstance) => { 23 | //将代币转移到锁仓合约的账户中 24 | ERC20FixedSupplyInstance.transfer(IssueTokenWithTimelockInstance.address, web3.utils.toWei(amount.toString(),'ether')); 25 | }) 26 | }); 27 | }; -------------------------------------------------------------------------------- /migrations/8_deploy_IssueTokenBeforeTimelock.js: -------------------------------------------------------------------------------- 1 | //可以将ERC20FixedSupply替换成自己想要布署的合约名称 2 | const ERC20FixedSupply = artifacts.require("ERC20FixedSupply"); 3 | const IssueTokenBeforeTimelock = artifacts.require("ERC20WithTokenTimelock"); 4 | 5 | module.exports = async (deployer, network, accounts) => { 6 | //锁仓总量 7 | const amount = 1000; 8 | //实例化ERC20合约 9 | const ERC20FixedSupplyInstance = await ERC20FixedSupply.deployed(); 10 | return deployer.deploy(IssueTokenBeforeTimelock, 11 | ERC20FixedSupplyInstance.address, //ERC20代币合约地址,如果你希望在未来的某个时间布署这个锁仓合约,可以将这里替换成合约地址 12 | accounts[1], //受益人 13 | parseInt(new Date().getTime() / 1000 + 10)//解锁时间戳 14 | ).then(function (IssueTokenBeforeTimelockInstance) { 15 | //将代币转移到锁仓合约的账户中 16 | //如果不是同时布署这个合约,可以通过其他方法随时调用ERC20的transfer方法 17 | ERC20FixedSupplyInstance.transfer(IssueTokenBeforeTimelockInstance.address, web3.utils.toWei(amount.toString(), 'ether')); 18 | }) 19 | }; -------------------------------------------------------------------------------- /migrations/9_deploy_AllowanceCrowdsale.js: -------------------------------------------------------------------------------- 1 | //可以将ERC20FixedSupply替换成自己想要布署的合约名称 2 | const ERC20FixedSupply = artifacts.require("ERC20FixedSupply"); 3 | const AllowanceCrowdsaleContract = artifacts.require("AllowanceCrowdsaleContract"); 4 | 5 | module.exports = function (deployer, network, accounts) { 6 | const totalSupply = 1000000000; //发行量 7 | deployer.deploy(ERC20FixedSupply, 8 | "My Golden Coin", //代币名称 9 | "MGC", //代币缩写 10 | 18, //精度 11 | totalSupply //发行量 12 | ).then((ERC20FixedSupplyInstance) => { 13 | return deployer.deploy(AllowanceCrowdsaleContract, 14 | 100, //兑换比例1ETH:100ERC20 15 | accounts[1], //接收ETH受益人地址 16 | ERC20FixedSupply.address, //代币地址 17 | accounts[0] //代币从这个地址发送 18 | ).then(() => { 19 | //在布署之后必须将发送者账户中的代币批准给众筹合约 20 | //totalSupply 是批准数量,默认是全部代币数量,你可以调整成自己需要的 21 | ERC20FixedSupplyInstance.approve(AllowanceCrowdsaleContract.address, web3.utils.toWei(totalSupply.toString(),'ether')); 22 | }); 23 | }) 24 | }; 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fankouzu-mint-cryptocurrency", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "dependencies": { 10 | "@davidqhr/ganache-cli": "6.4.3", 11 | "@openzeppelin/contracts": "^2.5.0", 12 | "@truffle/debug-utils": "^4.1.1", 13 | "@truffle/hdwallet-provider": "^1.0.34", 14 | "bip39": "^3.0.2", 15 | "ethers": "^4.0.47", 16 | "inquirer": "^7.1.0", 17 | "truffle": "5.0.22" 18 | }, 19 | "devDependencies": { 20 | "@openzeppelin/test-environment": "^0.1.4", 21 | "@openzeppelin/test-helpers": "^0.5.5", 22 | "chai": "^4.2.0", 23 | "eth-gas-reporter": "^0.2.17", 24 | "mocha": "^7.1.2" 25 | }, 26 | "scripts": { 27 | "test": "node script/test.js", 28 | "migrate": "node script/migrate.js", 29 | "compile": "truffle compile", 30 | "ganache": "ganache-cli -e 1000", 31 | "node": "node script/network.js", 32 | "mocha": "mocha --exit --recursive" 33 | }, 34 | "mocha": { 35 | "timeout": 100000, 36 | "useColors": true, 37 | "reporter": "spec" 38 | }, 39 | "keywords": [], 40 | "author": "", 41 | "license": "ISC" 42 | } 43 | -------------------------------------------------------------------------------- /script/migrate.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | var inquirer = require('inquirer'); 3 | const { spawn } = require('child_process'); 4 | 5 | const contractDir = 'migrations/'; 6 | getFiles = async (path) => { 7 | const dir = await fs.readdirSync(path, 'utf-8'); 8 | let files = [{ name: '全部布署', value: 'all' }]; 9 | dir.forEach((filename, index) => { 10 | 11 | const _filename = filename.split("_"); 12 | const num = _filename[0]; 13 | files[num] = { name: filename, value: num }; 14 | }) 15 | return files; 16 | } 17 | main = async () => { 18 | const files = await getFiles(contractDir); 19 | 20 | inquirer.prompt([ 21 | { 22 | type: 'list', 23 | name: 'step1', 24 | message: '选择要布署的合约', 25 | choices: files, 26 | } 27 | ]) 28 | .then(answers => { 29 | let argv; 30 | if (answers.step1 !== 'all') { 31 | console.log("\033[33mRun:\033[39m " + "truffle migrate --f " + answers.step1 + " --to " + answers.step1); 32 | argv = ["migrate","--f", answers.step1,"--to",answers.step1]; 33 | } else { 34 | argv = ["migrate","--reset"]; 35 | console.log("\033[33mRun:\033[39m " + "truffle migrate "); 36 | } 37 | spawn("truffle", argv, { 38 | stdio: 'inherit', 39 | shell: true 40 | }); 41 | 42 | }); 43 | } 44 | 45 | main(); -------------------------------------------------------------------------------- /script/network.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | var inquirer = require('inquirer'); 3 | const { spawn } = require('child_process'); 4 | const bip39 = require('bip39'); 5 | 6 | writeFile = (filename, data) => { 7 | fs.writeFile(filename, new Uint8Array(Buffer.from(data)), (err) => { 8 | if (err) throw err; 9 | }); 10 | } 11 | validateMnemonic = (mnemonic) => { 12 | if (mnemonic !== '') { 13 | if (lngDetector(mnemonic)) { 14 | return bip39.validateMnemonic(mnemonic, bip39.wordlists.EN) 15 | } else { 16 | return bip39.validateMnemonic(mnemonic.replace(/ /g, '').split('').join(' '), bip39.wordlists.chinese_simplified) 17 | } 18 | } else { 19 | return false 20 | } 21 | } 22 | lngDetector = (word) => { 23 | var regex = new RegExp('^([a-z]{0,200})$') 24 | return regex.test(word.replace(/ /g, '')) 25 | } 26 | main = async () => { 27 | inquirer.prompt([ 28 | { 29 | type: 'list', 30 | name: 'network', 31 | message: '选择网络 :', 32 | choices: [ 33 | { 34 | name: "ganache cli 测试环境", 35 | value: "ganache" 36 | }, 37 | { 38 | name: "truffle 测试环境", 39 | value: "develop" 40 | }, 41 | { 42 | name: "Ropsten 测试网", 43 | value: "ropsten" 44 | }, 45 | { 46 | name: "Rinkeby 测试网", 47 | value: "rinkeby" 48 | }, 49 | { 50 | name: "Kovan 测试网", 51 | value: "kovan" 52 | }, 53 | { 54 | name: "以太坊主网", 55 | value: "mainnet" 56 | }, 57 | ], 58 | }, 59 | { 60 | type: 'input', 61 | name: 'mnemonic', 62 | message: '输入助记词打开钱包 :', 63 | when: (answers) => { 64 | return answers.network === "ropsten" || 65 | answers.network === "rinkeby" || 66 | answers.network === "kovan" || 67 | answers.network === "mainnet"; 68 | }, 69 | validate: (value) => { 70 | var pass = validateMnemonic(value); 71 | if (pass) { 72 | return true; 73 | } 74 | return '助记词不正确!'; 75 | } 76 | }, 77 | { 78 | type: 'input', 79 | name: 'infura', 80 | message: '输入 Infura Key,可以在这里申请:https://infura.io/ :', 81 | when: function (answers) { 82 | return answers.mnemonic; 83 | } 84 | } 85 | ]) 86 | .then(answers => { 87 | if (answers.network === "ganache") { 88 | console.log("\033[33mRun:\033[39m " + "ganache-cli -e 1000"); 89 | argv = ["-e", "1000"]; 90 | spawn('ganache-cli', argv, { 91 | stdio: 'inherit', 92 | shell: true 93 | }); 94 | } else if (answers.network === "develop") { 95 | console.log("\033[33mRun:\033[39m " + "truffle develop"); 96 | argv = ['develop']; 97 | spawn('truffle', argv, { 98 | stdio: 'inherit', 99 | shell: true 100 | }); 101 | } else { 102 | writeFile('.mnemonic', answers.mnemonic); 103 | writeFile('.infuraKey', answers.infura); 104 | console.log("\033[33mRun:\033[39m " + "truffle console --network " + answers.network); 105 | argv = ["console", "--network", answers.network]; 106 | spawn('truffle', argv, { 107 | stdio: 'inherit', 108 | shell: true 109 | }); 110 | } 111 | }); 112 | } 113 | 114 | main(); -------------------------------------------------------------------------------- /script/test.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | var inquirer = require('inquirer'); 3 | const { spawn } = require('child_process'); 4 | 5 | const contractDir = 'test/'; 6 | getFiles = async (path) => { 7 | const dir = await fs.readdirSync(path, 'utf-8'); 8 | let files = [{name:'全部测试',value:'all'}]; 9 | dir.forEach(async (el, index) => { 10 | let stat = fs.statSync(path + el); 11 | if(el !== 'inc'){ 12 | if (stat.isDirectory()) { 13 | let dirFiles = await fs.readdirSync(path + el + '/', 'utf-8'); 14 | dirFiles.forEach((subel, index) => { 15 | files.push(el + '/' + subel); 16 | }) 17 | } else { 18 | files.push(el); 19 | } 20 | } 21 | }) 22 | return files; 23 | } 24 | main = async () => { 25 | const files = await getFiles(contractDir); 26 | 27 | inquirer.prompt([ 28 | { 29 | type: 'list', 30 | name: 'step1', 31 | message: '选择要测试的合约', 32 | choices: files, 33 | } 34 | ]) 35 | .then(answers => { 36 | let argv; 37 | if(answers.step1 !== 'all'){ 38 | console.log("\033[33mRun:\033[39m " + "truffle test " + contractDir + answers.step1); 39 | argv = ["mocha","--exit","--recursive",contractDir + answers.step1]; 40 | //argv = ["truffle","test",contractDir + answers.step1]; 41 | }else{ 42 | argv = ["mocha","--exit","--recursive"]; 43 | //argv = ["truffle","test"]; 44 | console.log("\033[33mRun:\033[39m " + "truffle test "); 45 | } 46 | spawn("npx",argv, { 47 | stdio: 'inherit', 48 | shell: true 49 | }); 50 | 51 | }); 52 | } 53 | 54 | main(); -------------------------------------------------------------------------------- /test-environment.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | accounts: { 3 | amount: 10, // Number of unlocked accounts 4 | ether: 1000, // Initial balance of unlocked accounts (in ether) 5 | }, 6 | 7 | contracts: { 8 | type: 'truffle', // Contract abstraction to use: 'truffle' for @truffle/contract or 'web3' for web3-eth-contract 9 | defaultGas: 6e6, // Maximum gas for contract calls (when unspecified) 10 | 11 | // Options available since v0.1.2 12 | defaultGasPrice: 20e9, // Gas price for contract calls (when unspecified) 13 | artifactsDir: 'build/contracts', // Directory where contract artifacts are stored 14 | }, 15 | 16 | node: { // Options passed directly to Ganache client 17 | gasLimit: 8e6, // Maximum gas per block 18 | gasPrice: 20e9 // Sets the default gas price for transactions if not otherwise specified. 19 | }, 20 | }; -------------------------------------------------------------------------------- /test/Crowdsale/AllowanceCrowdsale.js: -------------------------------------------------------------------------------- 1 | const { contract, accounts,web3 } = require('@openzeppelin/test-environment'); 2 | const { ether, time, constants } = require('@openzeppelin/test-helpers'); 3 | const CrowdsaleContract = contract.fromArtifact("AllowanceCrowdsaleContract"); 4 | const ERC20Contract = contract.fromArtifact("ERC20FixedSupply"); 5 | const ERC20 = require('../inc/ERC20'); 6 | const Crowdsale = require('../inc/Crowdsale'); 7 | //通用的众筹合约 8 | const totalSupply = '10000';//发行总量 9 | [owner, sender, receiver, purchaser, beneficiary] = accounts; 10 | EthValue = '10'; 11 | rate = '1000'; 12 | TokenValue = (EthValue * rate).toString(); 13 | describe("布署合约", function () { 14 | it('布署代币合约', async function () { 15 | ERC20Param = [ 16 | "My Golden Coin", //代币名称 17 | "MGC", //代币缩写 18 | 18, //精度 19 | totalSupply //发行总量 20 | ]; 21 | ERC20Instance = await ERC20Contract.new(...ERC20Param, { from: owner }); 22 | }); 23 | it('布署众筹合约', async function () { 24 | CrowdsaleParam = [ 25 | rate, //兑换比例1ETH:100ERC20 26 | sender, //接收ETH受益人地址 27 | ERC20Instance.address, //代币地址 28 | owner, //代币从这个地址发送 29 | ] 30 | CrowdsaleInstance = await CrowdsaleContract.new(...CrowdsaleParam, { from: owner }); 31 | }); 32 | }); 33 | describe("布署后首先执行", function () { 34 | it('将代币批准给众筹合约', async function () { 35 | await ERC20Instance.approve(CrowdsaleInstance.address, ether(totalSupply), { from: owner }); 36 | }); 37 | }); 38 | describe("测试ERC20合约基本信息", function () { 39 | ERC20.detail(); 40 | }); 41 | describe("测试通用的众筹方法", function () { 42 | Crowdsale.token(); 43 | Crowdsale.wallet(sender); 44 | Crowdsale.rate(rate); 45 | Crowdsale.tokenWallet(owner); 46 | Crowdsale.buyTokens(purchaser, EthValue, '购买代币'); 47 | Crowdsale.weiRaised(EthValue, '众筹收入为'+EthValue); 48 | ERC20.balanceOf(TokenValue.toString(), purchaser, '购买者账户余额为'+TokenValue) 49 | Crowdsale.remainingTokens(totalSupply - TokenValue,'配额中剩余的代币数量'); 50 | }); -------------------------------------------------------------------------------- /test/Crowdsale/CappedCrowdsale.js: -------------------------------------------------------------------------------- 1 | const { contract, accounts,web3 } = require('@openzeppelin/test-environment'); 2 | const { ether, time, constants } = require('@openzeppelin/test-helpers'); 3 | const CrowdsaleContract = contract.fromArtifact("CappedCrowdsaleContract"); 4 | const ERC20Contract = contract.fromArtifact("ERC20FixedSupply"); 5 | const ERC20 = require('../inc/ERC20'); 6 | const Crowdsale = require('../inc/Crowdsale'); 7 | //有封顶的众筹合约 8 | const totalSupply = '100000000';//发行总量 9 | [owner, sender, receiver, purchaser, beneficiary] = accounts; 10 | EthValue = '10'; 11 | rate = '1000'; 12 | const cap = '20'; //封顶数额 13 | TokenValue = (EthValue * rate).toString(); 14 | describe("有封顶的众筹合约", function () { 15 | it('布署代币合约', async function () { 16 | ERC20Param = [ 17 | "My Golden Coin", //代币名称 18 | "MGC", //代币缩写 19 | 18, //精度 20 | totalSupply //发行总量 21 | ]; 22 | ERC20Instance = await ERC20Contract.new(...ERC20Param, { from: owner }); 23 | }); 24 | it('布署众筹合约', async function () { 25 | CrowdsaleParam = [ 26 | rate, //兑换比例1ETH:100ERC20 27 | sender, //接收ETH受益人地址 28 | ERC20Instance.address, //代币地址 29 | owner, //代币从这个地址发送 30 | ether(cap) //封顶数额 31 | ] 32 | CrowdsaleInstance = await CrowdsaleContract.new(...CrowdsaleParam, { from: owner }); 33 | }); 34 | }); 35 | describe("布署后首先执行", function () { 36 | it('将代币批准给众筹合约', async function () { 37 | await ERC20Instance.approve(CrowdsaleInstance.address, ether(totalSupply), { from: owner }); 38 | }); 39 | }); 40 | describe("测试ERC20合约基本信息", function () { 41 | ERC20.detail(); 42 | }); 43 | describe("测试通用的众筹方法", function () { 44 | Crowdsale.token(); 45 | Crowdsale.wallet(sender); 46 | Crowdsale.rate(rate); 47 | Crowdsale.tokenWallet(owner); 48 | Crowdsale.buyTokens(purchaser, EthValue, '购买代币'); 49 | Crowdsale.weiRaised(EthValue, '众筹收入为'+EthValue); 50 | ERC20.balanceOf(TokenValue.toString(), purchaser, '购买者账户余额为'+TokenValue) 51 | Crowdsale.remainingTokens(totalSupply - TokenValue,'配额中剩余的代币数量'); 52 | }); 53 | describe("测试众筹合约的封顶方法", function () { 54 | Crowdsale.cap(cap);// 55 | Crowdsale.capReached(false, '众筹没有到达封顶');// 56 | Crowdsale.buyTokens(beneficiary, cap, '超额购买代币', true, /CappedCrowdsale: cap exceeded/); 57 | Crowdsale.buyTokens(beneficiary, EthValue, '购买代币'); 58 | Crowdsale.capReached(true, '众筹已经到达封顶');// 59 | }); -------------------------------------------------------------------------------- /test/Crowdsale/FinalizableCrowdsale.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | const { contract, accounts,web3 } = require('@openzeppelin/test-environment'); 3 | const { ether, time, constants } = require('@openzeppelin/test-helpers'); 4 | const CrowdsaleContract = contract.fromArtifact("FinalizableCrowdsaleContract"); 5 | const ERC20Contract = contract.fromArtifact("ERC20FixedSupply"); 6 | const ERC20 = require('../inc/ERC20'); 7 | const Crowdsale = require('../inc/Crowdsale'); 8 | //可终结的众筹 9 | const totalSupply = '10000';//发行总量 10 | [owner, sender, receiver, purchaser, beneficiary] = accounts; 11 | EthValue = '10'; 12 | rate = '1000'; 13 | TokenValue = (EthValue * rate).toString(); 14 | describe("可终结的众筹", function () { 15 | it('布署代币合约', async function () { 16 | ERC20Param = [ 17 | "My Golden Coin", //代币名称 18 | "MGC", //代币缩写 19 | 18, //精度 20 | totalSupply //发行总量 21 | ]; 22 | ERC20Instance = await ERC20Contract.new(...ERC20Param, { from: owner }); 23 | }); 24 | it('布署众筹合约', async function () { 25 | openingTime = parseInt(await time.latest()) + 60; 26 | closingTime = parseInt(await time.latest()) + 600; 27 | CrowdsaleParam = [ 28 | rate, //兑换比例1ETH:100ERC20 29 | sender, //接收ETH受益人地址 30 | ERC20Instance.address, //代币地址 31 | owner, //代币从这个地址发送 32 | openingTime, //众筹开始时间 33 | closingTime, //众筹结束时间 34 | ] 35 | CrowdsaleInstance = await CrowdsaleContract.new(...CrowdsaleParam, { from: owner }); 36 | }); 37 | }); 38 | describe("布署后首先执行", function () { 39 | it('将代币批准给众筹合约', async function () { 40 | await ERC20Instance.approve(CrowdsaleInstance.address, ether(totalSupply), { from: owner }); 41 | }); 42 | }); 43 | describe("测试ERC20合约基本信息", function () { 44 | ERC20.detail(); 45 | }); 46 | describe("测试通用的众筹方法", function () { 47 | Crowdsale.token(); 48 | Crowdsale.wallet(sender); 49 | Crowdsale.rate(rate); 50 | Crowdsale.tokenWallet(owner); 51 | }); 52 | describe("测试众筹结束的方法", function () { 53 | Crowdsale.finalized(false, '验证众筹未结束'); 54 | Crowdsale.finalize('验证众筹未到期无法结束', true, /FinalizableCrowdsale: not closed/);// 55 | }); 56 | describe("测试有时限众筹合约的特殊方法", async function () { 57 | it('验证开始时间: openingTime()', async function () { 58 | assert.equal(openingTime, await CrowdsaleInstance.openingTime()); 59 | }); 60 | it('验证结束时间: closingTime()', async function () { 61 | assert.equal(closingTime, await CrowdsaleInstance.closingTime()); 62 | }); 63 | Crowdsale.isOpen(false, '验证合约未开始'); 64 | Crowdsale.hasClosed(false, '验证未到期'); 65 | Crowdsale.buyTokens(purchaser, EthValue, '开始前购买代币错误',true,/TimedCrowdsale: not open/); 66 | it('推进时间到众筹开始时间: time.increaseTo(openingTime)', async function () { 67 | await time.increaseTo(openingTime); 68 | }); 69 | Crowdsale.isOpen(true, '验证合约已开始'); 70 | Crowdsale.buyTokens(purchaser, EthValue, '购买代币'); 71 | Crowdsale.weiRaised(EthValue, '众筹收入为'+EthValue); 72 | ERC20.balanceOf(TokenValue.toString(), purchaser, '购买者账户余额为'+TokenValue) 73 | Crowdsale.remainingTokens(totalSupply - TokenValue,'配额中剩余的代币数量'); 74 | it('推进时间到众筹结束时间: time.increaseTo(closingTime)', async function () { 75 | await time.increaseTo(closingTime + 1); 76 | }); 77 | Crowdsale.hasClosed(true, '验证众筹已到期'); 78 | Crowdsale.finalize('验证众筹到期触发结束'); 79 | Crowdsale.finalized(true, '验证众筹已结束'); 80 | Crowdsale.buyTokens(purchaser, EthValue, '结束后购买代币错误',true,/TimedCrowdsale: not open/); 81 | }); -------------------------------------------------------------------------------- /test/Crowdsale/IndividuallyCappedCrowdsale.js: -------------------------------------------------------------------------------- 1 | const { contract, accounts,web3 } = require('@openzeppelin/test-environment'); 2 | const { ether, time, constants } = require('@openzeppelin/test-helpers'); 3 | const CrowdsaleContract = contract.fromArtifact("IndividuallyCappedCrowdsaleContract"); 4 | const ERC20Contract = contract.fromArtifact("ERC20FixedSupply"); 5 | const ERC20 = require('../inc/ERC20'); 6 | const Crowdsale = require('../inc/Crowdsale'); 7 | //有配额众筹 8 | const totalSupply = '10000';//发行总量 9 | [owner, sender, receiver, purchaser, beneficiary] = accounts; 10 | EthValue = '10'; 11 | rate = '1000'; 12 | TokenValue = (EthValue * rate).toString(); 13 | describe("有配额众筹", function () { 14 | it('布署代币合约', async function () { 15 | ERC20Param = [ 16 | "My Golden Coin", //代币名称 17 | "MGC", //代币缩写 18 | 18, //精度 19 | totalSupply //发行总量 20 | ]; 21 | ERC20Instance = await ERC20Contract.new(...ERC20Param, { from: owner }); 22 | }); 23 | it('布署众筹合约', async function () { 24 | CrowdsaleParam = [ 25 | rate, //兑换比例1ETH:100ERC20 26 | sender, //接收ETH受益人地址 27 | ERC20Instance.address, //代币地址 28 | owner, //代币从这个地址发送 29 | ] 30 | CrowdsaleInstance = await CrowdsaleContract.new(...CrowdsaleParam, { from: owner }); 31 | }); 32 | }); 33 | describe("布署后首先执行", function () { 34 | it('将代币批准给众筹合约', async function () { 35 | await ERC20Instance.approve(CrowdsaleInstance.address, ether(totalSupply), { from: owner }); 36 | }); 37 | }); 38 | describe("测试ERC20合约基本信息", function () { 39 | ERC20.detail(); 40 | }); 41 | describe("测试通用的众筹方法", function () { 42 | Crowdsale.token(); 43 | Crowdsale.wallet(sender); 44 | Crowdsale.rate(rate); 45 | Crowdsale.tokenWallet(owner); 46 | }); 47 | describe("测试设置配额管理员的方法", function () { 48 | Crowdsale.addCapper(sender, sender, '无权添加配额管理员错误', true, /CapperRole: caller does not have the Capper role/); 49 | Crowdsale.addCapper(sender, owner, '添加配额管理员'); 50 | Crowdsale.addCapper(sender, owner, '重复添加配额管理员错误', true, /Roles: account already has role/); 51 | Crowdsale.isCapper(sender, true, '验证账户是配额管理员'); 52 | Crowdsale.renounceCapper(sender, '撤销配额管理员'); 53 | Crowdsale.isCapper(sender, false, '验证账户不是配额管理员'); 54 | Crowdsale.renounceCapper(sender, '重复撤销配额管理员错误', true, /Roles: account does not have role/); 55 | }); 56 | describe("测试众筹合约的配额管理方法", function () { 57 | Crowdsale.setCap(sender, owner, EthValue, '设置配额'); 58 | Crowdsale.setCap(purchaser, sender, EthValue, '无权设置配额', true, /CapperRole: caller does not have the Capper role/); 59 | Crowdsale.getCap(sender, EthValue, '验证账户配额'); 60 | Crowdsale.getContribution(sender, '0', '验证账户贡献为0');// 61 | 62 | Crowdsale.buyTokens(sender, EthValue, '购买代币'); 63 | Crowdsale.weiRaised(EthValue, '众筹收入为'+EthValue); 64 | ERC20.balanceOf(TokenValue.toString(), sender, '购买者账户余额为'+TokenValue) 65 | Crowdsale.remainingTokens(totalSupply - TokenValue,'配额中剩余的代币数量'); 66 | Crowdsale.getContribution(sender, EthValue, '验证账户贡献为'+EthValue);// 67 | 68 | }); -------------------------------------------------------------------------------- /test/Crowdsale/MintedCrowdsale.js: -------------------------------------------------------------------------------- 1 | const { contract, accounts, web3 } = require('@openzeppelin/test-environment'); 2 | const { ether, time, constants } = require('@openzeppelin/test-helpers'); 3 | const CrowdsaleContract = contract.fromArtifact("MintedCrowdsaleContract"); 4 | const ERC20Contract = contract.fromArtifact("ERC20WithMintable"); 5 | const ERC20 = require('../inc/ERC20'); 6 | const Crowdsale = require('../inc/Crowdsale'); 7 | //可增发的众筹 8 | const totalSupply = '10000';//发行总量 9 | [owner, sender, receiver, purchaser, beneficiary] = accounts; 10 | EthValue = '10'; 11 | rate = '1000'; 12 | TokenValue = (EthValue * rate).toString(); 13 | describe("可增发的众筹", function () { 14 | it('布署代币合约', async function () { 15 | ERC20Param = [ 16 | "My Golden Coin", //代币名称 17 | "MGC", //代币缩写 18 | 18, //精度 19 | totalSupply //发行总量 20 | ]; 21 | ERC20Instance = await ERC20Contract.new(...ERC20Param, { from: owner }); 22 | }); 23 | it('布署众筹合约', async function () { 24 | CrowdsaleParam = [ 25 | rate, //兑换比例1ETH:100ERC20 26 | sender, //接收ETH受益人地址 27 | ERC20Instance.address, //代币地址 28 | ] 29 | CrowdsaleInstance = await CrowdsaleContract.new(...CrowdsaleParam, { from: owner }); 30 | }); 31 | }); 32 | describe("布署后首先执行", function () { 33 | it('将代币批准给众筹合约', async function () { 34 | await ERC20Instance.approve(CrowdsaleInstance.address, ether(totalSupply.toString()), { from: owner }); 35 | }); 36 | it('添加众筹合约的铸造权: addMinter()', async function () { 37 | await ERC20Instance.addMinter(CrowdsaleInstance.address, { from: owner }); 38 | }); 39 | ERC20.renounceMinter(owner, '撤销发送者的铸造权'); 40 | }); 41 | describe("测试ERC20合约基本信息", function () { 42 | ERC20.detail(); 43 | }); 44 | describe("测试通用的众筹方法", function () { 45 | Crowdsale.token(); 46 | Crowdsale.wallet(sender); 47 | Crowdsale.rate(rate); 48 | }); 49 | describe("测试众筹合约的铸币方法", function () { 50 | Crowdsale.buyTokens(purchaser, EthValue, '购买代币'); 51 | Crowdsale.weiRaised(EthValue, '众筹收入为' + EthValue); 52 | ERC20.balanceOf(TokenValue.toString(), purchaser, '购买者账户余额为' + TokenValue); 53 | const totalSupplyNow = parseInt(totalSupply) + parseInt(TokenValue); 54 | ERC20.totalSupply(totalSupplyNow.toString()); 55 | }); -------------------------------------------------------------------------------- /test/Crowdsale/PausableCrowdsale.js: -------------------------------------------------------------------------------- 1 | const { contract, accounts,web3 } = require('@openzeppelin/test-environment'); 2 | const { ether, time, constants } = require('@openzeppelin/test-helpers'); 3 | const CrowdsaleContract = contract.fromArtifact("PausableCrowdsaleContract"); 4 | const ERC20Contract = contract.fromArtifact("ERC20FixedSupply"); 5 | const ERC20 = require('../inc/ERC20'); 6 | const Crowdsale = require('../inc/Crowdsale'); 7 | //可暂停的众筹 8 | const totalSupply = '10000';//发行总量 9 | [owner, sender, receiver, purchaser, beneficiary] = accounts; 10 | EthValue = '10'; 11 | rate = '1000'; 12 | TokenValue = (EthValue * rate).toString(); 13 | describe("可暂停的众筹", function () { 14 | it('布署代币合约', async function () { 15 | ERC20Param = [ 16 | "My Golden Coin", //代币名称 17 | "MGC", //代币缩写 18 | 18, //精度 19 | totalSupply //发行总量 20 | ]; 21 | ERC20Instance = await ERC20Contract.new(...ERC20Param, { from: owner }); 22 | }); 23 | it('布署众筹合约', async function () { 24 | CrowdsaleParam = [ 25 | rate, //兑换比例1ETH:100ERC20 26 | sender, //接收ETH受益人地址 27 | ERC20Instance.address, //代币地址 28 | owner, //代币从这个地址发送 29 | ] 30 | CrowdsaleInstance = await CrowdsaleContract.new(...CrowdsaleParam, { from: owner }); 31 | }); 32 | }); 33 | describe("布署后首先执行", function () { 34 | it('将代币批准给众筹合约', async function () { 35 | await ERC20Instance.approve(CrowdsaleInstance.address, ether(totalSupply), { from: owner }); 36 | }); 37 | }); 38 | describe("测试ERC20合约基本信息", function () { 39 | ERC20.detail(); 40 | }); 41 | describe("测试通用的众筹方法", function () { 42 | Crowdsale.token(); 43 | Crowdsale.wallet(sender); 44 | Crowdsale.rate(rate); 45 | Crowdsale.tokenWallet(owner); 46 | Crowdsale.buyTokens(purchaser, EthValue, '购买代币'); 47 | Crowdsale.weiRaised(EthValue, '众筹收入为'+EthValue); 48 | ERC20.balanceOf(TokenValue.toString(), purchaser, '购买者账户余额为'+TokenValue) 49 | Crowdsale.remainingTokens(totalSupply - TokenValue,'配额中剩余的代币数量'); 50 | }); 51 | 52 | describe("测试设置暂停管理员的方法", function () { 53 | Crowdsale.addPauser(sender, sender, '无权添加暂停管理员错误', true, /PauserRole: caller does not have the Pauser role/); 54 | Crowdsale.addPauser(sender, owner, '添加暂停管理员'); 55 | Crowdsale.addPauser(sender, owner, '重复添加暂停管理员错误', true, /Roles: account already has role/); 56 | Crowdsale.isPauser(sender, true, '验证账户是暂停管理员'); 57 | Crowdsale.renouncePauser(sender, '撤销暂停管理员'); 58 | Crowdsale.isPauser(sender, false, '验证账户不是暂停管理员'); 59 | Crowdsale.renouncePauser(sender, '重复撤销暂停管理员错误', true, /Roles: account does not have role/); 60 | }); 61 | describe("测试众筹合约的暂停管理方法", function () {// 62 | Crowdsale.paused(false, '验证合约未暂停'); 63 | Crowdsale.pause(owner, '暂停合约'); 64 | Crowdsale.paused(true, '验证合约已暂停'); 65 | Crowdsale.pause(owner, '验证重复暂停错误', true, /Pausable: paused/); 66 | Crowdsale.pause(sender, '验证无权暂停错误', true, /PauserRole: caller does not have the Pauser role/); 67 | Crowdsale.buyTokens(purchaser, EthValue, '购买代币错误', true, /Pausable: paused/); 68 | Crowdsale.unpause(owner, '恢复暂停合约'); 69 | Crowdsale.paused(false, '验证合约未暂停'); 70 | Crowdsale.unpause(owner, '验证重复恢复暂停错误', true, /Pausable: not paused/); 71 | Crowdsale.unpause(sender, '验证无权恢复暂停错误', true, /PauserRole: caller does not have the Pauser role/); 72 | }); 73 | -------------------------------------------------------------------------------- /test/Crowdsale/PostDeliveryCrowdsale.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | const { contract, accounts,web3 } = require('@openzeppelin/test-environment'); 3 | const { ether, time, constants } = require('@openzeppelin/test-helpers'); 4 | const CrowdsaleContract = contract.fromArtifact("PostDeliveryCrowdsaleContract"); 5 | const ERC20Contract = contract.fromArtifact("ERC20FixedSupply"); 6 | const ERC20 = require('../inc/ERC20'); 7 | const Crowdsale = require('../inc/Crowdsale'); 8 | //到期后交付的众筹 9 | const totalSupply = '10000';//发行总量 10 | [owner, sender, receiver, purchaser, beneficiary] = accounts; 11 | EthValue = '10'; 12 | rate = '1000'; 13 | TokenValue = (EthValue * rate).toString(); 14 | describe("到期后交付的众筹", function () { 15 | it('布署代币合约', async function () { 16 | ERC20Param = [ 17 | "My Golden Coin", //代币名称 18 | "MGC", //代币缩写 19 | 18, //精度 20 | totalSupply //发行总量 21 | ]; 22 | ERC20Instance = await ERC20Contract.new(...ERC20Param, { from: owner }); 23 | }); 24 | it('布署众筹合约', async function () { 25 | openingTime = parseInt(await time.latest()) + 60; 26 | closingTime = parseInt(await time.latest()) + 600; 27 | CrowdsaleParam = [ 28 | rate, //兑换比例1ETH:100ERC20 29 | sender, //接收ETH受益人地址 30 | ERC20Instance.address, //代币地址 31 | owner, //代币从这个地址发送 32 | openingTime, //众筹开始时间 33 | closingTime, //众筹结束时间 34 | ] 35 | CrowdsaleInstance = await CrowdsaleContract.new(...CrowdsaleParam, { from: owner }); 36 | }); 37 | }); 38 | describe("布署后首先执行", function () { 39 | it('将代币批准给众筹合约', async function () { 40 | await ERC20Instance.approve(CrowdsaleInstance.address, ether(totalSupply), { from: owner }); 41 | }); 42 | }); 43 | describe("测试ERC20合约基本信息", function () { 44 | ERC20.detail(); 45 | }); 46 | describe("测试通用的众筹方法", function () { 47 | Crowdsale.token(); 48 | Crowdsale.wallet(sender); 49 | Crowdsale.rate(rate); 50 | Crowdsale.tokenWallet(owner); 51 | }); 52 | 53 | describe("测试众筹合约的方法", async function () { 54 | it('验证开始时间: openingTime()', async function () { 55 | assert.equal(openingTime, await CrowdsaleInstance.openingTime()); 56 | }); 57 | it('验证结束时间: closingTime()', async function () { 58 | assert.equal(closingTime, await CrowdsaleInstance.closingTime()); 59 | }); 60 | Crowdsale.isOpen(false, '验证合约未开始'); 61 | Crowdsale.hasClosed(false, '验证未到期'); 62 | Crowdsale.buyTokens(purchaser, EthValue, '开始前购买代币错误',true,/TimedCrowdsale: not open/); 63 | it('推进时间到众筹开始时间: time.increaseTo(openingTime)', async function () { 64 | await time.increaseTo(openingTime); 65 | }); 66 | Crowdsale.isOpen(true, '验证合约已开始'); 67 | Crowdsale.buyTokens(purchaser, EthValue, '购买代币'); 68 | Crowdsale.weiRaised(EthValue, '众筹收入为'+EthValue); 69 | ERC20.balanceOf('0', purchaser, '购买者账户余额为0'); 70 | Crowdsale.balanceOf(TokenValue.toString(), purchaser, '验证账户在众筹合约的余额为' + TokenValue); 71 | Crowdsale.withdrawTokens(purchaser, '验证众筹未结束账户无法提款', true, /PostDeliveryCrowdsale: not closed/); 72 | Crowdsale.remainingTokens(totalSupply - TokenValue,'配额中剩余的代币数量'); 73 | it('推进时间到众筹结束时间: time.increaseTo(closingTime)', async function () { 74 | await time.increaseTo(closingTime + 1); 75 | }); 76 | Crowdsale.withdrawTokens(purchaser, '验证众筹结束后提款'); 77 | ERC20.balanceOf(TokenValue, purchaser, '购买者账户余额为' + TokenValue); 78 | Crowdsale.balanceOf('0', beneficiary, '验证账户在众筹合约的余额为0'); 79 | Crowdsale.hasClosed(true, '验证众筹已到期'); 80 | Crowdsale.buyTokens(purchaser, EthValue, '结束后购买代币错误',true,/TimedCrowdsale: not open/); 81 | }); 82 | -------------------------------------------------------------------------------- /test/Crowdsale/RefundableCrowdsaleNotReach.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | const { contract, accounts,web3 } = require('@openzeppelin/test-environment'); 3 | const { ether, time, constants } = require('@openzeppelin/test-helpers'); 4 | const CrowdsaleContract = contract.fromArtifact("RefundableCrowdsaleContract"); 5 | const ERC20Contract = contract.fromArtifact("ERC20FixedSupply"); 6 | const ERC20 = require('../inc/ERC20'); 7 | const Crowdsale = require('../inc/Crowdsale'); 8 | //不成功退款的众筹合约(众筹不成功) 9 | const totalSupply = '10000';//发行总量 10 | [owner, sender, receiver, purchaser, beneficiary] = accounts; 11 | EthValue = '10'; 12 | const goal = '15'; 13 | rate = '1000'; 14 | TokenValue = (EthValue * rate).toString(); 15 | describe("不成功退款的众筹合约(众筹不成功)", function () { 16 | it('布署代币合约', async function () { 17 | ERC20Param = [ 18 | "My Golden Coin", //代币名称 19 | "MGC", //代币缩写 20 | 18, //精度 21 | totalSupply //发行总量 22 | ]; 23 | ERC20Instance = await ERC20Contract.new(...ERC20Param, { from: owner }); 24 | }); 25 | it('布署众筹合约', async function () { 26 | openingTime = parseInt(await time.latest()) + 60; 27 | closingTime = parseInt(await time.latest()) + 600; 28 | CrowdsaleParam = [ 29 | rate, //兑换比例1ETH:100ERC20 30 | sender, //接收ETH受益人地址 31 | ERC20Instance.address, //代币地址 32 | owner, //代币从这个地址发送 33 | openingTime, //众筹开始时间 34 | closingTime, //众筹结束时间 35 | ether(goal), //众筹目标 36 | ] 37 | CrowdsaleInstance = await CrowdsaleContract.new(...CrowdsaleParam, { from: owner }); 38 | }); 39 | }); 40 | describe("布署后首先执行", function () { 41 | it('将代币批准给众筹合约', async function () { 42 | await ERC20Instance.approve(CrowdsaleInstance.address, ether(totalSupply), { from: owner }); 43 | }); 44 | }); 45 | describe("测试ERC20合约基本信息", function () { 46 | ERC20.detail(); 47 | }); 48 | describe("测试通用的众筹方法", function () { 49 | Crowdsale.token(); 50 | Crowdsale.wallet(sender); 51 | Crowdsale.rate(rate); 52 | Crowdsale.tokenWallet(owner); 53 | }); 54 | 55 | describe("测试众筹合约的时限方法", async function () { 56 | it('验证开始时间: openingTime()', async function () { 57 | assert.equal(openingTime, await CrowdsaleInstance.openingTime()); 58 | }); 59 | it('验证结束时间: closingTime()', async function () { 60 | assert.equal(closingTime, await CrowdsaleInstance.closingTime()); 61 | }); 62 | Crowdsale.isOpen(false, '验证合约未开始'); 63 | Crowdsale.hasClosed(false, '验证未到期'); 64 | Crowdsale.buyTokens(purchaser, EthValue, '开始前购买代币错误',true,/TimedCrowdsale: not open/); 65 | it('推进时间到众筹开始时间: time.increaseTo(openingTime)', async function () { 66 | await time.increaseTo(openingTime); 67 | }); 68 | Crowdsale.isOpen(true, '验证合约已开始'); 69 | Crowdsale.buyTokens(purchaser, EthValue, '购买代币'); 70 | Crowdsale.weiRaised(EthValue, '众筹收入为'+EthValue); 71 | ERC20.balanceOf('0', purchaser, '购买者账户余额为0'); 72 | Crowdsale.balanceOf(TokenValue.toString(), purchaser, '验证账户在众筹合约的余额为' + TokenValue); 73 | Crowdsale.withdrawTokens(purchaser, '验证众筹未结束账户无法提款', true, /RefundablePostDeliveryCrowdsale: not finalized/); 74 | Crowdsale.remainingTokens(totalSupply - TokenValue,'配额中剩余的代币数量'); 75 | Crowdsale.claimRefund(owner, '众筹未结束不能退款', true, /RefundableCrowdsale: not finalized/); 76 | it('推进时间到众筹结束时间: time.increaseTo(closingTime)', async function () { 77 | await time.increaseTo(closingTime + 1); 78 | }); 79 | it('记录purchaser余额', async function () { 80 | purchaserBalance = await web3.eth.getBalance(purchaser); 81 | }); 82 | ERC20.balanceOf('0', purchaser, '购买者账户余额为0'); 83 | Crowdsale.balanceOf(TokenValue, purchaser, '验证账户在众筹合约的余额为0'); 84 | Crowdsale.hasClosed(true, '验证众筹已到期'); 85 | Crowdsale.finalize('验证众筹到期触发结束'); 86 | Crowdsale.finalized(true, '验证众筹已结束'); 87 | Crowdsale.withdrawTokens(purchaser, '验证众筹结束后提款错误',true,/RefundablePostDeliveryCrowdsale: goal not reached/); 88 | Crowdsale.goalReached(false, '验证没有到达众筹目标');// 89 | Crowdsale.buyTokens(purchaser, EthValue, '结束后购买代币错误',true,/TimedCrowdsale: not open/); 90 | Crowdsale.claimRefund(purchaser, '众筹结束未到目标退款'); 91 | 92 | it('验证purchaser的ETH余额增加' + EthValue, async function () { 93 | let _purchaserBalance = Math.ceil(web3.utils.fromWei((await web3.eth.getBalance(purchaser) - purchaserBalance).toString(), 'ether')); 94 | assert.equal(EthValue, _purchaserBalance); 95 | }); 96 | }); 97 | 98 | 99 | -------------------------------------------------------------------------------- /test/Crowdsale/RefundableCrowdsaleReached.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | const { contract, accounts,web3 } = require('@openzeppelin/test-environment'); 3 | const { ether, time, constants } = require('@openzeppelin/test-helpers'); 4 | const CrowdsaleContract = contract.fromArtifact("RefundableCrowdsaleContract"); 5 | const ERC20Contract = contract.fromArtifact("ERC20FixedSupply"); 6 | const ERC20 = require('../inc/ERC20'); 7 | const Crowdsale = require('../inc/Crowdsale'); 8 | //不成功退款的众筹合约(众筹成功) 9 | const totalSupply = '10000';//发行总量 10 | [owner, sender, receiver, purchaser, beneficiary] = accounts; 11 | EthValue = '10'; 12 | const goal = '10'; 13 | rate = '1000'; 14 | TokenValue = (EthValue * rate).toString(); 15 | describe("不成功退款的众筹合约(众筹成功)", function () { 16 | it('布署代币合约', async function () { 17 | ERC20Param = [ 18 | "My Golden Coin", //代币名称 19 | "MGC", //代币缩写 20 | 18, //精度 21 | totalSupply //发行总量 22 | ]; 23 | ERC20Instance = await ERC20Contract.new(...ERC20Param, { from: owner }); 24 | }); 25 | it('布署众筹合约', async function () { 26 | openingTime = parseInt(await time.latest()) + 60; 27 | closingTime = parseInt(await time.latest()) + 600; 28 | CrowdsaleParam = [ 29 | rate, //兑换比例1ETH:100ERC20 30 | sender, //接收ETH受益人地址 31 | ERC20Instance.address, //代币地址 32 | owner, //代币从这个地址发送 33 | openingTime, //众筹开始时间 34 | closingTime, //众筹结束时间 35 | ether(goal), //众筹目标 36 | ] 37 | CrowdsaleInstance = await CrowdsaleContract.new(...CrowdsaleParam, { from: owner }); 38 | }); 39 | }); 40 | describe("布署后首先执行", function () { 41 | it('将代币批准给众筹合约', async function () { 42 | await ERC20Instance.approve(CrowdsaleInstance.address, ether(totalSupply), { from: owner }); 43 | }); 44 | }); 45 | describe("测试ERC20合约基本信息", function () { 46 | ERC20.detail(); 47 | }); 48 | describe("测试通用的众筹方法", function () { 49 | Crowdsale.token(); 50 | Crowdsale.wallet(sender); 51 | Crowdsale.rate(rate); 52 | Crowdsale.tokenWallet(owner); 53 | }); 54 | 55 | describe("测试众筹合约的时限方法", async function () { 56 | it('验证开始时间: openingTime()', async function () { 57 | assert.equal(openingTime, await CrowdsaleInstance.openingTime()); 58 | }); 59 | it('验证结束时间: closingTime()', async function () { 60 | assert.equal(closingTime, await CrowdsaleInstance.closingTime()); 61 | }); 62 | Crowdsale.isOpen(false, '验证合约未开始'); 63 | Crowdsale.hasClosed(false, '验证未到期'); 64 | Crowdsale.buyTokens(purchaser, EthValue, '开始前购买代币错误',true,/TimedCrowdsale: not open/); 65 | it('推进时间到众筹开始时间: time.increaseTo(openingTime)', async function () { 66 | await time.increaseTo(openingTime); 67 | }); 68 | Crowdsale.isOpen(true, '验证合约已开始'); 69 | Crowdsale.buyTokens(purchaser, EthValue, '购买代币'); 70 | Crowdsale.weiRaised(EthValue, '众筹收入为'+EthValue); 71 | ERC20.balanceOf('0', purchaser, '购买者账户余额为0'); 72 | Crowdsale.balanceOf(TokenValue.toString(), purchaser, '验证账户在众筹合约的余额为' + TokenValue); 73 | Crowdsale.withdrawTokens(purchaser, '验证众筹未结束账户无法提款', true, /RefundablePostDeliveryCrowdsale: not finalized/); 74 | Crowdsale.remainingTokens(totalSupply - TokenValue,'配额中剩余的代币数量'); 75 | Crowdsale.claimRefund(owner, '众筹未结束不能退款', true, /RefundableCrowdsale: not finalized/); 76 | it('推进时间到众筹结束时间: time.increaseTo(closingTime)', async function () { 77 | await time.increaseTo(closingTime + 1); 78 | }); 79 | it('记录purchaser余额', async function () { 80 | purchaserBalance = await web3.eth.getBalance(purchaser); 81 | }); 82 | ERC20.balanceOf('0', purchaser, '购买者账户余额为0'); 83 | Crowdsale.balanceOf(TokenValue, purchaser, '验证账户在众筹合约的余额为0'); 84 | Crowdsale.hasClosed(true, '验证众筹已到期'); 85 | Crowdsale.finalize('验证众筹到期触发结束'); 86 | Crowdsale.finalized(true, '验证众筹已结束'); 87 | Crowdsale.withdrawTokens(purchaser, '验证众筹结束后提款'); 88 | Crowdsale.goalReached(true, '验证到达众筹目标');// 89 | Crowdsale.buyTokens(purchaser, EthValue, '结束后购买代币错误',true,/TimedCrowdsale: not open/); 90 | Crowdsale.claimRefund(purchaser, '众筹达到目标退款错误',true,/RefundableCrowdsale: goal reached/); 91 | 92 | it('验证purchaser的ETH余额增加0', async function () { 93 | let _purchaserBalance = parseInt(web3.utils.fromWei((await web3.eth.getBalance(purchaser) - purchaserBalance).toString(), 'ether')); 94 | assert.equal(0, _purchaserBalance); 95 | }); 96 | }); 97 | 98 | 99 | -------------------------------------------------------------------------------- /test/Crowdsale/TimedCrowdsale.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | const { contract, accounts,web3 } = require('@openzeppelin/test-environment'); 3 | const { ether, time, constants } = require('@openzeppelin/test-helpers'); 4 | const CrowdsaleContract = contract.fromArtifact("TimedCrowdsaleContract"); 5 | const ERC20Contract = contract.fromArtifact("ERC20FixedSupply"); 6 | const ERC20 = require('../inc/ERC20'); 7 | const Crowdsale = require('../inc/Crowdsale'); 8 | //有时限的众筹 9 | const totalSupply = '10000';//发行总量 10 | [owner, sender, receiver, purchaser, beneficiary] = accounts; 11 | EthValue = '10'; 12 | eth = '10'; 13 | rate = '1000'; 14 | TokenValue = (EthValue * rate).toString(); 15 | describe("有时限的众筹", function () { 16 | it('布署代币合约', async function () { 17 | ERC20Param = [ 18 | "My Golden Coin", //代币名称 19 | "MGC", //代币缩写 20 | 18, //精度 21 | totalSupply //发行总量 22 | ]; 23 | ERC20Instance = await ERC20Contract.new(...ERC20Param, { from: owner }); 24 | }); 25 | it('布署众筹合约', async function () { 26 | openingTime = parseInt(await time.latest()) + 60; 27 | closingTime = parseInt(await time.latest()) + 600; 28 | CrowdsaleParam = [ 29 | rate, //兑换比例1ETH:100ERC20 30 | sender, //接收ETH受益人地址 31 | ERC20Instance.address, //代币地址 32 | owner, //代币从这个地址发送 33 | openingTime, //众筹开始时间 34 | closingTime, //众筹结束时间 35 | ] 36 | CrowdsaleInstance = await CrowdsaleContract.new(...CrowdsaleParam, { from: owner }); 37 | }); 38 | }); 39 | describe("布署后首先执行", function () { 40 | it('将代币批准给众筹合约', async function () { 41 | await ERC20Instance.approve(CrowdsaleInstance.address, ether(totalSupply), { from: owner }); 42 | }); 43 | }); 44 | describe("测试ERC20合约基本信息", function () { 45 | ERC20.detail(); 46 | }); 47 | describe("测试通用的众筹方法", function () { 48 | Crowdsale.token(); 49 | Crowdsale.wallet(sender); 50 | Crowdsale.rate(rate); 51 | Crowdsale.tokenWallet(owner); 52 | }); 53 | describe("测试有时限众筹合约的特殊方法", async function () { 54 | it('验证开始时间: openingTime()', async function () { 55 | assert.equal(openingTime, await CrowdsaleInstance.openingTime()); 56 | }); 57 | it('验证结束时间: closingTime()', async function () { 58 | assert.equal(closingTime, await CrowdsaleInstance.closingTime()); 59 | }); 60 | Crowdsale.isOpen(false, '验证合约未开始'); 61 | Crowdsale.hasClosed(false, '验证未到期'); 62 | Crowdsale.buyTokens(purchaser, EthValue, '开始前购买代币错误',true,/TimedCrowdsale: not open/); 63 | it('推进时间到众筹开始时间: time.increaseTo(openingTime)', async function () { 64 | await time.increaseTo(openingTime); 65 | }); 66 | Crowdsale.isOpen(true, '验证合约已开始'); 67 | Crowdsale.buyTokens(purchaser, EthValue, '购买代币'); 68 | Crowdsale.weiRaised(EthValue, '众筹收入为'+EthValue); 69 | ERC20.balanceOf(TokenValue.toString(), purchaser, '购买者账户余额为'+TokenValue) 70 | Crowdsale.remainingTokens(totalSupply - TokenValue,'配额中剩余的代币数量'); 71 | it('推进时间到众筹结束时间: time.increaseTo(closingTime)', async function () { 72 | await time.increaseTo(closingTime + 1); 73 | }); 74 | Crowdsale.hasClosed(true, '验证众筹已到期'); 75 | Crowdsale.buyTokens(purchaser, EthValue, '结束后购买代币错误',true,/TimedCrowdsale: not open/); 76 | }); 77 | -------------------------------------------------------------------------------- /test/Crowdsale/WhitelistCrowdsale.js: -------------------------------------------------------------------------------- 1 | const { contract, accounts,web3 } = require('@openzeppelin/test-environment'); 2 | const { ether, time, constants } = require('@openzeppelin/test-helpers'); 3 | const CrowdsaleContract = contract.fromArtifact("WhitelistCrowdsaleContract"); 4 | const ERC20Contract = contract.fromArtifact("ERC20FixedSupply"); 5 | const ERC20 = require('../inc/ERC20'); 6 | const Crowdsale = require('../inc/Crowdsale'); 7 | //有白名单的众筹 8 | const totalSupply = '10000';//发行总量 9 | [owner, sender, receiver, purchaser, beneficiary] = accounts; 10 | EthValue = '10'; 11 | rate = '1000'; 12 | TokenValue = (EthValue * rate).toString(); 13 | describe("有白名单的众筹", function () { 14 | it('布署代币合约', async function () { 15 | ERC20Param = [ 16 | "My Golden Coin", //代币名称 17 | "MGC", //代币缩写 18 | 18, //精度 19 | totalSupply //发行总量 20 | ]; 21 | ERC20Instance = await ERC20Contract.new(...ERC20Param, { from: owner }); 22 | }); 23 | it('布署众筹合约', async function () { 24 | CrowdsaleParam = [ 25 | rate, //兑换比例1ETH:100ERC20 26 | sender, //接收ETH受益人地址 27 | ERC20Instance.address, //代币地址 28 | owner, //代币从这个地址发送 29 | ] 30 | CrowdsaleInstance = await CrowdsaleContract.new(...CrowdsaleParam, { from: owner }); 31 | }); 32 | }); 33 | describe("布署后首先执行", function () { 34 | it('将代币批准给众筹合约', async function () { 35 | await ERC20Instance.approve(CrowdsaleInstance.address, ether(totalSupply), { from: owner }); 36 | }); 37 | }); 38 | describe("测试ERC20合约基本信息", function () { 39 | ERC20.detail(); 40 | }); 41 | describe("测试通用的众筹方法", function () { 42 | Crowdsale.token(); 43 | Crowdsale.wallet(sender); 44 | Crowdsale.rate(rate); 45 | Crowdsale.tokenWallet(owner); 46 | }); 47 | 48 | 49 | describe("测试设置白名单管理员的方法", function () { 50 | Crowdsale.addWhitelistAdmin(sender, sender, '无权添加白名单管理员错误', true, /WhitelistAdminRole: caller does not have the WhitelistAdmin role/); 51 | Crowdsale.addWhitelistAdmin(sender, owner, '添加白名单管理员'); 52 | Crowdsale.addWhitelistAdmin(sender, owner, '重复添加白名单管理员错误', true, /Roles: account already has role/); 53 | Crowdsale.isWhitelistAdmin(sender, true, '验证账户是白名单管理员'); 54 | Crowdsale.renounceWhitelistAdmin(sender, '撤销白名单管理员'); 55 | Crowdsale.isWhitelistAdmin(sender, false, '验证账户不是白名单管理员'); 56 | Crowdsale.renounceWhitelistAdmin(sender, '重复撤销白名单管理员错误', true, /Roles: account does not have role/); 57 | }); 58 | describe("测试设置白名单的方法", function () { 59 | Crowdsale.addWhitelisted(sender, sender, '无权添加白名单错误', true, /WhitelistAdminRole: caller does not have the WhitelistAdmin role/); 60 | Crowdsale.addWhitelisted(sender, owner, '添加白名单'); 61 | Crowdsale.addWhitelisted(sender, owner, '重复添加白名单错误', true, /Roles: account already has role/); 62 | Crowdsale.isWhitelisted(sender, true, '验证账户是白名单'); 63 | 64 | Crowdsale.buyTokens(sender, EthValue, '购买代币'); 65 | Crowdsale.weiRaised(EthValue, '众筹收入为'+EthValue); 66 | ERC20.balanceOf(TokenValue.toString(), sender, '购买者账户余额为'+TokenValue) 67 | Crowdsale.remainingTokens(totalSupply - TokenValue,'配额中剩余的代币数量'); 68 | 69 | Crowdsale.renounceWhitelisted(sender, '撤销白名单'); 70 | Crowdsale.isWhitelisted(sender, false, '验证账户不是白名单'); 71 | Crowdsale.renounceWhitelisted(sender, '重复撤销白名单错误', true, /Roles: account does not have role/); 72 | Crowdsale.addWhitelisted(purchaser, owner, '再次添加白名单'); 73 | Crowdsale.removeWhitelisted(purchaser, owner, '删除白名单'); 74 | Crowdsale.removeWhitelisted(purchaser, owner, '重复删除白名单', true, /Roles: account does not have role/); 75 | Crowdsale.removeWhitelisted(purchaser, sender, '无权删除白名单', true, /WhitelistAdminRole: caller does not have the WhitelistAdmin role/); 76 | }); -------------------------------------------------------------------------------- /test/ERC20/ERC20FixedSupply.js: -------------------------------------------------------------------------------- 1 | const { contract, accounts } = require('@openzeppelin/test-environment'); 2 | const { constants } = require('@openzeppelin/test-helpers'); 3 | const ERC20Contract = contract.fromArtifact("ERC20FixedSupply"); 4 | const ERC20 = require('../inc/ERC20'); 5 | //固定总量代币 6 | const totalSupply = '10000';//发行总量 7 | [owner, sender, receiver, purchaser, beneficiary] = accounts; 8 | EthValue = '10'; 9 | 10 | describe("固定总量代币", function () { 11 | it('布署代币合约', async function () { 12 | ERC20Param = [ 13 | "My Golden Coin", //代币名称 14 | "MGC", //代币缩写 15 | 18, //精度 16 | totalSupply, //发行总量 17 | ]; 18 | ERC20Instance = await ERC20Contract.new(...ERC20Param, { from: owner }); 19 | }); 20 | }); 21 | 22 | describe("测试ERC20合约基本信息", function () { 23 | ERC20.detail(); 24 | }); 25 | describe("测试ERC20合约的标准方法", async function () { 26 | //测试余额 27 | ERC20.balanceOf(totalSupply, owner, '创建者账户余额'); 28 | //测试发送 29 | ERC20.transfer(owner, constants.ZERO_ADDRESS, EthValue, '代币发送,0地址错误', true, /ERC20: transfer to the zero address/); 30 | ERC20.transfer(owner, receiver, EthValue, '代币发送'); 31 | //测试超额发送 32 | ERC20.transfer(owner, receiver, totalSupply, '超额发送错误', true, /ERC20: transfer amount exceeds balance/); 33 | //测试余额 34 | ERC20.balanceOf(EthValue, receiver, '接收者账户余额');//receiver.balance = value 35 | //测试批准 36 | ERC20.approve(owner, constants.ZERO_ADDRESS, EthValue, '批准代币,0地址错误', true, /ERC20: approve to the zero address/); 37 | ERC20.approve(receiver, purchaser, EthValue, '批准代币'); 38 | //验证批准 39 | ERC20.allowance(receiver, purchaser, EthValue, '验证批准数额');//receiver=>purchaser = value 40 | //测试传送批准 41 | ERC20.transferFrom(receiver, purchaser, beneficiary, EthValue, '批准发送');//beneficiary.balance = value 42 | //测试余额 43 | ERC20.balanceOf(EthValue, beneficiary, '接收者账户余额');//receiver.balance = value 44 | //测试超额发送批准 45 | ERC20.transferFrom(receiver, purchaser, beneficiary, EthValue, '超额批准发送', true, /ERC20: transfer amount exceeds balance/); 46 | //验证批准归零 47 | ERC20.allowance(receiver, purchaser, '0', '批准额归零');//receiver=>purchaser = 0 48 | //增加批准 49 | ERC20.increaseAllowance(receiver, purchaser, EthValue, '增加批准额'); 50 | //验证批准 51 | ERC20.allowance(receiver, purchaser, EthValue, '验证批准数额');//receiver=>purchaser = value 52 | //减少批准 53 | ERC20.decreaseAllowance(receiver, purchaser, EthValue, '减少批准额'); 54 | //验证批准 55 | ERC20.allowance(receiver, purchaser, '0', '批准数额归零');//receiver=>purchaser = 0 56 | //超额减少批准 57 | ERC20.decreaseAllowance(receiver, purchaser, EthValue, '超额减少批准额', true, /ERC20: decreased allowance below zero/); 58 | }); -------------------------------------------------------------------------------- /test/ERC20/ERC20WithBurnable.js: -------------------------------------------------------------------------------- 1 | const { contract, accounts } = require('@openzeppelin/test-environment'); 2 | const { constants } = require('@openzeppelin/test-helpers'); 3 | const ERC20Contract = contract.fromArtifact("ERC20WithBurnable"); 4 | const ERC20 = require('../inc/ERC20'); 5 | //可销毁代币 6 | const totalSupply = '10000';//发行总量 7 | [owner, sender, receiver, purchaser, beneficiary] = accounts; 8 | EthValue = '10'; 9 | describe("可销毁代币", function () { 10 | it('布署代币合约', async function () { 11 | ERC20Param = [ 12 | "My Golden Coin", //代币名称 13 | "MGC", //代币缩写 14 | 18, //精度 15 | totalSupply, //发行总量 16 | ]; 17 | ERC20Instance = await ERC20Contract.new(...ERC20Param, { from: owner }); 18 | }); 19 | }); 20 | 21 | describe("测试ERC20合约基本信息", function () { 22 | ERC20.detail(); 23 | }); 24 | describe("测试ERC20合约的标准方法", async function () { 25 | //测试余额 26 | ERC20.balanceOf(totalSupply, owner, '创建者账户余额'); 27 | //测试发送 28 | ERC20.transfer(owner, constants.ZERO_ADDRESS, EthValue, '代币发送,0地址错误', true, /ERC20: transfer to the zero address/); 29 | ERC20.transfer(owner, receiver, EthValue, '代币发送'); 30 | //测试超额发送 31 | ERC20.transfer(owner, receiver, totalSupply, '超额发送错误', true, /ERC20: transfer amount exceeds balance/); 32 | //测试余额 33 | ERC20.balanceOf(EthValue, receiver, '接收者账户余额');//receiver.balance = value 34 | //测试批准 35 | ERC20.approve(owner, constants.ZERO_ADDRESS, EthValue, '批准代币,0地址错误', true, /ERC20: approve to the zero address/); 36 | ERC20.approve(receiver, purchaser, EthValue, '批准代币'); 37 | //验证批准 38 | ERC20.allowance(receiver, purchaser, EthValue, '验证批准数额');//receiver=>purchaser = value 39 | //测试传送批准 40 | ERC20.transferFrom(receiver, purchaser, beneficiary, EthValue, '批准发送');//beneficiary.balance = value 41 | //测试余额 42 | ERC20.balanceOf(EthValue, beneficiary, '接收者账户余额');//receiver.balance = value 43 | //测试超额发送批准 44 | ERC20.transferFrom(receiver, purchaser, beneficiary, EthValue, '超额批准发送', true, /ERC20: transfer amount exceeds balance/); 45 | //验证批准归零 46 | ERC20.allowance(receiver, purchaser, '0', '批准额归零');//receiver=>purchaser = 0 47 | //增加批准 48 | ERC20.increaseAllowance(receiver, purchaser, EthValue, '增加批准额'); 49 | //验证批准 50 | ERC20.allowance(receiver, purchaser, EthValue, '验证批准数额');//receiver=>purchaser = value 51 | //减少批准 52 | ERC20.decreaseAllowance(receiver, purchaser, EthValue, '减少批准额'); 53 | //验证批准 54 | ERC20.allowance(receiver, purchaser, '0', '批准数额归零');//receiver=>purchaser = 0 55 | //超额减少批准 56 | ERC20.decreaseAllowance(receiver, purchaser, EthValue, '超额减少批准额', true, /ERC20: decreased allowance below zero/); 57 | }); 58 | describe("测试ERC20合约的销毁方法", async function () { 59 | ERC20.burn(beneficiary, EthValue, '销毁代币'); 60 | ERC20.balanceOf('0', beneficiary, '销毁后余额归零'); 61 | ERC20.burn(beneficiary, EthValue, '超额销毁', true, /ERC20: burn amount exceeds balance/); 62 | ERC20.approve(owner, receiver, EthValue, '增加批准额'); 63 | ERC20.allowance(owner, receiver, EthValue, '测试批准数额');//owner=>receiver = value 64 | ERC20.burnFrom(owner, receiver, EthValue, '销毁批准额'); 65 | ERC20.allowance(owner, receiver, '0', '销毁销毁后批准额归零');//owner=>receiver = 0 66 | ERC20.burnFrom(owner, receiver, EthValue, '超额销毁批准额', true, /ERC20: burn amount exceeds allowance/); 67 | }); -------------------------------------------------------------------------------- /test/ERC20/ERC20WithCapped.js: -------------------------------------------------------------------------------- 1 | const { contract, accounts } = require('@openzeppelin/test-environment'); 2 | const { ether, constants } = require('@openzeppelin/test-helpers'); 3 | const ERC20Contract = contract.fromArtifact("ERC20WithCapped"); 4 | const ERC20 = require('../inc/ERC20'); 5 | //有封顶代币 6 | const totalSupply = '10000';//发行总量 7 | [owner, sender, receiver, purchaser, beneficiary] = accounts; 8 | EthValue = '10'; 9 | const cap = '20000'; 10 | 11 | describe("有封顶代币", function () { 12 | it('布署代币合约', async function () { 13 | ERC20Param = [ 14 | "My Golden Coin", //代币名称 15 | "MGC", //代币缩写 16 | 18, //精度 17 | totalSupply, //发行总量 18 | cap //封顶数额 19 | ]; 20 | ERC20Instance = await ERC20Contract.new(...ERC20Param, { from: owner }); 21 | }); 22 | }); 23 | 24 | describe("测试ERC20合约基本信息", function () { 25 | ERC20.detail(); 26 | ERC20.cap(cap, '验证封顶额'); 27 | }); 28 | describe("测试ERC20合约的标准方法", async function () { 29 | ERC20.balanceOf(totalSupply, owner, '创建者账户余额'); 30 | ERC20.transfer(owner, constants.ZERO_ADDRESS, EthValue, '代币发送,0地址错误', true, /ERC20: transfer to the zero address/); 31 | ERC20.transfer(owner, receiver, EthValue, '代币发送'); 32 | ERC20.balanceOf(EthValue, receiver, '接收者账户余额');//receiver.balance = value 33 | ERC20.approve(owner, constants.ZERO_ADDRESS, EthValue, '批准代币,0地址错误', true, /ERC20: approve to the zero address/); 34 | ERC20.approve(receiver, purchaser, EthValue, '批准代币'); 35 | ERC20.allowance(receiver, purchaser, EthValue, '验证批准数额');//receiver=>purchaser = value 36 | ERC20.transferFrom(receiver, purchaser, beneficiary, EthValue, '批准发送');//beneficiary.balance = value 37 | ERC20.balanceOf(EthValue, beneficiary, '接收者账户余额');//receiver.balance = value 38 | ERC20.transferFrom(receiver, purchaser, beneficiary, EthValue, '超额批准发送', true, /ERC20: transfer amount exceeds balance/); 39 | ERC20.allowance(receiver, purchaser, '0', '批准额归零');//receiver=>purchaser = 0 40 | ERC20.increaseAllowance(receiver, purchaser, EthValue, '增加批准额'); 41 | ERC20.allowance(receiver, purchaser, EthValue, '验证批准数额');//receiver=>purchaser = value 42 | ERC20.decreaseAllowance(receiver, purchaser, EthValue, '减少批准额'); 43 | ERC20.allowance(receiver, purchaser, '0', '批准数额归零');//receiver=>purchaser = 0 44 | ERC20.decreaseAllowance(receiver, purchaser, EthValue, '超额减少批准额', true, /ERC20: decreased allowance below zero/); 45 | }); 46 | 47 | describe("测试设置铸币管理员的方法", function () { 48 | ERC20.addMinter(sender, sender, '无权添加铸币管理员错误', true, /MinterRole: caller does not have the Minter role/); 49 | ERC20.addMinter(sender, owner, '添加铸币管理员'); 50 | ERC20.addMinter(sender, owner, '重复添加铸币管理员错误', true, /Roles: account already has role/); 51 | ERC20.isMinter(sender, true, '验证账户是铸币管理员'); 52 | ERC20.renounceMinter(sender, '撤销铸币管理员'); 53 | ERC20.isMinter(sender, false, '验证账户不是铸币管理员'); 54 | ERC20.renounceMinter(sender, '重复撤销铸币管理员错误', true, /Roles: account does not have role/); 55 | }); 56 | 57 | describe("测试代币合约的铸币方法", function () { 58 | ERC20.mint(owner, purchaser, EthValue, '铸币方法'); 59 | ERC20.balanceOf(EthValue, purchaser, '账户铸币后余额'); 60 | ERC20.mint(owner, purchaser, ether('1000000000'), '超额铸币错误', true, /ERC20Capped: cap exceeded/); 61 | }); -------------------------------------------------------------------------------- /test/ERC20/ERC20WithMintable.js: -------------------------------------------------------------------------------- 1 | const { contract, accounts } = require('@openzeppelin/test-environment'); 2 | const { ether, constants } = require('@openzeppelin/test-helpers'); 3 | const ERC20Contract = contract.fromArtifact("ERC20WithMintable"); 4 | const ERC20 = require('../inc/ERC20'); 5 | //可增发代币 6 | const totalSupply = '10000';//发行总量 7 | [owner, sender, receiver, purchaser, beneficiary] = accounts; 8 | EthValue = '10'; 9 | 10 | describe("可增发代币", function () { 11 | it('布署代币合约', async function () { 12 | ERC20Param = [ 13 | "My Golden Coin", //代币名称 14 | "MGC", //代币缩写 15 | 18, //精度 16 | totalSupply, //发行总量 17 | ]; 18 | ERC20Instance = await ERC20Contract.new(...ERC20Param, { from: owner }); 19 | }); 20 | }); 21 | 22 | describe("测试ERC20合约基本信息", function () { 23 | ERC20.detail(); 24 | }); 25 | describe("测试ERC20合约的标准方法", async function () { 26 | ERC20.balanceOf(totalSupply, owner, '创建者账户余额'); 27 | ERC20.transfer(owner, constants.ZERO_ADDRESS, EthValue, '代币发送,0地址错误', true, /ERC20: transfer to the zero address/); 28 | ERC20.transfer(owner, receiver, EthValue, '代币发送'); 29 | ERC20.balanceOf(EthValue, receiver, '接收者账户余额');//receiver.balance = value 30 | ERC20.approve(owner, constants.ZERO_ADDRESS, EthValue, '批准代币,0地址错误', true, /ERC20: approve to the zero address/); 31 | ERC20.approve(receiver, purchaser, EthValue, '批准代币'); 32 | ERC20.allowance(receiver, purchaser, EthValue, '验证批准数额');//receiver=>purchaser = value 33 | ERC20.transferFrom(receiver, purchaser, beneficiary, EthValue, '批准发送');//beneficiary.balance = value 34 | ERC20.balanceOf(EthValue, beneficiary, '接收者账户余额');//receiver.balance = value 35 | ERC20.transferFrom(receiver, purchaser, beneficiary, EthValue, '超额批准发送', true, /ERC20: transfer amount exceeds balance/); 36 | ERC20.allowance(receiver, purchaser, '0', '批准额归零');//receiver=>purchaser = 0 37 | ERC20.increaseAllowance(receiver, purchaser, EthValue, '增加批准额'); 38 | ERC20.allowance(receiver, purchaser, EthValue, '验证批准数额');//receiver=>purchaser = value 39 | ERC20.decreaseAllowance(receiver, purchaser, EthValue, '减少批准额'); 40 | ERC20.allowance(receiver, purchaser, '0', '批准数额归零');//receiver=>purchaser = 0 41 | ERC20.decreaseAllowance(receiver, purchaser, EthValue, '超额减少批准额', true, /ERC20: decreased allowance below zero/); 42 | }); 43 | describe("测试设置铸币管理员的方法", function () { 44 | ERC20.addMinter(sender, sender, '无权添加铸币管理员错误', true, /MinterRole: caller does not have the Minter role/); 45 | ERC20.addMinter(sender, owner, '添加铸币管理员'); 46 | ERC20.addMinter(sender, owner, '重复添加铸币管理员错误', true, /Roles: account already has role/); 47 | ERC20.isMinter(sender, true, '验证账户是铸币管理员'); 48 | ERC20.renounceMinter(sender, '撤销铸币管理员'); 49 | ERC20.isMinter(sender, false, '验证账户不是铸币管理员'); 50 | ERC20.renounceMinter(sender, '重复撤销铸币管理员错误', true, /Roles: account does not have role/); 51 | }); 52 | 53 | describe("测试代币合约的铸币方法", function () { 54 | ERC20.mint(owner, purchaser, EthValue, '铸币方法'); 55 | ERC20.balanceOf(EthValue, purchaser, '账户铸币后余额'); 56 | }); -------------------------------------------------------------------------------- /test/ERC20/ERC20WithPausable.js: -------------------------------------------------------------------------------- 1 | 2 | const { contract, accounts } = require('@openzeppelin/test-environment'); 3 | const { constants } = require('@openzeppelin/test-helpers'); 4 | const ERC20Contract = contract.fromArtifact("ERC20WithPausable"); 5 | const ERC20 = require('../inc/ERC20'); 6 | //可暂停代币 7 | const totalSupply = '10000';//发行总量 8 | [owner, sender, receiver, purchaser, beneficiary] = accounts; 9 | EthValue = '10'; 10 | 11 | describe("可暂停代币", function () { 12 | it('布署代币合约', async function () { 13 | ERC20Param = [ 14 | "My Golden Coin", //代币名称 15 | "MGC", //代币缩写 16 | 18, //精度 17 | totalSupply, //发行总量 18 | ]; 19 | ERC20Instance = await ERC20Contract.new(...ERC20Param, { from: owner }); 20 | }); 21 | }); 22 | 23 | describe("测试ERC20合约基本信息", function () { 24 | ERC20.detail(); 25 | }); 26 | describe("测试ERC20合约的标准方法", async function () { 27 | ERC20.balanceOf(totalSupply, owner, '创建者账户余额'); 28 | ERC20.transfer(owner, constants.ZERO_ADDRESS, EthValue, '代币发送,0地址错误', true, /ERC20: transfer to the zero address/); 29 | ERC20.transfer(owner, receiver, EthValue, '代币发送'); 30 | ERC20.balanceOf(EthValue, receiver, '接收者账户余额');//receiver.balance = value 31 | ERC20.approve(owner, constants.ZERO_ADDRESS, EthValue, '批准代币,0地址错误', true, /ERC20: approve to the zero address/); 32 | ERC20.approve(receiver, purchaser, EthValue, '批准代币'); 33 | ERC20.allowance(receiver, purchaser, EthValue, '验证批准数额');//receiver=>purchaser = value 34 | ERC20.transferFrom(receiver, purchaser, beneficiary, EthValue, '批准发送');//beneficiary.balance = value 35 | ERC20.balanceOf(EthValue, beneficiary, '接收者账户余额');//receiver.balance = value 36 | ERC20.transferFrom(receiver, purchaser, beneficiary, EthValue, '超额批准发送', true, /ERC20: transfer amount exceeds balance/); 37 | ERC20.allowance(receiver, purchaser, '0', '批准额归零');//receiver=>purchaser = 0 38 | ERC20.increaseAllowance(receiver, purchaser, EthValue, '增加批准额'); 39 | ERC20.allowance(receiver, purchaser, EthValue, '验证批准数额');//receiver=>purchaser = value 40 | ERC20.decreaseAllowance(receiver, purchaser, EthValue, '减少批准额'); 41 | ERC20.allowance(receiver, purchaser, '0', '批准数额归零');//receiver=>purchaser = 0 42 | ERC20.decreaseAllowance(receiver, purchaser, EthValue, '超额减少批准额', true, /ERC20: decreased allowance below zero/); 43 | }); 44 | describe("测试设置暂停管理员的方法", function () { 45 | ERC20.addPauser(sender, sender, '无权添加暂停管理员错误', true, /PauserRole: caller does not have the Pauser role/); 46 | ERC20.addPauser(sender, owner, '添加暂停管理员'); 47 | ERC20.addPauser(sender, owner, '重复添加暂停管理员错误', true, /Roles: account already has role/); 48 | ERC20.isPauser(sender, true, '验证账户是暂停管理员'); 49 | ERC20.renouncePauser(sender, '撤销暂停管理员'); 50 | ERC20.isPauser(sender, false, '验证账户不是暂停管理员'); 51 | ERC20.renouncePauser(sender, '重复撤销暂停管理员错误', true, /Roles: account does not have role/); 52 | 53 | }); 54 | describe("测试代币合约的暂停管理方法", function () {// 55 | ERC20.paused(false, '验证合约未暂停'); 56 | ERC20.pause(owner, '暂停合约'); 57 | ERC20.paused(true, '验证合约已暂停'); 58 | ERC20.transfer(owner, receiver, EthValue, '暂停后代币发送错误', true, /Pausable: paused/); 59 | ERC20.pause(owner, '验证重复暂停错误', true, /Pausable: paused/); 60 | ERC20.pause(sender, '验证无权暂停错误', true, /PauserRole: caller does not have the Pauser role/); 61 | ERC20.unpause(owner, '恢复暂停合约'); 62 | ERC20.paused(false, '验证合约未暂停'); 63 | ERC20.unpause(owner, '验证重复恢复暂停错误', true, /Pausable: not paused/); 64 | ERC20.unpause(sender, '验证无权恢复暂停错误', true, /PauserRole: caller does not have the Pauser role/); 65 | }); -------------------------------------------------------------------------------- /test/ERC20/ERC20WithTokenTimelock.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | const { contract, accounts } = require('@openzeppelin/test-environment'); 3 | const { expectEvent, expectRevert, ether, time, constants } = require('@openzeppelin/test-helpers'); 4 | const ERC20Contract = contract.fromArtifact("ERC20FixedSupply"); 5 | const ERC20WithTokenTimelock = contract.fromArtifact("ERC20WithTokenTimelock"); 6 | const ERC20 = require('../inc/ERC20'); 7 | //可锁仓代币 8 | const totalSupply = '10000';//发行总量 9 | [owner, sender, receiver, purchaser, beneficiary] = accounts; 10 | EthValue = '10'; 11 | const lockAmount = '1000'; 12 | 13 | describe("可锁仓代币", function () { 14 | it('布署代币合约', async function () { 15 | ERC20Param = [ 16 | "My Golden Coin", //代币名称 17 | "MGC", //代币缩写 18 | 18, //精度 19 | totalSupply, //发行总量 20 | ]; 21 | ERC20Instance = await ERC20Contract.new(...ERC20Param, { from: owner }); 22 | }); 23 | }); 24 | describe("测试ERC20合约基本信息", function () { 25 | ERC20.detail(); 26 | }); 27 | describe("测试ERC20合约的标准方法", async function () { 28 | ERC20.balanceOf(totalSupply, owner, '创建者账户余额'); 29 | ERC20.transfer(owner, constants.ZERO_ADDRESS, EthValue, '代币发送,0地址错误', true, /ERC20: transfer to the zero address/); 30 | ERC20.transfer(owner, receiver, EthValue, '代币发送'); 31 | ERC20.balanceOf(EthValue, receiver, '接收者账户余额');//receiver.balance = EthValue 32 | ERC20.approve(owner, constants.ZERO_ADDRESS, EthValue, '批准代币,0地址错误', true, /ERC20: approve to the zero address/); 33 | ERC20.approve(receiver, purchaser, EthValue, '批准代币'); 34 | ERC20.allowance(receiver, purchaser, EthValue, '验证批准数额');//receiver=>purchaser = EthValue 35 | ERC20.transferFrom(receiver, purchaser, beneficiary, EthValue, '批准发送');//beneficiary.balance = EthValue 36 | ERC20.balanceOf(EthValue, beneficiary, '接收者账户余额');//receiver.balance = EthValue 37 | ERC20.transferFrom(receiver, purchaser, beneficiary, EthValue, '超额批准发送', true, /ERC20: transfer amount exceeds balance/); 38 | ERC20.allowance(receiver, purchaser, '0', '批准额归零');//receiver=>purchaser = 0 39 | ERC20.increaseAllowance(receiver, purchaser, EthValue, '增加批准额'); 40 | ERC20.allowance(receiver, purchaser, EthValue, '验证批准数额');//receiver=>purchaser = EthValue 41 | ERC20.decreaseAllowance(receiver, purchaser, EthValue, '减少批准额'); 42 | ERC20.allowance(receiver, purchaser, '0', '批准数额归零');//receiver=>purchaser = 0 43 | ERC20.decreaseAllowance(receiver, purchaser, EthValue, '超额减少批准额', true, /ERC20: decreased allowance below zero/); 44 | }); 45 | describe("锁仓合约", function () { 46 | it('布署锁仓合约', async function () { 47 | releaseTime = parseInt(await time.latest()) + 60; 48 | const param = [ 49 | ERC20Instance.address, //ERC20代币合约地址 50 | receiver, //受益人为当前账户 51 | releaseTime //解锁时间戳 52 | ] 53 | TokenTimelockInstance = await ERC20WithTokenTimelock.new(...param, { from: owner }); 54 | }); 55 | it('传送代币到锁仓账户', async function () { 56 | let receipt = await ERC20Instance.transfer(TokenTimelockInstance.address, ether(lockAmount), { from: owner }); 57 | expectEvent(receipt, 'Transfer', { 58 | from: owner, 59 | to: TokenTimelockInstance.address, 60 | value: ether(lockAmount), 61 | }); 62 | }); 63 | }); 64 | describe("测试可锁仓代币的特殊方法", function () { 65 | //测试返回锁仓代币地址 66 | it('返回锁仓代币地址: token()', async function () { 67 | assert.equal(ERC20Instance.address, await TokenTimelockInstance.token()); 68 | }); 69 | //测试锁仓数量 70 | it('锁仓数量: balance()', async function () { 71 | assert.equal(ether(lockAmount), (await ERC20Instance.balanceOf(TokenTimelockInstance.address)).toString()); 72 | }); 73 | //测试返回受益人 74 | it('返回受益人: beneficiary()', async function () { 75 | assert.equal(receiver, await TokenTimelockInstance.beneficiary()); 76 | }); 77 | //测试返回解锁时间 78 | it('返回解锁时间: releaseTime()', async function () { 79 | const releaseTime = await TokenTimelockInstance.releaseTime(); 80 | assert.ok(Math.ceil(new Date().getTime() / 1000) < releaseTime.toString()); 81 | }); 82 | //测试未到时间不能解锁 83 | it('未到时间不能解锁: rejects release()', async function () { 84 | await expectRevert(TokenTimelockInstance.release(), 'current time is before release time'); 85 | }); 86 | //测试解锁方法 87 | it('解锁方法: release()', async function () { 88 | await time.increaseTo(releaseTime + 1); 89 | assert.equal('0', (await ERC20Instance.balanceOf(receiver)).toString()); 90 | TokenTimelockInstance.release({ from: owner }); 91 | assert.equal( 92 | ether(lockAmount), 93 | (await ERC20Instance.balanceOf(receiver)).toString() 94 | ); 95 | }); 96 | }); -------------------------------------------------------------------------------- /test/ERC721/ERC721Burnable.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | const { contract, accounts } = require('@openzeppelin/test-environment'); 3 | const { constants } = require('@openzeppelin/test-helpers'); 4 | const ERC721Contract = contract.fromArtifact("ERC721BurnableContract"); 5 | const ERC721 = require('../inc/ERC721'); 6 | //全功能ERC721代币 7 | [owner, sender, receiver, purchaser, beneficiary] = accounts; 8 | EthValue = '10'; 9 | baseURI = 'https://github.com/Fankouzu/MintCoin/blob/master/'; 10 | tokenURI = 'token.json'; 11 | let tokenId; 12 | describe("全功能ERC721代币", function () { 13 | it('布署ERC721合约', async function () { 14 | ERC721Param = [ 15 | "My Golden Coin", //代币名称 16 | "MGC", //代币缩写 17 | baseURI //代币基本地址 18 | ]; 19 | ERC721Instance = await ERC721Contract.new(...ERC721Param, { from: owner }); 20 | }); 21 | }); 22 | describe("测试ERC721合约", async function () { 23 | ERC721.detail(); 24 | ERC721.awardItem(owner, tokenURI, '添加代币方法'); 25 | 26 | ERC721.balanceOf('1', owner, '验证账户代币数量'); 27 | ERC721.balanceOf('1', constants.ZERO_ADDRESS, '验证账户代币数量0地址错误', true, /ERC721: balance query for the zero address/); 28 | 29 | ERC721.tokenOfOwnerByIndex(owner, '0', '根据账户的代币索引获取代币id'); 30 | ERC721.tokenOfOwnerByIndex(owner, '10', '根据错误的代币索引获取代币id', true, /ERC721Enumerable: owner index out of bounds/); 31 | 32 | ERC721.ownerOf(owner, false, '根据tokenID验证账户地址'); 33 | ERC721.ownerOf(owner, '999', '根据错误的tokenID验证账户地址', true, /ERC721: owner query for nonexistent token/); 34 | 35 | ERC721.tokenURI(baseURI + tokenURI, false, '验证tokenURI'); 36 | ERC721.tokenURI(baseURI + tokenURI, '999', '根据错误的tokenId验证tokenURI', true, /ERC721Metadata: URI query for nonexistent token/); 37 | 38 | ERC721.approve(owner, owner, false, '批准代币给自己的错误', true, /ERC721: approval to current owner/); 39 | ERC721.approve(sender, owner, '999', '批准错误的代币', true, /ERC721: owner query for nonexistent token/); 40 | ERC721.approve(sender, owner, false, '批准代币'); 41 | 42 | ERC721.getApproved(sender, '获取代币批准的地址'); 43 | ERC721.getApproved(sender, '获取错误的代币的批准地址', true, /ERC721: approved query for nonexistent token/); 44 | 45 | ERC721.transferFrom(sender, owner, receiver, false, '发送批准'); 46 | ERC721.transferFrom(sender, owner, receiver, '999', '发送错误的tokenId批准', true, /ERC721: operator query for nonexistent token/); 47 | ERC721.ownerOf(receiver, false, '账户的代币id'); 48 | ERC721.getApproved(constants.ZERO_ADDRESS, '验证代币批准的地址为0x0'); 49 | ERC721.transferFrom(sender, owner, receiver, false, '重复发送批准错误', true, /ERC721: transfer caller is not owner nor approved/); 50 | 51 | ERC721.awardItem(receiver, tokenURI, '再次添加代币'); 52 | ERC721.balanceOf('2', receiver, '验证账户代币数量'); 53 | ERC721.setApprovalForAll(receiver, receiver, '批准全部代币给自己的错误', true, /ERC721: approve to caller/); 54 | ERC721.setApprovalForAll(receiver, purchaser, '批准全部代币'); 55 | ERC721.approve( 56 | purchaser, owner, false, '批准代币的所有者错误', true, 57 | /ERC721: approve caller is not owner nor approved for all/ 58 | ); 59 | ERC721.isApprovedForAll(receiver, purchaser, '验证代币全部被批准'); 60 | 61 | ERC721.awardItem(receiver, tokenURI, '再次添加代币'); 62 | ERC721.balanceOf('3', receiver, '验证账户代币数量'); 63 | ERC721.tokenOfOwnerByIndex(receiver, '0', '根据账户的代币索引获取代币id'); 64 | ERC721.approve(sender, receiver, false, '批准代币'); 65 | ERC721.safeTransferFrom( 66 | sender, receiver, beneficiary, '999', '安全发送错误的tokenId批准', true, 67 | /ERC721: operator query for nonexistent token/ 68 | ); 69 | ERC721.safeTransferFrom( 70 | sender, receiver, constants.ZERO_ADDRESS, false, '安全发送批准0地址错误', true, 71 | /ERC721: transfer to the zero address/ 72 | ); 73 | ERC721.safeTransferFrom( 74 | sender, purchaser, beneficiary, false, '安全发送批准错误的拥有者', true, 75 | /ERC721: transfer of token that is not own/ 76 | ); 77 | ERC721.safeTransferFrom(sender, receiver, beneficiary, false, '安全发送批准'); 78 | ERC721.ownerOf(beneficiary, false, '根据tokenID验证账户地址'); 79 | 80 | ERC721.transferFrom(beneficiary, beneficiary, receiver, false, '发送自己的代币'); 81 | ERC721.ownerOf(receiver, false, '根据tokenID验证账户地址'); 82 | ERC721.totalSupply('3'); 83 | 84 | ERC721.tokenByIndex('2', '3', '根据代币索引获取代币id'); 85 | ERC721.tokenByIndex('10', false, '根据错误的代币索引获取代币id', true, /ERC721Enumerable: global index out of bounds/); 86 | 87 | ERC721.burn(beneficiary, '3', '错误的用户销毁代币', true, /ERC721Burnable: caller is not owner nor approved/); 88 | ERC721.burn(receiver, '3', '销毁代币'); 89 | ERC721.burn(receiver, '3', '重复销毁代币错误', true, /ERC721: operator query for nonexistent token/); 90 | 91 | }); 92 | describe("测试安全发送到合约方法", function () { 93 | it('布署ERC721合约', async function () { 94 | ERC721Param = [ 95 | "My Holder Coin", //代币名称 96 | "MHC", //代币缩写 97 | baseURI //代币基本地址 98 | ]; 99 | ERC721Holder = await ERC721Contract.new(...ERC721Param, { from: owner }); 100 | }); 101 | it('验证安全发送到合约地址: safeTransferFrom()', async function () { 102 | await ERC721Instance.safeTransferFrom(receiver, ERC721Holder.address, '1', { from: receiver }); 103 | }); 104 | it('根据tokenID验证账户地址: ownerOf()', async function () { 105 | assert.equal(ERC721Holder.address, await ERC721Instance.ownerOf('1')); 106 | }); 107 | }); -------------------------------------------------------------------------------- /test/Multi/ERC20Migrator.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | const { contract, accounts, web3 } = require('@openzeppelin/test-environment'); 3 | const { ether, time, expectEvent } = require('@openzeppelin/test-helpers'); 4 | const ERC20FixedSupply = contract.fromArtifact("ERC20FixedSupply"); 5 | const ERC20Migrator = contract.fromArtifact("ERC20MigratorContract"); 6 | const ERC20WithMintable = contract.fromArtifact("ERC20WithMintable"); 7 | 8 | const ERC20 = require('../inc/ERC20'); 9 | const totalSupply = '1000000000';//发行总量 10 | [owner, sender, receiver, purchaser, beneficiary] = accounts; 11 | EthValue = '100'; 12 | let balanceBefore = []; 13 | 14 | migrateBalance = async (account) => { 15 | await ERC20Instance.approve(ERC20MigratorInstance.address, balanceBefore[account], { from: account }); 16 | await ERC20MigratorInstance.migrate(account,balanceBefore[account]); 17 | } 18 | 19 | assertBalanceAfter = async (account) => { 20 | let balanceAfter = await ERC20WithMintableInstance.balanceOf(account); 21 | assert.equal(balanceBefore[account].toString(), balanceAfter.toString()); 22 | } 23 | //代币迁移合约 24 | describe("代币迁移合约", function () { 25 | it('布署旧代币合约', async function () { 26 | ERC20Param = [ 27 | "My Golden Coin", //代币名称 28 | "MGC", //代币缩写 29 | 18, //精度 30 | totalSupply //发行总量 31 | ]; 32 | ERC20Instance = await ERC20FixedSupply.new(...ERC20Param, { from: owner }); 33 | }); 34 | it('布署代币迁移合约', async function () { 35 | ERC20MigratorInstance = await ERC20Migrator.new( 36 | ERC20Instance.address, //旧代币合约地址 37 | { from: owner }); 38 | }); 39 | it('布署新代币合约', async function () { 40 | ERC20WithMintableParam = [ 41 | "My Golden Coin", //代币名称 42 | "MGC", //代币缩写 43 | 18, //精度 44 | 0 //发行总量 45 | ]; 46 | ERC20WithMintableInstance = await ERC20WithMintable.new(...ERC20WithMintableParam, { from: owner }); 47 | }); 48 | }); 49 | describe("布署后首先执行", function () { 50 | it('将代币批准给众筹合约', async function () { 51 | await ERC20Instance.approve(ERC20MigratorInstance.address, ether(totalSupply.toString()), { from: owner }); 52 | }); 53 | it('添加众筹合约的铸造权: addMinter()', async function () { 54 | await ERC20WithMintableInstance.addMinter(ERC20MigratorInstance.address, { from: owner }); 55 | }); 56 | it('撤销发送者的铸造权: renounceMinter()', async function () { 57 | let receipt = await ERC20WithMintableInstance.renounceMinter({ from: owner }); 58 | expectEvent(receipt, 'MinterRemoved', { 59 | account: owner 60 | }); 61 | }); 62 | }); 63 | describe("测试ERC20合约基本信息", function () { 64 | ERC20.detail(); 65 | }); 66 | describe("迁移合约基本信息", function () { 67 | it('旧合约地址: legacyToken()', async function () { 68 | assert.equal(ERC20Instance.address, await ERC20MigratorInstance.legacyToken()); 69 | }); 70 | }); 71 | describe("将旧合约代币分配给一些账户", function () { 72 | ERC20.transfer(owner, sender, (EthValue*5).toString(), '代币发送给sender'); 73 | ERC20.transfer(owner, receiver, (EthValue*10).toString(), '代币发送给receiver'); 74 | ERC20.transfer(owner, purchaser, (EthValue*15).toString(), '代币发送给purchaser'); 75 | ERC20.transfer(owner, beneficiary, (EthValue*25).toString(), '代币发送给beneficiary'); 76 | it('记录账户旧合约余额: balanceOf()', async function () { 77 | balanceBefore[owner] = await ERC20Instance.balanceOf(owner); 78 | balanceBefore[sender] = await ERC20Instance.balanceOf(sender); 79 | balanceBefore[receiver] = await ERC20Instance.balanceOf(receiver); 80 | balanceBefore[purchaser] = await ERC20Instance.balanceOf(purchaser); 81 | balanceBefore[beneficiary] = await ERC20Instance.balanceOf(beneficiary); 82 | }); 83 | }); 84 | describe("开始迁移", function () { 85 | it('开始迁移: beginMigration()', async function () { 86 | await ERC20MigratorInstance.beginMigration(ERC20WithMintableInstance.address,{from:owner}); 87 | }); 88 | it('验证新约地址: newToken()', async function () { 89 | assert.equal(ERC20WithMintableInstance.address, await ERC20MigratorInstance.newToken()); 90 | }); 91 | it('迁移owner账户全部余额方法: migrateAll()', async function () { 92 | await ERC20MigratorInstance.migrateAll(owner); 93 | }); 94 | it('迁移指定账户余额方法: migrate()', async function () { 95 | await migrateBalance(sender); 96 | await migrateBalance(receiver); 97 | await migrateBalance(purchaser); 98 | await migrateBalance(beneficiary); 99 | }); 100 | }); 101 | describe("验证余额", function () { 102 | it('验证账户迁移后新合约余额: balanceOf()', async function () { 103 | await assertBalanceAfter(owner); 104 | await assertBalanceAfter(sender); 105 | await assertBalanceAfter(receiver); 106 | await assertBalanceAfter(purchaser); 107 | await assertBalanceAfter(beneficiary); 108 | }); 109 | ERC20.balanceOf('0', owner, '验证迁移后旧合约余额'); 110 | ERC20.balanceOf('0', sender, '验证迁移后旧合约余额'); 111 | ERC20.balanceOf('0', receiver, '验证迁移后旧合约余额'); 112 | ERC20.balanceOf('0', purchaser, '验证迁移后旧合约余额'); 113 | ERC20.balanceOf('0', beneficiary, '验证迁移后旧合约余额'); 114 | }); 115 | -------------------------------------------------------------------------------- /test/Multi/ERC20MultiFunction.js: -------------------------------------------------------------------------------- 1 | const { contract, accounts } = require('@openzeppelin/test-environment'); 2 | const { ether, constants } = require('@openzeppelin/test-helpers'); 3 | const ERC20Contract = contract.fromArtifact("ERC20MultiFunction"); 4 | const ERC20 = require('../inc/ERC20'); 5 | //ERC20多功能代币,可增发,可销毁,可暂停,有封顶 6 | const totalSupply = '100000';//发行总量 7 | [owner, sender, receiver, purchaser, beneficiary] = accounts; 8 | EthValue = '10'; 9 | rate = '1000'; 10 | const cap = '200000'; 11 | TokenValue = (EthValue * rate).toString(); 12 | describe("ERC20多功能代币", function () { 13 | it('布署代币合约', async function () { 14 | ERC20Param = [ 15 | "My Golden Coin", //代币名称 16 | "MGC", //代币缩写 17 | 18, //精度 18 | totalSupply, //发行总量 19 | cap //封顶数额 20 | ]; 21 | ERC20Instance = await ERC20Contract.new(...ERC20Param, { from: owner }); 22 | }); 23 | }); 24 | 25 | describe("测试ERC20合约基本信息", function () { 26 | ERC20.detail(); 27 | ERC20.cap(cap, '验证封顶额'); 28 | }); 29 | describe("测试ERC20合约的标准方法", function () { 30 | ERC20.balanceOf(totalSupply, owner, '创建者账户余额'); 31 | ERC20.transfer(owner, constants.ZERO_ADDRESS, TokenValue, '代币发送,0地址错误', true, /ERC20: transfer to the zero address/); 32 | ERC20.transfer(owner, receiver, TokenValue, '代币发送'); 33 | ERC20.balanceOf(TokenValue, receiver, '接收者账户余额');//receiver.balance = value 34 | ERC20.approve(owner, constants.ZERO_ADDRESS, TokenValue, '批准代币,0地址错误', true, /ERC20: approve to the zero address/); 35 | ERC20.approve(receiver, purchaser, TokenValue, '批准代币'); 36 | ERC20.allowance(receiver, purchaser, TokenValue, '验证批准数额');//receiver=>purchaser = value 37 | ERC20.transferFrom(receiver, purchaser, beneficiary, TokenValue, '批准发送');//beneficiary.balance = value 38 | ERC20.balanceOf(TokenValue, beneficiary, '接收者账户余额');//receiver.balance = value 39 | ERC20.transferFrom(receiver, purchaser, beneficiary, TokenValue, '超额批准发送', true, /ERC20: transfer amount exceeds balance/); 40 | ERC20.allowance(receiver, purchaser, '0', '批准额归零');//receiver=>purchaser = 0 41 | ERC20.increaseAllowance(receiver, purchaser, TokenValue, '增加批准额'); 42 | ERC20.allowance(receiver, purchaser, TokenValue, '验证批准数额');//receiver=>purchaser = value 43 | ERC20.decreaseAllowance(receiver, purchaser, TokenValue, '减少批准额'); 44 | ERC20.allowance(receiver, purchaser, '0', '批准数额归零');//receiver=>purchaser = 0 45 | ERC20.decreaseAllowance(receiver, purchaser, TokenValue, '超额减少批准额', true, /ERC20: decreased allowance below zero/); 46 | }); 47 | describe("测试ERC20合约的销毁方法", function () { 48 | ERC20.burn(beneficiary, TokenValue, '销毁代币'); 49 | ERC20.balanceOf('0', beneficiary, '销毁后余额归零'); 50 | ERC20.burn(beneficiary, TokenValue, '超额销毁', true, /ERC20: burn amount exceeds balance/); 51 | ERC20.approve(owner, receiver, TokenValue, '增加批准额'); 52 | ERC20.allowance(owner, receiver, TokenValue, '测试批准数额');//owner=>receiver = value 53 | ERC20.burnFrom(owner, receiver, TokenValue, '销毁批准额'); 54 | ERC20.allowance(owner, receiver, '0', '销毁销毁后批准额归零');//owner=>receiver = 0 55 | ERC20.burnFrom(owner, receiver, TokenValue, '超额销毁批准额', true, /ERC20: burn amount exceeds allowance/); 56 | }); 57 | describe("测试设置铸币管理员的方法", function () { 58 | ERC20.addMinter(sender, sender, '无权添加铸币管理员错误', true, /MinterRole: caller does not have the Minter role/); 59 | ERC20.addMinter(sender, owner, '添加铸币管理员'); 60 | ERC20.addMinter(sender, owner, '重复添加铸币管理员错误', true, /Roles: account already has role/); 61 | ERC20.isMinter(sender, true, '验证账户是铸币管理员'); 62 | ERC20.renounceMinter(sender, '撤销铸币管理员'); 63 | ERC20.isMinter(sender, false, '验证账户不是铸币管理员'); 64 | ERC20.renounceMinter(sender, '重复撤销铸币管理员错误', true, /Roles: account does not have role/); 65 | }); 66 | 67 | describe("测试代币合约的铸币方法", function () { 68 | ERC20.mint(owner, beneficiary, TokenValue, '铸币方法'); 69 | ERC20.balanceOf(TokenValue, beneficiary, '账户铸币后余额'); 70 | ERC20.mint(owner, beneficiary, ether('1000000000'), '超额铸币错误', true, /ERC20Capped: cap exceeded/); 71 | }); 72 | describe("测试设置暂停管理员的方法", function () { 73 | ERC20.addPauser(sender, sender, '无权添加暂停管理员错误', true, /PauserRole: caller does not have the Pauser role/); 74 | ERC20.addPauser(sender, owner, '添加暂停管理员'); 75 | ERC20.addPauser(sender, owner, '重复添加暂停管理员错误', true, /Roles: account already has role/); 76 | ERC20.isPauser(sender, true, '验证账户是暂停管理员'); 77 | ERC20.renouncePauser(sender, '撤销暂停管理员'); 78 | ERC20.isPauser(sender, false, '验证账户不是暂停管理员'); 79 | ERC20.renouncePauser(sender, '重复撤销暂停管理员错误', true, /Roles: account does not have role/); 80 | 81 | }); 82 | describe("测试代币合约的暂停管理方法", function () {// 83 | ERC20.paused(false, '验证合约未暂停'); 84 | ERC20.pause(owner, '暂停合约'); 85 | ERC20.paused(true, '验证合约已暂停'); 86 | ERC20.transfer(owner, receiver, TokenValue, '暂停后代币发送错误', true, /Pausable: paused/); 87 | ERC20.pause(owner, '验证重复暂停错误', true, /Pausable: paused/); 88 | ERC20.pause(sender, '验证无权暂停错误', true, /PauserRole: caller does not have the Pauser role/); 89 | ERC20.unpause(owner, '恢复暂停合约'); 90 | ERC20.paused(false, '验证合约未暂停'); 91 | ERC20.unpause(owner, '验证重复恢复暂停错误', true, /Pausable: not paused/); 92 | ERC20.unpause(sender, '验证无权恢复暂停错误', true, /PauserRole: caller does not have the Pauser role/); 93 | }); -------------------------------------------------------------------------------- /test/Multi/ERC20WithSnapshot.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | const { contract, accounts } = require('@openzeppelin/test-environment'); 3 | const { constants, expectEvent, ether } = require('@openzeppelin/test-helpers'); 4 | const ERC20Contract = contract.fromArtifact("ERC20WithSnapshot"); 5 | const ERC20 = require('../inc/ERC20'); 6 | //可快照的ERC20代币 7 | const totalSupply = '10000';//发行总量 8 | [owner, sender, receiver, purchaser, beneficiary] = accounts; 9 | EthValue = '10'; 10 | 11 | let balanceBefore = []; 12 | describe("固定总量代币", function () { 13 | it('布署代币合约', async function () { 14 | ERC20Param = [ 15 | "My Golden Coin", //代币名称 16 | "MGC", //代币缩写 17 | 18, //精度 18 | totalSupply, //发行总量 19 | ]; 20 | ERC20Instance = await ERC20Contract.new(...ERC20Param, { from: owner }); 21 | }); 22 | }); 23 | 24 | describe("测试ERC20合约基本信息", function () { 25 | ERC20.detail(); 26 | }); 27 | describe("第一次将代币分配给一些账户", function () { 28 | ERC20.transfer(owner, sender, (EthValue * 5).toString(), '代币发送给sender'); 29 | ERC20.transfer(owner, receiver, (EthValue * 10).toString(), '代币发送给receiver'); 30 | ERC20.transfer(owner, purchaser, (EthValue * 15).toString(), '代币发送给purchaser'); 31 | ERC20.transfer(owner, beneficiary, (EthValue * 25).toString(), '代币发送给beneficiary'); 32 | it('第一次记录账户余额: balanceOf()', async function () { 33 | balanceBefore[owner] = await ERC20Instance.balanceOf(owner); 34 | balanceBefore[sender] = await ERC20Instance.balanceOf(sender); 35 | balanceBefore[receiver] = await ERC20Instance.balanceOf(receiver); 36 | balanceBefore[purchaser] = await ERC20Instance.balanceOf(purchaser); 37 | balanceBefore[beneficiary] = await ERC20Instance.balanceOf(beneficiary); 38 | }); 39 | }); 40 | describe("第一次执行快照", async function () { 41 | it('第一次执行快照: snapshot()', async function () { 42 | let receipt = await ERC20Instance.snapshot(); 43 | snapshotId = receipt.logs[0].args.id; 44 | expectEvent(receipt, 'Snapshot', { 45 | id: receipt.logs[0].args.id 46 | } 47 | ); 48 | }); 49 | }); 50 | 51 | describe("第二次将代币分配给一些账户", function () { 52 | ERC20.transfer(owner, sender, (EthValue * 5).toString(), '代币发送给sender'); 53 | ERC20.transfer(owner, receiver, (EthValue * 10).toString(), '代币发送给receiver'); 54 | ERC20.transfer(owner, purchaser, (EthValue * 15).toString(), '代币发送给purchaser'); 55 | ERC20.transfer(owner, beneficiary, (EthValue * 25).toString(), '代币发送给beneficiary'); 56 | }); 57 | describe("第一次验证快照", async function () { 58 | it('第一次验证快照: balanceOfAt()', async function () { 59 | assert.equal(balanceBefore[owner].toString(), (await ERC20Instance.balanceOfAt(owner, snapshotId)).toString()); 60 | assert.equal(balanceBefore[sender].toString(), (await ERC20Instance.balanceOfAt(sender, snapshotId)).toString()); 61 | assert.equal(balanceBefore[receiver].toString(), (await ERC20Instance.balanceOfAt(receiver, snapshotId)).toString()); 62 | assert.equal(balanceBefore[purchaser].toString(), (await ERC20Instance.balanceOfAt(purchaser, snapshotId)).toString()); 63 | assert.equal(balanceBefore[beneficiary].toString(), (await ERC20Instance.balanceOfAt(beneficiary, snapshotId)).toString()); 64 | }); 65 | it('第一次验证总额快照: totalSupplyAt()', async function () { 66 | assert.equal(ether(ERC20Param[3].toString()).toString(), (await ERC20Instance.totalSupplyAt(snapshotId)).toString()); 67 | }); 68 | }); 69 | 70 | describe("第二次记录账户余额", function () { 71 | it('第二次记录账户余额: balanceOf()', async function () { 72 | balanceBefore[owner] = await ERC20Instance.balanceOf(owner); 73 | balanceBefore[sender] = await ERC20Instance.balanceOf(sender); 74 | balanceBefore[receiver] = await ERC20Instance.balanceOf(receiver); 75 | balanceBefore[purchaser] = await ERC20Instance.balanceOf(purchaser); 76 | balanceBefore[beneficiary] = await ERC20Instance.balanceOf(beneficiary); 77 | }); 78 | }); 79 | describe("第二次执行快照", async function () { 80 | it('第二次执行快照: snapshot()', async function () { 81 | let receipt = await ERC20Instance.snapshot(); 82 | snapshotId = receipt.logs[0].args.id; 83 | expectEvent(receipt, 'Snapshot', { 84 | id: receipt.logs[0].args.id 85 | } 86 | ); 87 | }); 88 | }); 89 | 90 | describe("第二次验证快照", async function () { 91 | it('第二次验证快照: balanceOfAt()', async function () { 92 | assert.equal(balanceBefore[owner].toString(), (await ERC20Instance.balanceOfAt(owner, snapshotId)).toString()); 93 | assert.equal(balanceBefore[sender].toString(), (await ERC20Instance.balanceOfAt(sender, snapshotId)).toString()); 94 | assert.equal(balanceBefore[receiver].toString(), (await ERC20Instance.balanceOfAt(receiver, snapshotId)).toString()); 95 | assert.equal(balanceBefore[purchaser].toString(), (await ERC20Instance.balanceOfAt(purchaser, snapshotId)).toString()); 96 | assert.equal(balanceBefore[beneficiary].toString(), (await ERC20Instance.balanceOfAt(beneficiary, snapshotId)).toString()); 97 | }); 98 | it('第二次验证总额快照: totalSupplyAt()', async function () { 99 | assert.equal(ether(ERC20Param[3].toString()).toString(), (await ERC20Instance.totalSupplyAt(snapshotId)).toString()); 100 | }); 101 | }); -------------------------------------------------------------------------------- /test/Multi/ERC20WithTokenVesting.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | const { contract, accounts } = require('@openzeppelin/test-environment'); 3 | const { expectEvent, expectRevert, ether, time, constants } = require('@openzeppelin/test-helpers'); 4 | const ERC20Contract = contract.fromArtifact("ERC20FixedSupply"); 5 | const ERC20WithTokenVesting = contract.fromArtifact("ERC20WithTokenVesting"); 6 | const ERC20 = require('../inc/ERC20'); 7 | //分期释放合约 8 | const totalSupply = '100000';//发行总量 9 | [owner, sender, receiver, purchaser, beneficiary] = accounts; 10 | EthValue = '10'; 11 | const lockAmount = '24000'; //锁仓数额 12 | let amount; 13 | describe("固定总量代币", function () { 14 | it('布署代币合约', async function () { 15 | ERC20Param = [ 16 | "My Golden Coin", //代币名称 17 | "MGC", //代币缩写 18 | 18, //精度 19 | totalSupply, //发行总量 20 | ]; 21 | ERC20Instance = await ERC20Contract.new(...ERC20Param, { from: owner }); 22 | }); 23 | }); 24 | describe("测试ERC20合约基本信息", function () { 25 | ERC20.detail(); 26 | }); 27 | describe("分期释放合约", function () { 28 | it('布署分期释放合约', async function () { 29 | start = parseInt(await time.latest()) + 60; 30 | cliffDuration = '3600'; 31 | duration = '86400'; 32 | revocable = true; 33 | VestParam = [ 34 | beneficiary, //受益人账户 35 | start, //开始时间 36 | cliffDuration, //断崖时间 37 | duration, //持续时间 38 | revocable //是否可撤销 39 | ] 40 | ERC20WithTokenVestingInstance = await ERC20WithTokenVesting.new(...VestParam, { from: owner }); 41 | }); 42 | it('传送代币到分期释放合约', async function () { 43 | let receipt = await ERC20Instance.transfer(ERC20WithTokenVestingInstance.address, ether(lockAmount), { from: owner }); 44 | expectEvent(receipt, 'Transfer', { 45 | from: owner, 46 | to: ERC20WithTokenVestingInstance.address, 47 | value: ether(lockAmount), 48 | }); 49 | }); 50 | }); 51 | describe("测试分期释放合约的特殊方法", function () { 52 | //测试返回断崖时间 53 | it('返回受益人地址: beneficiary()', async function () { 54 | assert.equal(beneficiary, await ERC20WithTokenVestingInstance.beneficiary()); 55 | }); 56 | //测试返回开始时间 57 | it('返回开始时间: start()', async function () { 58 | assert.equal(start, (await ERC20WithTokenVestingInstance.start()).toString()); 59 | }); 60 | //测试返回断崖时间 61 | it('返回断崖时间: cliff()', async function () { 62 | assert.equal(parseInt(start) + parseInt(cliffDuration), (await ERC20WithTokenVestingInstance.cliff()).toString()); 63 | }); 64 | //测试返回持续时间 65 | it('返回持续时间: duration()', async function () { 66 | assert.equal(VestParam[3], (await ERC20WithTokenVestingInstance.duration()).toString()); 67 | }); 68 | //返回能否撤销 69 | it('返回能否撤销: revocable()', async function () { 70 | assert.equal(VestParam[4].toString(), (await ERC20WithTokenVestingInstance.revocable()).toString()); 71 | }); 72 | //时间流逝 73 | it('推进到断崖时间', async function () { 74 | await time.increaseTo(parseInt(start) + parseInt(cliffDuration)); 75 | }); 76 | //测试释放方法 77 | it('释放方法: release()', async function () { 78 | let receipt = await ERC20WithTokenVestingInstance.release(ERC20Instance.address); 79 | amount = lockAmount * ((await time.latest() - start) / duration); 80 | expectEvent(receipt, 'TokensReleased', { 81 | token: ERC20Instance.address, 82 | amount: ether(amount.toString()) 83 | }); 84 | }); 85 | //测试返回已经释放数量 86 | it('返回已经释放数量: released()', async function () { 87 | assert.equal(ether(amount.toString()), (await ERC20WithTokenVestingInstance.released(ERC20Instance.address)).toString()); 88 | }); 89 | //测试返回是否撤销 90 | it('返回没有撤销: revoked()', async function () { 91 | assert.ok(!await ERC20WithTokenVestingInstance.revoked(ERC20Instance.address)); 92 | }); 93 | //测试撤销方法 94 | it('撤销方法: revoke()', async function () { 95 | await ERC20WithTokenVestingInstance.revoke(ERC20Instance.address,{from:owner}); 96 | }); 97 | //测试返回是否撤销 98 | it('返回已经撤销: revoked()', async function () { 99 | assert.ok(await ERC20WithTokenVestingInstance.revoked(ERC20Instance.address)); 100 | }); 101 | }); -------------------------------------------------------------------------------- /test/inc/ERC777.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | const { ether, constants, expectEvent } = require('@openzeppelin/test-helpers'); 3 | exports.detail = () => { 4 | it('代币名称: name()', async function () { 5 | assert.equal(ERC777Param[0], await ERC777Instance.name()); 6 | }); 7 | it('代币缩写: symbol()', async function () { 8 | assert.equal(ERC777Param[1], await ERC777Instance.symbol()); 9 | }); 10 | it('代币精度: decimals()', async function () { 11 | assert.equal('18', (await ERC777Instance.decimals()).toString()); 12 | }); 13 | it('代币总量: totalSupply()', async function () { 14 | assert.equal(ERC777Param[2].toString(), (await ERC777Instance.totalSupply()).toString()); 15 | }); 16 | it('代币最小单位: granularity()', async function () { 17 | assert.equal('1', (await ERC777Instance.granularity()).toString()); 18 | }); 19 | } 20 | exports.totalSupply = (totalSupply) => { 21 | //测试代币总量 22 | it('代币总量: totalSupply()', async function () { 23 | assert.equal(ether(totalSupply).toString(), (await ERC777Instance.totalSupply()).toString()); 24 | }); 25 | } 26 | exports.balanceOf = (balance, account, desc) => { 27 | //测试账户余额 28 | it(desc + ': balanceOf()', async function () { 29 | assert.equal(ether(balance).toString(), (await ERC777Instance.balanceOf(account)).toString()); 30 | }); 31 | } 32 | exports.cap = (cap,desc) => { 33 | //测试封顶额 34 | it(desc + ': cap()', async function () { 35 | assert.equal(ether(cap).toString(), (await ERC777Instance.cap()).toString()); 36 | }); 37 | } 38 | exports.transfer = (sender, receiver, amount, desc, reject, msg) => { 39 | //测试代币发送 40 | it(desc + ': transfer()', async function () { 41 | if (reject) { 42 | await assert.rejects(ERC777Instance.transfer(receiver, ether(amount), { from: sender }), msg); 43 | } else { 44 | let receipt = await ERC777Instance.transfer(receiver, ether(amount), { from: sender }); 45 | expectEvent(receipt, 'Transfer', { 46 | from: sender, 47 | to: receiver, 48 | value: ether(amount), 49 | }); 50 | } 51 | }); 52 | } 53 | exports.approve = (sender, receiver, amount, desc, reject, msg) => { 54 | it(desc + ': approve()', async function () { 55 | if (reject) { 56 | await assert.rejects(ERC777Instance.approve(receiver, ether(amount), { from: sender }), msg); 57 | } else { 58 | let receipt = await ERC777Instance.approve(receiver, ether(amount), { from: sender }); 59 | expectEvent(receipt, 'Approval', { 60 | owner: sender, 61 | spender: receiver, 62 | value: ether(amount), 63 | }); 64 | } 65 | }); 66 | } 67 | exports.transferFrom = (owner, sender, receiver, amount, desc, reject, msg) => { 68 | //测试批准发送 69 | it(desc + ': transferFrom()', async function () { 70 | if (reject) { 71 | await assert.rejects(ERC777Instance.transferFrom(owner, receiver, ether(amount), { from: sender }), msg); 72 | } else { 73 | let receipt = await ERC777Instance.transferFrom(owner, receiver, ether(amount), { from: sender }); 74 | expectEvent(receipt, 'Transfer', { 75 | from: owner, 76 | to: receiver, 77 | value: ether(amount), 78 | }); 79 | } 80 | }); 81 | } 82 | exports.allowance = (owner, sender, amount, desc) => { 83 | //测试批准数额 84 | it(desc + ': allowance()', async function () { 85 | assert.equal(ether(amount), (await ERC777Instance.allowance(owner, sender)).toString()); 86 | }); 87 | } 88 | exports.burn = (sender, amount, desc, reject, msg) => { 89 | //测试销毁方法 90 | it(desc + ': burn()', async function () { 91 | if (reject) { 92 | await assert.rejects(ERC777Instance.burn(ether(amount), { from: sender }), msg); 93 | } else { 94 | let receipt = await ERC777Instance.burn(ether(amount), { from: sender }); 95 | expectEvent(receipt, 'Transfer', { 96 | from: sender, 97 | to: constants.ZERO_ADDRESS, 98 | value: ether(amount), 99 | }); 100 | } 101 | }); 102 | } -------------------------------------------------------------------------------- /token.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Asset Metadata", 3 | "type": "object", 4 | "properties": { 5 | "name": { 6 | "type": "string", 7 | "description": "指示NFT代表什么" 8 | }, 9 | "description": { 10 | "type": "string", 11 | "description": "描述NFT 代表的资产" 12 | }, 13 | "image": { 14 | "type": "string", 15 | "description": "指向NFT表示资产的资源的URI(MIME 类型为 image/*) , 可以考虑宽度在320到1080像素之间,宽高比在1.91:1到4:5之间的图像。" 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /truffle-config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Use this file to configure your truffle project. It's seeded with some 3 | * common settings for different networks and features like migrations, 4 | * compilation and testing. Uncomment the ones you need or modify 5 | * them to suit your project as necessary. 6 | * 7 | * More information about configuration can be found at: 8 | * 9 | * truffleframework.com/docs/advanced/configuration 10 | * 11 | * To deploy via Infura you'll need a wallet provider (like @truffle/hdwallet-provider) 12 | * to sign your transactions before they're sent to a remote public node. Infura accounts 13 | * are available for free at: infura.io/register. 14 | * 15 | * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate 16 | * public/private key pairs. If you're publishing your code to GitHub make sure you load this 17 | * phrase from a file you've .gitignored so it doesn't accidentally become public. 18 | * 19 | */ 20 | const fs = require('fs'); 21 | 22 | const HDWalletProvider = require('@truffle/hdwallet-provider'); 23 | const infuraKey = fs.readFileSync(".infuraKey").toString().trim(); 24 | const mnemonic = fs.readFileSync(".mnemonic").toString().trim(); 25 | 26 | module.exports = { 27 | /** 28 | * Networks define how you connect to your ethereum client and let you set the 29 | * defaults web3 uses to send transactions. If you don't specify one truffle 30 | * will spin up a development blockchain for you on port 9545 when you 31 | * run `develop` or `test`. You can ask a truffle command to use a specific 32 | * network from the command line, e.g 33 | * 34 | * $ truffle test --network 35 | */ 36 | 37 | networks: { 38 | // Useful for testing. The `development` name is special - truffle uses it by default 39 | // if it's defined here and no other network is specified at the command line. 40 | // You should run a client (like ganache-cli, geth or parity) in a separate terminal 41 | // tab if you use this network and you must also set the `host`, `port` and `network_id` 42 | // options below to some value. 43 | // 44 | 45 | ganache: { 46 | host: "127.0.0.1", // Localhost (default: none) 47 | port: 7545, // Standard Ethereum port (default: none) 48 | network_id: "*", // Any network (default: none) 49 | }, 50 | development: { 51 | host: "127.0.0.1", // Localhost (default: none) 52 | port: 8545, // Standard Ethereum port (default: none) 53 | network_id: "*", // Any network (default: none) 54 | }, 55 | develop: { 56 | host: "127.0.0.1", // Localhost (default: none) 57 | port: 8545, // Standard Ethereum port (default: none) 58 | network_id: "*", // Any network (default: none) 59 | gas: 8500000, // Gas sent with each transaction (default: ~6700000) 60 | gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei) 61 | }, 62 | 63 | // Another network with more advanced options... 64 | // advanced: { 65 | // port: 8777, // Custom port 66 | // network_id: 1342, // Custom network 67 | // gas: 8500000, // Gas sent with each transaction (default: ~6700000) 68 | // gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei) 69 | // from:
, // Account to send txs from (default: accounts[0]) 70 | // websockets: true // Enable EventEmitter interface for web3 (default: false) 71 | // }, 72 | 73 | // Useful for deploying to a public network. 74 | // NB: It's important to wrap the provider as a function. 75 | ropsten: { 76 | provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/` + infuraKey), 77 | network_id: 3, // Ropsten's id 78 | gas: 5500000, // Ropsten has a lower block limit than mainnet 79 | confirmations: 2, // # of confs to wait between deployments. (default: 0) 80 | timeoutBlocks: 20000, // # of blocks before a deployment times out (minimum/default: 50) 81 | skipDryRun: true, // Skip dry run before migrations? (default: false for public nets ) 82 | port: 8545 83 | }, 84 | 85 | rinkeby: { 86 | provider: () => new HDWalletProvider(mnemonic, `https://rinkeby.infura.io/v3/` + infuraKey), 87 | network_id: 4, 88 | }, 89 | kovan: { 90 | provider: () => new HDWalletProvider(mnemonic, `https://kovan.infura.io/v3/` + infuraKey), 91 | network_id: 42, 92 | }, 93 | mainnet: { 94 | provider: () => new HDWalletProvider(mnemonic, `https://mainnet.infura.io/v3/` + infuraKey), 95 | network_id: 1, 96 | }, 97 | // Useful for private networks 98 | // private: { 99 | // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), 100 | // network_id: 2111, // This network is yours, in the cloud. 101 | // production: true // Treats this network as if it was a public net. (default: false) 102 | // } 103 | }, 104 | 105 | // Set default mocha options here, use special reporters etc. 106 | mocha: { 107 | reporter: 'eth-gas-reporter', 108 | reporterOptions: { excludeContracts: ['Migrations'] } 109 | }, 110 | 111 | // Configure your compilers 112 | compilers: { 113 | solc: { 114 | // version: "0.5.1", // Fetch exact version from solc-bin (default: truffle's version) 115 | // docker: true, // Use "0.5.1" you've installed locally with docker (default: false) 116 | // settings: { // See the solidity docs for advice about optimization and evmVersion 117 | // optimizer: { 118 | // enabled: false, 119 | // runs: 200 120 | // }, 121 | // evmVersion: "byzantium" 122 | // } 123 | } 124 | } 125 | } 126 | --------------------------------------------------------------------------------