github.com/codingfuture/orig-energi3@v0.8.4/energi/contracts/test/MasternodeTokenV2.spec.js (about)

     1  // Copyright 2019 The Energi Core Authors
     2  // This file is part of the Energi Core library.
     3  //
     4  // The Energi Core library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The Energi Core library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the Energi Core library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // Energi Governance system is the fundamental part of Energi Core.
    18  
    19  'use strict';
    20  
    21  const MockProposal = artifacts.require('MockProposal');
    22  const MockProxy = artifacts.require('MockProxy');
    23  const MockContract = artifacts.require('MockContract');
    24  const MockSporkRegistry = artifacts.require('MockSporkRegistry');
    25  const MasternodeTokenV1 = artifacts.require('MasternodeTokenV1');
    26  const MasternodeTokenV2 = artifacts.require('MasternodeTokenV2');
    27  const IMasternodeToken = artifacts.require('IMasternodeToken');
    28  const StorageMasternodeTokenV1 = artifacts.require('StorageMasternodeTokenV1');
    29  
    30  const common = require('./common');
    31  
    32  contract("MasternodeTokenV2", async accounts => {
    33      const s = {
    34          artifacts,
    35          accounts,
    36          assert,
    37          it,
    38          web3,
    39          storage: null,
    40      };
    41  
    42      const COLLATERAL_01 = web3.utils.toWei('1000', 'ether');
    43      const COLLATERAL_1 = web3.utils.toWei('10000', 'ether');
    44      const COLLATERAL_2 = web3.utils.toWei('20000', 'ether');
    45      const COLLATERAL_3 = web3.utils.toWei('30000', 'ether');
    46      const COLLATERAL_4 = web3.utils.toWei('40000', 'ether');
    47      const COLLATERAL_7 = web3.utils.toWei('70000', 'ether');
    48      const COLLATERAL_9 = web3.utils.toWei('90000', 'ether');
    49      const COLLATERAL_10 = web3.utils.toWei('100000', 'ether');
    50      const COLLATERAL_13 = web3.utils.toWei('130000', 'ether');
    51      const check_age = async (age) => {
    52          const bn = await web3.eth.getBlockNumber();
    53          expect(age.toString()).equal(bn.toString());
    54      };
    55  
    56      before(async () => {
    57          s.orig = await MasternodeTokenV2.deployed();
    58          s.proxy = await MockProxy.at(await s.orig.proxy());
    59          s.registry_proxy = await MockProxy.at(await s.orig.registry_proxy());
    60          s.fake = await MockContract.new(s.proxy.address);
    61          s.proxy_abi = await MasternodeTokenV2.at(s.proxy.address);
    62          s.token_abi = await IMasternodeToken.at(s.proxy.address);
    63          await s.proxy.setImpl(s.orig.address);
    64          s.storage = await StorageMasternodeTokenV1.at(await s.proxy_abi.v1storage());
    65          Object.freeze(s);
    66      });
    67  
    68      after(async () => {
    69          const impl = await MasternodeTokenV2.new(s.proxy.address, s.registry_proxy.address);
    70          await s.proxy.setImpl(impl.address);
    71  
    72          await s.fake.testDrain(COLLATERAL_3, {from: accounts[1]});
    73          await s.fake.testDrain(COLLATERAL_1, {from: accounts[0]});
    74      });
    75      
    76      describe('common pre', () => common.govPreTests(s) );
    77  
    78      //---
    79      describe('ERC20', () => {
    80          it('should emit Transfer in c-tor', async () => {
    81              const tmp = await MasternodeTokenV2.new(s.proxy.address, s.registry_proxy.address);
    82  
    83              const evt = await tmp.getPastEvents('Transfer', common.evt_last_block);
    84              expect(evt).lengthOf(1);
    85              expect(evt[0].args).deep.include({
    86                  '__length__': 3,
    87                  'from': '0x0000000000000000000000000000000000000000',
    88                  'to': '0x0000000000000000000000000000000000000000',
    89                  'value': web3.utils.toBN('0'),
    90              });
    91          });
    92  
    93          it('should support totalSupply()', async () => {
    94              const res = await s.token_abi.totalSupply();
    95              assert.equal(res.valueOf(), 0);
    96          });
    97  
    98          it('should support name()', async () => {
    99              const res = await s.token_abi.name();
   100              assert.equal(res, "Masternode Collateral");
   101          });
   102  
   103          it('should support symbol()', async () => {
   104              const res = await s.token_abi.symbol();
   105              assert.equal(res, "MNRG");
   106          });
   107  
   108          it('should support decimals()', async () => {
   109              const res = await s.token_abi.decimals();
   110              assert.equal(res.valueOf(), 18);
   111          });
   112  
   113          it('should support balanceOf()', async () => {
   114              const res = await s.token_abi.balanceOf(s.fake.address);
   115              assert.equal(res.valueOf(), 0);
   116          });
   117  
   118          it('should support allowance()', async () => {
   119              const res = await s.token_abi.allowance(s.fake.address, s.fake.address);
   120              assert.equal(res.valueOf(), 0);
   121          });
   122  
   123          it('should refuse transfer()', async () => {
   124              try {
   125                  await s.token_abi.transfer(s.fake.address, '0');
   126                  assert.fail("It must fail");
   127              } catch (e) {
   128                  assert.match(e.message, /Not allowed/);
   129              }
   130          });
   131  
   132          it('should refuse transferFrom()', async () => {
   133              try {
   134                  await s.token_abi.transferFrom(s.fake.address, s.fake.address, '0');
   135                  assert.fail("It must fail");
   136              } catch (e) {
   137                  assert.match(e.message, /Not allowed/);
   138              }
   139          });
   140  
   141          it('should refuse approve()', async () => {
   142              try {
   143                  await s.token_abi.approve(s.fake.address, '0');
   144                  assert.fail("It must fail");
   145              } catch (e) {
   146                  assert.match(e.message, /Not allowed/);
   147              }
   148          });
   149      });
   150  
   151      //---
   152      describe('Primary', () => {
   153          it('should support balanceInfo()', async () => {
   154              const res = await s.token_abi.balanceInfo(s.fake.address);
   155              assert.equal(res['0'].valueOf(), 0);
   156          });
   157  
   158          it('should allow depositCollateral()', async () => {
   159              const { logs } = await s.token_abi.depositCollateral({
   160                  from: accounts[0],
   161                  value: COLLATERAL_1,
   162              });
   163              assert.equal(logs.length, 1);
   164              const res = await s.token_abi.balanceInfo(accounts[0]);
   165              assert.equal(res['0'].valueOf(), COLLATERAL_1);
   166              await check_age(res['1']);
   167  
   168              const res2 = await s.token_abi.balanceOf(accounts[0]);
   169              assert.equal(res2.valueOf(), COLLATERAL_1);
   170  
   171              const res3 = await s.token_abi.totalSupply();
   172              assert.equal(res3.valueOf(), COLLATERAL_1);
   173  
   174              const evt = await s.orig.getPastEvents('Transfer', common.evt_last_block);
   175              expect(evt).lengthOf(1);
   176              expect(evt[0].args).deep.include({
   177                  '__length__': 3,
   178                  'from': '0x0000000000000000000000000000000000000000',
   179                  'to': accounts[0],
   180                  'value': web3.utils.toBN(COLLATERAL_1),
   181              });
   182          });
   183  
   184          it('should correctly reflect last block', async () => {
   185              const res1 = await s.token_abi.balanceInfo(accounts[0]);
   186              await common.moveTime(web3, 3600);
   187  
   188              const res2 = await s.token_abi.balanceInfo(accounts[0]);
   189              assert.equal(res2['0'].valueOf(), COLLATERAL_1);
   190              assert.equal(res1['1'].toString(), res2['1'].toString());
   191          });
   192          
   193          it('should allow depositCollateral() direct', async () => {
   194              const { logs } = await s.orig.depositCollateral({
   195                  from: accounts[0],
   196                  value: COLLATERAL_2,
   197              });
   198              assert.equal(logs.length, 1);
   199              const res = await s.token_abi.balanceInfo(accounts[0]);
   200              assert.equal(res['0'].valueOf(), COLLATERAL_3);
   201              await check_age(res['1']);
   202  
   203              const res2 = await s.token_abi.balanceOf(accounts[0]);
   204              assert.equal(res2.valueOf(), COLLATERAL_3);
   205  
   206              const total = await s.token_abi.totalSupply();
   207  
   208              assert.equal(total.valueOf(), COLLATERAL_3);
   209  
   210              const evt = await s.orig.getPastEvents('Transfer', common.evt_last_block);
   211              expect(evt).lengthOf(1);
   212              expect(evt[0].args).deep.include({
   213                  '__length__': 3,
   214                  'from': '0x0000000000000000000000000000000000000000',
   215                  'to': accounts[0],
   216                  'value': web3.utils.toBN(COLLATERAL_2),
   217              });
   218          });
   219  
   220          it('should refuse depositCollateral() not a multiple of', async () => {
   221              try {
   222                  await s.token_abi.depositCollateral({
   223                      from: accounts[0],
   224                      value: web3.utils.toWei('10001', 'ether'),
   225                  });
   226                  assert.fail("It must fail");
   227              } catch (e) {
   228                  assert.match(e.message, /Not a multiple/);
   229              }
   230  
   231              const evt = await s.orig.getPastEvents('Transfer', common.evt_last_block);
   232              expect(evt).lengthOf(0);
   233          });
   234  
   235          it('should allow depositCollateral() - max', async () => {
   236              const { logs } = await s.token_abi.depositCollateral({
   237                  from: accounts[0],
   238                  value: COLLATERAL_7,
   239              });
   240              assert.equal(logs.length, 1);
   241              const res = await s.token_abi.balanceInfo(accounts[0]);
   242              assert.equal(res['0'].valueOf(), COLLATERAL_10);
   243              await check_age(res['1']);
   244  
   245              const res2 = await s.token_abi.balanceOf(accounts[0]);
   246              assert.equal(res2.valueOf(), COLLATERAL_10);
   247  
   248              const total = await s.token_abi.totalSupply();
   249              assert.equal(total.valueOf(), COLLATERAL_10);
   250          });
   251  
   252          it('should refuse to depositCollateral() over max', async () => {
   253              try {
   254                  await s.token_abi.depositCollateral({
   255                      from: accounts[0],
   256                      value: web3.utils.toWei(COLLATERAL_1, 'ether'),
   257                  });
   258                  assert.fail("It must fail");
   259              } catch (e) {
   260                  assert.match(e.message, /Too much/);
   261              }
   262          });
   263  
   264          it('should allow depositCollateral() another account', async () => {
   265              const { logs } = await s.orig.depositCollateral({
   266                  from: accounts[1],
   267                  value: COLLATERAL_3,
   268              });
   269              assert.equal(logs.length, 1);
   270  
   271              const res = await s.token_abi.balanceInfo(accounts[1]);
   272              assert.equal(res['0'].valueOf(), COLLATERAL_3);
   273              await check_age(res['1']);
   274  
   275              const res2 = await s.token_abi.balanceOf(accounts[1]);
   276              assert.equal(res2.valueOf(), COLLATERAL_3);
   277  
   278              const total = await s.token_abi.totalSupply();
   279              assert.equal(total.valueOf(), COLLATERAL_13);
   280          });
   281  
   282          it('should allow withdrawCollateral()', async () => {
   283              const { logs } = await s.token_abi.withdrawCollateral(COLLATERAL_9, {
   284                  from: accounts[0],
   285              });
   286              assert.equal(logs.length, 1);
   287              const res = await s.token_abi.balanceInfo(accounts[0]);
   288              assert.equal(res['0'].valueOf(), COLLATERAL_1);
   289              await check_age(res['1']);
   290  
   291              const total = await s.token_abi.totalSupply();
   292              assert.equal(total.valueOf(), COLLATERAL_4);
   293  
   294              const evt = await s.orig.getPastEvents('Transfer', common.evt_last_block);
   295              expect(evt).lengthOf(1);
   296              expect(evt[0].args).deep.include({
   297                  '__length__': 3,
   298                  'from': accounts[0],
   299                  'to': '0x0000000000000000000000000000000000000000',
   300                  'value': web3.utils.toBN(COLLATERAL_9),
   301              });
   302          });
   303  
   304          it('should refuse withdrawCollateral() over balance', async () => {
   305              try {
   306                  await s.token_abi.withdrawCollateral(COLLATERAL_2, {
   307                      from: accounts[0],
   308                  });
   309                  assert.fail("It must fail");
   310              } catch (e) {
   311                  assert.match(e.message, /Not enough/);
   312              }
   313  
   314              const evt = await s.orig.getPastEvents('Transfer', common.evt_last_block);
   315              expect(evt).lengthOf(0);
   316          });
   317  
   318          it('should refuse setBalance() on s.storage', async () => {
   319              try {
   320                  await s.storage.setBalance(s.fake.address, COLLATERAL_1, COLLATERAL_1);
   321                  assert.fail("It must fail");
   322              } catch (e) {
   323                  assert.match(e.message, /Not owner/);
   324              }
   325          });
   326  
   327          it('should allow depositCollateral() - V2 min', async () => {
   328              const { logs } = await s.token_abi.depositCollateral({
   329                  from: accounts[2],
   330                  value: COLLATERAL_01,
   331              });
   332              assert.equal(logs.length, 1);
   333              const res = await s.token_abi.balanceInfo(accounts[2]);
   334              assert.equal(res['0'].valueOf(), COLLATERAL_01);
   335              await check_age(res['1']);
   336          });
   337  
   338          it('should migrate from V1', async () => {
   339              // Spork registry
   340              const registry_proxy = await MockProxy.new();
   341              const registry = await MockSporkRegistry.new(registry_proxy.address);
   342              await registry_proxy.setImpl(registry.address);
   343  
   344              // MNToken proxy
   345              const mn_proxy = await MockProxy.new();
   346              const imn = await IMasternodeToken.at(mn_proxy.address);
   347  
   348              const impl1 = await MasternodeTokenV1.new(mn_proxy.address, registry_proxy.address);
   349              const impl2 = await MasternodeTokenV2.new(mn_proxy.address, registry_proxy.address);
   350              await mn_proxy.setImpl(impl1.address);
   351  
   352              // Deposit before migration
   353              await imn.depositCollateral({
   354                  from: accounts[0],
   355                  value: COLLATERAL_1,
   356              });
   357  
   358              // Upgrade
   359              const { logs } = await mn_proxy.proposeUpgrade(impl2.address, 0);
   360              s.assert.equal(logs.length, 1);
   361  
   362              const proposal = await MockProposal.at(logs[0].args['1']);
   363  
   364              await proposal.setAccepted();
   365              await mn_proxy.upgrade(proposal.address);
   366  
   367              const res = await impl2.balanceInfo(accounts[0]);
   368              assert.equal(res['0'].valueOf(), COLLATERAL_1);
   369  
   370              await imn.withdrawCollateral(COLLATERAL_1, {
   371                  from: accounts[0],
   372              });
   373  
   374              const res2 = await impl2.balanceInfo(accounts[0]);
   375              assert.equal(res2['0'].valueOf(), 0);
   376          });
   377      });
   378  
   379      //---
   380      describe('common post', () => common.govPostTests(s) );
   381  });