diff --git a/contracts/root/TokenPredicates/MintableERC1155Predicate.sol b/contracts/root/TokenPredicates/MintableERC1155Predicate.sol index ed7c3029..b67e599f 100644 --- a/contracts/root/TokenPredicates/MintableERC1155Predicate.sol +++ b/contracts/root/TokenPredicates/MintableERC1155Predicate.sol @@ -105,6 +105,24 @@ contract MintableERC1155Predicate is data ); } + + // Used when attempting to exit with single token, single amount/ id is converted into + // slice of amounts/ ids + // Generally size is going to be `1` i.e. single element array, but it's kept generic + function makeArrayWithValue(uint256 val, uint size) internal pure returns(uint256[] memory) { + require( + size > 0, + "MintableERC1155Predicate: Invalid resulting array length" + ); + + uint256[] memory vals = new uint256[](size); + + for (uint256 i = 0; i < size; i++) { + vals[i] = val; + } + + return vals; + } /** * @notice Creates an array of `size` by repeating provided address, @@ -206,7 +224,15 @@ contract MintableERC1155Predicate is // it'll mint those tokens for this contract and return // safely transfer those to withdrawer if (tokenBalance < amount) { - token.mint(address(this), id, amount - tokenBalance, bytes("")); + // @notice We could have done `mint`, but that would require + // us implementing `onERC1155Received`, which we avoid intentionally + // for sake of only supporting batch deposit. + // + // Which is why this transfer is wrapped as single element batch minting + token.mintBatch(address(this), + makeArrayWithValue(id, 1), + makeArrayWithValue(amount - tokenBalance, 1), + bytes("")); } token.safeTransferFrom( diff --git a/flat/MintableERC1155Predicate.sol b/flat/MintableERC1155Predicate.sol index 5de32399..2b6693f4 100644 --- a/flat/MintableERC1155Predicate.sol +++ b/flat/MintableERC1155Predicate.sol @@ -1378,6 +1378,24 @@ contract MintableERC1155Predicate is data ); } + + // Used when attempting to exit with single token, single amount/ id is converted into + // slice of amounts/ ids + // Generally size is going to be `1` i.e. single element array, but it's kept generic + function makeArrayWithValue(uint256 val, uint size) internal pure returns(uint256[] memory) { + require( + size > 0, + "MintableERC1155Predicate: Invalid resulting array length" + ); + + uint256[] memory vals = new uint256[](size); + + for (uint256 i = 0; i < size; i++) { + vals[i] = val; + } + + return vals; + } /** * @notice Creates an array of `size` by repeating provided address, @@ -1479,7 +1497,10 @@ contract MintableERC1155Predicate is // it'll mint those tokens for this contract and return // safely transfer those to withdrawer if (tokenBalance < amount) { - token.mint(address(this), id, amount - tokenBalance, bytes("")); + token.mintBatch(address(this), + makeArrayWithValue(id, 1), + makeArrayWithValue(amount - tokenBalance, 1), + bytes("")); } token.safeTransferFrom( diff --git a/package.json b/package.json index ac64d4ec..6430e824 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@maticnetwork/pos-portal", - "version": "1.5.1", + "version": "1.5.2", "description": "Contracts to facilitate transfer of assets between Ethereum Main Network and Matic Network, using security of Matic POS layer", "main": "index.js", "scripts": { diff --git a/test/predicates/MintableERC1155Predicate.test.js b/test/predicates/MintableERC1155Predicate.test.js index de8d40b4..90c2c901 100644 --- a/test/predicates/MintableERC1155Predicate.test.js +++ b/test/predicates/MintableERC1155Predicate.test.js @@ -212,12 +212,13 @@ contract('MintableERC1155Predicate', (accounts) => { const PREDICATE_ROLE = await dummyMintableERC1155.PREDICATE_ROLE() await dummyMintableERC1155.grantRole(PREDICATE_ROLE, mintableERC1155Predicate.address) - const burnLog = getERC1155TransferBatchLog({ + // Force predicate to `mint` + const burnLog = getERC1155TransferSingleLog({ operator: depositor, from: depositor, to: mockValues.zeroAddress, - tokenIds: [tokenId], - amounts: [amount] + tokenId, + amount }) await mintableERC1155Predicate.exitTokens(depositor, dummyMintableERC1155.address, burnLog) @@ -262,10 +263,10 @@ contract('MintableERC1155Predicate', (accounts) => { describe('exitTokens batch', () => { const amountA = mockValues.amounts[9] const amountB = mockValues.amounts[8] - + const tokenIdA = mockValues.numbers[4] const tokenIdB = mockValues.numbers[5] - + const depositData = constructERC1155DepositData([tokenIdA, tokenIdB], [amountA, amountB]) const depositor = accounts[1] const withdrawer = mockValues.addresses[8] @@ -298,7 +299,7 @@ contract('MintableERC1155Predicate', (accounts) => { await dummyMintableERC1155.setApprovalForAll(mintableERC1155Predicate.address, true, { from: depositor }) await mintableERC1155Predicate.lockTokens(depositor, mockValues.addresses[2], dummyMintableERC1155.address, depositData) - + oldAccountBalanceA = await dummyMintableERC1155.balanceOf(withdrawer, tokenIdA) oldAccountBalanceB = await dummyMintableERC1155.balanceOf(withdrawer, tokenIdB) @@ -355,10 +356,10 @@ contract('MintableERC1155Predicate', (accounts) => { describe('exitTokens called by different user', () => { const amountA = mockValues.amounts[9] const amountB = mockValues.amounts[8] - + const tokenIdA = mockValues.numbers[4] const tokenIdB = mockValues.numbers[5] - + const depositData = constructERC1155DepositData([tokenIdA, tokenIdB], [amountA, amountB]) const depositor = accounts[1] const withdrawer = mockValues.addresses[8] @@ -392,7 +393,7 @@ contract('MintableERC1155Predicate', (accounts) => { await dummyMintableERC1155.setApprovalForAll(mintableERC1155Predicate.address, true, { from: depositor }) await mintableERC1155Predicate.lockTokens(depositor, mockValues.addresses[2], dummyMintableERC1155.address, depositData) - + oldAccountBalanceA = await dummyMintableERC1155.balanceOf(withdrawer, tokenIdA) oldAccountBalanceB = await dummyMintableERC1155.balanceOf(withdrawer, tokenIdB) @@ -447,7 +448,7 @@ contract('MintableERC1155Predicate', (accounts) => { const depositData = constructERC1155DepositData([tokenId], [amount]) const depositor = accounts[1] const withdrawer = mockValues.addresses[8] - + let dummyMintableERC1155 let mintableERC1155Predicate @@ -459,12 +460,12 @@ contract('MintableERC1155Predicate', (accounts) => { const PREDICATE_ROLE = await dummyMintableERC1155.PREDICATE_ROLE() await dummyMintableERC1155.grantRole(PREDICATE_ROLE, mintableERC1155Predicate.address) - const burnLog = getERC1155TransferBatchLog({ + const burnLog = getERC1155TransferSingleLog({ operator: depositor, from: depositor, to: mockValues.zeroAddress, - tokenIds: [tokenId], - amounts: [amount] + tokenId, + amount }) await mintableERC1155Predicate.exitTokens(depositor, dummyMintableERC1155.address, burnLog) @@ -479,8 +480,8 @@ contract('MintableERC1155Predicate', (accounts) => { operator: withdrawer, from: withdrawer, to: mockValues.zeroAddress, - tokenId: tokenId, - amount: amount + tokenId, + amount }) await expectRevert(mintableERC1155Predicate.exitTokens(withdrawer, dummyMintableERC1155.address, burnLog), 'MintableERC1155Predicate: INVALID_WITHDRAW_SIG') }) @@ -548,12 +549,12 @@ contract('MintableERC1155Predicate', (accounts) => { const PREDICATE_ROLE = await dummyMintableERC1155.PREDICATE_ROLE() await dummyMintableERC1155.grantRole(PREDICATE_ROLE, mintableERC1155Predicate.address) - const burnLog = getERC1155TransferBatchLog({ + const burnLog = getERC1155TransferSingleLog({ operator: depositor, from: depositor, to: mockValues.zeroAddress, - tokenIds: [tokenId], - amounts: [amount] + tokenId, + amount }) await mintableERC1155Predicate.exitTokens(depositor, dummyMintableERC1155.address, burnLog) @@ -567,8 +568,8 @@ contract('MintableERC1155Predicate', (accounts) => { operator: withdrawer, from: withdrawer, to: mockValues.zeroAddress, - tokenId: tokenId, - amount: amount + tokenId, + amount }) await expectRevert( mintableERC1155Predicate.exitTokens(withdrawer, dummyMintableERC1155.address, burnLog, { from: accounts[2] }),