Contract-Development

如何在 NFT 市場中整合 2.5% 的銷售費用

  • December 4, 2021

我目前正在建立一個 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 並直接與智能合約互動,通過這樣做,他們可以將費用設置為他們想要的任何東西。我將使用SafeMathOpenZeppelin 提供的契約為您建構一個範例費用方法,其中費用將直接從作為值傳遞給方法的內容中提取(來自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

引用自:https://ethereum.stackexchange.com/questions/114948