torn.test.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /* global artifacts, web3, contract */
  2. require('chai').use(require('bn-chai')(web3.utils.BN)).use(require('chai-as-promised')).should()
  3. const { takeSnapshot, revertSnapshot } = require('../scripts/ganacheHelper')
  4. const { PermitSigner } = require('../lib/Permit')
  5. const { toBN, BN } = require('web3-utils')
  6. const Torn = artifacts.require('./TORNMock.sol')
  7. contract('Torn', (accounts) => {
  8. let torn
  9. const governance = accounts[3]
  10. const mining = accounts[4]
  11. const airdrop = accounts[5]
  12. let snapshotId
  13. const owner = accounts[0]
  14. const ownerPrivateKey = '0xc87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3'
  15. const spender = accounts[1]
  16. // eslint-disable-next-line no-unused-vars
  17. const spenderPrivateKey = '0xae6ae8e5ccbfb04590405997ee2d52d2b330726137b875053c36d94e974d162f'
  18. // eslint-disable-next-line no-unused-vars
  19. const recipient = accounts[2]
  20. // eslint-disable-next-line no-unused-vars
  21. const recipientPrivateKey = '0x0dbbe8e4ae425a6d2687f1a7e3ba17bc98c673636790f1b8ad91193c05875ef1'
  22. const value = toBN(10 ** 18)
  23. let domain
  24. let chainId
  25. const cap = toBN(10000000).mul(toBN(10 ** 18))
  26. let currentTime
  27. const thirtyDays = 30 * 24 * 3600
  28. before(async () => {
  29. chainId = await web3.eth.net.getId()
  30. torn = await Torn.new(governance, thirtyDays, [
  31. { to: mining, amount: '0' },
  32. { to: airdrop, amount: cap.toString() },
  33. ])
  34. currentTime = await torn.blockTimestamp()
  35. await torn.transfer(owner, cap.div(toBN(2)), { from: airdrop })
  36. await torn.setChainId(chainId)
  37. await torn.setFakeTimestamp(currentTime)
  38. const blockTimestamp = await torn.blockTimestamp()
  39. blockTimestamp.should.be.eq.BN(toBN(currentTime))
  40. domain = {
  41. name: await torn.name(),
  42. version: '1',
  43. chainId,
  44. verifyingContract: torn.address,
  45. }
  46. snapshotId = await takeSnapshot()
  47. })
  48. describe('#constructor', () => {
  49. it('transfers ownership to governance', async () => {
  50. const ownerFromContract = await torn.governance()
  51. ownerFromContract.should.be.equal(governance)
  52. ;(await torn.allowedTransferee(governance)).should.be.true
  53. ;(await torn.allowedTransferee(mining)).should.be.true
  54. ;(await torn.allowedTransferee(airdrop)).should.be.true
  55. ;(await torn.allowedTransferee(owner)).should.be.false
  56. })
  57. })
  58. describe('pausable', () => {
  59. it('transfers disabled by default', async () => {
  60. await torn.transfer(accounts[1], 1, { from: spender }).should.be.rejectedWith('TORN: paused')
  61. })
  62. it('can only transfer to governance and mining', async () => {
  63. await torn.transfer(governance, 1).should.be.fulfilled
  64. await torn.transfer(mining, 1).should.be.fulfilled
  65. await torn.transfer(accounts[5], 1, { from: mining }).should.be.fulfilled
  66. })
  67. it('can transfer after governace decision', async () => {
  68. await torn.transfer(mining, 10).should.be.fulfilled
  69. await torn.transfer(recipient, 5, { from: mining }).should.be.fulfilled
  70. await torn.transfer(accounts[9], 1, { from: recipient }).should.be.rejectedWith('TORN: paused')
  71. await torn
  72. .changeTransferability(true, { from: governance })
  73. .should.be.rejectedWith('TORN: cannot change transferability yet')
  74. await torn.setFakeTimestamp(currentTime + thirtyDays + 1)
  75. await torn.changeTransferability(true, { from: governance })
  76. await torn.transfer(accounts[9], 1, { from: recipient })
  77. const balance = await torn.balanceOf(accounts[9])
  78. balance.should.be.eq.BN(toBN(1))
  79. })
  80. })
  81. describe('#permit', () => {
  82. it('permitSigner class should work', async () => {
  83. const args = {
  84. owner,
  85. spender,
  86. value,
  87. nonce: 0,
  88. deadline: new BN('123123123123123'),
  89. }
  90. const permitSigner = new PermitSigner(domain, args)
  91. // const message = permitSigner.getPayload()
  92. // console.log('message', JSON.stringify(message));
  93. // Generate the signature in place
  94. const privateKey = '0x6370fd033278c143179d81c5526140625662b8daa446c22ee2d73db3707e620c'
  95. const address = '0x22d491Bde2303f2f43325b2108D26f1eAbA1e32b'
  96. const signature = await permitSigner.getSignature(privateKey)
  97. const signer = await permitSigner.getSignerAddress(args, signature.hex)
  98. address.should.be.equal(signer)
  99. })
  100. it('calls approve if signature is valid', async () => {
  101. const chainIdFromContract = await torn.chainId()
  102. chainIdFromContract.should.be.eq.BN(new BN(domain.chainId))
  103. const args = {
  104. owner,
  105. spender,
  106. value,
  107. nonce: 0,
  108. deadline: new BN(currentTime + thirtyDays),
  109. }
  110. const permitSigner = new PermitSigner(domain, args)
  111. const signature = await permitSigner.getSignature(ownerPrivateKey)
  112. const signer = await permitSigner.getSignerAddress(args, signature.hex)
  113. signer.should.be.equal(owner)
  114. const allowanceBefore = await torn.allowance(owner, spender)
  115. await torn.permit(
  116. args.owner,
  117. args.spender,
  118. args.value.toString(),
  119. args.deadline.toString(),
  120. signature.v,
  121. signature.r,
  122. signature.s,
  123. { from: owner },
  124. )
  125. const allowanceAfter = await torn.allowance(owner, spender)
  126. allowanceAfter.should.be.eq.BN(toBN(allowanceBefore).add(args.value))
  127. })
  128. it('reverts if signature is corrupted', async () => {
  129. const args = {
  130. owner,
  131. spender,
  132. value,
  133. nonce: 0,
  134. deadline: new BN(currentTime + thirtyDays),
  135. }
  136. const permitSigner = new PermitSigner(domain, args)
  137. const signature = await permitSigner.getSignature(ownerPrivateKey)
  138. signature.r = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
  139. const allowanceBefore = await torn.allowance(owner, spender)
  140. await torn
  141. .permit(
  142. args.owner,
  143. args.spender,
  144. args.value.toString(),
  145. args.deadline.toString(),
  146. signature.v,
  147. signature.r,
  148. signature.s,
  149. { from: owner },
  150. )
  151. .should.be.rejectedWith('ECDSA: invalid signature')
  152. const allowanceAfter = await torn.allowance(owner, spender)
  153. allowanceAfter.should.be.eq.BN(allowanceBefore)
  154. })
  155. it('reverts if signature is expired', async () => {
  156. const args = {
  157. owner,
  158. spender,
  159. value,
  160. nonce: 0,
  161. deadline: new BN('1593388800'), // 06/29/2020 @ 12:00am (UTC)
  162. }
  163. const permitSigner = new PermitSigner(domain, args)
  164. const signature = await permitSigner.getSignature(ownerPrivateKey)
  165. const allowanceBefore = await torn.allowance(owner, spender)
  166. await torn
  167. .permit(
  168. args.owner,
  169. args.spender,
  170. args.value.toString(),
  171. args.deadline.toString(),
  172. signature.v,
  173. signature.r,
  174. signature.s,
  175. { from: owner },
  176. )
  177. .should.be.rejectedWith('ERC20Permit: expired deadline')
  178. const allowanceAfter = await torn.allowance(owner, spender)
  179. allowanceAfter.should.be.eq.BN(BN(allowanceBefore))
  180. })
  181. })
  182. afterEach(async () => {
  183. await revertSnapshot(snapshotId.result)
  184. // eslint-disable-next-line require-atomic-updates
  185. snapshotId = await takeSnapshot()
  186. })
  187. })