Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
5f30c99
update design doc for Pack
kumaryash90 Jul 14, 2022
f69fc98
openPack out of gas -- fuzz test
kumaryash90 Jul 25, 2022
16922e9
[M-1] Lost pack tokens result in permanently locked assets
kumaryash90 Aug 1, 2022
58cbb2b
[G-2] Reduce function calls in openPack
kumaryash90 Aug 1, 2022
728abff
[L-3] supportsInterface() may prevent ERC721 tokens from transferring…
kumaryash90 Aug 1, 2022
39ac972
[H-1] Reward selection exploits
kumaryash90 Aug 5, 2022
e660250
optimize openPack
kumaryash90 Aug 5, 2022
cb8646d
merge pack audit changes
kumaryash90 Aug 5, 2022
b92d836
pack refactor: adding more tokens to a pack
kumaryash90 Aug 5, 2022
4dacb78
add tests
kumaryash90 Aug 5, 2022
83c21f2
wip: reduce size
kumaryash90 Aug 18, 2022
0405fd0
cremoved stuffs
jakeloo Aug 22, 2022
6f1fc78
restore roles, token-bundle getters; remove withdrawUnclaimedAssets, …
kumaryash90 Aug 24, 2022
610e3bd
immutable forwarder; edit revert strings;
kumaryash90 Aug 24, 2022
58f6629
cleanup
kumaryash90 Aug 24, 2022
30e1f86
update tests
kumaryash90 Aug 29, 2022
b4d53f2
eoa-only forwarder
kumaryash90 Aug 29, 2022
0ad85bb
run prettier
kumaryash90 Aug 29, 2022
46c058a
merge with main
kumaryash90 Aug 29, 2022
bc9986b
update tests
kumaryash90 Aug 29, 2022
fd0e73f
minor changes: supports interface, role vars, check recipient in addP…
kumaryash90 Aug 31, 2022
c7f1688
update tests
kumaryash90 Aug 31, 2022
263d982
run prettier
kumaryash90 Aug 31, 2022
c264cbd
Merge branch 'main' into pack-refactor-downsized
kumaryash90 Aug 31, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions contracts/ForwarderEOAOnly.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.11;

import "./openzeppelin-presets/metatx/MinimalForwarderEOAOnly.sol";

/*
* @dev Minimal forwarder for GSNv2
*/
contract ForwarderEOAOnly is MinimalForwarderEOAOnly {
// solhint-disable-next-line no-empty-blocks
constructor() MinimalForwarderEOAOnly() {}
}
26 changes: 13 additions & 13 deletions contracts/extension/TokenBundle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ interface IERC165 {

abstract contract TokenBundle is ITokenBundle {
/// @dev Mapping from bundle UID => bundle info.
mapping(uint256 => BundleInfo) private bundle;
mapping(uint256 => BundleInfo) public bundle;

/// @dev Returns the total number of assets in a particular bundle.
function getTokenCountOfBundle(uint256 _bundleId) public view returns (uint256) {
Expand All @@ -38,8 +38,8 @@ abstract contract TokenBundle is ITokenBundle {
function _createBundle(Token[] calldata _tokensToBind, uint256 _bundleId) internal {
uint256 targetCount = _tokensToBind.length;

require(targetCount > 0, "TokenBundle: no tokens to bind.");
require(bundle[_bundleId].count == 0, "TokenBundle: existent at bundleId");
require(targetCount > 0, "no tokens to bind");
require(bundle[_bundleId].count == 0, "existent at bundleId");

for (uint256 i = 0; i < targetCount; i += 1) {
_checkTokenType(_tokensToBind[i]);
Expand All @@ -50,8 +50,8 @@ abstract contract TokenBundle is ITokenBundle {
}

/// @dev Lets the calling contract update a bundle, by passing in a list of tokens and a unique id.
function _updateBundle(Token[] calldata _tokensToBind, uint256 _bundleId) internal {
require(_tokensToBind.length > 0, "TokenBundle: no tokens to bind.");
function _updateBundle(Token[] memory _tokensToBind, uint256 _bundleId) internal {
require(_tokensToBind.length > 0, "no tokens to bind");

uint256 currentCount = bundle[_bundleId].count;
uint256 targetCount = _tokensToBind.length;
Expand Down Expand Up @@ -84,7 +84,7 @@ abstract contract TokenBundle is ITokenBundle {
uint256 _bundleId,
uint256 _index
) internal {
require(_index < bundle[_bundleId].count, "TokenBundle: index DNE.");
require(_index < bundle[_bundleId].count, "index DNE");
_checkTokenType(_tokenToBind);
bundle[_bundleId].tokens[_index] = _tokenToBind;
}
Expand All @@ -93,32 +93,32 @@ abstract contract TokenBundle is ITokenBundle {
function _checkTokenType(Token memory _token) internal view {
if (_token.tokenType == TokenType.ERC721) {
try IERC165(_token.assetContract).supportsInterface(0x80ac58cd) returns (bool supported721) {
require(supported721, "Asset doesn't match TokenType");
require(supported721, "!TokenType");
} catch {
revert("Asset doesn't match TokenType");
revert("!TokenType");
}
} else if (_token.tokenType == TokenType.ERC1155) {
try IERC165(_token.assetContract).supportsInterface(0xd9b67a26) returns (bool supported1155) {
require(supported1155, "Asset doesn't match TokenType");
require(supported1155, "!TokenType");
} catch {
revert("Asset doesn't match TokenType");
revert("!TokenType");
}
} else if (_token.tokenType == TokenType.ERC20) {
if (_token.assetContract != CurrencyTransferLib.NATIVE_TOKEN) {
// 0x36372b07
try IERC165(_token.assetContract).supportsInterface(0x80ac58cd) returns (bool supported721) {
require(!supported721, "Asset doesn't match TokenType");
require(!supported721, "!TokenType");

try IERC165(_token.assetContract).supportsInterface(0xd9b67a26) returns (bool supported1155) {
require(!supported1155, "Asset doesn't match TokenType");
require(!supported1155, "!TokenType");
} catch Error(string memory) {} catch {}
} catch Error(string memory) {} catch {}
}
}
}

/// @dev Lets the calling contract set/update the uri of a particular bundle.
function _setUriOfBundle(string calldata _uri, uint256 _bundleId) internal {
function _setUriOfBundle(string memory _uri, uint256 _bundleId) internal {
bundle[_bundleId].uri = _uri;
}

Expand Down
5 changes: 1 addition & 4 deletions contracts/extension/TokenStore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@ import "../lib/CurrencyTransferLib.sol";
*/

contract TokenStore is TokenBundle, ERC721Holder, ERC1155Holder {
/// @dev The address interpreted as native token of the chain.
address public constant NATIVE_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

/// @dev The address of the native token wrapper contract.
address internal immutable nativeTokenWrapper;

Expand All @@ -36,7 +33,7 @@ contract TokenStore is TokenBundle, ERC721Holder, ERC1155Holder {
function _storeTokens(
address _tokenOwner,
Token[] calldata _tokens,
string calldata _uriForTokens,
string memory _uriForTokens,
uint256 _idForTokens
) internal {
_createBundle(_tokens, _idForTokens);
Expand Down
10 changes: 4 additions & 6 deletions contracts/interfaces/IPack.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,10 @@ interface IPack is ITokenBundle {
}

/// @notice Emitted when a set of packs is created.
event PackCreated(
uint256 indexed packId,
address indexed packCreator,
address recipient,
uint256 totalPacksCreated
);
event PackCreated(uint256 indexed packId, address recipient, uint256 totalPacksCreated);

/// @notice Emitted when more packs are minted for a packId.
event PackUpdated(uint256 indexed packId, address recipient, uint256 totalPacksCreated);

/// @notice Emitted when a pack is opened.
event PackOpened(
Expand Down
68 changes: 68 additions & 0 deletions contracts/openzeppelin-presets/metatx/MinimalForwarderEOAOnly.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (metatx/MinimalForwarder.sol)

pragma solidity ^0.8.0;

import "../utils/cryptography/ECDSA.sol";
import "../utils/cryptography/EIP712.sol";

/**
* @dev Simple minimal forwarder to be used together with an ERC2771 compatible contract. See {ERC2771Context}.
*/
contract MinimalForwarderEOAOnly is EIP712 {
using ECDSA for bytes32;

struct ForwardRequest {
address from;
address to;
uint256 value;
uint256 gas;
uint256 nonce;
bytes data;
}

bytes32 private constant _TYPEHASH =
keccak256("ForwardRequest(address from,address to,uint256 value,uint256 gas,uint256 nonce,bytes data)");

mapping(address => uint256) private _nonces;

constructor() EIP712("MinimalForwarderEOAOnly", "0.0.1") {}

function getNonce(address from) public view returns (uint256) {
return _nonces[from];
}

function verify(ForwardRequest calldata req, bytes calldata signature) public view returns (bool) {
address signer = _hashTypedDataV4(
keccak256(abi.encode(_TYPEHASH, req.from, req.to, req.value, req.gas, req.nonce, keccak256(req.data)))
).recover(signature);
return _nonces[req.from] == req.nonce && signer == req.from;
}

function execute(ForwardRequest calldata req, bytes calldata signature)
public
payable
returns (bool, bytes memory)
{
require(msg.sender == tx.origin, "not EOA");
require(verify(req, signature), "MinimalForwarder: signature does not match request");
_nonces[req.from] = req.nonce + 1;

(bool success, bytes memory returndata) = req.to.call{ gas: req.gas, value: req.value }(
abi.encodePacked(req.data, req.from)
);

// Validate that the relayer has sent enough gas for the call.
// See https://ronan.eth.link/blog/ethereum-gas-dangers/
if (gasleft() <= req.gas / 63) {
// We explicitly trigger invalid opcode to consume all gas and bubble-up the effects, since
// neither revert or assert consume all gas since Solidity 0.8.0
// https://docs.soliditylang.org/en/v0.8.0/control-structures.html#panic-via-assert-and-error-via-require
assembly {
invalid()
}
}

return (success, returndata);
}
}
Loading