区块链——solidity语法

1、SimpleStorage|一些基础语法

// SPDX-License-Identifier: MIT
pragma solidity 0.8.8; // 定义使用的solidity版本

// EVM:Ethereum Virtual Machine:向以太坊区块链上部署的一个标准
contract SimpleStorage { // 定义一个合约,类似于Java中的class关键字
    // --------------------------------基本数据机构、函数等--------------------------------
    // Solidity中的四种基础数据类型:bool、uint、int、address、bytes:另一种底层类型
    bool hasFavoriteNumber = false;
    // 表示一个256位的无符号整数,不带修饰符时,默认是private,
    //public:合约内、外部都可见,会给该变量添加一个getter函数
    // private:合约内部可见,合约外部不可见
    // external:合约外部可见
    // internal:表示该合约以及继承他的合约可见
    uint256 public favoriteNumber = 5;
    string favoriteInText = "Five";
    int256 favoriteInt = 5;
    address myAddress = 0x25A338f01d0Caf3953C9cBa5779E98B39dCf9630;
    bytes32 favoriteBytes = "cat"; // string 可以自动转化为bytes

    // 定义一个方法,表示这个方法可以被继承
    function store(uint256 _favoritNumber) public virtual {
        favoriteNumber = _favoritNumber;
        retrieve();
    }

    // view:意味着只会读取这个合约的状态,不会修改状态
    // pure:意味着既不能修改也不能读取合约的状态
    function retrieve() public view returns(uint256) {
        return favoriteNumber;
    }

    function add() public pure returns(uint256) {
        return (1 + 1);
    }

    // --------------------------------结构体、数组等--------------------------------
    struct People {
        uint8 age;
        string name;
        uint256 favoriteNumber;
    }
    People public zhangsan = People({age: 25, name: "zhangsan", favoriteNumber: 255});

    // 数组,这里我们定义的是一个动态数组,如果[3]表示最多存放3个对象
    People[] public personList;
    
    
    /*
    * storage: 用于长期存储合约的状态变量,数据永久保存在区块链上,读取和写入都需要消耗gas。
    * memory: 用于函数执行期间的临时数据存储,数据在函数调用结束后被自动清理,使用成本低。
    * calldata: 用于传递函数调用参数,数据只读且仅在函数调用期间存在,使用它可以节省gas成本。
    */
    // 定义一个函数,向personList中添加元素
    function addPerson(uint8 _age, string memory _name, uint256 _favoriteNumber) public {
        personList.push(People(_age, _name, _favoriteNumber));
    }

    // --------------------------------Mappings等--------------------------------
    mapping(string => People) public nameToPeopleMap;

    // 定义一个方法,向map中存入数据
    function addToMap(uint8 _age, string memory _name, uint256 _favoriteNumber) public returns(People memory) {
        People memory people = People(_age, _name, _favoriteNumber);
        nameToPeopleMap[_name] = people;
        return nameToPeopleMap[_name];
    }
}

2、StorageFactory|使用合约部署合约

// SPDX-License-Identifier: MIT 
pragma solidity ^0.8.7;
// 引入我们自己写的第一个简单合约
import "./SimpleStorage.sol"; 
// 定义一个合约生产工厂
contract StorageFactory {
    
    SimpleStorage[] public simpleStorageArray;
    
    function createSimpleStorageContract() public {
        // new关键字的作用
        // 创建新的智能合约实例
        SimpleStorage simpleStorage = new SimpleStorage();
        simpleStorageArray.push(simpleStorage);
    }
    
    function sfStore(uint256 _simpleStorageIndex, uint256 _simpleStorageNumber) public {
        // Address 
        // ABI 
        // SimpleStorage(address(simpleStorageArray[_simpleStorageIndex])).store(_simpleStorageNumber);
        simpleStorageArray[_simpleStorageIndex].store(_simpleStorageNumber);
    }
    
    function sfGet(uint256 _simpleStorageIndex) public view returns (uint256) {
        // return SimpleStorage(address(simpleStorageArray[_simpleStorageIndex])).retrieve();
        return simpleStorageArray[_simpleStorageIndex].retrieve();
    }
}

3、ExtraStorage|合约的继承

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

// 合约的继承,先导入需要继承的合约
import "./SimpleStorage.sol";

contract ExtraStorage is SimpleStorage {

    function store(uint256 _favoriteNumber) public override {
        favoriteNumber = _favoriteNumber + 5;
    }
}

4、PriceConverter|引入其他库以及自定义库

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

// 通过npm从github中获取喂价服务合约
import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol";

library PriceConverter {

    // 该方法获取ETH/USD汇率
    function getPrice() public view returns(uint256) {
        AggregatorV3Interface priceFeed = AggregatorV3Interface(0x694AA1769357215DE4FAC081bf1f309aDC325306);
        // 对返回的元组进行解构
        (
            /* uint80 roundID */,
            int price,
            /*uint startedAt*/,
            /*uint timeStamp*/,
            /*uint80 answeredInRound*/
        ) = priceFeed.latestRoundData();
        // 1e18是ETH的最小单位,1e17是1e18的1/10
        require(price >= 1e17, "price too low!");
        return uint256(price * 1e10);
    }

    // 传入eth数量,获取对应的USDT数量
    function getConversionRate(uint256 _ethAmount) internal view returns(uint256) {
        // 获取1eth兑换为usdt的价格
        uint256 usdtPrice = getPrice();
        return (usdtPrice * _ethAmount) / 1e18;
    }

}

5、FundMe|给合约转账以及从合约取现的功能

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

import "./PriceConverter.sol";

// 节约gas的一些小技巧
// 1.尽量使用constant、immutable来修饰常量和不可修改的量,
// 2.定义自定义错误,来代替require,更加节约gas
error NotOwnerError();
error CallFailed();

contract FundMe {
    // 这样定义后,PriceConverter库就可以使用uint256来调用了
    using PriceConverter for uint256;

    uint256 public number;

    // 定义一个最小发送的usdt数量,假设是1个
    // constant:定义一个常量
    uint256 internal constant MINIMUM_USDT = 1 * 1e18;

    // 定义一个数组,记录所有发送代币的地址
    address[] public funders;

    // 定义一个mapping记录每个地址发送的代币数量
    mapping(address => uint256) public addressToAmountFouded;

    // 定义一个owner,表示合约的拥有者
    // 因为这个我们只需要在constructor中设置一次,所以我们可以定义为不可变的
    // immutable:只能设置一次
    address public immutable i_owner;

    // 创建一个constructor,在创建合约的时候自动执行这个方法,并且只能执行一次
    constructor() {
        // 这里的owner就是合约创建者,也就是msg.sender
        i_owner = msg.sender;
    }

    // 这个方法用来让大家捐款
    function fund() public payable {
        // 调用这个方法,至少需要向合约地址发送价值50个usdt的eth,否则报错dont send enough
        // 什么是revert,如果require这个条件没达到,number=5这个操作也会被撤销
        number = 5;
        require(
            msg.value.getConversionRate() >= MINIMUM_USDT,
            "dont send enough!"
        );
        // 记录发送代币的地址
        funders.push(msg.sender);
        // 记录发送代币的数量
        addressToAmountFouded[msg.sender] += msg.value;
    }

    // 获取费率
    function getEthToUsdtPrice() public view {
        PriceConverter.getPrice();
    }

    // 这个方法用来将合约中的代币转到创建合约的账户,这里用到了修饰器
    function withdraw() public onlyOwner {
        // 首先使用for循环将addressToAmountFouded中的数据清零
        for (uint256 i = 0; i < funders.length; i++) {
            address funder = funders[i];
            addressToAmountFouded[funder] = 0;
        }
        // 将数组置为空
        funders = new address[](0);
        // 这里就是区块链上真实的转账,有以下三种方式
        // 1、transfer:只有payable address才能进行转账操作
        // payable(msg.sender).transfer(address(this).balance);
        // 2、send:与上面的类似
        // bool sendSuccess = payable(msg.sender).send(address(this).balance);
        // require(sendSuccess, "send error");
        // 3、call,call可以调用任何函数,这里我们以转账为例,如果函数有返回值就存储到第二个参数bytes dataReturned中
        (bool callSuccess, ) = payable(msg.sender).call{
            value: address(this).balance
        }("");
        // require(callSuccess, "call error");
        if (!callSuccess) {
            revert CallFailed();
        }
    }

    // 定义修饰器,修饰器在函数执行前调用这里面的函数
    modifier onlyOwner() {
        // 这个修饰器表示只有合约的拥有者才能调用
        // require(i_owner == msg.sender, "you isn't owner");
        if (i_owner != msg.sender) {
            revert NotOwnerError();
        }
        // _表示余下的代码,也就是被我们onlyOwner修饰的函数
        _;
    }

    // receive函数是solidity中自带的函数,他的触发条件是msg.data中没有数据,并且定义了receive
    // 为了防止有人不调用fund,就向我们的合约中转账,无法记录转账人信息的问题,我们可以用receive记录
    receive() external payable {
        fund();
    }

    // fallback函数:msg.data中有数据但是没找到具体的函数时就触发、或者当msg.data没有数据且没有定义receive时触发
    fallback() external payable {
        fund();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值