Solidity 实战【二】:手写一个「链上资金托管合约」

前言

如果说实战【一】解决的是:

"我终于会写合约了"

那这一篇解决的就是:

"原来合约还能这样用"

从这一篇开始,你会真正感受到:

👉 智能合约不是玩具,而是"可自动执行的资金规则"

一、什么是资金托管合约?为什么它非常重要?

先别急着写代码,我们先搞清楚 业务模型。

1️⃣ 现实世界的托管场景

现实中我们经常遇到:

买卖双方互不信任

需要一个"中间人"暂时保管钱

条件满足后,再放款

例如:

二手交易平台

自由职业接单

保证金 / 押金

传统模式是:

平台 / 银行 / 第三方 → 托管资金

2️⃣ 链上托管解决了什么?

链上托管的本质是:

代码即规则,资产由合约控制

特点:

无法私吞

规则透明

无需信任第三方

满足条件 → 自动放款

👉 这是 Solidity 最经典、最有价值的应用场景之一

二、实战目标(先定规则,再写代码)

这一点非常重要,也是新手最容易跳过的。

我们要实现一个最小可用的托管合约:

规则如下:

1️⃣ 合约由 托管人(owner) 部署

2️⃣ 任何人可以向合约 存入 ETH

3️⃣ 只有 owner 可以 释放资金

4️⃣ 释放后,钱打到指定地址

5️⃣ 合约余额可随时查询

👉 这是一个 可真实部署、可真实收钱的合约

三、合约整体结构设计(工程思维)

Escrow.sol

├── 状态变量

├── 构造函数

├── 收款逻辑

├── 放款逻辑

├── 查询逻辑

我们一步一步来。

四、合约骨架(从零开始)

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

contract Escrow {

}

老规矩:

SPDX:协议声明

pragma:版本锁定

合约名清晰表达业务语义

五、定义核心状态变量(资金 + 权限)

5.1 owner(托管人)

address public owner;

5.2 构造函数初始化

constructor() {

owner = msg.sender;

}

谁部署,谁就是规则制定者

六、让合约"能收钱"(关键一步)

这是新手第一次真正接触 payable。

6.1 最简单的存钱方式

function deposit() external payable {

// 只要转钱进来,就会记在合约余额里

}

解释:

payable:允许接收 ETH

msg.value:本次转入金额

钱不会进某个变量

👉 而是直接进合约账户

6.2 查看合约当前余额

function getBalance() external view returns (uint256) {

return address(this).balance;

}

这是 Solidity 非常重要的一行:

address(this).balance

含义是:

当前合约地址上的 ETH 余额

七、核心功能:释放资金(托管的本质)

7.1 权限校验(必须)

modifier onlyOwner() {

require(msg.sender == owner, "not owner");

_;

}

这是 modifier 的标准用法:

抽离权限逻辑

代码更干净

工程必备

7.2 放款函数(重点)

function release(address payable to, uint256 amount)

external

onlyOwner

{

require(amount <= address(this).balance, "insufficient balance");

复制代码
to.transfer(amount);

}

解释逐行拆解:

address payable:允许接收 ETH 的地址

校验余额,防止超额转账

transfer:最简单、安全的转账方式

👉 这是合约真正"动钱"的地方

八、完整合约代码(可直接部署)

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

contract Escrow {

复制代码
address public owner;

constructor() {
    owner = msg.sender;
}

modifier onlyOwner() {
    require(msg.sender == owner, "not owner");
    _;
}

// 存钱
function deposit() external payable {}

// 查看合约余额
function getBalance() external view returns (uint256) {
    return address(this).balance;
}

// 放款
function release(address payable to, uint256 amount)
    external
    onlyOwner
{
    require(amount <= address(this).balance, "insufficient balance");
    to.transfer(amount);
}

}

九、你已经掌握的 Solidity 核心能力(不知不觉)

这一篇你已经会了:

payable 的真实用法

合约如何持有 ETH

address(this).balance

modifier 权限抽象

ETH 转账完整流程

真实资金托管模型

👉 这已经不是"玩具合约"了

十、工程师一定要知道的 3 个关键安全点

❗1️⃣ transfer 不是万能的

在复杂场景中:

transfer 有 2300 gas 限制

新合约更推荐 call

但:

👉 新手阶段,transfer 是最安全的

❗2️⃣ 放款逻辑一定要简单

放款函数里:

❌ 不要 for 循环

❌ 不要复杂判断

❌ 不要调用不可信合约

❗3️⃣ 这是"半托管模型"

真正的业务托管还会涉及:

多方签名

状态机

仲裁机制

但 第一步走稳,比什么都重要

十一、正确的练习方式(非常重要)

强烈建议你做这 4 步:

1️⃣ 自己手敲一遍

2️⃣ 存 0.01 ETH 试试

3️⃣ 非 owner 调用 release

4️⃣ 把 transfer 改成 call(提前预习)

总结

如果说实战【一】是:

"我终于看懂 Solidity 了"

那实战【二】就是:

"原来智能合约真的能管钱"

你已经正式迈入 Web3 工程实战门槛。

下一篇预告(含金量更高)

👉 Solidity 实战【三】:重入攻击与防御(从 0 到 1 看懂 DAO 事件)

我们会:

写一个"有漏洞的合约"

亲手复现重入攻击

再一步步修复

这是 区块链工程师必会的一关。

相关推荐
暴躁小师兄数据学院2 分钟前
【WEB3.0零基础转行笔记】Rust编程篇-第一讲:课程简介
rust·web3·区块链·智能合约
devmoon13 分钟前
在 Paseo 测试网上获取 Coretime:On-demand 与 Bulk 的完整实操指南
开发语言·web3·区块链·测试用例·智能合约·solidity
lekami_兰5 小时前
MySQL 长事务:藏在业务里的性能 “隐形杀手”
数据库·mysql·go·长事务
devmoon6 小时前
在 Polkadot Runtime 中添加多个 Pallet 实例实战指南
java·开发语言·数据库·web3·区块链·波卡
Web3VentureView8 小时前
SYNBO Protocol AMA回顾:下一个起点——什么将真正推动比特币重返10万美元?
大数据·人工智能·金融·web3·区块链
软件工程小施同学8 小时前
区块链论文速读 CCF A--VLDB 2025 (1) 附pdf下载
pdf·区块链
却尘8 小时前
一篇小白也能看懂的 Go 字符串拼接 & Builder & cap 全家桶
后端·go
ん贤9 小时前
一次批量删除引发的死锁,最终我选择不加锁
数据库·安全·go·死锁
blockcoach10 小时前
比特币撕裂,以太坊削藩
区块链
devmoon10 小时前
在 Polkadot 链上添加智能合约功能全指南
安全·区块链·智能合约·polkadot·erc-20·测试网·独立链