# 智能合约的收付款和提现

By [Chris Gao](https://paragraph.com/@sec-dao) · 2022-05-13

---

### 前言：

一开始总以为是必须要在函数上设置一个参数，让调用者用户把eth转过来，后来发现不是。只要是交易message（msg）中包含了msg.value信息，则代表这个包含了一个eth转账的动作。函数接收的地方标记payable，则这笔钱会自动存入到智能合约的账号地址中，并且花费的是调用者的gas费。

另外，即便是不通过智能合约的函数，其他用户也可以直接给这个智能合约的账户转账，但是有一个前提：合约中必须声明了receive函数或者是fallback函数，并且这两个函数一定要标记为payable，代表可以接收转账。

> 下面介绍的付款、转账和提现等，都是指针对**_以太坊ETH_**的操作，并不是指合约自己的代币，合约自己发的代币的转账/销毁等逻辑合约自身可根据实际情况定义函数和逻辑实现。

### 给智能合约付款的几种方式

1、直接通过钱包转账到合约地址；（合约中必须声明了receive函数或者是fallback函数）

2、通过合约提供的专门收款函数调用，例如：

        //给合约转账 transfer
        function transferToContract() payable external {
            payable(address(this)).transfer(msg.value);
        }
    

3、通过合约买合约代币或者mint NFT函数（调用时transaction消息体要传入value信息）

> 只要消息体带了value信息，则交易会自动实现转账到合约地址

      function mint() external payable {
        //其他逻辑，例如给调用者发币和记录余额等操作
      }
    
      function buy(可能的参数) external payable {
        //其他逻辑，例如给调用者发币和记录余额等操作
      }
    

### 合约提现/转账

合约账号本身是没有私钥的，所以不能直接通过钱包转账，要通过合约提供的函数来进行转账到其他钱包地址。

      //注意：这个地方需要增加判断权限，只有合约发起人才能调用，不然钱就被任何人转走了！！！可以通过onlyOwner modifier实现。
      //地址可以传入，也可以考虑在合约中提前设置好；如果是传入地址，则可实现给任何人转账
      function getEth(address payable addr, uint amount) external onlyOwner {
            addr.transfer(amount);
      }
    

### 合约退款

    //这个地方是给调用者退款，但要判断逻辑，TA之前是不是付过钱
    function withDrawEth() external {
      //require(之前付过钱)
      value = 之前付的钱 or 退款逻辑计算出来的钱 //gas费由调用者花费
      msg.sender.transfer(value); //转账给当前调用者
    }

---

*Originally published on [Chris Gao](https://paragraph.com/@sec-dao/t19OP9UUvGjeJvGAKbok)*
