ERC827Token.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  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 _ = 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. const abiMethod = findMethod(token.abi, 'increaseApproval', 'address,uint256,bytes');
  151. const increaseApprovalData = ethjsABI.encodeMethod(abiMethod,
  152. [message.contract.address, 50, extraData]
  153. );
  154. const transaction = await token.sendTransaction(
  155. { from: accounts[0], data: increaseApprovalData }
  156. );
  157. assert.equal(2, transaction.receipt.logs.length);
  158. new BigNumber(50).should.be.bignumber.equal(
  159. await token.allowance(accounts[0], message.contract.address)
  160. );
  161. });
  162. it(
  163. 'should return correct allowance after decreaseApproval (with data) and show the event on receiver contract'
  164. , async function () {
  165. const message = await Message.new();
  166. await token.approve(message.contract.address, 100);
  167. const extraData = message.contract.showMessage.getData(
  168. web3.toHex(123456), 666, 'Transfer Done'
  169. );
  170. const abiMethod = findMethod(token.abi, 'decreaseApproval', 'address,uint256,bytes');
  171. const decreaseApprovalData = ethjsABI.encodeMethod(abiMethod,
  172. [message.contract.address, 60, extraData]
  173. );
  174. const transaction = await token.sendTransaction(
  175. { from: accounts[0], data: decreaseApprovalData }
  176. );
  177. assert.equal(2, transaction.receipt.logs.length);
  178. new BigNumber(40).should.be.bignumber.equal(
  179. await token.allowance(accounts[0], message.contract.address)
  180. );
  181. });
  182. it(
  183. 'should return correct balances after transferFrom (with data) and show the event on receiver contract'
  184. , async function () {
  185. const message = await Message.new();
  186. const extraData = message.contract.showMessage.getData(
  187. web3.toHex(123456), 666, 'Transfer Done'
  188. );
  189. await token.approve(accounts[1], 100, { from: accounts[0] });
  190. new BigNumber(100).should.be.bignumber.equal(
  191. await token.allowance(accounts[0], accounts[1])
  192. );
  193. const abiMethod = findMethod(token.abi, 'transferFrom', 'address,address,uint256,bytes');
  194. const transferFromData = ethjsABI.encodeMethod(abiMethod,
  195. [accounts[0], message.contract.address, 100, extraData]
  196. );
  197. const transaction = await token.sendTransaction(
  198. { from: accounts[1], data: transferFromData }
  199. );
  200. assert.equal(2, transaction.receipt.logs.length);
  201. new BigNumber(100).should.be.bignumber.equal(
  202. await token.balanceOf(message.contract.address)
  203. );
  204. });
  205. it('should fail inside approve (with data)', async function () {
  206. const message = await Message.new();
  207. const extraData = message.contract.fail.getData();
  208. const abiMethod = findMethod(token.abi, 'approve', 'address,uint256,bytes');
  209. const approveData = ethjsABI.encodeMethod(abiMethod,
  210. [message.contract.address, 10, extraData]
  211. );
  212. await token.sendTransaction(
  213. { from: accounts[0], data: approveData }
  214. ).should.be.rejectedWith(EVMRevert);
  215. // approval should not have gone through so allowance is still 0
  216. new BigNumber(0).should.be.bignumber
  217. .equal(await token.allowance(accounts[1], message.contract.address));
  218. });
  219. it('should fail inside transfer (with data)', async function () {
  220. const message = await Message.new();
  221. const extraData = message.contract.fail.getData();
  222. const abiMethod = findMethod(token.abi, 'transfer', 'address,uint256,bytes');
  223. const transferData = ethjsABI.encodeMethod(abiMethod,
  224. [message.contract.address, 10, extraData]
  225. );
  226. await token.sendTransaction(
  227. { from: accounts[0], data: transferData }
  228. ).should.be.rejectedWith(EVMRevert);
  229. // transfer should not have gone through, so balance is still 0
  230. new BigNumber(0).should.be.bignumber
  231. .equal(await token.balanceOf(message.contract.address));
  232. });
  233. it('should fail inside transferFrom (with data)', async function () {
  234. const message = await Message.new();
  235. const extraData = message.contract.fail.getData();
  236. await token.approve(accounts[1], 10, { from: accounts[2] });
  237. const abiMethod = findMethod(token.abi, 'transferFrom', 'address,address,uint256,bytes');
  238. const transferFromData = ethjsABI.encodeMethod(abiMethod,
  239. [accounts[2], message.contract.address, 10, extraData]
  240. );
  241. await token.sendTransaction(
  242. { from: accounts[1], data: transferFromData }
  243. ).should.be.rejectedWith(EVMRevert);
  244. // transferFrom should have failed so balance is still 0 but allowance is 10
  245. new BigNumber(10).should.be.bignumber
  246. .equal(await token.allowance(accounts[2], accounts[1]));
  247. new BigNumber(0).should.be.bignumber
  248. .equal(await token.balanceOf(message.contract.address));
  249. });
  250. it('should fail approve (with data) when using token contract address as receiver', async function () {
  251. const message = await Message.new();
  252. const extraData = message.contract.showMessage.getData(
  253. web3.toHex(123456), 666, 'Transfer Done'
  254. );
  255. const abiMethod = findMethod(token.abi, 'approve', 'address,uint256,bytes');
  256. const approveData = ethjsABI.encodeMethod(abiMethod,
  257. [token.contract.address, 100, extraData]
  258. );
  259. await token.sendTransaction(
  260. { from: accounts[0], data: approveData }
  261. ).should.be.rejectedWith(EVMRevert);
  262. });
  263. it('should fail transfer (with data) when using token contract address as receiver', async function () {
  264. const message = await Message.new();
  265. const extraData = message.contract.showMessage.getData(
  266. web3.toHex(123456), 666, 'Transfer Done'
  267. );
  268. const abiMethod = findMethod(token.abi, 'transfer', 'address,uint256,bytes');
  269. const transferData = ethjsABI.encodeMethod(abiMethod,
  270. [token.contract.address, 100, extraData]
  271. );
  272. await token.sendTransaction(
  273. { from: accounts[0], data: transferData }
  274. ).should.be.rejectedWith(EVMRevert);
  275. });
  276. it('should fail transferFrom (with data) when using token contract address as receiver', async function () {
  277. const message = await Message.new();
  278. const extraData = message.contract.showMessage.getData(
  279. web3.toHex(123456), 666, 'Transfer Done'
  280. );
  281. await token.approve(accounts[1], 1, { from: accounts[0] });
  282. const abiMethod = findMethod(token.abi, 'transferFrom', 'address,address,uint256,bytes');
  283. const transferFromData = ethjsABI.encodeMethod(abiMethod,
  284. [accounts[0], token.contract.address, 1, extraData]
  285. );
  286. await token.sendTransaction(
  287. { from: accounts[1], data: transferFromData }
  288. ).should.be.rejectedWith(EVMRevert);
  289. });
  290. });
  291. });