ERC827Token.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. import EVMRevert from './helpers/EVMRevert';
  2. var Message = artifacts.require('./mock/MessageHelper.sol');
  3. var ERC827TokenMock = artifacts.require('./mock/ERC827TokenMock.sol');
  4. var BigNumber = web3.BigNumber;
  5. var ethjsABI = require('ethjs-abi');
  6. require('chai')
  7. .use(require('chai-as-promised'))
  8. .use(require('chai-bignumber')(BigNumber))
  9. .should();
  10. contract('ERC827 Token', function (accounts) {
  11. let token;
  12. beforeEach(async function () {
  13. token = await ERC827TokenMock.new(accounts[0], 100);
  14. });
  15. it('should return the correct totalSupply after construction', async function () {
  16. let totalSupply = await token.totalSupply();
  17. assert.equal(totalSupply, 100);
  18. });
  19. it('should return the correct allowance amount after approval', async function () {
  20. let token = await ERC827TokenMock.new();
  21. await token.approve(accounts[1], 100);
  22. let allowance = await token.allowance(accounts[0], accounts[1]);
  23. assert.equal(allowance, 100);
  24. });
  25. it('should return correct balances after transfer', async function () {
  26. await token.transfer(accounts[1], 100);
  27. let balance0 = await token.balanceOf(accounts[0]);
  28. assert.equal(balance0, 0);
  29. let balance1 = await token.balanceOf(accounts[1]);
  30. assert.equal(balance1, 100);
  31. });
  32. it('should throw an error when trying to transfer more than balance', async function () {
  33. await token.transfer(accounts[1], 101).should.be.rejectedWith(EVMRevert);
  34. });
  35. it('should return correct balances after transfering from another account', async function () {
  36. await token.approve(accounts[1], 100);
  37. await token.transferFrom(accounts[0], accounts[2], 100, { from: accounts[1] });
  38. let balance0 = await token.balanceOf(accounts[0]);
  39. assert.equal(balance0, 0);
  40. let balance1 = await token.balanceOf(accounts[2]);
  41. assert.equal(balance1, 100);
  42. let balance2 = await token.balanceOf(accounts[1]);
  43. assert.equal(balance2, 0);
  44. });
  45. it('should throw an error when trying to transfer more than allowed', async function () {
  46. await token.approve(accounts[1], 99);
  47. await token.transferFrom(
  48. accounts[0], accounts[2], 100,
  49. { from: accounts[1] }
  50. ).should.be.rejectedWith(EVMRevert);
  51. });
  52. it('should throw an error when trying to transferFrom more than _from has', async function () {
  53. let balance0 = await token.balanceOf(accounts[0]);
  54. await token.approve(accounts[1], 99);
  55. await token.transferFrom(
  56. accounts[0], accounts[2], balance0 + 1,
  57. { from: accounts[1] }
  58. ).should.be.rejectedWith(EVMRevert);
  59. });
  60. describe('validating allowance updates to spender', function () {
  61. let preApproved;
  62. it('should start with zero', async function () {
  63. preApproved = await token.allowance(accounts[0], accounts[1]);
  64. assert.equal(preApproved, 0);
  65. });
  66. it('should increase by 50 then decrease by 10', async function () {
  67. await token.increaseApproval(accounts[1], 50);
  68. let postIncrease = await token.allowance(accounts[0], accounts[1]);
  69. preApproved.plus(50).should.be.bignumber.equal(postIncrease);
  70. await token.decreaseApproval(accounts[1], 10);
  71. let postDecrease = await token.allowance(accounts[0], accounts[1]);
  72. postIncrease.minus(10).should.be.bignumber.equal(postDecrease);
  73. });
  74. });
  75. it('should increase by 50 then set to 0 when decreasing by more than 50', async function () {
  76. await token.approve(accounts[1], 50);
  77. await token.decreaseApproval(accounts[1], 60);
  78. let postDecrease = await token.allowance(accounts[0], accounts[1]);
  79. postDecrease.should.be.bignumber.equal(0);
  80. });
  81. it('should throw an error when trying to transfer to 0x0', async function () {
  82. await token.transfer(0x0, 100).should.be.rejectedWith(EVMRevert);
  83. });
  84. it('should throw an error when trying to transferFrom to 0x0', async function () {
  85. await token.approve(accounts[1], 100);
  86. await token.transferFrom(accounts[0], 0x0, 100, { from: accounts[1] })
  87. .should.be.rejectedWith(EVMRevert);
  88. });
  89. describe('Test ERC827 methods', function () {
  90. it('should return correct balances after transfer (with data) and show the event on receiver contract', async function () {
  91. const message = await Message.new();
  92. const extraData = message.contract.showMessage.getData(
  93. web3.toHex(123456), 666, 'Transfer Done'
  94. );
  95. // Use method #8 tranfer of the abi to encode the data tx
  96. const transferData = ethjsABI.encodeMethod(token.abi[8],
  97. [message.contract.address, 100, extraData]
  98. );
  99. const transaction = await token.sendTransaction(
  100. { from: accounts[0], data: transferData }
  101. );
  102. assert.equal(2, transaction.receipt.logs.length);
  103. new BigNumber(100).should.be.bignumber.equal(
  104. await token.balanceOf(message.contract.address)
  105. );
  106. });
  107. it('should return correct allowance after approve (with data) and show the event on receiver contract', async function () {
  108. const message = await Message.new();
  109. const extraData = message.contract.showMessage.getData(
  110. web3.toHex(123456), 666, 'Transfer Done'
  111. );
  112. // Use method #3 approve of the abi to encode the data tx
  113. const approveData = ethjsABI.encodeMethod(token.abi[3],
  114. [message.contract.address, 100, extraData]
  115. );
  116. const transaction = await token.sendTransaction(
  117. { from: accounts[0], data: approveData }
  118. );
  119. assert.equal(2, transaction.receipt.logs.length);
  120. new BigNumber(100).should.be.bignumber.equal(
  121. await token.allowance(accounts[0], message.contract.address)
  122. );
  123. });
  124. it('should return correct balances after transferFrom (with data) and show the event on receiver contract', async function () {
  125. const message = await Message.new();
  126. const extraData = message.contract.showMessage.getData(
  127. web3.toHex(123456), 666, 'Transfer Done'
  128. );
  129. await token.approve(accounts[1], 100, { from: accounts[0] });
  130. new BigNumber(100).should.be.bignumber.equal(
  131. await token.allowance(accounts[0], accounts[1])
  132. );
  133. // Use method #7 transferFrom of the abi to encode the data tx
  134. const transferFromData = ethjsABI.encodeMethod(token.abi[7],
  135. [accounts[0], message.contract.address, 100, extraData]
  136. );
  137. const transaction = await token.sendTransaction(
  138. { from: accounts[1], data: transferFromData }
  139. );
  140. assert.equal(2, transaction.receipt.logs.length);
  141. new BigNumber(100).should.be.bignumber.equal(
  142. await token.balanceOf(message.contract.address)
  143. );
  144. });
  145. it('should fail inside approve (with data)', async function () {
  146. const message = await Message.new();
  147. const extraData = message.contract.fail.getData();
  148. // Use method #3 approve of the abi to encode the data tx
  149. const approveData = ethjsABI.encodeMethod(token.abi[3],
  150. [message.contract.address, 10, extraData]
  151. );
  152. await token.sendTransaction(
  153. { from: accounts[0], data: approveData }
  154. ).should.be.rejectedWith(EVMRevert);
  155. // approval should not have gone through so allowance is still 0
  156. new BigNumber(0).should.be.bignumber
  157. .equal(await token.allowance(accounts[1], message.contract.address));
  158. });
  159. it('should fail inside transfer (with data)', async function () {
  160. const message = await Message.new();
  161. const extraData = message.contract.fail.getData();
  162. // Use method #8 tranfer of the abi to encode the data tx
  163. const transferData = ethjsABI.encodeMethod(token.abi[8],
  164. [message.contract.address, 10, extraData]
  165. );
  166. await token.sendTransaction(
  167. { from: accounts[0], data: transferData }
  168. ).should.be.rejectedWith(EVMRevert);
  169. // transfer should not have gone through, so balance is still 0
  170. new BigNumber(0).should.be.bignumber
  171. .equal(await token.balanceOf(message.contract.address));
  172. });
  173. it('should fail inside transferFrom (with data)', async function () {
  174. const message = await Message.new();
  175. const extraData = message.contract.fail.getData();
  176. await token.approve(accounts[1], 10, { from: accounts[2] });
  177. // Use method #7 tranferFrom of the abi to encode the data tx
  178. const transferFromData = ethjsABI.encodeMethod(token.abi[7],
  179. [accounts[2], message.contract.address, 10, extraData]
  180. );
  181. await token.sendTransaction(
  182. { from: accounts[1], data: transferFromData }
  183. ).should.be.rejectedWith(EVMRevert);
  184. // transferFrom should have failed so balance is still 0 but allowance is 10
  185. new BigNumber(10).should.be.bignumber
  186. .equal(await token.allowance(accounts[2], accounts[1]));
  187. new BigNumber(0).should.be.bignumber
  188. .equal(await token.balanceOf(message.contract.address));
  189. });
  190. it('should fail approve (with data) when using token contract address as receiver', async function () {
  191. const message = await Message.new();
  192. const extraData = message.contract.showMessage.getData(
  193. web3.toHex(123456), 666, 'Transfer Done'
  194. );
  195. // Use method #3 approve of the abi to encode the data tx
  196. const approveData = ethjsABI.encodeMethod(token.abi[3],
  197. [token.contract.address, 100, extraData]
  198. );
  199. await token.sendTransaction(
  200. { from: accounts[0], data: approveData }
  201. ).should.be.rejectedWith(EVMRevert);
  202. });
  203. it('should fail transfer (with data) when using token contract address as receiver', async function () {
  204. const message = await Message.new();
  205. const extraData = message.contract.showMessage.getData(
  206. web3.toHex(123456), 666, 'Transfer Done'
  207. );
  208. // Use method #8 tranfer of the abi to encode the data tx
  209. const transferData = ethjsABI.encodeMethod(token.abi[8],
  210. [token.contract.address, 100, extraData]
  211. );
  212. await token.sendTransaction(
  213. { from: accounts[0], data: transferData }
  214. ).should.be.rejectedWith(EVMRevert);
  215. });
  216. it('should fail transferFrom (with data) when using token contract address as receiver', async function () {
  217. const message = await Message.new();
  218. const extraData = message.contract.showMessage.getData(
  219. web3.toHex(123456), 666, 'Transfer Done'
  220. );
  221. await token.approve(accounts[1], 1, { from: accounts[0] });
  222. // Use method #7 tranferFrom of the abi to encode the data tx
  223. const transferFromData = ethjsABI.encodeMethod(token.abi[7],
  224. [accounts[0], token.contract.address, 1, extraData]
  225. );
  226. await token.sendTransaction(
  227. { from: accounts[1], data: transferFromData }
  228. ).should.be.rejectedWith(EVMRevert);
  229. });
  230. });
  231. });