solidity基础语法与简单案例20221201

1、回退函数

        fallback():当调用的函数不存在或者直接向合约发送主币的时候调用fallback函数。

        receive():不能接受数据,仅向合约发送主币时触发

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

contract Fallback {
    event Log(string func,address sender , uint value ,bytes data);

    fallback() external payable {
        emit Log("fallback", msg.sender, msg.value,msg.data);
    }

    //receive 不接受数据
    receive() external payable  {
        emit Log("receive", msg.sender, msg.value, "");
    }
}

2、发送ETH

        可以通过send、transfer和call进行主笔发送。

        send返回true和false来确定是否发送失败;

        transfer返回revert来确定是否发送失败;

        call返回ture和false,如果接收地址有信息时可以返回信息data

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

contract SendETH {
    constructor() payable{}

    receive() external payable {}

    function sendViaTransfer(address payable _to) external payable {
        _to.transfer(123);
    }

    function sendViaSend(address payable _to) external payable{
        bool sent = _to.send(123);
        require(sent,"send failde");
    }

    //发送所有的gas
    function sendViaCall(address payable _to) external payable{
        (bool success,) = _to.call{value: 123}("");
        require(success, "send failed")
    }
}

3、小案例:建立简单钱包合约

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

contract SimpleWallet{
    address payable public owner;

    constructor(){
        owner = payable(msg.sender);
    }

    receive() external payable{}

    function withdraw(uint amount) public{
        require(msg.sender == owner);
        owner.transfer(amount);
    }

    function getBalance() public view returns (uint){
        return address(this).balance;
    }
}

4、调用其他合约

        输入其他合约的地址,之后可以直接把其他合约当作类型进行使用。还可以把类型当作直接输入的变量的类型进行传入。

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

contract CallTestContract {
    //为调用函数传参
    function setX(address _test, uint _x) external {
        TestContract(_test).setX(_x);
    }
    //获取从方法得到的参数
    function getX(address _test) external view returns(uint x){
        return x = TestContract(_test).getX();
    }
    //传参并发送主币
    function setXandReceiveEther(address _test, uint _x) external payable {
        TestContract(_test).setXandReceiveEther(_x);
    }
    //获取两个参数
    function getXandValue(address _test) external returns(uint x,uint value) {
        (x,value) = TestContract(_test).getXandValue();
    }
}

contract TestContract {
    uint public x;
    uint public value = 123;

    function setX(uint _x) external {
        x = _x;
    }  

    function getX() external view returns (uint) {
        return x;
    }

    function setXandReceiveEther(uint _x) external payable {
        x = _x;
        value = msg.value;
    }

    function getXandValue() external view returns (uint,uint) {
        return(x,value);
    }
}

5、接口合约

不知道另一个合约的源代码或者代码量特别大时,可以使用接口合约。

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

contract Counter {
    uint public count;
    function inc() external {
        count += 1;
    }
    function dec() external {
        count -= 1;
    }
}

//在接口合约中调用了两个合约的函数
interface ICounter {
     function count() external view returns (uint);
     function inc() external;
}

contract CallInterface {
    uint public count;

    function examples(address _counter) external{
        ICounter(_counter).inc();
        count = ICounter(_counter).count();
    }
}

6、低级调用 Call

使用Call直接根据合约地址调用合约功能。

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

contract TestCall{
    string public message;
    uint public x;

    event Log(string message);

    fallback() external payable{
        emit Log("fallback was called");
    }

    function foo(string memory _message, uint _x) external payable returns (bool,uint){
        message = _message;
        x = _x;
        return(true,999);
    }
}

contract Call{
    bytes public data;

    function callFoo(address _test) external {
        //使用call调用目标地址的函数,返回是否调用成功,以及一个返回值,该返回值转载了所有返回的数据
        //可以携带一定数量的主币和gas进行调用
        (bool success, bytes memory data) = _test.call{value: 111, gas:5000}(abi.encodeWithSignature(
            "foo(string,uint256)","call foo",123
        ));
        require(success,"call failed");
    } 

    function callDoesNotExit(address _test) external{
        (bool success,) = _test.call(abi.encodeWithSignature("DONTEXIST(string,uint)"));
        require(success,"call failed");
    }
}

7、委托调用:

        用于观测其他合约的交互。

        例如:A向B发送100wei,B委托调用C,站在C的视角能够看到A向B发送100wei,但C自身的状态变量不发生改变。

        委托调用可以用来实现合约升级。

        委托调用执行函数后的值在委托调用合约中修改。

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

contract TestDelegateCall {
    uint public num;
    address public sender;
    uint public value;

    function setVars(uint _num) external payable {
        num = _num;
        sender = msg.sender;
        value = msg.value;
    }
}

contract DelegateCall {
    uint public num;
    address public sender;
    uint public value;

    function setVars(address _test,uint _num) external payable{
        //使用签名进行编码
        // _test.delegatecall(
        //     abi.encodeWithSignature("setVars(uint256)",_num)
        // );
        //使用selector进行编码
        (bool success,bytes memory data) = _test.delegatecall(
            abi.encodeWithSelector(TestDelegateCall.setVars.selector, _num)
        );
        require(success,"delegatecall failed");

    }
}

8、工厂合约

用于生成新的合约

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

contract Account {
    address public bank;
    address public owner;

    constructor(address _owner) payable{
        bank = msg.sender;
        owner = _owner;
    }
}

contract AccountFactory {
    Account[] public accounts;
    address public owner;

    constructor() payable{
        owner = msg.sender;
    }

    function createAccount(address _owner,uint amount) external {
        //account 变量记录了新建立的账户的地址,通过增加{value}来向新创建的合约中发送主币。
        //在构建包含主币的合约前应当向账户工厂发送一定数量的主币
        Account account = new Account{value:amount} (_owner);
        //构建accounts以记录所有由该合约生成的合约
        accounts.push(account);
    }
    function Val() external view returns(uint val){
        return address(this).balance;
    }
}

9、库合约

将一些常用的算法抽象出来,形成数据库,以后可以直接调用,从而避免代码的重复使用。

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

library Math{
    function max(uint x,uint y) internal pure returns (uint){
        return x>=y ? x:y;
    }
}

contract Test{
    function testMax(uint x,uint y) external pure returns (uint){
        return Math.max(x,y);
    }
}

library ArrayLib {
    function find(uint[] storage arr,uint x) internal view returns (uint){
        for (uint i =0;i<arr.length;i++){
            if(arr[i] == x){
                return x;
            }
        }
        revert("not found");
    }
}

contract TestArray{
    using ArrayLib for uint[];
    uint[] public arr = [3,2,1];

    function testFind() external view returns (uint i){
        // return ArrayLib.find(arr,2);
        return arr.find(2);
    }
}

10、哈希算法

通常用于签名运算和获取特定ID

在对数据进行打包时,如果使用api.encodePacked方法,可能会造成哈希碰撞(加密内容不相同但哈希运算结果相同)的问题。

两种打包方法:

abi.encodePacked()

abi.encode()

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

contract HashFunc{
    function hash1(string memory text ,uint num ,address addr) external pure returns(bytes32){
        return keccak256(abi.encodePacked(text,num,addr));
    }
    function hash2(string memory text ,uint num ,address addr) external pure returns(bytes32){
        return keccak256(abi.encode(text,num,addr));
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值