# pxn合约的简单分析

By [ Trembling bear](https://paragraph.com/@trembling-bear) · 2022-05-08

---

本人纯小白，第一次尝试分析合约代码，仅供学习参考！

**合约地址：**

[https://rinkeby.etherscan.io/address/0x3201fe090e70bd464bc93469545be5278595d1f5#code](https://rinkeby.etherscan.io/address/0x3201fe090e70bd464bc93469545be5278595d1f5#code)

**合约类型：**

ERC721A

**审计分析**：

**Reentrancy**: safemint 总是发生在最后一步 √

**Ownership take over:** 合约继承了Ownerable

**Timestamp dependency:**

    //Require DA started
            require(
                block.timestamp >= DA_STARTING_TIMESTAMP,
                "DA has not started!"
            );
            require(block.timestamp <= WL_STARTING_TIMESTAMP, "DA is finished");
    

**Contract interact:**

callerIsUser()这个函数要求调用者不能是其他合约

     modifier callerIsUser() {
            require(tx.origin == msg.sender, "The caller is another contract");
            _;
        }
    

**业务逻辑分析：**

（1）白单Mint

    function mintWL(bytes calldata signature) public payable callerIsUser {
            require(DA_FINAL_PRICE > 0, "Dutch action must be over!");
    
            require(
                !userToHasMintedPublicWL[msg.sender],
                "Can only mint once during public WL!"
            );
            require(
                block.timestamp >= WL_STARTING_TIMESTAMP,
                "WL has not started yet!"
            );
            require(
                block.timestamp <= WL_STARTING_TIMESTAMP + 86400,
                "WL has finished!"
            );
            //Require max supply just in case.
            require(
                PUBLIC_WL_MINTED + 1 <= WL_QUANTITY,
                "Max supply of 6000!"
            );
    
            require(
                wlSigner ==
                    keccak256(
                        abi.encodePacked(
                            "\x19Ethereum Signed Message:\n32",
                            bytes32(uint256(uint160(msg.sender)))
                        )
                    ).recover(signature),
                "Signer address mismatch."
            );
    
            require(msg.value >= WLprice, "Must send enough eth for WL Mint");
    
            userToHasMintedPublicWL[msg.sender] = true;
            PUBLIC_WL_MINTED++;
    
            //Mint them
            _safeMint(msg.sender, 1);
        
    

必须在荷兰拍以后进行；

!userToHasMintedPublicWL\[msg.sender\] 是否已经mint；

到时间才能开启mint；

block.timestamp <= WL\_STARTING\_TIMESTAMP + 86400 mint时间；

上限为6000个；

看起来没有问题。

（2）荷兰拍函数

    function mintDutchAuction(uint8 quantity) public payable callerIsUser {
            require(
                DA_ACTIVE == true,
                "DA isnt active"
            );
            
            //Require DA started
            require(
                block.timestamp >= DA_STARTING_TIMESTAMP,
                "DA has not started!"
            );
            require(block.timestamp <= WL_STARTING_TIMESTAMP, "DA is finished");
            //Require max 2 per tx
            require(quantity > 0 && quantity < 3, "Can only mint max 2 NFTs!");
    
            //Require max 2 per wallet
            require(balanceOf(msg.sender) + quantity < 3, "Can only mint max 2 NFTs!");
    
            uint256 _currentPrice = currentPrice();
    
            //Require enough ETH
            require(
                msg.value >= quantity * _currentPrice,
                "Did not send enough eth."
            );
    
            //Max supply
            require(
                totalSupply() + quantity <= DA_QUANTITY,
                "Max supply for DA reached!"
            );
    
            //This calculates the final price
            if (totalSupply() + quantity == DA_QUANTITY) {
                DA_FINAL_PRICE = _currentPrice;
                if (((DA_FINAL_PRICE / 100) * 50) < WLprice) {
                    WLprice = ((DA_FINAL_PRICE / 100) * 50);
                }
            }
    
            userToTokenBatchPriceData[msg.sender].push(
                TokenBatchPriceData(uint128(msg.value), quantity)
            );
    
            //Mint the quantity
            _safeMint(msg.sender, quantity);
        }
    

需要在规定时间mint,限制了最多两个钱包，每个两次mint。totalSupply() + quantity <= DA\_QUANTITY 不超过最大的荷兰拍总数。当达到最大的荷兰拍总数时，计算此时的的价格，如果此时的价格小于白名单价格，此时价格+0.5是白名单的价格。

if (((DA\_FINAL\_PRICE / 100) \* 50) < WLprice) { WLprice = ((DA\_FINAL\_PRICE / 100) \* 50); }

（3）项目方保留

     function devMint() external onlyOwner {
            require(
                block.timestamp >= WL_STARTING_TIMESTAMP + 86400,
                "WL hasnt finished!"
            );
            uint256 leftOver = 10000 - totalSupply();
            _safeMint(DEV_FUND, leftOver);
        }
    

（4）

    function teamMint(uint8 quantity) public payable {
            require(
                block.timestamp >= WL_STARTING_TIMESTAMP,
                "WL has finished!"
            );
            require(_teamList[msg.sender] >= quantity, "already claimed");
            require(
                msg.value >= quantity * WLprice,
                "Must send enough eth for WL Mint"
            );
            require(totalSupply() + quantity <= 10000, "exceeds supply");
            _teamList[msg.sender] = _teamList[msg.sender] - quantity;
            _safeMint(msg.sender, quantity);
        }
    

数量上限是10000个，需要eth余额足够。

---

*Originally published on [ Trembling bear](https://paragraph.com/@trembling-bear/pxn)*
