欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

[区块链] 记坑: 以太坊智能合约开发, transfer

程序员文章站 2022-06-19 16:47:19
...

前景提要

以太坊地址类型

所有的账户地址 皆是 address 类型, address 类型比较特殊, 本质是一个 uint 类型
但又可以调用 .balance .transfer .send 等, 具体可见官方文档描述

合约相关的几个概念

  1. 合约地址 : 在合约中 this 代表合约地址, 合约地址可存储以太币, 他人发起向合约转入以太币(通过 value), 默认存入 this
  2. 合约发起者: 在合约中 msg.sender 代表合约发起者, 用户通过 dApp 发起一个合约, msg.sender 即是用户使用钱包浏览器内所选地址, 即用户钱包地址

合约交易 transfer

  • 用户向合约转钱, 发起合约时传入 value 即可
  • 合约向用户转钱 address(user).transfer(address(this).balance), 当然不必是合约的所有余额, 只要不超过余额, 都可以转出去
  • 用户通过合约向另一个用户转钱: 买家–>卖家 (买家转钱到合约, 合约转到卖家), 买家传入 value 调用 address(seller).transfer(msg.value)

实战例子 (官网例子)

pragma solidity ^0.4.22;

contract Purchase {
    uint public value;    // 商品金额
    address public seller;//卖家地址
    address public buyer; //买家地址
    enum State { Created, Locked, Inactive }
    State public state;   

    //确保 `msg.value` 是一个偶数。
    //如果它是一个奇数,则它将被截断。
    //通过乘法检查它不是奇数。
    constructor() public payable {
        // 这个例子是, 合约部署者即是卖家, 部署时传入的 value/2 就是商品价格
        // 部署后, 传入的 value, 自动进入 this.balance
        seller = msg.sender;
        value = msg.value / 2;
        require((2 * value) == msg.value, "Value has to be even.");
    }

    // 查看合约内金额
    function getBalance() public returns(uint) {
         return this.balance;
    }

    //
    modifier condition(bool _condition) {
        require(
            _condition,
            "Some thing not right"
        );
        _;
    }

    modifier onlyBuyer() {
        require(
            msg.sender == buyer,
            "Only buyer can call this."
        );
        _;
    }

    modifier onlySeller() {
        require(
            msg.sender == seller,
            "Only seller can call this."
        );
        _;
    }

    modifier inState(State _state) {
        require(
            state == _state,
            "Invalid state."
        );
        _;
    }

    event Aborted();
    event PurchaseConfirmed();
    event ItemReceived();

    ///中止购买并回收以太币。
    ///只能在合约被锁定之前由卖家调用。
    function abort()
        public
        onlySeller
        inState(State.Created)
    {
        emit Aborted();
        state = State.Inactive;
        seller.transfer(address(this).balance);
    }

    /// 买家确认购买。
    /// 交易必须包含 `2 * value` 个以太币。
    /// 以太币会被锁定,直到 confirmReceived 被调用。
    function confirmPurchase()
        public
        inState(State.Created)
        condition(msg.value == (2 * value))
        payable
    {
        // 购买第一步, 买家也转入 商品价*2 的 value, 自动进入合约地址( 我一直以为需要调用 this.send(msg.value) )
        emit PurchaseConfirmed();
        buyer = msg.sender;
        state = State.Locked;
    }

    /// 确认你(买家)已经收到商品。
    /// 这会释放被锁定的以太币。
    function confirmReceived()
        public
        onlyBuyer
        inState(State.Locked)
    {
        // 购买第二部, 结算: 确认收货, 此时 this.balance 有4*value, 将退回 一个value 给买家, 而卖家则收到 剩余的 3 * value, 2*value 是之前就转入的保证金
        emit ItemReceived();
        // 首先修改状态很重要,否则的话,由 `transfer` 所调用的合约可以回调进这里(再次接收以太币)。
        state = State.Inactive;

        // 注意: 这实际上允许买方和卖方阻止退款 - 应该使用取回模式。
        buyer.transfer(value);
        seller.transfer(address(this).balance);
    }
}

PS: 顺便说下这个例子拿去改造成中介平台很不错啊

相关标签: transfer