Contract-Development
如何在 NFT 市場中整合 2.5% 的銷售費用
我目前正在建立一個 NFT 市場,我已經完成了所有主要功能,即上市、銷售、購買等。但問題是,在之前編寫程式碼時,我使用了 0.1 乙太幣的固定上市費用,現在我想要對每筆銷售收取 2.5% 的費用
這是我的可靠程式碼
function createMarketSale(address nftContract, uint256 itemId, uint256 commission) public payable nonReentrant { uint256 price = idToMarketItem[itemId].price; uint256 tokenId = idToMarketItem[itemId].tokenId; require( msg.value == price, "Please submit the asking price in order to complete the purchase" ); idToMarketItem[itemId].seller.transfer(msg.value); IERC721(nftContract).transferFrom(address(this), msg.sender, tokenId); idToMarketItem[itemId].owner = payable(msg.sender); idToMarketItem[itemId].sold = true; _itemsSold.increment(); payable(owner).transfer(commission); }
這是我的 web3 前端如何與合約互動
async function buyNFT() { const web3Modal = new Web3Modal(); const connection = await web3Modal.connect(); const provider = new ethers.providers.Web3Provider(connection); const signer = provider.getSigner(); const contract = new ethers.Contract(nftmarketaddress, Market.abi, signer); const price = ethers.utils.parseUnits(nft.price.toString(), "ether"); const fee = +((2.5 / 100) * nft.price); let commission = fee.toString(); let transaction = await contract.createMarketSale(nftaddress, nft.itemId, commission, { value: price, }); await transaction.wait(); window.location.replace("/profile"); }
但我不斷收到錯誤:事務已恢復:函式呼叫在到達此行時無法執行:
payable(owner).transfer(commission);
您的項目存在一個主要問題 - 您應該將費用邏輯移到智能合約中並將其從前端部分中刪除。在目前的邏輯中,惡意使用者可以跳過使用 dApp 並直接與智能合約互動,通過這樣做,他們可以將費用設置為他們想要的任何東西。我將使用
SafeMath
OpenZeppelin 提供的契約為您建構一個範例費用方法,其中費用將直接從作為值傳遞給方法的內容中提取(來自msg.value
):// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.0 <0.9.0; library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // 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 (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { return a + b; } /** * @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 a - b; } /** * @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) { return a * b; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting 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 a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { unchecked { require(b <= a, errorMessage); return a - b; } } /** * @dev Returns the integer division of two unsigned integers, reverting 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) { unchecked { require(b > 0, errorMessage); return a / b; } } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * 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) { unchecked { require(b > 0, errorMessage); return a % b; } } } contract TestContract { using SafeMath for uint256; function calculateFee(uint256 _num) public view returns (uint256){ uint256 onePercentofTokens = _num.mul(100).div(100 * 10 ** uint256(2)); uint256 twoPercentOfTokens = onePercentofTokens.mul(2); uint256 halfPercentOfTokens = onePercentofTokens.div(2); return twoPercentOfTokens + halfPercentOfTokens; } function createMarketSale() public payable { // logic, logic, logic uint256 extractFee = this.calculateFee(msg.value); // logic, logic, logic } }
不幸的是,在使用浮點數進行計算時,solidity 非常原始,因此您需要像我在 method 中所做的那樣的解決方法
calculateFee
。