From 3c027c7882dc31c82e5125caf5ef95e367198a0d Mon Sep 17 00:00:00 2001 From: owen05 Date: Tue, 6 Apr 2021 18:47:35 +0800 Subject: [PATCH] add nft event --- .../impl/NFTCollateralVault.sol | 10 +- .../CollateralVault/intf/ICollateralVault.sol | 2 +- contracts/DODOFee/FeeDistributer.sol | 8 + contracts/Factory/ERC721Factory.sol | 61 ---- contracts/Factory/NFTTokenFactory.sol | 75 +++++ .../GeneralizedFragment/impl/Fragment.sol | 16 +- contracts/SmartRoute/proxies/DODONFTProxy.sol | 8 +- .../external/ERC1155/InitializableERC1155.sol | 282 ++++++++++++++++++ contracts/intf/IERC1155MetadataURI.sol | 22 ++ 9 files changed, 415 insertions(+), 69 deletions(-) delete mode 100644 contracts/Factory/ERC721Factory.sol create mode 100644 contracts/Factory/NFTTokenFactory.sol create mode 100644 contracts/external/ERC1155/InitializableERC1155.sol create mode 100644 contracts/intf/IERC1155MetadataURI.sol diff --git a/contracts/CollateralVault/impl/NFTCollateralVault.sol b/contracts/CollateralVault/impl/NFTCollateralVault.sol index a099585..7944c5e 100644 --- a/contracts/CollateralVault/impl/NFTCollateralVault.sol +++ b/contracts/CollateralVault/impl/NFTCollateralVault.sol @@ -20,6 +20,8 @@ contract NFTCollateralVault is InitializableOwnable, IERC721Receiver, IERC1155Re // ============ Storage ============ string public name; + string public baseURI; + struct NftInfo { uint256 tokenId; uint256 amount; @@ -29,15 +31,18 @@ contract NFTCollateralVault is InitializableOwnable, IERC721Receiver, IERC1155Re function init( address owner, - string memory _name + string memory _name, + string memory _baseURI ) external { initOwner(owner); name = _name; + baseURI = _baseURI; } // ============ Event ============ event RemoveNftToken(address nftContract, uint256 tokenId, uint256 amount); event AddNftToken(address nftContract, uint256 tokenId, uint256 amount); + event CreateFragment(); // ============ Ownable ============ @@ -49,9 +54,10 @@ contract NFTCollateralVault is InitializableOwnable, IERC721Receiver, IERC1155Re function createFragment(address nftProxy, bytes calldata data) external onlyOwner { require(nftProxy != address(0), "DODONftVault: PROXY_INVALID"); _OWNER_ = nftProxy; - emit OwnershipTransferred(_OWNER_, nftProxy); (bool success, ) = nftProxy.call(data); require(success, "DODONftVault: TRANSFER_OWNER_FAILED"); + emit OwnershipTransferred(_OWNER_, nftProxy); + emit CreateFragment(); } function withdrawERC721(address nftContract, uint256 tokenId) external onlyOwner { diff --git a/contracts/CollateralVault/intf/ICollateralVault.sol b/contracts/CollateralVault/intf/ICollateralVault.sol index 3be1d60..728c878 100644 --- a/contracts/CollateralVault/intf/ICollateralVault.sol +++ b/contracts/CollateralVault/intf/ICollateralVault.sol @@ -11,7 +11,7 @@ pragma solidity 0.6.9; interface ICollateralVault { function _OWNER_() external returns (address); - function init(address owner, string memory name) external; + function init(address owner, string memory name, string memory baseURI) external; function directTransferOwnership(address newOwner) external; } diff --git a/contracts/DODOFee/FeeDistributer.sol b/contracts/DODOFee/FeeDistributer.sol index aa7c0ca..d727ce1 100644 --- a/contracts/DODOFee/FeeDistributer.sol +++ b/contracts/DODOFee/FeeDistributer.sol @@ -40,6 +40,11 @@ contract FeeDistributor { bool internal _FEE_INITIALIZED_; + // ============ Event ============ + event Stake(address sender, uint256 amount); + event UnStake(address sender, uint256 amount); + event Claim(address sender, uint256 baseAmount, uint256 quoteAmount); + function init( address baseToken, address quoteToken, @@ -60,6 +65,7 @@ contract FeeDistributor { uint256 stakeVault = IERC20(_STAKE_TOKEN_).balanceOf(_STAKE_VAULT_); uint256 stakeInput = stakeVault.sub(_STAKE_RESERVE_); _addShares(stakeInput, to); + emit Stake(to, stakeInput); } function claim(address to) external { @@ -79,6 +85,7 @@ contract FeeDistributor { _removeShares(amount, msg.sender); StakeVault(_STAKE_VAULT_).transferOut(_STAKE_TOKEN_, amount, to); + emit UnStake(msg.sender, amount); } // ============ Internal ============ @@ -90,6 +97,7 @@ contract FeeDistributor { IERC20(_QUOTE_TOKEN_).safeTransfer(to, allQuote); _USER_BASE_REWARDS_[sender] = 0; _USER_BASE_REWARDS_[sender] = 0; + emit Claim(sender, allBase, allQuote); } function _updateGlobalState() internal { diff --git a/contracts/Factory/ERC721Factory.sol b/contracts/Factory/ERC721Factory.sol deleted file mode 100644 index f01c8ec..0000000 --- a/contracts/Factory/ERC721Factory.sol +++ /dev/null @@ -1,61 +0,0 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ -pragma solidity 0.6.9; -pragma experimental ABIEncoderV2; - -import {ICloneFactory} from "../lib/CloneFactory.sol"; -import {InitializableERC721} from "../external/ERC721/InitializableERC721.sol"; - -/** - * @title DODO ERC721Factory - * @author DODO Breeder - * - * @notice Help user to create erc721 token - */ -contract ERC721Facotry { - // ============ Templates ============ - - address public immutable _CLONE_FACTORY_; - address public immutable _ERC721_TEMPLATE_; - - // ============ Events ============ - - event NewERC721(address erc721, address creator); - - // ============ Registry ============ - mapping(address => address[]) public _USER_REGISTRY_; - - // ============ Functions ============ - - constructor( - address cloneFactory, - address erc721Template - ) public { - _CLONE_FACTORY_ = cloneFactory; - _ERC721_TEMPLATE_ = erc721Template; - } - - function createERC721( - string memory name, - string memory symbol, - string memory baseUrl - ) external returns (address newERC721) { - newERC721 = ICloneFactory(_CLONE_FACTORY_).clone(_ERC721_TEMPLATE_); - InitializableERC721(newERC721).init(name, symbol, baseUrl); - _USER_REGISTRY_[msg.sender].push(newERC721); - emit NewERC721(newERC721, msg.sender); - } - - - function getTokenByUser(address user) - external - view - returns (address[] memory tokens) - { - return _USER_REGISTRY_[user]; - } -} diff --git a/contracts/Factory/NFTTokenFactory.sol b/contracts/Factory/NFTTokenFactory.sol new file mode 100644 index 0000000..aaa7447 --- /dev/null +++ b/contracts/Factory/NFTTokenFactory.sol @@ -0,0 +1,75 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {ICloneFactory} from "../lib/CloneFactory.sol"; +import {InitializableERC721} from "../external/ERC721/InitializableERC721.sol"; +import {InitializableERC1155} from "../external/ERC1155/InitializableERC1155.sol"; + +/** + * @title DODO NFTTokenFactory + * @author DODO Breeder + * + * @notice Help user to create erc721 && erc1155 token + */ +contract NFTTokenFactory { + // ============ Templates ============ + + address public immutable _CLONE_FACTORY_; + address public immutable _ERC721_TEMPLATE_; + address public immutable _ERC1155_TEMPLATE_; + + // ============ Events ============ + + event NewERC721(address erc721, address creator); + event NewERC1155(address erc1155, address creator); + + // ============ Registry ============ + mapping(address => address[]) public _USER_ERC721_REGISTRY_; + mapping(address => address[]) public _USER_ERC1155_REGISTRY_; + + // ============ Functions ============ + + constructor( + address cloneFactory, + address erc721Template, + address erc1155Tempalte + ) public { + _CLONE_FACTORY_ = cloneFactory; + _ERC721_TEMPLATE_ = erc721Template; + _ERC1155_TEMPLATE_ = erc1155Tempalte; + } + + function createERC721( + string memory baseUrl + ) external returns (address newERC721) { + newERC721 = ICloneFactory(_CLONE_FACTORY_).clone(_ERC721_TEMPLATE_); + InitializableERC721(newERC721).init("DODONFT", "DODONFT", baseUrl); + _USER_ERC721_REGISTRY_[msg.sender].push(newERC721); + emit NewERC721(newERC721, msg.sender); + } + + function createERC1155( + uint256 amount, + string memory baseUrl + ) external returns (address newERC1155) { + newERC1155 = ICloneFactory(_CLONE_FACTORY_).clone(_ERC1155_TEMPLATE_); + InitializableERC1155(newERC1155).init(amount, baseUrl); + _USER_ERC1155_REGISTRY_[msg.sender].push(newERC1155); + emit NewERC1155(newERC1155, msg.sender); + } + + + function getERC721TokenByUser(address user) + external + view + returns (address[] memory tokens) + { + return _USER_ERC721_REGISTRY_[user]; + } +} diff --git a/contracts/GeneralizedFragment/impl/Fragment.sol b/contracts/GeneralizedFragment/impl/Fragment.sol index 62bc757..ffab479 100644 --- a/contracts/GeneralizedFragment/impl/Fragment.sol +++ b/contracts/GeneralizedFragment/impl/Fragment.sol @@ -34,6 +34,15 @@ contract Fragment is InitializableERC20 { bool internal _FRAG_INITIALIZED_; + // ============ Event ============ + event RemoveNftToken(address nftContract, uint256 tokenId, uint256 amount); + event AddNftToken(address nftContract, uint256 tokenId, uint256 amount); + event InitInfo(address vault, string name, string baseURI); + event CreateFragment(); + event Buyout(address newOwner); + event Redeem(address sender, uint256 baseAmount, uint256 quoteAmount); + + function init( address dvm, address vaultPreOwner, @@ -99,13 +108,16 @@ contract Fragment is InitializableERC20 { _clearBalance(newVaultOwner); ICollateralVault(_COLLATERAL_VAULT_).directTransferOwnership(newVaultOwner); + + emit Buyout(newVaultOwner); } function redeem(address to, bytes calldata data) external { require(_IS_BUYOUT_, "DODOFragment: NEED_BUYOUT"); - uint256 quoteAmount = DecimalMath.mulFloor(_BUYOUT_PRICE_, balances[msg.sender]); + uint256 baseAmount = balances[msg.sender]; + uint256 quoteAmount = DecimalMath.mulFloor(_BUYOUT_PRICE_, baseAmount); IERC20(_QUOTE_).safeTransfer(to, quoteAmount); _clearBalance(msg.sender); @@ -116,6 +128,8 @@ contract Fragment is InitializableERC20 { data ); } + + emit Redeem(msg.sender, baseAmount, quoteAmount); } function getBuyoutRequirement() external view returns (uint256 requireQuote){ diff --git a/contracts/SmartRoute/proxies/DODONFTProxy.sol b/contracts/SmartRoute/proxies/DODONFTProxy.sol index 1f30a73..e4edf7e 100644 --- a/contracts/SmartRoute/proxies/DODONFTProxy.sol +++ b/contracts/SmartRoute/proxies/DODONFTProxy.sol @@ -50,7 +50,7 @@ contract DODONFTProxy is ReentrancyGuard, InitializableOwnable { event ChangeVaultTemplate(address newVaultTemplate); event ChangeFragTemplate(address newFragTemplate); event ChangeFeeTemplate(address newFeeTemplate); - event CreateNFTCollateralVault(address creator, address vault); + event CreateNFTCollateralVault(address creator, address vault, string name, string baseURI); event CreateFragment(address vault, address fragment, address dvm, address feeDistributor); event Buyout(address from, address fragment, uint256 amount); event Stake(address from, address feeDistributor, uint256 amount); @@ -80,10 +80,10 @@ contract DODONFTProxy is ReentrancyGuard, InitializableOwnable { _NFT_REGISTY_ = nftRegistry; } - function createNFTCollateralVault(string memory name) external returns (address newVault) { + function createNFTCollateralVault(string memory name, string memory baseURI) external returns (address newVault) { newVault = ICloneFactory(_CLONE_FACTORY_).clone(_VAULT_TEMPLATE_); - ICollateralVault(newVault).init(msg.sender, name); - emit CreateNFTCollateralVault(msg.sender, newVault); + ICollateralVault(newVault).init(msg.sender, name, baseURI); + emit CreateNFTCollateralVault(msg.sender, newVault, name, baseURI); } function createFragment( diff --git a/contracts/external/ERC1155/InitializableERC1155.sol b/contracts/external/ERC1155/InitializableERC1155.sol new file mode 100644 index 0000000..dcd54ec --- /dev/null +++ b/contracts/external/ERC1155/InitializableERC1155.sol @@ -0,0 +1,282 @@ +/* + + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 + +*/ + +pragma solidity 0.6.9; + +import {IERC1155} from "../../intf/IERC1155.sol"; +import {IERC1155Receiver} from "../../intf/IERC1155Receiver.sol"; +import {IERC1155MetadataURI} from "../../intf/IERC1155MetadataURI.sol"; +import {IERC165} from "../../intf/IERC165.sol"; +import {Strings} from "../../lib/Strings.sol"; +import {Address} from "../../lib/Address.sol"; + + +contract InitializableERC1155 is IERC165, IERC1155, IERC1155MetadataURI { + using Address for address; + + mapping (uint256 => mapping(address => uint256)) private _balances; + + mapping (address => mapping(address => bool)) private _operatorApprovals; + + string private _uri; + + + function init( + uint256 amount, + string memory baseUrI + ) public { + _setURI(baseUrI); + _mint(msg.sender, 0, amount ,""); + } + + function supportsInterface(bytes4 interfaceId) public view override returns (bool) { + return interfaceId == type(IERC1155).interfaceId + || interfaceId == type(IERC1155MetadataURI).interfaceId; + } + + function uri(uint256) public view virtual override returns (string memory) { + return _uri; + } + + function balanceOf(address account, uint256 id) public view virtual override returns (uint256) { + require(account != address(0), "ERC1155: balance query for the zero address"); + return _balances[id][account]; + } + + function balanceOfBatch( + address[] memory accounts, + uint256[] memory ids + ) + public + view + virtual + override + returns (uint256[] memory) + { + require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch"); + + uint256[] memory batchBalances = new uint256[](accounts.length); + + for (uint256 i = 0; i < accounts.length; ++i) { + batchBalances[i] = balanceOf(accounts[i], ids[i]); + } + + return batchBalances; + } + + function setApprovalForAll(address operator, bool approved) public virtual override { + require(msg.sender != operator, "ERC1155: setting approval status for self"); + + _operatorApprovals[msg.sender][operator] = approved; + emit ApprovalForAll(msg.sender, operator, approved); + } + + function isApprovedForAll(address account, address operator) public view virtual override returns (bool) { + return _operatorApprovals[account][operator]; + } + + function safeTransferFrom( + address from, + address to, + uint256 id, + uint256 amount, + bytes memory data + ) + public + virtual + override + { + require(to != address(0), "ERC1155: transfer to the zero address"); + require( + from == msg.sender || isApprovedForAll(from, msg.sender), + "ERC1155: caller is not owner nor approved" + ); + + address operator = msg.sender; + + _beforeTokenTransfer(operator, from, to, _asSingletonArray(id), _asSingletonArray(amount), data); + + uint256 fromBalance = _balances[id][from]; + require(fromBalance >= amount, "ERC1155: insufficient balance for transfer"); + _balances[id][from] = fromBalance - amount; + _balances[id][to] += amount; + + emit TransferSingle(operator, from, to, id, amount); + + _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data); + } + + function safeBatchTransferFrom( + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) + public + virtual + override + { + require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); + require(to != address(0), "ERC1155: transfer to the zero address"); + require( + from == msg.sender || isApprovedForAll(from, msg.sender), + "ERC1155: transfer caller is not owner nor approved" + ); + + address operator = msg.sender; + + _beforeTokenTransfer(operator, from, to, ids, amounts, data); + + for (uint256 i = 0; i < ids.length; ++i) { + uint256 id = ids[i]; + uint256 amount = amounts[i]; + + uint256 fromBalance = _balances[id][from]; + require(fromBalance >= amount, "ERC1155: insufficient balance for transfer"); + _balances[id][from] = fromBalance - amount; + _balances[id][to] += amount; + } + + emit TransferBatch(operator, from, to, ids, amounts); + + _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data); + } + + function _setURI(string memory newuri) internal virtual { + _uri = newuri; + } + + function _mint(address account, uint256 id, uint256 amount, bytes memory data) internal virtual { + require(account != address(0), "ERC1155: mint to the zero address"); + + address operator = msg.sender; + + _beforeTokenTransfer(operator, address(0), account, _asSingletonArray(id), _asSingletonArray(amount), data); + + _balances[id][account] += amount; + emit TransferSingle(operator, address(0), account, id, amount); + + _doSafeTransferAcceptanceCheck(operator, address(0), account, id, amount, data); + } + + function _mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) internal virtual { + require(to != address(0), "ERC1155: mint to the zero address"); + require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); + + address operator = msg.sender; + + _beforeTokenTransfer(operator, address(0), to, ids, amounts, data); + + for (uint i = 0; i < ids.length; i++) { + _balances[ids[i]][to] += amounts[i]; + } + + emit TransferBatch(operator, address(0), to, ids, amounts); + + _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data); + } + + function _burn(address account, uint256 id, uint256 amount) internal virtual { + require(account != address(0), "ERC1155: burn from the zero address"); + + address operator = msg.sender; + + _beforeTokenTransfer(operator, account, address(0), _asSingletonArray(id), _asSingletonArray(amount), ""); + + uint256 accountBalance = _balances[id][account]; + require(accountBalance >= amount, "ERC1155: burn amount exceeds balance"); + _balances[id][account] = accountBalance - amount; + + emit TransferSingle(operator, account, address(0), id, amount); + } + + function _burnBatch(address account, uint256[] memory ids, uint256[] memory amounts) internal virtual { + require(account != address(0), "ERC1155: burn from the zero address"); + require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); + + address operator = msg.sender; + + _beforeTokenTransfer(operator, account, address(0), ids, amounts, ""); + + for (uint i = 0; i < ids.length; i++) { + uint256 id = ids[i]; + uint256 amount = amounts[i]; + + uint256 accountBalance = _balances[id][account]; + require(accountBalance >= amount, "ERC1155: burn amount exceeds balance"); + _balances[id][account] = accountBalance - amount; + } + + emit TransferBatch(operator, account, address(0), ids, amounts); + } + + function _beforeTokenTransfer( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) + internal + virtual + { } + + function _doSafeTransferAcceptanceCheck( + address operator, + address from, + address to, + uint256 id, + uint256 amount, + bytes memory data + ) + private + { + if (to.isContract()) { + try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) { + if (response != IERC1155Receiver(to).onERC1155Received.selector) { + revert("ERC1155: ERC1155Receiver rejected tokens"); + } + } catch Error(string memory reason) { + revert(reason); + } catch { + revert("ERC1155: transfer to non ERC1155Receiver implementer"); + } + } + } + + function _doSafeBatchTransferAcceptanceCheck( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) + private + { + if (to.isContract()) { + try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (bytes4 response) { + if (response != IERC1155Receiver(to).onERC1155BatchReceived.selector) { + revert("ERC1155: ERC1155Receiver rejected tokens"); + } + } catch Error(string memory reason) { + revert(reason); + } catch { + revert("ERC1155: transfer to non ERC1155Receiver implementer"); + } + } + } + + function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) { + uint256[] memory array = new uint256[](1); + array[0] = element; + + return array; + } +} diff --git a/contracts/intf/IERC1155MetadataURI.sol b/contracts/intf/IERC1155MetadataURI.sol new file mode 100644 index 0000000..0d8fb03 --- /dev/null +++ b/contracts/intf/IERC1155MetadataURI.sol @@ -0,0 +1,22 @@ +// This is a file copied from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol +// SPDX-License-Identifier: MIT + +pragma solidity 0.6.9; + +import "./IERC1155.sol"; + +/** + * @dev Interface of the optional ERC1155MetadataExtension interface, as defined + * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP]. + * + * _Available since v3.1._ + */ +interface IERC1155MetadataURI is IERC1155 { + /** + * @dev Returns the URI for token type `id`. + * + * If the `\{id\}` substring is present in the URI, it must be replaced by + * clients with the actual token type ID. + */ + function uri(uint256 id) external view returns (string memory); +} \ No newline at end of file