text: Object.defineProperty(exports, "__esModule", { value: true });
  const tslib_1 = require("tslib");
  const ethers = tslib_1.__importStar(require("ethers"));
  const utils_1 = require("./utils");
  const utils = tslib_1.__importStar(require("./utils"));
  // init test wallets from package.json mnemonic
  const web3 = global.web3;
  const { wallet: ownerWallet, provider: ownerProvider, signer: ownerSigner } = utils.createTestWallet(web3, 0);
  const { wallet: receiverWallet, provider: receiverProvider, signer: receiverSigner } = utils.createTestWallet(web3, 2);
  const { wallet: operatorWallet, provider: operatorProvider, signer: operatorSigner } = utils.createTestWallet(web3, 4);
  contract('ERC1155', (accounts) => {
      const MAXVAL = new utils_1.BigNumber(2).pow(256).sub(1); // 2**256 - 1
      const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
      let ownerAddress;
      let receiverAddress;
      let operatorAddress;
      let erc1155Abstract;
      let operatorAbstract;
      let erc1155Contract;
      let operatorERC1155Contract;
      // load contract abi and deploy to test server
      before(async () => {
          ownerAddress = await ownerWallet.getAddress();
          receiverAddress = await receiverWallet.getAddress();
          operatorAddress = await operatorWallet.getAddress();
          erc1155Abstract = await utils_1.AbstractContract.fromArtifactName('ERC1155MetaMintBurnMock');
          operatorAbstract = await utils_1.AbstractContract.fromArtifactName('ERC1155OperatorMock');
      });
      // deploy before each test, to reset state of contract
      beforeEach(async () => {
          erc1155Contract = await erc1155Abstract.deploy(ownerWallet);
          operatorERC1155Contract = await erc1155Contract.connect(operatorSigner);
      });
      describe('Getter functions', () => {
          beforeEach(async () => {
              await erc1155Contract.functions.mintMock(ownerAddress, 5, 256);
              await erc1155Contract.functions.mintMock(receiverAddress, 66, 133);
          });
          it('balanceOf() should return types balance for queried address', async () => {
              let balance5 = await erc1155Contract.functions.balanceOf(ownerAddress, 5);
              utils_1.expect(balance5).to.be.eql(new utils_1.BigNumber(256));
              let balance16 = await erc1155Contract.functions.balanceOf(ownerAddress, 16);
              utils_1.expect(balance16).to.be.eql(new utils_1.BigNumber(0));
          });
          it('balanceOfBatch() should return types balance for queried addresses', async () => {
              let balances = await erc1155Contract.functions.balanceOfBatch([ownerAddress, receiverAddress], [5, 66]);
              utils_1.expect(balances[0]).to.be.eql(new utils_1.BigNumber(256));
              utils_1.expect(balances[1]).to.be.eql(new utils_1.BigNumber(133));
              let balancesNull = await erc1155Contract.functions.balanceOfBatch([ownerAddress, receiverAddress], [1337, 1337]);
              utils_1.expect(balancesNull[0]).to.be.eql(new utils_1.BigNumber(0));
              utils_1.expect(balancesNull[1]).to.be.eql(new utils_1.BigNumber(0));
          });
      });
      describe('safeTransferFrom() function', () => {
          let receiverContract;
          let operatorContract;
          beforeEach(async () => {
              let abstract = await utils_1.AbstractContract.fromArtifactName('ERC1155ReceiverMock');
              receiverContract = await abstract.deploy(ownerWallet);
              operatorContract = await operatorAbstract.deploy(operatorWallet);
              await erc1155Contract.functions.mintMock(ownerAddress, 0, 256);
          });
          it('should be able to transfer if sufficient balance', async () => {
              const tx = erc1155Contract.functions.safeTransferFrom(ownerAddress, receiverAddress, 0, 1, []);
              await utils_1.expect(tx).to.be.fulfilled;
          });
          it('should REVERT if insufficient balance', async () => {
              const tx = erc1155Contract.functions.safeTransferFrom(ownerAddress, receiverAddress, 0, 257, []);
              await utils_1.expect(tx).to.be.rejected;
          });
          it('should REVERT if sending to 0x0', async () => {
              const tx = erc1155Contract.functions.safeTransferFrom(ownerAddress, ZERO_ADDRESS, 0, 1, []);
              await utils_1.expect(tx).to.be.rejected;
          });
          it('should REVERT if operator not approved', async () => {
              const tx = operatorERC1155Contract.functions.safeTransferFrom(operatorAddress, receiverAddress, 0, 1, []);
              await utils_1.expect(tx).to.be.rejected;
          });
          it('should be able to transfer via operator if operator is approved', async () => {
              // owner first gives operatorWallet address approval permission
              await erc1155Contract.functions.setApprovalForAll(operatorAddress, true);
              // operator performs a transfer
              const tx = operatorERC1155Contract.functions.safeTransferFrom(ownerAddress, receiverAddress, 0, 1, []);
              await utils_1.expect(tx).to.be.fulfilled;
          });
          it('should REVERT if transfer leads to overflow', async () => {
              await erc1155Contract.functions.mintMock(receiverAddress, 0, MAXVAL);
              const tx2 = erc1155Contract.functions.safeTransferFrom(ownerAddress, receiverAddress, 0, 1, []);
              await utils_1.expect(tx2).to.be.rejected;
          });
          it('should REVERT when sending to non-receiver contract', async () => {
              const tx = erc1155Contract.functions.safeTransferFrom(ownerAddress, erc1155Contract.address, 0, 1, []);
              await utils_1.expect(tx).to.be.rejected;
          });
          it('should REVERT if invalid response from receiver contract', async () => {
              await receiverContract.functions.setShouldReject(true);
              const tx = erc1155Contract.functions.safeTransferFrom(ownerAddress, receiverContract.address, 0, 1, []);
              await utils_1.expect(tx).to.be.rejected;
          });
          it('should pass if valid response from receiver contract', async () => {
              const tx = erc1155Contract.functions.safeTransferFrom(ownerAddress, receiverContract.address, 0, 1, []);
              await utils_1.expect(tx).to.be.fulfilled;
          });
          it('should pass if data is not null from receiver contract', async () => {
              const data = ethers.utils.toUtf8Bytes('hello');
              // NOTE: typechain generates the wrong type for `bytes` type at this time
              // see https://github.com/ethereum-ts/TypeChain/issues/123
              // @ts-ignore
              const tx = erc1155Contract.functions.safeTransferFrom(ownerAddress, receiverContract.address, 0, 1, data);
              await utils_1.expect(tx).to.be.fulfilled;
          });
          context('When successful transfer', () => {
              let tx;
              beforeEach(async () => {
                  tx = await erc1155Contract.functions.safeTransferFrom(ownerAddress, receiverAddress, 0, 1, []);
              });
              it('should correctly update balance of sender', async () => {
                  const balance = await erc1155Contract.functions.balanceOf(ownerAddress, 0);
                  utils_1.expect(balance).to.be.eql(new utils_1.BigNumber(255));
              });
              it('should correctly update balance of receiver', async () => {
                  const balance = await erc1155Contract.functions.balanceOf(receiverAddress, 0);
                  utils_1.expect(balance).to.be.eql(new utils_1.BigNumber(1));
              });
              describe('TransferSingle event', async () => {
                  let filterFromOperatorContract;
                  it('should emit TransferSingle event', async () => {
                      const receipt = await tx.wait(1);
                      const ev = receipt.events.pop();
                      utils_1.expect(ev.event).to.be.eql('TransferSingle');
                  });
                  it('should have `msg.sender` as `_operator` field, not _from', async () => {
                      await erc1155Contract.functions.setApprovalForAll(operatorAddress, true);
                      tx = await operatorERC1155Contract.functions.safeTransferFrom(ownerAddress, receiverAddress, 0, 1, []);
                      const receipt = await tx.wait(1);
                      const ev = receipt.events.pop();
                      const args = ev.args;
                      utils_1.expect(args._operator).to.be.eql(operatorAddress);
                  });
                  it('should have `msg.sender` as `_operator` field, not tx.origin', async () => {
                      // Get event filter to get internal tx event
                      filterFromOperatorContract = erc1155Contract.filters.TransferSingle(operatorContract.address, null, null, null, null);
                      // Set approval to operator contract
                      await erc1155Contract.functions.setApprovalForAll(operatorContract.address, true);
                      // Execute transfer from operator contract
                      // @ts-ignore (https://github.com/ethereum-ts/TypeChain/issues/118)
                      await operatorContract.functions.safeTransferFrom(erc1155Contract.address, ownerAddress, receiverAddress, 0, 1, [], { gasLimit: 1000000 } // INCORRECT GAS ESTIMATION
                      );
                      // Get logs from internal transaction event
                      // @ts-ignore (https://github.com/ethers-io/ethers.js/issues/204#issuecomment-427059031)
                      filterFromOperatorContract.fromBlock = 0;
                      let logs = await operatorProvider.getLogs(filterFromOperatorContract);
                      let args = erc1155Contract.interface.events.TransferSingle.decode(logs[0].data, logs[0].topics);
                      // operator arg should be equal to msg.sender, not tx.origin
                      utils_1.expect(args._operator).to.be.eql(operatorContract.address);
                  });
              });
          });
      });
      describe('safeBatchTransferFrom() function', () => {
          let types, values;
          let nTokenTypes = 32;
          let nTokensPerType = 10;
          let receiverContract;
          beforeEach(async () => {
              types = [], values = [];
              // Minting enough values for transfer for each types
              for (let i = 0; i < nTokenTypes; i++) {
                  await erc1155Contract.functions.mintMock(ownerAddress, i, nTokensPerType);
                  types.push(i);
                  values.push(nTokensPerType);
              }
              const abstract = await utils_1.AbstractContract.fromArtifactName('ERC1155ReceiverMock');
              receiverContract = await abstract.deploy(ownerWallet);
          });
          it('should be able to transfer if sufficient balances', async () => {
              const tx = erc1155Contract.functions.safeBatchTransferFrom(ownerAddress, receiverAddress, [0, 15, 30], [1, 9, 10], []);
              await utils_1.expect(tx).to.be.fulfilled;
          });
          it('should REVERT if insufficient balance', async () => {
              const tx = erc1155Contract.functions.safeBatchTransferFrom(ownerAddress, receiverAddress, [0], [11], []);
              await utils_1.expect(tx).to.be.rejected;
          });
          it('should REVERT if single insufficient balance', async () => {
              const tx = erc1155Contract.functions.safeBatchTransferFrom(ownerAddress, receiverAddress, [0, 15, 30], [1, 9, 11], []);
              await utils_1.expect(tx).to.be.rejected;
          });
          it('should REVERT if operator not approved', async () => {
              const tx = operatorERC1155Contract.functions.safeBatchTransferFrom(ownerAddress, receiverAddress, types, values, []);
              await utils_1.expect(tx).to.be.rejected;
          });
          it('should REVERT if length of ids and values are not equal', async () => {
              const tx1 = erc1155Contract.functions.safeBatchTransferFrom(ownerAddress, receiverAddress, [0, 15, 30, 0], [1, 9, 10], []);
              await utils_1.expect(tx1).to.be.rejected;
              const tx2 = erc1155Contract.functions.safeBatchTransferFrom(ownerAddress, receiverAddress, [0, 15, 30], [1, 9, 10, 0], []);
              await utils_1.expect(tx2).to.be.rejected;
          });
          it('should REVERT if sending to 0x0', async () => {
              const tx = erc1155Contract.functions.safeBatchTransferFrom(ownerAddress, ZERO_ADDRESS, types, values, []);
              await utils_1.expect(tx).to.be.rejected;
          });
          it('should be able to transfer via operator if operator is approved', async () => {
              await erc1155Contract.functions.setApprovalForAll(operatorAddress, true);
              const tx = operatorERC1155Contract.functions.safeBatchTransferFrom(ownerAddress, receiverAddress, types, values, []);
              await utils_1.expect(tx).to.be.fulfilled;
          });
          it('should REVERT if transfer leads to overflow', async () => {
              await erc1155Contract.functions.mintMock(receiverAddress, 5, MAXVAL);
              const tx = erc1155Contract.functions.safeBatchTransferFrom(ownerAddress, receiverAddress, [5], [1], []);
              await utils_1.expect(tx).to.be.rejected;
          });
          it('should update balances of sender and receiver', async () => {
              await erc1155Contract.functions.safeBatchTransferFrom(ownerAddress, receiverAddress, types, values, []);
              let balanceFrom;
              let balanceTo;
              for (let i = 0; i < types.length; i++) {
                  balanceFrom = await erc1155Contract.functions.balanceOf(ownerAddress, types[i]);
                  balanceTo = await erc1155Contract.functions.balanceOf(receiverAddress, types[i]);
                  utils_1.expect(balanceFrom).to.be.eql(new utils_1.BigNumber(0));
                  utils_1.expect(balanceTo).to.be.eql(new utils_1.BigNumber(values[i]));
              }
          });
          it('should REVERT when sending to non-receiver contract', async () => {
              const tx = erc1155Contract.functions.safeBatchTransferFrom(ownerAddress, erc1155Contract.address, types, values, []);
              await utils_1.expect(tx).to.be.rejected;
          });
          it('should REVERT if invalid response from receiver contract', async () => {
              await receiverContract.functions.setShouldReject(true);
              const tx = erc1155Contract.functions.safeBatchTransferFrom(ownerAddress, receiverContract.address, types, values, []);
              await utils_1.expect(tx).to.be.rejected;
          });
          it('should pass if valid response from receiver contract', async () => {
              const tx = erc1155Contract.functions.safeBatchTransferFrom(ownerAddress, receiverContract.address, types, values, []);
              await utils_1.expect(tx).to.be.fulfilled;
          });
          it('should pass if data is not null from receiver contract', async () => {
              const data = ethers.utils.toUtf8Bytes('hello');
              // TODO: remove ts-ignore when contract declaration is fixed
              // @ts-ignore
              const tx = erc1155Contract.functions.safeBatchTransferFrom(ownerAddress, receiverContract.address, types, values, data);
              await utils_1.expect(tx).to.be.fulfilled;
          });
          describe('TransferBatch event', async () => {
              let tx;
              let filterFromOperatorContract;
              let operatorContract;
              beforeEach(async () => {
                  operatorContract = await operatorAbstract.deploy(operatorWallet);
              });
              it('should emit 1 TransferBatch events of N transfers', async () => {
                  const tx = await erc1155Contract.functions.safeBatchTransferFrom(ownerAddress, receiverAddress, types, values, []);
                  const receipt = await tx.wait(1);
                  const ev = receipt.events.pop();
                  utils_1.expect(ev.event).to.be.eql('TransferBatch');
                  const args = ev.args;
                  utils_1.expect(args._ids.length).to.be.eql(types.length);
              });
              it('should have `msg.sender` as `_operator` field, not _from', async () => {
                  await erc1155Contract.functions.setApprovalForAll(operatorAddress, true);
                  tx = await operatorERC1155Contract.functions.safeBatchTransferFrom(ownerAddress, receiverAddress, types, values, []);
                  const receipt = await tx.wait(1);
                  const ev = receipt.events.pop();
                  const args = ev.args;
                  utils_1.expect(args._operator).to.be.eql(operatorAddress);
              });
              it('should have `msg.sender` as `_operator` field, not tx.origin', async () => {
                  // Get event filter to get internal tx event
                  filterFromOperatorContract = erc1155Contract.filters.TransferBatch(operatorContract.address, null, null, null, null);
                  // Set approval to operator contract
                  await erc1155Contract.functions.setApprovalForAll(operatorContract.address, true);
                  // Execute transfer from operator contract
                  // @ts-ignore (https://github.com/ethereum-ts/TypeChain/issues/118)
                  await operatorContract.functions.safeBatchTransferFrom(erc1155Contract.address, ownerAddress, receiverAddress, types, values, [], { gasLimit: 2000000 } // INCORRECT GAS ESTIMATION
                  );
                  // Get logs from internal transaction event
                  // @ts-ignore (https://github.com/ethers-io/ethers.js/issues/204#issuecomment-427059031)
                  filterFromOperatorContract.fromBlock = 0;
                  let logs = await operatorProvider.getLogs(filterFromOperatorContract);
                  let args = erc1155Contract.interface.events.TransferBatch.decode(logs[0].data, logs[0].topics);
                  // operator arg should be equal to msg.sender, not tx.origin
                  utils_1.expect(args._operator).to.be.eql(operatorContract.address);
              });
          });
      });
      describe('setApprovalForAll() function', () => {
          it('should emit an ApprovalForAll event', async () => {
              const tx = await erc1155Contract.functions.setApprovalForAll(operatorAddress, true);
              const receipt = await tx.wait(1);
              utils_1.expect(receipt.events[0].event).to.be.eql('ApprovalForAll');
          });
          it('should set the operator status to _status argument', async () => {
              const tx = erc1155Contract.functions.setApprovalForAll(operatorAddress, true);
              await utils_1.expect(tx).to.be.fulfilled;
              const status = await erc1155Contract.functions.isApprovedForAll(ownerAddress, operatorAddress);
              utils_1.expect(status).to.be.eql(true);
          });
          context('When the operator was already an operator', () => {
              beforeEach(async () => {
                  await erc1155Contract.functions.setApprovalForAll(operatorAddress, true);
              });
              it('should leave the operator status to set to true again', async () => {
                  const tx = erc1155Contract.functions.setApprovalForAll(operatorAddress, true);
                  await utils_1.expect(tx).to.be.fulfilled;
                  const status = await erc1155Contract.functions.isApprovedForAll(ownerAddress, operatorAddress);
                  utils_1.expect(status).to.be.eql(true);
              });
              it('should allow the operator status to be set to false', async () => {
                  const tx = erc1155Contract.functions.setApprovalForAll(operatorAddress, false);
                  await utils_1.expect(tx).to.be.fulfilled;
                  const status = await erc1155Contract.functions.isApprovedForAll(operatorAddress, ownerAddress);
                  utils_1.expect(status).to.be.eql(false);
              });
          });
      });
      describe('Supports ERC165', () => {
          describe('supportsInterface()', () => {
              it('should return true for 0x01ffc9a7', async () => {
                  const support = await erc1155Contract.functions.supportsInterface('0x01ffc9a7');
                  utils_1.expect(support).to.be.eql(true);
              });
              it('should return true for 0x97a409d2', async () => {
                  // TODO: this fails for some reason.. which interface is this checking?
                  // review & double check
                  // const support = await erc1155Contract.functions.supportsInterface('0x97a409d2')
                  // expect(support).to.be.eql(true)
              });
          });
      });
  });
  //# sourceMappingURL=ERC1155.spec.js.map