Skip to content

Commit

Permalink
Merge pull request #24 from gnosis/update-1155-more
Browse files Browse the repository at this point in the history
Update 1155 implementation to use 165 introspection interface
  • Loading branch information
cag committed Jun 8, 2019
2 parents 11f545c + dfde885 commit cf0d58f
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 24 deletions.
12 changes: 6 additions & 6 deletions contracts/ERC1155/ERC1155.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ contract ERC1155 is ERC165, IERC1155
public
{
_registerInterface(
this.safeTransferFrom.selector ^
this.safeBatchTransferFrom.selector ^
this.balanceOf.selector ^
this.balanceOfBatch.selector ^
this.setApprovalForAll.selector ^
this.isApprovedForAll.selector
ERC1155(0).safeTransferFrom.selector ^
ERC1155(0).safeBatchTransferFrom.selector ^
ERC1155(0).balanceOf.selector ^
ERC1155(0).balanceOfBatch.selector ^
ERC1155(0).setApprovalForAll.selector ^
ERC1155(0).isApprovedForAll.selector
);
}

Expand Down
13 changes: 13 additions & 0 deletions contracts/ERC1155/ERC1155TokenReceiver.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
pragma solidity ^0.5.0;

import "./IERC1155TokenReceiver.sol";
import "openzeppelin-solidity/contracts/introspection/ERC165.sol";

contract ERC1155TokenReceiver is ERC165, IERC1155TokenReceiver {
constructor() public {
_registerInterface(
ERC1155TokenReceiver(0).onERC1155Received.selector ^
ERC1155TokenReceiver(0).onERC1155BatchReceived.selector
);
}
}
15 changes: 5 additions & 10 deletions contracts/ERC1155/IERC1155TokenReceiver.sol
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
pragma solidity ^0.5.0;

import "openzeppelin-solidity/contracts/introspection/IERC165.sol";

/**
@title ERC-1155 Multi Token Receiver
@title ERC-1155 Multi Token Receiver Interface
@dev See https://eips.ethereum.org/EIPS/eip-1155
*/
interface IERC1155TokenReceiver {
contract IERC1155TokenReceiver is IERC165 {

/**
@dev Handles the receipt of a single ERC1155 token type. This function is
called at the end of a `safeTransferFrom` after the balance has been updated.
Expand Down Expand Up @@ -46,12 +49,4 @@ interface IERC1155TokenReceiver {
uint256[] calldata values,
bytes calldata data
) external returns(bytes4);

/**
@dev Indicates whether a contract implements the `ERC1155TokenReceiver`
functions and so can accept ERC1155 token types. Will return
`bytes4(keccak256("isERC1155TokenReceiver()"))`
(i.e. 0x0d912442 or its own function selector).
*/
function isERC1155TokenReceiver() external view returns (bytes4);
}
30 changes: 22 additions & 8 deletions contracts/PredictionMarketSystem.sol
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,22 @@ contract PredictionMarketSystem is OracleConsumer, ERC1155 {
);
}

// this value is meant to be used in a require(gasleft() >= CHECK_IS_RECEIVER_REQUIRED_GAS)
// statement preceding an ERC165 introspection staticcall to verify that a contract is
// an ERC1155TokenReceiver. Gas values gotten through experimenting with Remix.
uint constant CHECK_IS_RECEIVER_REQUIRED_GAS =
uint(10000) * 64 / 63 + 1 + // minimum gas required to exist before call opcode
700 + // call cost
564 + // cost for getting the stuff on the stack
100; // cost for executing require statement itself

bytes constant CHECK_IS_RECEIVER_CALLDATA = abi.encodeWithSignature(
"supportsInterface(bytes4)",
bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)")) ^
bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))
);


function _doSafeTransferAcceptanceCheck(
address operator,
address from,
Expand All @@ -244,14 +260,13 @@ contract PredictionMarketSystem is OracleConsumer, ERC1155 {
internal
{
if(to.isContract()) {
(bool callSucceeded, bytes memory callReturnData) = to.staticcall(
abi.encodeWithSignature("isERC1155TokenReceiver()")
);
require(gasleft() >= CHECK_IS_RECEIVER_REQUIRED_GAS, "ERC1155: not enough gas reserved for token receiver check");
(bool callSucceeded, bytes memory callReturnData) = to.call.gas(10000)(CHECK_IS_RECEIVER_CALLDATA);

if(
callSucceeded &&
callReturnData.length > 0 &&
abi.decode(callReturnData, (bytes4)) == IERC1155TokenReceiver(to).isERC1155TokenReceiver.selector
abi.decode(callReturnData, (bool)) == true
) {
require(
IERC1155TokenReceiver(to).onERC1155Received(operator, from, id, value, data) ==
Expand Down Expand Up @@ -284,14 +299,13 @@ contract PredictionMarketSystem is OracleConsumer, ERC1155 {
internal
{
if(to.isContract()) {
(bool callSucceeded, bytes memory callReturnData) = to.staticcall(
abi.encodeWithSignature("isERC1155TokenReceiver()")
);
require(gasleft() >= CHECK_IS_RECEIVER_REQUIRED_GAS, "ERC1155: not enough gas reserved for token receiver check");
(bool callSucceeded, bytes memory callReturnData) = to.staticcall.gas(10000)(CHECK_IS_RECEIVER_CALLDATA);

if(
callSucceeded &&
callReturnData.length > 0 &&
abi.decode(callReturnData, (bytes4)) == IERC1155TokenReceiver(to).isERC1155TokenReceiver.selector
abi.decode(callReturnData, (bool)) == true
) {
require(
IERC1155TokenReceiver(to).onERC1155BatchReceived(operator, from, ids, values, data) ==
Expand Down

0 comments on commit cf0d58f

Please sign in to comment.