ERC827Token.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. import EVMRevert from '../../helpers/EVMRevert';
  2. var Message = artifacts.require('MessageHelper.sol');
  3. var ERC827TokenMock = artifacts.require('ERC827TokenMock.sol');
  4. var BigNumber = web3.BigNumber;
  5. var _ = require('lodash');
  6. var ethjsABI = require('ethjs-abi');
  7. require('chai')
  8. .use(require('chai-as-promised'))
  9. .use(require('chai-bignumber')(BigNumber))
  10. .should();
  11. contract('ERC827 Token', function (accounts) {
  12. let token;
  13. function findMethod (abi, name, args) {
  14. for (var i = 0; i < abi.length; i++) {
  15. const methodArgs = _.map(abi[i].inputs, 'type').join(',');
  16. if ((abi[i].name === name) && (methodArgs === args)) {
  17. return abi[i];
  18. }
  19. }
  20. }
  21. beforeEach(async function () {
  22. token = await ERC827TokenMock.new(accounts[0], 100);
  23. });
  24. it('should return the correct totalSupply after construction', async function () {
  25. let totalSupply = await token.totalSupply();
  26. assert.equal(totalSupply, 100);
  27. });
  28. it('should return the correct allowance amount after approval', async function () {
  29. let token = await ERC827TokenMock.new();
  30. await token.approve(accounts[1], 100);
  31. let allowance = await token.allowance(accounts[0], accounts[1]);
  32. assert.equal(allowance, 100);
  33. });
  34. it('should return correct balances after transfer', async function () {
  35. await token.transfer(accounts[1], 100);
  36. let balance0 = await token.balanceOf(accounts[0]);
  37. assert.equal(balance0, 0);
  38. let balance1 = await token.balanceOf(accounts[1]);
  39. assert.equal(balance1, 100);
  40. });
  41. it('should throw an error when trying to transfer more than balance', async function () {
  42. await token.transfer(accounts[1], 101).should.be.rejectedWith(EVMRevert);
  43. });
  44. it('should return correct balances after transfering from another account', async function () {
  45. await token.approve(accounts[1], 100);
  46. await token.transferFrom(accounts[0], accounts[2], 100, { from: accounts[1] });
  47. let balance0 = await token.balanceOf(accounts[0]);
  48. assert.equal(balance0, 0);
  49. let balance1 = await token.balanceOf(accounts[2]);
  50. assert.equal(balance1, 100);
  51. let balance2 = await token.balanceOf(accounts[1]);
  52. assert.equal(balance2, 0);
  53. });
  54. it('should throw an error when trying to transfer more than allowed', async function () {
  55. await token.approve(accounts[1], 99);
  56. await token.transferFrom(
  57. accounts[0], accounts[2], 100,
  58. { from: accounts[1] }
  59. ).should.be.rejectedWith(EVMRevert);
  60. });
  61. it('should throw an error when trying to transferFrom more than _from has', async function () {
  62. let balance0 = await token.balanceOf(accounts[0]);
  63. await token.approve(accounts[1], 99);
  64. await token.transferFrom(
  65. accounts[0], accounts[2], balance0 + 1,
  66. { from: accounts[1] }
  67. ).should.be.rejectedWith(EVMRevert);
  68. });
  69. describe('validating allowance updates to spender', function () {
  70. let preApproved;
  71. it('should start with zero', async function () {
  72. preApproved = await token.allowance(accounts[0], accounts[1]);
  73. assert.equal(preApproved, 0);
  74. });
  75. it('should increase by 50 then decrease by 10', async function () {
  76. const abiMethod = findMethod(token.abi, 'increaseApproval', 'address,uint256');
  77. const increaseApprovalData = ethjsABI.encodeMethod(abiMethod,
  78. [accounts[1], 50]
  79. );
  80. await token.sendTransaction(
  81. { from: accounts[0], data: increaseApprovalData }
  82. );
  83. let postIncrease = await token.allowance(accounts[0], accounts[1]);
  84. preApproved.plus(50).should.be.bignumber.equal(postIncrease);
  85. await token.decreaseApproval(accounts[1], 10);
  86. let postDecrease = await token.allowance(accounts[0], accounts[1]);
  87. postIncrease.minus(10).should.be.bignumber.equal(postDecrease);
  88. });
  89. });
  90. it('should increase by 50 then set to 0 when decreasing by more than 50', async function () {
  91. await token.approve(accounts[1], 50);
  92. await token.decreaseApproval(accounts[1], 60);
  93. let postDecrease = await token.allowance(accounts[0], accounts[1]);
  94. postDecrease.should.be.bignumber.equal(0);
  95. });
  96. it('should throw an error when trying to transfer to 0x0', async function () {
  97. await token.transfer(0x0, 100).should.be.rejectedWith(EVMRevert);
  98. });
  99. it('should throw an error when trying to transferFrom to 0x0', async function () {
  100. await token.approve(accounts[1], 100);
  101. await token.transferFrom(accounts[0], 0x0, 100, { from: accounts[1] })
  102. .should.be.rejectedWith(EVMRevert);
  103. });
  104. describe('Test ERC827 methods', function () {
  105. it(
  106. 'should return correct balances after transfer (with data) and show the event on receiver contract'
  107. , async function () {
  108. const message = await Message.new();
  109. const extraData = message.contract.showMessage.getData(
  110. web3.toHex(123456), 666, 'Transfer Done'
  111. );
  112. const abiMethod = findMethod(token.abi, 'transfer', 'address,uint256,bytes');
  113. const transferData = ethjsABI.encodeMethod(abiMethod,
  114. [message.contract.address, 100, extraData]
  115. );
  116. const transaction = await token.sendTransaction(
  117. { from: accounts[0], data: transferData }
  118. );
  119. assert.equal(2, transaction.receipt.logs.length);
  120. new BigNumber(100).should.be.bignumber.equal(
  121. await token.balanceOf(message.contract.address)
  122. );
  123. });
  124. it(
  125. 'should return correct allowance after approve (with data) and show the event on receiver contract'
  126. , async function () {
  127. const message = await Message.new();
  128. const extraData = message.contract.showMessage.getData(
  129. web3.toHex(123456), 666, 'Transfer Done'
  130. );
  131. const abiMethod = findMethod(token.abi, 'approve', 'address,uint256,bytes');
  132. const approveData = ethjsABI.encodeMethod(abiMethod,
  133. [message.contract.address, 100, extraData]
  134. );
  135. const transaction = await token.sendTransaction(
  136. { from: accounts[0], data: approveData }
  137. );
  138. assert.equal(2, transaction.receipt.logs.length);
  139. new BigNumber(100).should.be.bignumber.equal(
  140. await token.allowance(accounts[0], message.contract.address)
  141. );
  142. });
  143. it(
  144. 'should return correct allowance after increaseApproval (with data) and show the event on receiver contract'
  145. , async function () {
  146. const message = await Message.new();
  147. const extraData = message.contract.showMessage.getData(
  148. web3.toHex(123456), 666, 'Transfer Done'
  149. );
  150. await token.approve(message.contract.address, 10);
  151. new BigNumber(10).should.be.bignumber.equal(
  152. await token.allowance(accounts[0], message.contract.address)
  153. );
  154. const abiMethod = findMethod(token.abi, 'increaseApproval', 'address,uint256,bytes');
  155. const increaseApprovalData = ethjsABI.encodeMethod(abiMethod,
  156. [message.contract.address, 50, extraData]
  157. );
  158. const transaction = await token.sendTransaction(
  159. { from: accounts[0], data: increaseApprovalData }
  160. );
  161. assert.equal(2, transaction.receipt.logs.length);
  162. new BigNumber(60).should.be.bignumber.equal(
  163. await token.allowance(accounts[0], message.contract.address)
  164. );
  165. });
  166. it(
  167. 'should return correct allowance after decreaseApproval (with data) and show the event on receiver contract'
  168. , async function () {
  169. const message = await Message.new();
  170. await token.approve(message.contract.address, 100);
  171. new BigNumber(100).should.be.bignumber.equal(
  172. await token.allowance(accounts[0], message.contract.address)
  173. );
  174. const extraData = message.contract.showMessage.getData(
  175. web3.toHex(123456), 666, 'Transfer Done'
  176. );
  177. const abiMethod = findMethod(token.abi, 'decreaseApproval', 'address,uint256,bytes');
  178. const decreaseApprovalData = ethjsABI.encodeMethod(abiMethod,
  179. [message.contract.address, 60, extraData]
  180. );
  181. const transaction = await token.sendTransaction(
  182. { from: accounts[0], data: decreaseApprovalData }
  183. );
  184. assert.equal(2, transaction.receipt.logs.length);
  185. new BigNumber(40).should.be.bignumber.equal(
  186. await token.allowance(accounts[0], message.contract.address)
  187. );
  188. });
  189. it(
  190. 'should return correct balances after transferFrom (with data) and show the event on receiver contract'
  191. , async function () {
  192. const message = await Message.new();
  193. const extraData = message.contract.showMessage.getData(
  194. web3.toHex(123456), 666, 'Transfer Done'
  195. );
  196. await token.approve(accounts[1], 100, { from: accounts[0] });
  197. new BigNumber(100).should.be.bignumber.equal(
  198. await token.allowance(accounts[0], accounts[1])
  199. );
  200. const abiMethod = findMethod(token.abi, 'transferFrom', 'address,address,uint256,bytes');
  201. const transferFromData = ethjsABI.encodeMethod(abiMethod,
  202. [accounts[0], message.contract.address, 100, extraData]
  203. );
  204. const transaction = await token.sendTransaction(
  205. { from: accounts[1], data: transferFromData }
  206. );
  207. assert.equal(2, transaction.receipt.logs.length);
  208. new BigNumber(100).should.be.bignumber.equal(
  209. await token.balanceOf(message.contract.address)
  210. );
  211. });
  212. it('should fail inside approve (with data)', async function () {
  213. const message = await Message.new();
  214. const extraData = message.contract.fail.getData();
  215. const abiMethod = findMethod(token.abi, 'approve', 'address,uint256,bytes');
  216. const approveData = ethjsABI.encodeMethod(abiMethod,
  217. [message.contract.address, 10, extraData]
  218. );
  219. await token.sendTransaction(
  220. { from: accounts[0], data: approveData }
  221. ).should.be.rejectedWith(EVMRevert);
  222. // approval should not have gone through so allowance is still 0
  223. new BigNumber(0).should.be.bignumber
  224. .equal(await token.allowance(accounts[1], message.contract.address));
  225. });
  226. it('should fail inside transfer (with data)', async function () {
  227. const message = await Message.new();
  228. const extraData = message.contract.fail.getData();
  229. const abiMethod = findMethod(token.abi, 'transfer', 'address,uint256,bytes');
  230. const transferData = ethjsABI.encodeMethod(abiMethod,
  231. [message.contract.address, 10, extraData]
  232. );
  233. await token.sendTransaction(
  234. { from: accounts[0], data: transferData }
  235. ).should.be.rejectedWith(EVMRevert);
  236. // transfer should not have gone through, so balance is still 0
  237. new BigNumber(0).should.be.bignumber
  238. .equal(await token.balanceOf(message.contract.address));
  239. });
  240. it('should fail inside transferFrom (with data)', async function () {
  241. const message = await Message.new();
  242. const extraData = message.contract.fail.getData();
  243. await token.approve(accounts[1], 10, { from: accounts[2] });
  244. const abiMethod = findMethod(token.abi, 'transferFrom', 'address,address,uint256,bytes');
  245. const transferFromData = ethjsABI.encodeMethod(abiMethod,
  246. [accounts[2], message.contract.address, 10, extraData]
  247. );
  248. await token.sendTransaction(
  249. { from: accounts[1], data: transferFromData }
  250. ).should.be.rejectedWith(EVMRevert);
  251. // transferFrom should have failed so balance is still 0 but allowance is 10
  252. new BigNumber(10).should.be.bignumber
  253. .equal(await token.allowance(accounts[2], accounts[1]));
  254. new BigNumber(0).should.be.bignumber
  255. .equal(await token.balanceOf(message.contract.address));
  256. });
  257. it('should fail approve (with data) when using token contract address as receiver', async function () {
  258. const message = await Message.new();
  259. const extraData = message.contract.showMessage.getData(
  260. web3.toHex(123456), 666, 'Transfer Done'
  261. );
  262. const abiMethod = findMethod(token.abi, 'approve', 'address,uint256,bytes');
  263. const approveData = ethjsABI.encodeMethod(abiMethod,
  264. [token.contract.address, 100, extraData]
  265. );
  266. await token.sendTransaction(
  267. { from: accounts[0], data: approveData }
  268. ).should.be.rejectedWith(EVMRevert);
  269. });
  270. it('should fail transfer (with data) when using token contract address as receiver', async function () {
  271. const message = await Message.new();
  272. const extraData = message.contract.showMessage.getData(
  273. web3.toHex(123456), 666, 'Transfer Done'
  274. );
  275. const abiMethod = findMethod(token.abi, 'transfer', 'address,uint256,bytes');
  276. const transferData = ethjsABI.encodeMethod(abiMethod,
  277. [token.contract.address, 100, extraData]
  278. );
  279. await token.sendTransaction(
  280. { from: accounts[0], data: transferData }
  281. ).should.be.rejectedWith(EVMRevert);
  282. });
  283. it('should fail transferFrom (with data) when using token contract address as receiver', async function () {
  284. const message = await Message.new();
  285. const extraData = message.contract.showMessage.getData(
  286. web3.toHex(123456), 666, 'Transfer Done'
  287. );
  288. await token.approve(accounts[1], 1, { from: accounts[0] });
  289. const abiMethod = findMethod(token.abi, 'transferFrom', 'address,address,uint256,bytes');
  290. const transferFromData = ethjsABI.encodeMethod(abiMethod,
  291. [accounts[0], token.contract.address, 1, extraData]
  292. );
  293. await token.sendTransaction(
  294. { from: accounts[1], data: transferFromData }
  295. ).should.be.rejectedWith(EVMRevert);
  296. });
  297. });
  298. });