Solidity basic grammar and simple cases 20221203

1. Function signature

Function: Understand how the virtual machine finds a function.

The data for calling a function consists of two parts, the first part: function signature; the second part: parameters.

// SPDX-License-Identifier:MIT
pragma solidity ^0.8.7;

contract functionSelector{
    function getSelector(string calldata _func) external pure returns (bytes4){
        return bytes4(keccak256(bytes(_func)));
    }
}

contract Receiver{
    event Log(bytes data);

    function transfer(address _to, uint _amount) external{
        //获取调用时的发送的数据
        emit Log(msg.data);
    }
    //0xa9059cbb 函数名称
    //00000000000000000000000078731d3ca6b7e34ac0f824c42a7cc18a495cabab 地址
    //0000000000000000000000000000000000000000000000000000000000000001 参数
}

(1) After calling the transfer function, the data is returned, including the function name, address and parameters. The parameters used here are 1.

(2) How did the function name come about?

        0xa9059cbb generation method: return bytes4(keccak256(bytes(_func)))

        Here _func is "transfer(address,uint256)"

2. Dutch auction

        There is a countdown, and as time goes by, the auction price will gradually decrease. Until someone raises a sign.

// SPDX-License-Identifier:MIT
pragma solidity ^0.8.7;

interface IERC721{
    function transferFrom(
        address _from,
        address _to,
        uint _nftID
    )external;
}

contract DutchAuction {
    uint private constant DURATION = 7 days;

    IERC721 public immutable nft;
    uint public immutable nftID;

    address payable public immutable seller; //销售者
    uint public immutable startingPrice; //起拍价
    uint public immutable startAt;//起拍时间
    uint public immutable expiresAt;//流拍时间
    uint public immutable discountRate; //折扣率,每秒都在起拍价格上减去一定数量

    constructor(
        uint _startingPrice,
        uint _discountRate,
        address _nft,
        uint _nftID
    ){
        seller = payable(msg.sender); //销售成功时将主币发送给出售者
        startingPrice = _startingPrice;
        discountRate = _discountRate;
        startAt = block.timestamp;
        expiresAt = block.timestamp + DURATION;

        //要求拍卖结束后价格不为负,折扣率*拍卖时间>起拍价格
        require(
            _startingPrice >= _discountRate * DURATION,"discountRate*time should bigger then startingPrice"
        );

        nft = IERC721(_nft);
        nftID = _nftID;
    }

    //获取拍卖价格
    function getPrice() public view returns (uint){
        uint timeElapsed = block.timestamp - startAt;
        uint discount = discountRate * timeElapsed;
        return startingPrice - discount;
    }

    //购买,通过传入主币进行购买
    function buy() external payable{
        //购买时间应当在拍卖期内
        require(block.timestamp < expiresAt,"auction expired");

        uint price = getPrice();
        //要求支付的主币数量大于等于拍卖价格
        require(msg.value >= price,"ETH < price");

        //将NFT从拍卖者账户发送到购买者的账户中
        nft.transferFrom(seller, msg.sender, nftID);

        //为购买者找零
        uint refund = msg.value - price;
        if(refund > 0){
            payable(msg.sender).transfer(refund);
        }
        //将主币发送到出售者账户中、销毁拍卖合约
        selfdestruct(seller);
    }
    
}

(1) Deploy ERC721

(2) Minting NFTs

(3) Deploy the auction contract

(4) Approval of NFT transactions

(5) Purchase NFT

(6) Check NFT owner

3. Crowdfunding

Including: setting crowdfunding target time and target amount. Investors can fund crowdfunding projects and investors can withdraw tokens. Crowdfunding project creators can get crowdfunding tokens

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.6;

import "./ERC20.sol";

contract CrowdFund{

    struct Campaign{
        address creator;
        uint goal;
        uint pledge;
        //时间戳采用uint32格式
        uint32 startAt;
        uint32 endAt;

        //筹款是否被创建者领取过
        bool claimed;
    }
    IERC20 public immutable token;
    uint public count;
    mapping(uint => Campaign) public campaigns;
    mapping(uint => mapping(address => uint)) public pledgedAmount;

    constructor(address _token){
        token = IERC20(_token);
    }

    event launch(uint count,address indexed addr,uint goal,uint32 startAt,uint32 endAt);
    event Cancel(uint id);
    event Pledge(uint id,address indexed addr,uint amount);
    event unPledge(uint id,address indexed addr,uint amount);
    event Claimed(uint id);
    event reFund(uint id,address indexed addr);

    function Launch(
        uint _goal,
        uint32 _startAt,
        uint32 _endAt
    )external{
        require(_startAt >= block.timestamp,"start at < now");
        require(_endAt >= _startAt,"end at<start at");
        //方法:days能够转换为秒数,block.timestamp是指合约建立时的时间戳
        require(_endAt<=block.timestamp + 90 days,"end at>max duration");
    
        count += 1;

        //构建一个众筹结构体,并添加至所有结构体中
        campaigns[count] = Campaign({
            creator:msg.sender,
            goal: _goal,
            pledge:0,
            startAt: _startAt,
            endAt: _endAt,
            claimed:false
        });

        emit launch(count,msg.sender,_goal,_startAt,_endAt);
    }
    //取消众筹, 如果众筹已经开始,那么该众筹无法取消
    function cancel(uint _id) external {
        Campaign storage campaign = campaigns[_id];
        require(msg.sender == campaign.creator);
        require(block.timestamp < campaign.startAt);

        delete campaigns[_id];
        emit Cancel(_id);
    }

    //筹集资金
    function pledge(uint _id,uint _amount) external {
        Campaign storage campaign = campaigns[_id];
        require(block.timestamp >= campaign.startAt,"not started");
        require(block.timestamp <= campaign.endAt,"has ended");

        campaign.pledge += _amount;
        pledgedAmount[_id][msg.sender] += _amount;
        token.transferFrom(msg.sender,address(this), _amount);

        emit Pledge(_id, msg.sender, _amount);
    }

    //撤回资金:众筹结束之前可以反悔
    function unpledge(uint _id,uint _amount) external{
        Campaign storage campaign = campaigns[_id];
        require(block.timestamp <= campaign.endAt,"has ended");
        require(_amount<=pledgedAmount[_id][msg.sender]);

        campaign.pledge -= _amount;
        pledgedAmount[_id][msg.sender] -= _amount;
        token.transfer(msg.sender, _amount);

        emit unPledge(_id,msg.sender,_amount);
    }
    //达到目标领取资金
    function claim(uint _id) external{
        Campaign storage campaign = campaigns[_id];
        require(msg.sender == campaign.creator,"not creater");
        require(block.timestamp > campaign.endAt,"not ended");
        require(campaign.pledge >= campaign.goal,"not arrive goal");
        require(!campaign.claimed,"claimed");

        campaign.claimed = true;
        token.transfer(msg.sender,campaign.pledge);

        emit Claimed(_id);
    }
    //没达到目标,付款用户撤回资金
    function refund(uint _id) external{
        Campaign storage campaign = campaigns[_id];
        require(block.timestamp > campaign.endAt,"not ended");
        require(campaign.pledge < campaign.goal,"pledged < goal");
    
        uint bal = pledgedAmount[_id][msg.sender];
        pledgedAmount[_id][msg.sender] = 0;
        token.transfer(msg.sender,bal);
        
        emit reFund(_id,msg.sender);
    }


}

4. create2 method: used to predict the address of the new contract

It is used to generate new contracts and predict the addresses of new contracts, which can be used to verify contracts.

The address of the new contract is calculated with the address of the factory contract + salt, so the address of the new contract can be predicted.

You can add {salt} after the new contract, and the salt is used to determine the variable for the contract deployment address.

The address of the newly generated contract is generated by four parts:

        Fixed value: 0xff

        Parent contract address: address(this)

        Parameter: salt

        Contract machine code: code

When the parent contract address, parameters, and contract machine code remain unchanged, the generated child contract address remains unchanged.

The contract machine code is generated in the following ways:

       Use type(DeployWithCreate2).creationCode to generate the machine code of the contract code.

       Use abi.encode(_owner) to package an address.

        Use abi.encodePacked() to package the contract machine code and the packaged address to generate code.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.6;

contract DeployWithCreate2{
    address public owner;

    constructor(address _owner){
        owner = _owner;
    }
}

contract Create2Factory{
    event Deploy(address addr);

    //使用DeployWithCreate2构建合约
    function deploy(uint _salt) external {
        //new contract后可加{salt},salt用于为合约部署地址确定变量
        DeployWithCreate2 _contract = new DeployWithCreate2{
            salt: bytes32(_salt)
        }(msg.sender);
        emit Deploy(address(_contract));
    }

    function getAddress(bytes memory bytecode,uint _salt)
        public
        view
        returns(address)
    {
        //keccak256用于将打包数据生成为哈希值
        bytes32 hash = keccak256(
            //abi.encodePacked用于将一定数据打包
            abi.encodePacked(
                //固定字符串、本合约的地址、salt、要合约的机器码打包后进行哈希值运算得到的结果就是部署合约的地址
                bytes1(0xff),address(this),_salt,keccak256(bytecode)
            )
        );
        return address(uint160(uint(hash)));
    }

    function getBytecode(address _owner) public pure returns (bytes memory){
        //type(Contract).creationCode用于生成合约代码的机器码
        bytes memory bytecode = type(DeployWithCreate2).creationCode;
        //合约代码的机器码和合约的发布者地址打包后返回的机器码为用于生成合约地址的机器码
        return abi.encodePacked(bytecode,abi.encode(_owner));
    }
}

Guess you like

Origin blog.csdn.net/H_Roger/article/details/128158360