From 43e0f2fb3660fe43b4d5b58a9b815618cfcf2b65 Mon Sep 17 00:00:00 2001 From: dappsar Date: Tue, 14 Nov 2023 17:16:15 -0300 Subject: [PATCH 1/4] removed old contracts version --- contracts/alpha/Alpha.v1.sol | 288 ----- contracts/alpha/ContextMixin.v1.sol | 28 - contracts/gamma/GammaCards.v1.sol | 214 ---- contracts/gamma/GammaPacks.v1.sol | 147 --- contracts/testDai/TestDAI.v1.sol | 1618 --------------------------- 5 files changed, 2295 deletions(-) delete mode 100644 contracts/alpha/Alpha.v1.sol delete mode 100644 contracts/alpha/ContextMixin.v1.sol delete mode 100644 contracts/gamma/GammaCards.v1.sol delete mode 100644 contracts/gamma/GammaPacks.v1.sol delete mode 100644 contracts/testDai/TestDAI.v1.sol diff --git a/contracts/alpha/Alpha.v1.sol b/contracts/alpha/Alpha.v1.sol deleted file mode 100644 index 22813b3..0000000 --- a/contracts/alpha/Alpha.v1.sol +++ /dev/null @@ -1,288 +0,0 @@ -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; -import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; -import "@openzeppelin/contracts/utils/Counters.sol"; -import "@openzeppelin/contracts/access/Ownable.sol"; - -import "./ContextMixin.v1.sol"; - -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.4; - -contract NOF_Alpha is ERC721, ERC721URIStorage, Ownable, ContextMixin { - using Counters for Counters.Counter; - Counters.Counter private _tokenIdCounter; - // NOF Alpha Custom Code --> - string public baseUri; - - struct Season { - uint price; - uint[] cards; - uint[] albums; - mapping(address => bool) owners; - string folder; - } - - struct Card { - uint tokenId; - uint class; - uint collection; - string season; - uint completion; - uint number; - } - - - address public balanceReceiver; - mapping (string => Season) public seasons; - mapping (uint => Card) public cards;// this uint is the tokenId - mapping (string => address[]) private winners; - mapping (address => mapping(string => Card[])) public cardsByUserBySeason; - uint8[7] private prizes = [20, 14, 12, 10, 8, 6, 5]; - string[] public seasonNames; - uint256[] public seasonPrices; - uint256 public prizesBalance; - - address public DAI_TOKEN; - - // <-- NOF Alpha Custom Code - - event BuyPack(address buyer, string seasonName); - event Winner(address winner, string season, uint256 position); - - constructor(string memory __baseUri, address _daiTokenAddress, address _balanceReceiver) ERC721("NOF Alpha", "NOFA") { - baseUri = __baseUri; - DAI_TOKEN = _daiTokenAddress; - balanceReceiver = _balanceReceiver; - } - - function _baseURI() internal view override returns (string memory) { - return baseUri; - } - - function mint(address to, string memory uri, uint _class, uint _collection, string memory _season, uint carNumber) internal { - uint256 tokenId = _tokenIdCounter.current(); - _tokenIdCounter.increment(); - cards[tokenId].tokenId = tokenId; - cards[tokenId].class = _class; - cards[tokenId].collection = _collection; - cards[tokenId].season = _season; - cards[tokenId].number = carNumber; - cardsByUserBySeason[to][_season].push(cards[tokenId]); - _mint(to, tokenId); - _setTokenURI(tokenId, uri); - } - - // The following functions are overrides required by Solidity. - - function _beforeTokenTransfer(address from, address to, uint256 tokenId, uint256 batchSize) - internal - override(ERC721) - { - super._beforeTokenTransfer(from, to, tokenId, batchSize); - } - - function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) { - super._burn(tokenId); - } - - function tokenURI(uint256 tokenId) - public - view - override(ERC721, ERC721URIStorage) - returns (string memory) - { - return super.tokenURI(tokenId); - } - - function supportsInterface(bytes4 interfaceId) - public - view - override(ERC721) - returns (bool) - { - return super.supportsInterface(interfaceId); - } - - function isApprovedForAll( - address _owner, - address _operator - ) public override(ERC721) view returns (bool isOperator) { - // if OpenSea's ERC721 Proxy Address is detected, auto-return true - // for Polygon's Mumbai testnet, use 0xff7Ca10aF37178BdD056628eF42fD7F799fAc77c - if (_operator == address(0x58807baD0B376efc12F5AD86aAc70E78ed67deaE)) { - return true; - } - - // otherwise, use the default ERC721.isApprovedForAll() - return ERC721.isApprovedForAll(_owner, _operator); - } - - /** - * This is used instead of msg.sender as transactions won't be sent by the original token owner, but by OpenSea. - */ - function _msgSender() - internal - override - view - returns (address sender) - { - return ContextMixin.msgSender(); - } - - // NOF Alpha Custom Code --> - function buyPack(uint256 amount, string memory name) public { - require(!seasons[name].owners[msg.sender], "Ya tenes un pack wachin"); - seasons[name].owners[msg.sender] = true; - require(seasons[name].price == amount, "Send exact price for Pack"); - uint256 prizesAmount = amount * 75 / 100; - prizesBalance += prizesAmount; - IERC20(DAI_TOKEN).transferFrom(msg.sender, address(this), prizesAmount); - IERC20(DAI_TOKEN).transferFrom(msg.sender, balanceReceiver, amount - prizesAmount); - - { - uint index = uint(keccak256(abi.encodePacked(block.timestamp)))%seasons[name].albums.length; - uint cardNum = seasons[name].albums[index]; - seasons[name].albums[index] = seasons[name].albums[seasons[name].albums.length - 1]; - seasons[name].albums.pop(); - mint(msg.sender, string(abi.encodePacked(bytes(seasons[name].folder), bytes("/"), bytes(toString(cardNum)), bytes(".json"))), 0, cardNum/6-1, name, cardNum); - } - - for(uint i ; i < 5; i++) { - uint index = uint(keccak256(abi.encodePacked(block.timestamp)))%seasons[name].cards.length; - uint cardNum = seasons[name].cards[index]; - seasons[name].cards[index] = seasons[name].cards[seasons[name].cards.length - 1]; - seasons[name].cards.pop(); - mint(msg.sender, string(abi.encodePacked(bytes(seasons[name].folder), bytes("/"), bytes(toString(cardNum)), bytes(".json"))), 1, cardNum/6, name, cardNum); - } - - emit BuyPack(msg.sender, name); - } - - function newSeason(string memory name, uint price, uint amount, string memory folder) public onlyOwner { - require(price >= 100000000000000, "pack value must be at least 0.0001 DAI"); - require(amount % 6 == 0, "Amount must be multiple of 6"); - seasons[name].price = price; - seasons[name].folder = folder; - seasonNames.push(name); - seasonPrices.push(price); - - - for(uint i = 1; i <= amount; i++) { - if(i % 6 == 0) { - seasons[name].albums.push(i); - } else { - seasons[name].cards.push(i); - } - } - } - - function getSeasonData() public view returns(string[] memory, uint256[] memory) { - return (seasonNames, seasonPrices); - } - - //Devuelve un array con las cartas disponibles - function getSeasonCards(string memory name) public view returns(uint[] memory) { - return seasons[name].cards; - } - - //Devuelve un arrary con los albums disponibles - function getSeasonAlbums(string memory name) public view returns(uint[] memory) { - return seasons[name].albums; - } - - function getWinners(string calldata _seasonName) public view returns(address[] memory) { - return winners[_seasonName]; - } - - function getCardsByUserBySeason(address _user, string calldata _seasonName) public view returns(Card[] memory) { - return cardsByUserBySeason[_user][_seasonName]; - } - - function transferCardOwnership(address from, address to, uint256 tokenId) internal { - string memory seasonName = cards[tokenId].season; - for(uint8 i=0;i bool used) public usedNonces; - mapping (uint256 cardNumber => uint256 amount) public cardsInventory; // maximos: 119 => 4999 - mapping (uint256 albumNumber => uint256 amount) public albumsInventory; // definir maximos segun clase - mapping (uint256 tokenId => Card) public cards; - mapping(uint256 albumTokenId => mapping (uint256 cardNum => bool pasted)) public albumsCompletion; - mapping(address user => uint256[] tokenId) public cardsByUser; - - struct Card { - uint256 tokenId; - uint256 number; - bool pasted; - uint8 class; // 1 para cartas, 2 para album de 120, 3 para album de 60 - uint256 completion; // solo se modifica en el caso de los albums - } - - event PackOpened(address player, uint8[] packData, uint256 packNumber); - event AlbumCompleted(address player, uint8 class); - event CardPasted(address player, uint256 cardTokenId, uint256 albumTokenId); - event EmergencyWithdrawal(address receiver, uint256 amount); - - constructor(address _daiTokenAddress, address _packsContract, string memory _baseUri, /* address _balanceReceiver */ address _signer) ERC721("GammaCards", "NOF_GC") { - packsContractInterface = IGammaPacks(_packsContract); - DAI_TOKEN = _daiTokenAddress; - packsContract = _packsContract; - baseUri = _baseUri; - signer = _signer; - } - - function openPack(uint256 packNumber, uint8[] memory packData, bytes calldata signature) external { - require(packsContractInterface.ownerOf(packNumber) == msg.sender, "Este sobre no es tuyo"); - require(packData.length < 50, "Limite de cartas excedido"); // chequear este length - - packsContractInterface.openPack(packNumber); - prizesBalance += packPrice - packPrice / 6; - - // Recreates the message present in the `signature` - bytes32 messageHash = keccak256(abi.encodePacked(msg.sender, packNumber, packData, address(this))).toEthSignedMessageHash(); - require(messageHash.recover(signature) == signer, "Invalid signature"); - - - for(uint8 i=0;i 1, "Este ID no es un album"); - require(cards[cardTokenId].class == 1, "Este ID no es una carta"); - uint8 _class = cards[albumTokenId].class; - if(_class == 2){ - require(!albumsCompletion[albumTokenId][cards[cardTokenId].number], "Esta carta ya esta pegada"); - albumsCompletion[albumTokenId][cards[cardTokenId].number] = true; - } - - cards[albumTokenId].completion++; - cards[cardTokenId].pasted = true; - - emit CardPasted(msg.sender, cardTokenId, albumTokenId); - - if(_class == 2 && cards[albumTokenId].completion == 120){ - prizesBalance -= mainAlbumPrize; - IERC20(DAI_TOKEN).transfer(msg.sender, mainAlbumPrize); - emit AlbumCompleted(msg.sender, _class); - } else if(_class == 3 && cards[albumTokenId].completion == 60){ - prizesBalance -= secondaryAlbumPrize; - IERC20(DAI_TOKEN).transfer(msg.sender, secondaryAlbumPrize); - emit AlbumCompleted(msg.sender, _class); - } - _burn(cardTokenId); - } - - function transferCardOwnership(address from, address to, uint256 tokenId) internal { - for(uint i=0;i address owner) public packs; - mapping(address owner => uint256[] tokenIds) public packsByUser; - - event PackPurchase(address buyer, uint256 tokenId); - event PacksPurchase(address buyer, uint256[] tokenIds); - event NewPrice(uint256 newPrice); - event NewCardsContract(address newCardsContract); - event PackTransfer(address from, address to, uint256 tokenId); - - constructor(address _daiTokenAddress, address _balanceReceiver) { - DAI_TOKEN = _daiTokenAddress; - balanceReceiver = _balanceReceiver; - } - - function buyPack() public returns (uint256){ - require(address(cardsContract) != address(0), "Contrato de cartas no seteado"); // chequear tambien que el cards contract sea el correcto y no cualquiera - uint256 tokenId = _tokenIdCounter.current(); - require(tokenId < totalSupply, "Se acabaron los sobres"); - _tokenIdCounter.increment(); - - packs[tokenId] = msg.sender; - packsByUser[msg.sender].push(tokenId); - - uint256 prizesAmount = packPrice - packPrice / 6; - cardsContract.receivePrizesBalance(prizesAmount); - IERC20(DAI_TOKEN).transferFrom(msg.sender, address(cardsContract), prizesAmount); // envia monto de premios al contrato de cartas - IERC20(DAI_TOKEN).transferFrom(msg.sender, balanceReceiver, packPrice - prizesAmount); // envia monto de profit a cuenta de NoF - - emit PackPurchase(msg.sender, tokenId); - return tokenId; - } - - function buyPacks(uint256 numberOfPacks) public returns(uint256[] memory){ - require(address(cardsContract) != address(0), "Contrato de cartas no seteado"); // chequear tambien que el cards contract sea el correcto y no cualquiera - uint256 prizesAmount = (packPrice - packPrice / 6) * numberOfPacks; - uint256[] memory tokenIds = new uint256[](numberOfPacks); - for(uint256 i;i < numberOfPacks;i++){ - uint256 tokenId = _tokenIdCounter.current(); - require(tokenId < totalSupply, "Se acabaron los sobres"); - _tokenIdCounter.increment(); - - packs[tokenId] = msg.sender; - packsByUser[msg.sender].push(tokenId); - tokenIds[i] = tokenId; - } - cardsContract.receivePrizesBalance(prizesAmount); - IERC20(DAI_TOKEN).transferFrom(msg.sender, address(cardsContract), prizesAmount); // envia monto de premios al contrato de cartas - IERC20(DAI_TOKEN).transferFrom(msg.sender, balanceReceiver, packPrice * numberOfPacks - prizesAmount); // envia monto de profit a cuenta de NoF - - emit PacksPurchase(msg.sender, tokenIds); - - return tokenIds; - } - - function deleteTokenId(uint256 tokenId, address owner) internal { - uint256 packsByUserLength = packsByUser[owner].length; - for(uint256 i;i= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on - * overflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - * - Subtraction cannot overflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction overflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on - * overflow (when the result is negative). - * - * Counterpart to Solidity's `-` operator. - * - * Requirements: - * - * - Subtraction cannot overflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on - * overflow. - * - * Counterpart to Solidity's `*` operator. - * - * Requirements: - * - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring 'a' not being zero, but the - // benefit is lost if 'b' is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. Reverts on - * division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. Reverts with custom message on - * division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity's `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity's `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - -// File: @openzeppelin/contracts/utils/Address.sol - -// SPDX-License-Identifier: MIT - -pragma solidity ^0.6.2; - -/** - * @dev Collection of functions related to the address type - */ -library Address { - /** - * @dev Returns true if `account` is a contract. - * - * [IMPORTANT] - * ==== - * It is unsafe to assume that an address for which this function returns - * false is an externally-owned account (EOA) and not a contract. - * - * Among others, `isContract` will return false for the following - * types of addresses: - * - * - an externally-owned account - * - a contract in construction - * - an address where a contract will be created - * - an address where a contract lived, but was destroyed - * ==== - */ - function isContract(address account) internal view returns (bool) { - // According to EIP-1052, 0x0 is the value returned for not-yet created accounts - // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned - // for accounts without code, i.e. `keccak256('')` - bytes32 codehash; - bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; - // solhint-disable-next-line no-inline-assembly - assembly { codehash := extcodehash(account) } - return (codehash != accountHash && codehash != 0x0); - } - - /** - * @dev Replacement for Solidity's `transfer`: sends `amount` wei to - * `recipient`, forwarding all available gas and reverting on errors. - * - * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost - * of certain opcodes, possibly making contracts go over the 2300 gas limit - * imposed by `transfer`, making them unable to receive funds via - * `transfer`. {sendValue} removes this limitation. - * - * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. - * - * IMPORTANT: because control is transferred to `recipient`, care must be - * taken to not create reentrancy vulnerabilities. Consider using - * {ReentrancyGuard} or the - * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. - */ - function sendValue(address payable recipient, uint256 amount) internal { - require(address(this).balance >= amount, "Address: insufficient balance"); - - // solhint-disable-next-line avoid-low-level-calls, avoid-call-value - (bool success, ) = recipient.call{ value: amount }(""); - require(success, "Address: unable to send value, recipient may have reverted"); - } - - /** - * @dev Performs a Solidity function call using a low level `call`. A - * plain`call` is an unsafe replacement for a function call: use this - * function instead. - * - * If `target` reverts with a revert reason, it is bubbled up by this - * function (like regular Solidity function calls). - * - * Returns the raw returned data. To convert to the expected return value, - * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. - * - * Requirements: - * - * - `target` must be a contract. - * - calling `target` with `data` must not revert. - * - * _Available since v3.1._ - */ - function functionCall(address target, bytes memory data) internal returns (bytes memory) { - return functionCall(target, data, "Address: low-level call failed"); - } - - /** - * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with - * `errorMessage` as a fallback revert reason when `target` reverts. - * - * _Available since v3.1._ - */ - function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { - return _functionCallWithValue(target, data, 0, errorMessage); - } - - /** - * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], - * but also transferring `value` wei to `target`. - * - * Requirements: - * - * - the calling contract must have an ETH balance of at least `value`. - * - the called Solidity function must be `payable`. - * - * _Available since v3.1._ - */ - function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { - return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); - } - - /** - * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but - * with `errorMessage` as a fallback revert reason when `target` reverts. - * - * _Available since v3.1._ - */ - function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { - require(address(this).balance >= value, "Address: insufficient balance for call"); - return _functionCallWithValue(target, data, value, errorMessage); - } - - function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) { - require(isContract(target), "Address: call to non-contract"); - - // solhint-disable-next-line avoid-low-level-calls - (bool success, bytes memory returndata) = target.call{ value: weiValue }(data); - if (success) { - return returndata; - } else { - // Look for revert reason and bubble it up if present - if (returndata.length > 0) { - // The easiest way to bubble the revert reason is using memory via assembly - - // solhint-disable-next-line no-inline-assembly - assembly { - let returndata_size := mload(returndata) - revert(add(32, returndata), returndata_size) - } - } else { - revert(errorMessage); - } - } - } -} - -// File: contracts/child/ChildToken/UpgradeableChildERC20/ERC20.sol - -// SPDX-License-Identifier: MIT - -pragma solidity ^0.6.0; - - - - - -/** - * Modified openzeppelin implemtation to add setters for name, symbol and decimals. - * This was needed because the variables cannot be set in constructor as the contract is upgradeable. - */ - -/** - * @dev openzeppelin Implementation of the {IERC20} interface. - * - * Modified to add setters for name, symbol and decimals. This was needed - * because - * - * This implementation is agnostic to the way tokens are created. This means - * that a supply mechanism has to be added in a derived contract using {_mint}. - * For a generic mechanism see {ERC20PresetMinterPauser}. - * - * TIP: For a detailed writeup see our guide - * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How - * to implement supply mechanisms]. - * - * We have followed general OpenZeppelin guidelines: functions revert instead - * of returning `false` on failure. This behavior is nonetheless conventional - * and does not conflict with the expectations of ERC20 applications. - * - * Additionally, an {Approval} event is emitted on calls to {transferFrom}. - * This allows applications to reconstruct the allowance for all accounts just - * by listening to said events. Other implementations of the EIP may not emit - * these events, as it isn't required by the specification. - * - * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} - * functions have been added to mitigate the well-known issues around setting - * allowances. See {IERC20-approve}. - */ -contract ERC20 is Context, IERC20 { - using SafeMath for uint256; - using Address for address; - - mapping (address => uint256) private _balances; - - mapping (address => mapping (address => uint256)) private _allowances; - - uint256 private _totalSupply; - - string private _name; - string private _symbol; - uint8 private _decimals; - - /** - * @dev Sets the values for {name} and {symbol}, initializes {decimals} with - * a default value of 18. - * - * To select a different value for {decimals}, use {_setupDecimals}. - * - * All three of these values are immutable: they can only be set once during - * construction. - */ - constructor (string memory name, string memory symbol) public { - _name = name; - _symbol = symbol; - _decimals = 18; - } - - /** - * @dev Returns the name of the token. - */ - function name() public view returns (string memory) { - return _name; - } - - function setName(string memory newName) internal { - _name = newName; - } - - /** - * @dev Returns the symbol of the token, usually a shorter version of the - * name. - */ - function symbol() public view returns (string memory) { - return _symbol; - } - - function setSymbol(string memory newSymbol) internal { - _symbol = newSymbol; - } - - /** - * @dev Returns the number of decimals used to get its user representation. - * For example, if `decimals` equals `2`, a balance of `505` tokens should - * be displayed to a user as `5,05` (`505 / 10 ** 2`). - * - * Tokens usually opt for a value of 18, imitating the relationship between - * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is - * called. - * - * NOTE: This information is only used for _display_ purposes: it in - * no way affects any of the arithmetic of the contract, including - * {IERC20-balanceOf} and {IERC20-transfer}. - */ - function decimals() public view returns (uint8) { - return _decimals; - } - - function setDecimals(uint8 newDecimals) internal { - _decimals = newDecimals; - } - - /** - * @dev See {IERC20-totalSupply}. - */ - function totalSupply() public view override returns (uint256) { - return _totalSupply; - } - - /** - * @dev See {IERC20-balanceOf}. - */ - function balanceOf(address account) public view override returns (uint256) { - return _balances[account]; - } - - /** - * @dev See {IERC20-transfer}. - * - * Requirements: - * - * - `recipient` cannot be the zero address. - * - the caller must have a balance of at least `amount`. - */ - function transfer(address recipient, uint256 amount) public virtual override returns (bool) { - _transfer(_msgSender(), recipient, amount); - return true; - } - - /** - * @dev See {IERC20-allowance}. - */ - function allowance(address owner, address spender) public view virtual override returns (uint256) { - return _allowances[owner][spender]; - } - - /** - * @dev See {IERC20-approve}. - * - * Requirements: - * - * - `spender` cannot be the zero address. - */ - function approve(address spender, uint256 amount) public virtual override returns (bool) { - _approve(_msgSender(), spender, amount); - return true; - } - - /** - * @dev See {IERC20-transferFrom}. - * - * Emits an {Approval} event indicating the updated allowance. This is not - * required by the EIP. See the note at the beginning of {ERC20}; - * - * Requirements: - * - `sender` and `recipient` cannot be the zero address. - * - `sender` must have a balance of at least `amount`. - * - the caller must have allowance for ``sender``'s tokens of at least - * `amount`. - */ - function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { - _transfer(sender, recipient, amount); - _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); - return true; - } - - /** - * @dev Atomically increases the allowance granted to `spender` by the caller. - * - * This is an alternative to {approve} that can be used as a mitigation for - * problems described in {IERC20-approve}. - * - * Emits an {Approval} event indicating the updated allowance. - * - * Requirements: - * - * - `spender` cannot be the zero address. - */ - function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { - _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); - return true; - } - - /** - * @dev Atomically decreases the allowance granted to `spender` by the caller. - * - * This is an alternative to {approve} that can be used as a mitigation for - * problems described in {IERC20-approve}. - * - * Emits an {Approval} event indicating the updated allowance. - * - * Requirements: - * - * - `spender` cannot be the zero address. - * - `spender` must have allowance for the caller of at least - * `subtractedValue`. - */ - function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { - _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); - return true; - } - - /** - * @dev Moves tokens `amount` from `sender` to `recipient`. - * - * This is internal function is equivalent to {transfer}, and can be used to - * e.g. implement automatic token fees, slashing mechanisms, etc. - * - * Emits a {Transfer} event. - * - * Requirements: - * - * - `sender` cannot be the zero address. - * - `recipient` cannot be the zero address. - * - `sender` must have a balance of at least `amount`. - */ - function _transfer(address sender, address recipient, uint256 amount) internal virtual { - require(sender != address(0), "ERC20: transfer from the zero address"); - require(recipient != address(0), "ERC20: transfer to the zero address"); - - _beforeTokenTransfer(sender, recipient, amount); - - _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); - _balances[recipient] = _balances[recipient].add(amount); - emit Transfer(sender, recipient, amount); - } - - /** @dev Creates `amount` tokens and assigns them to `account`, increasing - * the total supply. - * - * Emits a {Transfer} event with `from` set to the zero address. - * - * Requirements - * - * - `to` cannot be the zero address. - */ - function _mint(address account, uint256 amount) public virtual { // @NOF_dev original is internal, now set to public to mint DAI - require(account != address(0), "ERC20: mint to the zero address"); - - _beforeTokenTransfer(address(0), account, amount); - - _totalSupply = _totalSupply.add(amount); - _balances[account] = _balances[account].add(amount); - emit Transfer(address(0), account, amount); - } - - /** - * @dev Destroys `amount` tokens from `account`, reducing the - * total supply. - * - * Emits a {Transfer} event with `to` set to the zero address. - * - * Requirements - * - * - `account` cannot be the zero address. - * - `account` must have at least `amount` tokens. - */ - function _burn(address account, uint256 amount) internal virtual { - require(account != address(0), "ERC20: burn from the zero address"); - - _beforeTokenTransfer(account, address(0), amount); - - _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); - _totalSupply = _totalSupply.sub(amount); - emit Transfer(account, address(0), amount); - } - - /** - * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. - * - * This is internal function is equivalent to `approve`, and can be used to - * e.g. set automatic allowances for certain subsystems, etc. - * - * Emits an {Approval} event. - * - * Requirements: - * - * - `owner` cannot be the zero address. - * - `spender` cannot be the zero address. - */ - function _approve(address owner, address spender, uint256 amount) internal virtual { - require(owner != address(0), "ERC20: approve from the zero address"); - require(spender != address(0), "ERC20: approve to the zero address"); - - _allowances[owner][spender] = amount; - emit Approval(owner, spender, amount); - } - - /** - * @dev Sets {decimals} to a value other than the default one of 18. - * - * WARNING: This function should only be called from the constructor. Most - * applications that interact with token contracts will not expect - * {decimals} to ever change, and may work incorrectly if it does. - */ - function _setupDecimals(uint8 decimals_) internal { - _decimals = decimals_; - } - - /** - * @dev Hook that is called before any transfer of tokens. This includes - * minting and burning. - * - * Calling conditions: - * - * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens - * will be to transferred to `to`. - * - when `from` is zero, `amount` tokens will be minted for `to`. - * - when `to` is zero, `amount` of ``from``'s tokens will be burned. - * - `from` and `to` are never both zero. - * - * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. - */ - function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { } -} - -// File: @openzeppelin/contracts/utils/EnumerableSet.sol - -// SPDX-License-Identifier: MIT - -pragma solidity ^0.6.0; - -/** - * @dev Library for managing - * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive - * types. - * - * Sets have the following properties: - * - * - Elements are added, removed, and checked for existence in constant time - * (O(1)). - * - Elements are enumerated in O(n). No guarantees are made on the ordering. - * - * ``` - * contract Example { - * // Add the library methods - * using EnumerableSet for EnumerableSet.AddressSet; - * - * // Declare a set state variable - * EnumerableSet.AddressSet private mySet; - * } - * ``` - * - * As of v3.0.0, only sets of type `address` (`AddressSet`) and `uint256` - * (`UintSet`) are supported. - */ -library EnumerableSet { - // To implement this library for multiple types with as little code - // repetition as possible, we write it in terms of a generic Set type with - // bytes32 values. - // The Set implementation uses private functions, and user-facing - // implementations (such as AddressSet) are just wrappers around the - // underlying Set. - // This means that we can only create new EnumerableSets for types that fit - // in bytes32. - - struct Set { - // Storage of set values - bytes32[] _values; - - // Position of the value in the `values` array, plus 1 because index 0 - // means a value is not in the set. - mapping (bytes32 => uint256) _indexes; - } - - /** - * @dev Add a value to a set. O(1). - * - * Returns true if the value was added to the set, that is if it was not - * already present. - */ - function _add(Set storage set, bytes32 value) private returns (bool) { - if (!_contains(set, value)) { - set._values.push(value); - // The value is stored at length-1, but we add 1 to all indexes - // and use 0 as a sentinel value - set._indexes[value] = set._values.length; - return true; - } else { - return false; - } - } - - /** - * @dev Removes a value from a set. O(1). - * - * Returns true if the value was removed from the set, that is if it was - * present. - */ - function _remove(Set storage set, bytes32 value) private returns (bool) { - // We read and store the value's index to prevent multiple reads from the same storage slot - uint256 valueIndex = set._indexes[value]; - - if (valueIndex != 0) { // Equivalent to contains(set, value) - // To delete an element from the _values array in O(1), we swap the element to delete with the last one in - // the array, and then remove the last element (sometimes called as 'swap and pop'). - // This modifies the order of the array, as noted in {at}. - - uint256 toDeleteIndex = valueIndex - 1; - uint256 lastIndex = set._values.length - 1; - - // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs - // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement. - - bytes32 lastvalue = set._values[lastIndex]; - - // Move the last value to the index where the value to delete is - set._values[toDeleteIndex] = lastvalue; - // Update the index for the moved value - set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based - - // Delete the slot where the moved value was stored - set._values.pop(); - - // Delete the index for the deleted slot - delete set._indexes[value]; - - return true; - } else { - return false; - } - } - - /** - * @dev Returns true if the value is in the set. O(1). - */ - function _contains(Set storage set, bytes32 value) private view returns (bool) { - return set._indexes[value] != 0; - } - - /** - * @dev Returns the number of values on the set. O(1). - */ - function _length(Set storage set) private view returns (uint256) { - return set._values.length; - } - - /** - * @dev Returns the value stored at position `index` in the set. O(1). - * - * Note that there are no guarantees on the ordering of values inside the - * array, and it may change when more values are added or removed. - * - * Requirements: - * - * - `index` must be strictly less than {length}. - */ - function _at(Set storage set, uint256 index) private view returns (bytes32) { - require(set._values.length > index, "EnumerableSet: index out of bounds"); - return set._values[index]; - } - - // AddressSet - - struct AddressSet { - Set _inner; - } - - /** - * @dev Add a value to a set. O(1). - * - * Returns true if the value was added to the set, that is if it was not - * already present. - */ - function add(AddressSet storage set, address value) internal returns (bool) { - return _add(set._inner, bytes32(uint256(value))); - } - - /** - * @dev Removes a value from a set. O(1). - * - * Returns true if the value was removed from the set, that is if it was - * present. - */ - function remove(AddressSet storage set, address value) internal returns (bool) { - return _remove(set._inner, bytes32(uint256(value))); - } - - /** - * @dev Returns true if the value is in the set. O(1). - */ - function contains(AddressSet storage set, address value) internal view returns (bool) { - return _contains(set._inner, bytes32(uint256(value))); - } - - /** - * @dev Returns the number of values in the set. O(1). - */ - function length(AddressSet storage set) internal view returns (uint256) { - return _length(set._inner); - } - - /** - * @dev Returns the value stored at position `index` in the set. O(1). - * - * Note that there are no guarantees on the ordering of values inside the - * array, and it may change when more values are added or removed. - * - * Requirements: - * - * - `index` must be strictly less than {length}. - */ - function at(AddressSet storage set, uint256 index) internal view returns (address) { - return address(uint256(_at(set._inner, index))); - } - - - // UintSet - - struct UintSet { - Set _inner; - } - - /** - * @dev Add a value to a set. O(1). - * - * Returns true if the value was added to the set, that is if it was not - * already present. - */ - function add(UintSet storage set, uint256 value) internal returns (bool) { - return _add(set._inner, bytes32(value)); - } - - /** - * @dev Removes a value from a set. O(1). - * - * Returns true if the value was removed from the set, that is if it was - * present. - */ - function remove(UintSet storage set, uint256 value) internal returns (bool) { - return _remove(set._inner, bytes32(value)); - } - - /** - * @dev Returns true if the value is in the set. O(1). - */ - function contains(UintSet storage set, uint256 value) internal view returns (bool) { - return _contains(set._inner, bytes32(value)); - } - - /** - * @dev Returns the number of values on the set. O(1). - */ - function length(UintSet storage set) internal view returns (uint256) { - return _length(set._inner); - } - - /** - * @dev Returns the value stored at position `index` in the set. O(1). - * - * Note that there are no guarantees on the ordering of values inside the - * array, and it may change when more values are added or removed. - * - * Requirements: - * - * - `index` must be strictly less than {length}. - */ - function at(UintSet storage set, uint256 index) internal view returns (uint256) { - return uint256(_at(set._inner, index)); - } -} - -// File: @openzeppelin/contracts/access/AccessControl.sol - -// SPDX-License-Identifier: MIT - -pragma solidity ^0.6.0; - - - - -/** - * @dev Contract module that allows children to implement role-based access - * control mechanisms. - * - * Roles are referred to by their `bytes32` identifier. These should be exposed - * in the external API and be unique. The best way to achieve this is by - * using `public constant` hash digests: - * - * ``` - * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); - * ``` - * - * Roles can be used to represent a set of permissions. To restrict access to a - * function call, use {hasRole}: - * - * ``` - * function foo() public { - * require(hasRole(MY_ROLE, msg.sender)); - * ... - * } - * ``` - * - * Roles can be granted and revoked dynamically via the {grantRole} and - * {revokeRole} functions. Each role has an associated admin role, and only - * accounts that have a role's admin role can call {grantRole} and {revokeRole}. - * - * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means - * that only accounts with this role will be able to grant or revoke other - * roles. More complex role relationships can be created by using - * {_setRoleAdmin}. - * - * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to - * grant and revoke this role. Extra precautions should be taken to secure - * accounts that have been granted it. - */ -abstract contract AccessControl is Context { - using EnumerableSet for EnumerableSet.AddressSet; - using Address for address; - - struct RoleData { - EnumerableSet.AddressSet members; - bytes32 adminRole; - } - - mapping (bytes32 => RoleData) private _roles; - - bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; - - /** - * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` - * - * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite - * {RoleAdminChanged} not being emitted signaling this. - * - * _Available since v3.1._ - */ - event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); - - /** - * @dev Emitted when `account` is granted `role`. - * - * `sender` is the account that originated the contract call, an admin role - * bearer except when using {_setupRole}. - */ - event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); - - /** - * @dev Emitted when `account` is revoked `role`. - * - * `sender` is the account that originated the contract call: - * - if using `revokeRole`, it is the admin role bearer - * - if using `renounceRole`, it is the role bearer (i.e. `account`) - */ - event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); - - /** - * @dev Returns `true` if `account` has been granted `role`. - */ - function hasRole(bytes32 role, address account) public view returns (bool) { - return _roles[role].members.contains(account); - } - - /** - * @dev Returns the number of accounts that have `role`. Can be used - * together with {getRoleMember} to enumerate all bearers of a role. - */ - function getRoleMemberCount(bytes32 role) public view returns (uint256) { - return _roles[role].members.length(); - } - - /** - * @dev Returns one of the accounts that have `role`. `index` must be a - * value between 0 and {getRoleMemberCount}, non-inclusive. - * - * Role bearers are not sorted in any particular way, and their ordering may - * change at any point. - * - * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure - * you perform all queries on the same block. See the following - * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] - * for more information. - */ - function getRoleMember(bytes32 role, uint256 index) public view returns (address) { - return _roles[role].members.at(index); - } - - /** - * @dev Returns the admin role that controls `role`. See {grantRole} and - * {revokeRole}. - * - * To change a role's admin, use {_setRoleAdmin}. - */ - function getRoleAdmin(bytes32 role) public view returns (bytes32) { - return _roles[role].adminRole; - } - - /** - * @dev Grants `role` to `account`. - * - * If `account` had not been already granted `role`, emits a {RoleGranted} - * event. - * - * Requirements: - * - * - the caller must have ``role``'s admin role. - */ - function grantRole(bytes32 role, address account) public virtual { - require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to grant"); - - _grantRole(role, account); - } - - /** - * @dev Revokes `role` from `account`. - * - * If `account` had been granted `role`, emits a {RoleRevoked} event. - * - * Requirements: - * - * - the caller must have ``role``'s admin role. - */ - function revokeRole(bytes32 role, address account) public virtual { - require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to revoke"); - - _revokeRole(role, account); - } - - /** - * @dev Revokes `role` from the calling account. - * - * Roles are often managed via {grantRole} and {revokeRole}: this function's - * purpose is to provide a mechanism for accounts to lose their privileges - * if they are compromised (such as when a trusted device is misplaced). - * - * If the calling account had been granted `role`, emits a {RoleRevoked} - * event. - * - * Requirements: - * - * - the caller must be `account`. - */ - function renounceRole(bytes32 role, address account) public virtual { - require(account == _msgSender(), "AccessControl: can only renounce roles for self"); - - _revokeRole(role, account); - } - - /** - * @dev Grants `role` to `account`. - * - * If `account` had not been already granted `role`, emits a {RoleGranted} - * event. Note that unlike {grantRole}, this function doesn't perform any - * checks on the calling account. - * - * [WARNING] - * ==== - * This function should only be called from the constructor when setting - * up the initial roles for the system. - * - * Using this function in any other way is effectively circumventing the admin - * system imposed by {AccessControl}. - * ==== - */ - function _setupRole(bytes32 role, address account) internal virtual { - _grantRole(role, account); - } - - /** - * @dev Sets `adminRole` as ``role``'s admin role. - * - * Emits a {RoleAdminChanged} event. - */ - function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { - emit RoleAdminChanged(role, _roles[role].adminRole, adminRole); - _roles[role].adminRole = adminRole; - } - - function _grantRole(bytes32 role, address account) private { - if (_roles[role].members.add(account)) { - emit RoleGranted(role, account, _msgSender()); - } - } - - function _revokeRole(bytes32 role, address account) private { - if (_roles[role].members.remove(account)) { - emit RoleRevoked(role, account, _msgSender()); - } - } -} - -// File: contracts/common/AccessControlMixin.sol - -pragma solidity 0.6.6; - - -contract AccessControlMixin is AccessControl { - string private _revertMsg; - function _setupContractId(string memory contractId) internal { - _revertMsg = string(abi.encodePacked(contractId, ": INSUFFICIENT_PERMISSIONS")); - } - - modifier only(bytes32 role) { - require( - hasRole(role, _msgSender()), - _revertMsg - ); - _; - } -} - -// File: contracts/child/ChildToken/IChildToken.sol - -pragma solidity 0.6.6; - -interface IChildToken { - function deposit(address user, bytes calldata depositData) external; -} - -// File: contracts/common/Initializable.sol - -pragma solidity 0.6.6; - -contract Initializable { - bool inited = false; - - modifier initializer() { - require(!inited, "already inited"); - _; - inited = true; - } -} - -// File: contracts/common/EIP712Base.sol - -pragma solidity 0.6.6; - - -contract EIP712Base is Initializable { - struct EIP712Domain { - string name; - string version; - address verifyingContract; - bytes32 salt; - } - - bytes32 internal constant EIP712_DOMAIN_TYPEHASH = keccak256( - bytes( - "EIP712Domain(string name,string version,address verifyingContract,bytes32 salt)" - ) - ); - bytes32 internal domainSeperator; - - // supposed to be called once while initializing. - // one of the contractsa that inherits this contract follows proxy pattern - // so it is not possible to do this in a constructor - function _initializeEIP712( - string memory name, - string memory version - ) - internal - initializer - { - _setDomainSeperator(name, version); - } - - function _setDomainSeperator(string memory name, string memory version) internal { - domainSeperator = keccak256( - abi.encode( - EIP712_DOMAIN_TYPEHASH, - keccak256(bytes(name)), - keccak256(bytes(version)), - address(this), - bytes32(getChainId()) - ) - ); - } - - function getDomainSeperator() public view returns (bytes32) { - return domainSeperator; - } - - function getChainId() public pure returns (uint256) { - uint256 id; - assembly { - id := chainid() - } - return id; - } - - /** - * Accept message hash and returns hash message in EIP712 compatible form - * So that it can be used to recover signer from signature signed using EIP712 formatted data - * https://eips.ethereum.org/EIPS/eip-712 - * "\\x19" makes the encoding deterministic - * "\\x01" is the version byte to make it compatible to EIP-191 - */ - function toTypedMessageHash(bytes32 messageHash) - internal - view - returns (bytes32) - { - return - keccak256( - abi.encodePacked("\x19\x01", getDomainSeperator(), messageHash) - ); - } -} - -// File: contracts/common/NativeMetaTransaction.sol - -pragma solidity 0.6.6; - - - -contract NativeMetaTransaction is EIP712Base { - using SafeMath for uint256; - bytes32 private constant META_TRANSACTION_TYPEHASH = keccak256( - bytes( - "MetaTransaction(uint256 nonce,address from,bytes functionSignature)" - ) - ); - event MetaTransactionExecuted( - address userAddress, - address payable relayerAddress, - bytes functionSignature - ); - mapping(address => uint256) nonces; - - /* - * Meta transaction structure. - * No point of including value field here as if user is doing value transfer then he has the funds to pay for gas - * He should call the desired function directly in that case. - */ - struct MetaTransaction { - uint256 nonce; - address from; - bytes functionSignature; - } - - function executeMetaTransaction( - address userAddress, - bytes memory functionSignature, - bytes32 sigR, - bytes32 sigS, - uint8 sigV - ) public payable returns (bytes memory) { - MetaTransaction memory metaTx = MetaTransaction({ - nonce: nonces[userAddress], - from: userAddress, - functionSignature: functionSignature - }); - - require( - verify(userAddress, metaTx, sigR, sigS, sigV), - "Signer and signature do not match" - ); - - // increase nonce for user (to avoid re-use) - nonces[userAddress] = nonces[userAddress].add(1); - - emit MetaTransactionExecuted( - userAddress, - msg.sender, - functionSignature - ); - - // Append userAddress and relayer address at the end to extract it from calling context - (bool success, bytes memory returnData) = address(this).call( - abi.encodePacked(functionSignature, userAddress) - ); - require(success, "Function call not successful"); - - return returnData; - } - - function hashMetaTransaction(MetaTransaction memory metaTx) - internal - pure - returns (bytes32) - { - return - keccak256( - abi.encode( - META_TRANSACTION_TYPEHASH, - metaTx.nonce, - metaTx.from, - keccak256(metaTx.functionSignature) - ) - ); - } - - function getNonce(address user) public view returns (uint256 nonce) { - nonce = nonces[user]; - } - - function verify( - address signer, - MetaTransaction memory metaTx, - bytes32 sigR, - bytes32 sigS, - uint8 sigV - ) internal view returns (bool) { - require(signer != address(0), "NativeMetaTransaction: INVALID_SIGNER"); - return - signer == - ecrecover( - toTypedMessageHash(hashMetaTransaction(metaTx)), - sigV, - sigR, - sigS - ); - } -} - -// File: contracts/ChainConstants.sol - -pragma solidity 0.6.6; - -contract ChainConstants { - string constant public ERC712_VERSION = "1"; - - uint256 constant public ROOT_CHAIN_ID = 1; - bytes constant public ROOT_CHAIN_ID_BYTES = hex"01"; - - uint256 constant public CHILD_CHAIN_ID = 137; - bytes constant public CHILD_CHAIN_ID_BYTES = hex"89"; -} - -// File: contracts/common/ContextMixin.sol - -pragma solidity 0.6.6; - -abstract contract ContextMixin { - function msgSender() - internal - view - returns (address payable sender) - { - if (msg.sender == address(this)) { - bytes memory array = msg.data; - uint256 index = msg.data.length; - assembly { - // Load the 32 bytes word from memory with the address on the lower 20 bytes, and mask those. - sender := and( - mload(add(array, index)), - 0xffffffffffffffffffffffffffffffffffffffff - ) - } - } else { - sender = msg.sender; - } - return sender; - } -} - -// File: contracts/child/ChildToken/UpgradeableChildERC20/UChildERC20.sol - -pragma solidity 0.6.6; - - - - - - - - -contract UChildERC20 is - ERC20, - IChildToken, - AccessControlMixin, - NativeMetaTransaction, - ChainConstants, - ContextMixin -{ - bytes32 public constant DEPOSITOR_ROLE = keccak256("DEPOSITOR_ROLE"); - - constructor() public ERC20("", "") {} - - /** - * @notice Initialize the contract after it has been proxified - * @dev meant to be called once immediately after deployment - */ - function initialize( - string calldata name_, - string calldata symbol_, - uint8 decimals_, - address childChainManager - ) - external - initializer - { - setName(name_); - setSymbol(symbol_); - setDecimals(decimals_); - _setupContractId(string(abi.encodePacked("Child", symbol_))); - _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); - _setupRole(DEPOSITOR_ROLE, childChainManager); - _initializeEIP712(name_, ERC712_VERSION); - } - - // This is to support Native meta transactions - // never use msg.sender directly, use _msgSender() instead - function _msgSender() - internal - override - view - returns (address payable sender) - { - return ContextMixin.msgSender(); - } - - function changeName(string calldata name_) external only(DEFAULT_ADMIN_ROLE) { - setName(name_); - _setDomainSeperator(name_, ERC712_VERSION); - } - - /** - * @notice called when token is deposited on root chain - * @dev Should be callable only by ChildChainManager - * Should handle deposit by minting the required amount for user - * Make sure minting is done only by this function - * @param user user address for whom deposit is being done - * @param depositData abi encoded amount - */ - function deposit(address user, bytes calldata depositData) - external - override - only(DEPOSITOR_ROLE) - { - uint256 amount = abi.decode(depositData, (uint256)); - _mint(user, amount); - } - - /** - * @notice called when user wants to withdraw tokens back to root chain - * @dev Should burn user's tokens. This transaction will be verified when exiting on root chain - * @param amount amount of tokens to withdraw - */ - function withdraw(uint256 amount) external { - _burn(_msgSender(), amount); - } -} - -// File: contracts/child/ChildToken/DappTokens/UChildDAI.sol - -pragma solidity 0.6.6; - - -contract UChildDAI is UChildERC20 { - // bytes32 public constant PERMIT_TYPEHASH = keccak256("Permit(address holder,address spender,uint256 nonce,uint256 expiry,bool allowed)"); - bytes32 public constant PERMIT_TYPEHASH = 0xea2aa0a1be11a07ed86d755c93467f4f82362b452371d1ba94d1715123511acb; - - // --- Alias --- - function push(address usr, uint wad) external { - transferFrom(msg.sender, usr, wad); - } - function pull(address usr, uint wad) external { - transferFrom(usr, msg.sender, wad); - } - function move(address src, address dst, uint wad) external { - transferFrom(src, dst, wad); - } - - // --- Approve by signature --- - function permit( - address holder, - address spender, - uint256 nonce, - uint256 expiry, - bool allowed, - uint8 v, - bytes32 r, - bytes32 s - ) external { - bytes32 digest = keccak256( - abi.encodePacked( - "\x19\x01", - getDomainSeperator(), - keccak256( - abi.encode( - PERMIT_TYPEHASH, - holder, - spender, - nonce, - expiry, - allowed - ) - ) - )); - - require(holder == ecrecover(digest, v, r, s), "UChildDAI: INVALID-PERMIT"); - require(expiry == 0 || now <= expiry, "UChildDAI: PERMIT-EXPIRED"); - require(nonce == nonces[holder]++, "UChildDAI: INVALID-NONCE"); - uint wad = allowed ? uint(-1) : 0; - _approve(holder, spender, wad); - } -} \ No newline at end of file From 07ab07020ef069398c7980e9289e82da8a902edb Mon Sep 17 00:00:00 2001 From: dappsar Date: Tue, 14 Nov 2023 17:18:02 -0300 Subject: [PATCH 2/4] prettier --- test/gamma.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/gamma.test.ts b/test/gamma.test.ts index fe0816f..0611680 100644 --- a/test/gamma.test.ts +++ b/test/gamma.test.ts @@ -70,7 +70,7 @@ describe('NoF - Gamma Tests', function () { expect(packOwner).to.equal(address0.address) }) - it("Pack could be open by its owner", async () => { + it('Pack could be open by its owner', async () => { const { testDAI, gammaPacks, gammaCards, address0 } = await loadFixture(deployNofFixture) const TenPacksPrice = ethers.BigNumber.from('10000000000000000000'.toString()) await testDAI._mint(address0.address, TenPacksPrice) From 0c07c01033e390aa497a3cea68670edaf4f4ed4e Mon Sep 17 00:00:00 2001 From: dappsar Date: Tue, 14 Nov 2023 17:18:28 -0300 Subject: [PATCH 3/4] improved deploy scripts for mumbai --- scripts/common.ts | 13 +++-- scripts/deploy-mock-data.ts | 110 +++++++++++++++++------------------- 2 files changed, 61 insertions(+), 62 deletions(-) diff --git a/scripts/common.ts b/scripts/common.ts index cda020e..b0af169 100644 --- a/scripts/common.ts +++ b/scripts/common.ts @@ -5,8 +5,8 @@ import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; import Web3 from 'web3'; import { config } from 'hardhat'; -const isLocalhost = (network.name === 'localhost') || (network.name === '127.0.0.1') -const isHardhat = (network.name === 'hardhat') +export const isLocalhost = (network.name === 'localhost') || (network.name === '127.0.0.1') +export const isHardhat = (network.name === 'hardhat') export async function getInitData() { if (isHardhat) { @@ -43,7 +43,9 @@ export async function deployContracts(addresses: SignerWithAddress[]) { const additionalOwners = (process.env.ADDITIONAL_OWNERS_WALLETS_ADDRESSES || '0x35dad65F60c1A32c9895BE97f6bcE57D32792E83,0x8a8F5e5ae88532c605921f320a92562c9599fB9E').split(',') const balanceReceiverAddress = - (isLocalhost || isHardhat) ? addresses[0].address : (process.env.BALANCE_RECEIVER_WALLET_ADDRESS || '0x6b510284C49705eA14e92aD35D86FD3075eC56e0') + (isLocalhost || isHardhat) + ? addresses[0].address + : (process.env.BALANCE_RECEIVER_WALLET_ADDRESS || '0x6b510284C49705eA14e92aD35D86FD3075eC56e0') console.log(`deploying contract ${nofDaiContractName}`) const TestDAI = await ethers.getContractFactory(nofDaiContractName); @@ -52,7 +54,7 @@ export async function deployContracts(addresses: SignerWithAddress[]) { console.log(`deploying contract ${nofAlphaContractName}`) const Alpha = await ethers.getContractFactory(nofAlphaContractName); - const alpha = await Alpha.deploy('https://nof.town', testDAI.address, balanceReceiverAddress); + const alpha = await Alpha.deploy('https://storage.googleapis.com/nof-alfa/T1', testDAI.address, balanceReceiverAddress); await alpha.deployed(); console.log(`deploying contract ${nofGammaPacksContractName}`) @@ -62,7 +64,8 @@ export async function deployContracts(addresses: SignerWithAddress[]) { console.log(`deploying contract ${nofGammaCardsContractName}`) const GammaCards = await ethers.getContractFactory(nofGammaCardsContractName); - const gammaCards = await GammaCards.deploy(testDAI.address, gammaPacks.address, 'https://storage.googleapis.com/nof-gamma/T1', microServiceSignatureWalletsAddresses[0]); + const gammaCards = await GammaCards.deploy(testDAI.address, gammaPacks.address, + 'https://storage.googleapis.com/nof-gamma/T1', microServiceSignatureWalletsAddresses[0]); await gammaCards.deployed(); await gammaPacks.setCardsContract(gammaCards.address); diff --git a/scripts/deploy-mock-data.ts b/scripts/deploy-mock-data.ts index dd2ff3f..f260b89 100644 --- a/scripts/deploy-mock-data.ts +++ b/scripts/deploy-mock-data.ts @@ -2,7 +2,7 @@ import "@nomiclabs/hardhat-ethers"; import { ethers } from "hardhat"; import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; import { Contract } from "ethers"; -import { generateSignature, getInitData, deployContracts } from "./common"; +import { generateSignature, getInitData, deployContracts, isHardhat, isLocalhost } from "./common"; async function createAlphaMockData( addresses: SignerWithAddress[], testDAI: Contract, alpha: Contract ) { // Alpha Data @@ -61,66 +61,62 @@ async function createGammaMockData( const allowance = await testDAI.allowance(addresses[0].address, gammaPacks.address) console.log(`${addresses[0].address} allowance to use with $ gamaPackAddress (${gammaPacks.address}): `, allowance) - console.log('buying Pack...') - const estimatedGas = await gammaPacks.estimateGas.buyPack(); - console.log('buying Pack, estimated gas', estimatedGas) - - const gasLimit = estimatedGas.add(10000) // security-margin - const tokenId = await gammaPacks.buyPack({ gasLimit, from: addresses[0].address }); - console.log('Buyed Pack token Id', tokenId.value) - - console.log('Verifing testDai balance...') - const balance2 = await testDAI.balanceOf(addresses[0].address) - console.log(`${addresses[0].address} balance: `, balance2) - - console.log('Verifing testDai allowance...') - const allowance2 = await testDAI.allowance(addresses[0].address, gammaPacks.address) - console.log(`${addresses[0].address} allowance to use with $ gamaPackAddress (${gammaPacks.address}): `, allowance2) - - console.log('Verifing pack owner...') - const packOwner = await gammaPacks.getPackOwner(tokenId.value) - console.log(`Owner of TokenId ${tokenId.value}: ${packOwner}`) - - console.log('buying 3 Packs...') - const estimatedGasTenPacks = await gammaPacks.estimateGas.buyPacks(3); - console.log('buying 3 Packs, estimated gas', estimatedGasTenPacks) - - const gasLimitTenPacks = estimatedGasTenPacks.add(10000) // security-margin - await gammaPacks.buyPacks(3, { gasLimit: gasLimitTenPacks, from: addresses[0].address }); - - console.log('Verifing user\'s packs...') - const packs:[any] = await gammaPacks.getPacksByUser(addresses[0].address) + if (isHardhat || isLocalhost) { + console.log('buying Pack (estimating gas)...') + const estimatedGas = await gammaPacks.estimateGas.buyPack({ from: addresses[0].address }); + console.log('buying Pack, estimated gas', estimatedGas) + + const gasLimit = estimatedGas.add(20000) // security-margin + console.log('buying Pack (real operation)...') + const tokenId = await gammaPacks.connect(addresses[0]).buyPack({ gasLimit }); + console.log('Buyed Pack token Id', tokenId.value) + + console.log('Verifing testDai balance...') + const balance2 = await testDAI.balanceOf(addresses[0].address) + console.log(`${addresses[0].address} balance: `, balance2) + + console.log('Verifing testDai allowance...') + const allowance2 = await testDAI.allowance(addresses[0].address, gammaPacks.address) + console.log(`${addresses[0].address} allowance to use with $ gamaPackAddress (${gammaPacks.address}): `, allowance2) + + console.log('Verifing pack owner...') + const packOwner = await gammaPacks.getPackOwner(tokenId.value) + console.log(`Owner of TokenId ${tokenId.value}: ${packOwner}`) + + console.log('buying 2 Packs (estimating gas)...') + const estimatedGasTenPacks = await gammaPacks.estimateGas.buyPacks(2); + console.log('buying 2 Packs, estimated gas', estimatedGasTenPacks) + + console.log('buying 2 Packs (operation)...') + const gasLimitTenPacks = estimatedGasTenPacks.add(20000) // security-margin + await gammaPacks.connect(addresses[0]).buyPacks(2, { gasLimit: gasLimitTenPacks }); + + console.log('Verifing user\'s packs...') + const packs:[any] = await gammaPacks.getPacksByUser(addresses[0].address) + + console.log('User\'s packs') + for (let i = 0; i < packs.length-1; i++) { + console.log(`\tPack ${i+1} Id: ${packs[i]}`) + } - console.log('User\'s packs') - for (let i = 0; i < packs.length-1; i++) { - console.log(`\tPack ${i+1} Id: ${packs[i]}`) - } + /* + // + TO-FIX: reason: 'invalid arrayify value', + // + console.log('Opening Pack with cardData simulating backend signature...') + const packNumber = ethers.BigNumber.from(packs[0]).toNumber() + const signatureData: any = await generateSignature(signatureMethod, addresses[0].address, packNumber) + const { packet_data, signature } = signatureData - /* - console.log('Opening Pack with cardData simulating backend signature...') - if (signatureMethod === '1') { - // tiene que cambiar la wallet del signer a la misma que hace la - // firma en el método generateSignature1 (la wallet 0 de hardhat). - // Se hace eso para que luego en el SC, al comparar ambas wallets, - // funciones bien (wallet de firma = signer) - gammaCards.setSigner(addresses[0].address) - - // en el caso de deploy fuera de local, el SC tiene que tener como signer - // la dirección de la clave privada que usa el micro-servicio: - // 0x20517cf8c140f7f393f92cea6158f57385a75733 + await gammaCards.openPack(packNumber, packet_data, signature) + + console.log('User\'s packs') + for (let i = 0; i < packs.length-1; i++) { + console.log(`\tPack ${i+1} Id: ${packs[i]}`) + } + */ } - const signatureData: any = await generateSignature(signatureMethod, addresses[0].address, 0) - const packNumber = ethers.BigNumber.from(packs[0]).toNumber() - const { packet_data, signature } = signatureData - - await gammaCards.openPack(packNumber, packet_data, signature) - */ - - console.log('User\'s packs') - for (let i = 0; i < packs.length-1; i++) { - console.log(`\tPack ${i+1} Id: ${packs[i]}`) - } } async function main() { From 86fa497ec9736a7ac544dbc4bd997a6b38ea38dc Mon Sep 17 00:00:00 2001 From: dappsar Date: Tue, 14 Nov 2023 17:19:05 -0300 Subject: [PATCH 4/4] added open pack validation flag --- contracts/gamma/GammaCards.v2.sol | 61 +++++++++++++++++++------------ 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/contracts/gamma/GammaCards.v2.sol b/contracts/gamma/GammaCards.v2.sol index 830fe48..e7b5bf0 100644 --- a/contracts/gamma/GammaCards.v2.sol +++ b/contracts/gamma/GammaCards.v2.sol @@ -47,6 +47,7 @@ contract NofGammaCardsV2 is ERC721, ERC721URIStorage, ERC721Burnable, Ownable { uint256 public secondaryAlbumPrize = 1e18; // 1 DAI por album secundario completado string public mainUri; string public secondaryUri; + bool public requireOpenPackSignerValidation; mapping (uint256 cardNumber => uint256 amount) public cardsInventory; // maximos: 119 => 4999 mapping (uint256 tokenId => Card) public cards; mapping(address user => mapping(uint8 cardNumber => uint8 amount)) public cardsByUser; @@ -69,6 +70,21 @@ contract NofGammaCardsV2 is ERC721, ERC721URIStorage, ERC721Burnable, Ownable { event NewSigner(address newSigner); event NewUris(string newMainUri, string newSecondaryUri); + constructor(address _daiTokenAddress, address _packsContract, string memory _baseUri, address _signer) + ERC721("GammaCards", "NOF_GC") { + packsContract = IGammaPacks(_packsContract); + DAI_TOKEN = _daiTokenAddress; + baseUri = _baseUri; + mainUri = string(abi.encodePacked(bytes(baseUri), bytes("/"), bytes("120"), bytes("F.json"))); + secondaryUri = string(abi.encodePacked(bytes(baseUri), bytes("/"), bytes("121"), bytes("F.json"))); + signers[_signer] = true; + requireOpenPackSignerValidation = false; + for(uint256 i;i<122;i++){ + cardsInventory[i] = 1; + } + owners[msg.sender] = true; + } + modifier onlyPacksContract { require(msg.sender == address(packsContract), "Solo contrato de packs"); _; @@ -105,40 +121,39 @@ contract NofGammaCardsV2 is ERC721, ERC721URIStorage, ERC721Burnable, Ownable { signers[_signerToRemove] = false; } - constructor(address _daiTokenAddress, address _packsContract, string memory _baseUri, address _signer) - ERC721("GammaCards", "NOF_GC") { - packsContract = IGammaPacks(_packsContract); - DAI_TOKEN = _daiTokenAddress; - baseUri = _baseUri; - mainUri = string(abi.encodePacked(bytes(baseUri), bytes("/"), bytes("120"), bytes("F.json"))); - secondaryUri = string(abi.encodePacked(bytes(baseUri), bytes("/"), bytes("121"), bytes("F.json"))); - signers[_signer] = true; - for(uint256 i;i<122;i++){ - cardsInventory[i] = 1; - } - owners[msg.sender] = true; + function changeRequireOpenPackSignerValidation(bool required) external onlyOwners { + requireOpenPackSignerValidation = required; + } + + function verifyPackSigner(uint256 packNumber, uint8[] memory packData, bytes calldata signature) public view + returns (address signer) { + bytes32 messageHash = keccak256(abi.encodePacked(msg.sender, packNumber, + packData, '0xf1dD71895e49b1563693969de50898197cDF3481')).toEthSignedMessageHash(); + address recoveredSigner = messageHash.recover(signature); + console.log('open pack signer recovered', recoveredSigner); + return recoveredSigner; } function openPack(uint256 packNumber, uint8[] memory packData, bytes calldata signature) external { require(packsContract.getPackOwner(packNumber) == msg.sender, "Este sobre no es tuyo"); require(packData.length < 15, "Limite de cartas excedido"); // chequear este length - packsContract.openPack(packNumber, msg.sender); - prizesBalance += packPrice - packPrice / 6; - - // Recreates the message present in the `signature` - bytes32 messageHash = - keccak256(abi.encodePacked( - msg.sender, packNumber, + if (requireOpenPackSignerValidation) { + // Recreates the message present in the `signature` + bytes32 messageHash = keccak256(abi.encodePacked(msg.sender, packNumber, packData, '0xf1dD71895e49b1563693969de50898197cDF3481')).toEthSignedMessageHash(); - address recoveredSigner = messageHash.recover(signature); - console.log('open pack signer recovered', recoveredSigner); - require(signers[recoveredSigner], "Invalid signature"); + address recoveredSigner = messageHash.recover(signature); + console.log('open pack signer recovered', recoveredSigner); + require(signers[recoveredSigner], "Invalid signature"); + } + packsContract.openPack(packNumber, msg.sender); + prizesBalance += packPrice - packPrice / 6; uint256 length = packData.length; for(uint8 i;i