Skip to content

Instantly share code, notes, and snippets.

@cag
Last active August 14, 2020 17:20
Show Gist options
  • Save cag/41c68a6402fc7c80b03f72cbf42f27f6 to your computer and use it in GitHub Desktop.
Save cag/41c68a6402fc7c80b03f72cbf42f27f6 to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.6.6+commit.6c089d02.js&optimize=false&gist=
pragma solidity ^0.6.0;
import { Address } from "github.com/OpenZeppelin/openzeppelin-contracts/contracts/utils/Address.sol";
import { ERC20 } from "github.com/OpenZeppelin/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";
import { IERC1155 } from "github.com/OpenZeppelin/openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol";
import { ERC1155Receiver } from "github.com/OpenZeppelin/openzeppelin-contracts/contracts/token/ERC1155/ERC1155Receiver.sol";
contract Wrapped1155Metadata {
// workaround which also arranges first storage slots of Wrapped1155
Wrapped1155Factory public factory;
IERC1155 public multiToken;
uint256 public tokenId;
modifier onlyFactory() {
require(msg.sender == address(factory), "Wrapped1155: only factory allowed to perform operation");
_;
}
}
contract Wrapped1155 is Wrapped1155Metadata, ERC20 {
constructor() public ERC20("Wrapped ERC-1155 Implementation", "WMT*") {}
function mint(address account, uint256 amount) external onlyFactory {
_mint(account, amount);
}
function burn(address account, uint256 amount) external onlyFactory {
_burn(account, amount);
}
}
contract Wrapped1155Factory is ERC1155Receiver {
using Address for address;
Wrapped1155 public erc20Implementation;
constructor() public {
erc20Implementation = new Wrapped1155();
}
function onERC1155Received(
address operator,
address /* from */,
uint256 id,
uint256 value,
bytes calldata data
)
external
override
returns (bytes4)
{
address recipient = abi.decode(data, (address));
if (recipient == address(0))
recipient = operator;
Wrapped1155 wrapped1155 = requireWrapped1155(IERC1155(msg.sender), id);
wrapped1155.mint(recipient, value);
return this.onERC1155Received.selector;
}
function onERC1155BatchReceived(
address operator,
address /* from */,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
)
external
override
returns (bytes4)
{
address recipient = abi.decode(data, (address));
if (recipient == address(0))
recipient = operator;
for (uint i = 0; i < ids.length; i++) {
requireWrapped1155(IERC1155(msg.sender), ids[i]).mint(recipient, values[i]);
}
return this.onERC1155BatchReceived.selector;
}
function unwrap(
IERC1155 multiToken,
uint256 tokenId,
uint256 amount,
address recipient,
bytes calldata data
)
external
{
getWrapped1155(multiToken, tokenId).burn(msg.sender, amount);
multiToken.safeTransferFrom(address(this), recipient, tokenId, amount, data);
}
function batchUnwrap(
IERC1155 multiToken,
uint256[] calldata tokenIds,
uint256[] calldata amounts,
address recipient,
bytes calldata data
)
external
{
require(tokenIds.length == amounts.length, "Wrapped1155Factory: mismatched input arrays");
for (uint i = 0; i < tokenIds.length; i++) {
getWrapped1155(multiToken, tokenIds[i]).burn(msg.sender, amounts[i]);
}
multiToken.safeBatchTransferFrom(address(this), recipient, tokenIds, amounts, data);
}
function getWrapped1155DeployBytecode(IERC1155 multiToken, uint256 tokenId)
public
view
returns (bytes memory)
{
return abi.encodePacked(
// assign factory
hex"73",
this,
hex"3d55",
// assign multiToken
hex"73",
multiToken,
hex"602055",
// assign tokenId
hex"7f",
tokenId,
hex"604055",
// assign name
hex"7f",
"Wrapped ERC-1155", uint128(32),
hex"60c055",
// assign symbol
hex"7f",
"WMT", uint232(6),
hex"60e055",
// assign decimals
hex"60",
uint8(18),
hex"61010055",
// push 44 (length of runtime)
hex"60", uint8(44),
// load free memory pointer
hex"604051",
// dup runtime length
hex"81",
// push offset in this calldata to runtime object,
hex"60", uint8(160),
// dup free memory pointer
hex"82"
// copy runtime to memory and return
hex"37f3",
// greetz 0age for More-Minimal Proxy runtime bytecode:
hex"3d3d3d3d363d3d37363d73",
address(erc20Implementation),
hex"5af43d3d93803e602a57fd5bf3"
);
}
function getWrapped1155(IERC1155 multiToken, uint256 tokenId)
public
view
returns (Wrapped1155)
{
return Wrapped1155(address(uint160(uint256(keccak256(abi.encodePacked(
uint8(0xff),
this,
uint256(1155),
getWrapped1155DeployBytecode(multiToken, tokenId)
))))));
}
function requireWrapped1155(IERC1155 multiToken, uint256 tokenId)
public
returns (Wrapped1155)
{
bytes memory deployBytecode = getWrapped1155DeployBytecode(multiToken, tokenId);
address wrapped1155Address = address(uint160(uint256(keccak256(abi.encodePacked(
uint8(0xff),
this,
uint256(1155),
deployBytecode
)))));
if (!wrapped1155Address.isContract()) {
address addr;
assembly {
addr := create2(0, add(deployBytecode, 0x20), mload(deployBytecode), 1155)
}
require(wrapped1155Address == addr, "Wrapped1155Factory: failed to deploy");
}
return Wrapped1155(wrapped1155Address);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment