ERC2771Context.test.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. const ethSigUtil = require('eth-sig-util');
  2. const Wallet = require('ethereumjs-wallet').default;
  3. const { getDomain, domainType } = require('../helpers/eip712');
  4. const { expectEvent } = require('@openzeppelin/test-helpers');
  5. const { expect } = require('chai');
  6. const ERC2771ContextMock = artifacts.require('ERC2771ContextMock');
  7. const MinimalForwarder = artifacts.require('MinimalForwarder');
  8. const ContextMockCaller = artifacts.require('ContextMockCaller');
  9. const { shouldBehaveLikeRegularContext } = require('../utils/Context.behavior');
  10. contract('ERC2771Context', function (accounts) {
  11. beforeEach(async function () {
  12. this.forwarder = await MinimalForwarder.new();
  13. this.recipient = await ERC2771ContextMock.new(this.forwarder.address);
  14. this.domain = await getDomain(this.forwarder);
  15. this.types = {
  16. EIP712Domain: domainType(this.domain),
  17. ForwardRequest: [
  18. { name: 'from', type: 'address' },
  19. { name: 'to', type: 'address' },
  20. { name: 'value', type: 'uint256' },
  21. { name: 'gas', type: 'uint256' },
  22. { name: 'nonce', type: 'uint256' },
  23. { name: 'data', type: 'bytes' },
  24. ],
  25. };
  26. });
  27. it('recognize trusted forwarder', async function () {
  28. expect(await this.recipient.isTrustedForwarder(this.forwarder.address));
  29. });
  30. context('when called directly', function () {
  31. beforeEach(async function () {
  32. this.context = this.recipient; // The Context behavior expects the contract in this.context
  33. this.caller = await ContextMockCaller.new();
  34. });
  35. shouldBehaveLikeRegularContext(...accounts);
  36. });
  37. context('when receiving a relayed call', function () {
  38. beforeEach(async function () {
  39. this.wallet = Wallet.generate();
  40. this.sender = web3.utils.toChecksumAddress(this.wallet.getAddressString());
  41. this.data = {
  42. types: this.types,
  43. domain: this.domain,
  44. primaryType: 'ForwardRequest',
  45. };
  46. });
  47. describe('msgSender', function () {
  48. it('returns the relayed transaction original sender', async function () {
  49. const data = this.recipient.contract.methods.msgSender().encodeABI();
  50. const req = {
  51. from: this.sender,
  52. to: this.recipient.address,
  53. value: '0',
  54. gas: '100000',
  55. nonce: (await this.forwarder.getNonce(this.sender)).toString(),
  56. data,
  57. };
  58. const sign = ethSigUtil.signTypedMessage(this.wallet.getPrivateKey(), { data: { ...this.data, message: req } });
  59. expect(await this.forwarder.verify(req, sign)).to.equal(true);
  60. const { tx } = await this.forwarder.execute(req, sign);
  61. await expectEvent.inTransaction(tx, ERC2771ContextMock, 'Sender', { sender: this.sender });
  62. });
  63. });
  64. describe('msgData', function () {
  65. it('returns the relayed transaction original data', async function () {
  66. const integerValue = '42';
  67. const stringValue = 'OpenZeppelin';
  68. const data = this.recipient.contract.methods.msgData(integerValue, stringValue).encodeABI();
  69. const req = {
  70. from: this.sender,
  71. to: this.recipient.address,
  72. value: '0',
  73. gas: '100000',
  74. nonce: (await this.forwarder.getNonce(this.sender)).toString(),
  75. data,
  76. };
  77. const sign = ethSigUtil.signTypedMessage(this.wallet.getPrivateKey(), { data: { ...this.data, message: req } });
  78. expect(await this.forwarder.verify(req, sign)).to.equal(true);
  79. const { tx } = await this.forwarder.execute(req, sign);
  80. await expectEvent.inTransaction(tx, ERC2771ContextMock, 'Data', { data, integerValue, stringValue });
  81. });
  82. });
  83. });
  84. });