Skip to content

Commit

Permalink
Merge branch 'main' into joaquim/twcontract
Browse files Browse the repository at this point in the history
  • Loading branch information
joaquim-verges committed May 20, 2022
2 parents a603d4a + 91228c7 commit 292119a
Show file tree
Hide file tree
Showing 27 changed files with 1,647 additions and 1,713 deletions.
Binary file added assets/multiwrap-diagram.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 4 additions & 1 deletion contracts/feature/ContractMetadata.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@ abstract contract ContractMetadata is IContractMetadata {
string public override contractURI;

/// @dev Lets a contract admin set the URI for contract-level metadata.
function setContractURI(string calldata _uri) external override {
function setContractURI(string memory _uri) public override {
require(_canSetContractURI(), "Not authorized");
string memory prevURI = contractURI;
contractURI = _uri;

emit ContractURIUpdated(prevURI, _uri);
}

/// @dev Returns whether contract metadata can be set in the given execution context.
Expand Down
45 changes: 32 additions & 13 deletions contracts/feature/Permissions.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,32 +19,31 @@ contract Permissions is IPermissions {
return _hasRole[role][account];
}

function hasRoleWithSwitch(bytes32 role, address account) public view returns (bool) {
if (!_hasRole[role][address(0)]) {
return _hasRole[role][account];
}

return true;
}

function getRoleAdmin(bytes32 role) public view override returns (bytes32) {
return _getRoleAdmin[role];
}

function grantRole(bytes32 role, address account) public virtual override {
_checkRole(_getRoleAdmin[role], msg.sender);

_hasRole[role][account] = true;

emit RoleGranted(role, account, msg.sender);
_setupRole(role, account);
}

function revokeRole(bytes32 role, address account) public virtual override {
_checkRole(_getRoleAdmin[role], msg.sender);

delete _hasRole[role][account];

emit RoleRevoked(role, account, msg.sender);
_revokeRole(role, account);
}

function renounceRole(bytes32 role, address account) public virtual override {
require(msg.sender == account, "Can only renounce for self");

delete _hasRole[role][account];

emit RoleRevoked(role, account, msg.sender);
_revokeRole(role, account);
}

function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
Expand All @@ -58,12 +57,32 @@ contract Permissions is IPermissions {
emit RoleGranted(role, account, msg.sender);
}

function _revokeRole(bytes32 role, address account) internal virtual {
delete _hasRole[role][account];
emit RoleRevoked(role, account, msg.sender);
}

function _checkRole(bytes32 role, address account) internal view virtual {
if (!_hasRole[role][account]) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
"Permissions: account ",
Strings.toHexString(uint160(account), 20),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}

function _checkRoleWithSwitch(bytes32 role, address account) internal view virtual {
if (!hasRoleWithSwitch(role, account)) {
revert(
string(
abi.encodePacked(
"Permissions: account ",
Strings.toHexString(uint160(account), 20),
" is missing role ",
Strings.toHexString(uint256(role), 32)
Expand Down
82 changes: 82 additions & 0 deletions contracts/feature/TokenStore.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

// ========== External imports ==========

import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";

import "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol";
import "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";

// ========== Internal imports ==========

import "./TokenBundle.sol";
import "../lib/CurrencyTransferLib.sol";

contract TokenStore is TokenBundle, ERC721Holder, ERC1155Holder {
/// @dev The address of the native token wrapper contract.
address private immutable nativeTokenWrapper;

constructor(address _nativeTokenWrapper) {
nativeTokenWrapper = _nativeTokenWrapper;
}

/// @dev Store / escrow multiple ERC1155, ERC721, ERC20 tokens.
function _storeTokens(
address _tokenOwner,
Token[] calldata _tokens,
string calldata _uriForTokens,
uint256 _idForTokens
) internal {
_setBundle(_tokens, _idForTokens);
_setUriOfBundle(_uriForTokens, _idForTokens);
_transferTokenBatch(_tokenOwner, address(this), _tokens);
}

/// @dev Release stored / escrowed ERC1155, ERC721, ERC20 tokens.
function _releaseTokens(address _recipient, uint256 _idForContent) internal {
uint256 count = getTokenCountOfBundle(_idForContent);
Token[] memory tokensToRelease = new Token[](count);

for (uint256 i = 0; i < count; i += 1) {
tokensToRelease[i] = getTokenOfBundle(_idForContent, i);
}

_deleteBundle(_idForContent);

_transferTokenBatch(address(this), _recipient, tokensToRelease);
}

/// @dev Transfers an arbitrary ERC20 / ERC721 / ERC1155 token.
function _transferToken(
address _from,
address _to,
Token memory _token
) internal {
if (_token.tokenType == TokenType.ERC20) {
CurrencyTransferLib.transferCurrencyWithWrapper(
_token.assetContract,
_from,
_to,
_token.totalAmount,
nativeTokenWrapper
);
} else if (_token.tokenType == TokenType.ERC721) {
IERC721(_token.assetContract).safeTransferFrom(_from, _to, _token.tokenId);
} else if (_token.tokenType == TokenType.ERC1155) {
IERC1155(_token.assetContract).safeTransferFrom(_from, _to, _token.tokenId, _token.totalAmount, "");
}
}

/// @dev Transfers multiple arbitrary ERC20 / ERC721 / ERC1155 tokens.
function _transferTokenBatch(
address _from,
address _to,
Token[] memory _tokens
) internal {
for (uint256 i = 0; i < _tokens.length; i += 1) {
_transferToken(_from, _to, _tokens[i]);
}
}
}
2 changes: 2 additions & 0 deletions contracts/feature/interface/IContractMetadata.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ interface IContractMetadata {
* Only module admin can call this function.
*/
function setContractURI(string calldata _uri) external;

event ContractURIUpdated(string prevURI, string newURI);
}
40 changes: 4 additions & 36 deletions contracts/interfaces/IMultiwrap.sol
Original file line number Diff line number Diff line change
@@ -1,47 +1,16 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.11;

import "../feature/interface/ITokenBundle.sol";

/**
* Thirdweb's Multiwrap contract lets you wrap arbitrary ERC20, ERC721 and ERC1155
* tokens you own into a single wrapped token / NFT.
*
* A wrapped NFT can be unwrapped i.e. burned in exchange for its underlying contents.
*/

interface IMultiwrap {
/// @notice The type of assets that can be wrapped.
enum TokenType {
ERC20,
ERC721,
ERC1155
}

/**
* @notice A generic interface to describe a token to wrap.
*
* @param assetContract The contract address of the asset to wrap.
* @param tokenType The token type (ERC20 / ERC721 / ERC1155) of the asset to wrap.
* @param tokenId The token Id of the asset to wrap, if the asset is an ERC721 / ERC1155 NFT.
* @param amount The amount of the asset to wrap, if the asset is an ERC20 / ERC1155 fungible token.
*/
struct Token {
address assetContract;
TokenType tokenType;
uint256 tokenId;
uint256 amount;
}

/**
* @notice An internal data structure to track the wrapped contents of a wrapped NFT.
*
* @param count The total kinds of assets i.e. `Token` wrapped.
* @param token Mapping from a UID -> to the asset i.e. `Token` at that UID.
*/
struct WrappedContents {
uint256 count;
mapping(uint256 => Token) token;
}

interface IMultiwrap is ITokenBundle {
/// @dev Emitted when tokens are wrapped.
event TokensWrapped(
address indexed wrapper,
Expand All @@ -54,8 +23,7 @@ interface IMultiwrap {
event TokensUnwrapped(
address indexed unwrapper,
address indexed recipientOfWrappedContents,
uint256 indexed tokenIdOfWrappedToken,
Token[] wrappedContents
uint256 indexed tokenIdOfWrappedToken
);

/**
Expand Down
Loading

0 comments on commit 292119a

Please sign in to comment.