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 事件)

我们会:

写一个"有漏洞的合约"

亲手复现重入攻击

再一步步修复

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

相关推荐
kida_yuan14 小时前
【以太来袭】6. Besu 的 API 与调试体系
运维·区块链
2501_9216494918 小时前
期货 Tick 级数据与基金净值历史数据 API 接口详解
开发语言·后端·python·websocket·金融·区块链
我叫黑大帅19 小时前
Go 中最强大的权限控制库(Casbin)
后端·面试·go
三秋树1 天前
Foundry Fuzz 测试完全指南:从入门到生产级智能合约安全测试
区块链
不知名的老吴1 天前
我们为什么要使用区块链?
区块链
古城小栈1 天前
Jenkins+K8s实现Go后端服务自动化部署
go·k8s·jenkins
不会写DN2 天前
Gin 实战入门:从环境搭建到企业级常用特性全解析
go·gin
下次一定x2 天前
深度解析 Kratos 客户端服务发现与负载均衡:从 Dial 入口到 gRPC 全链路落地(下篇)
后端·go
暴躁小师兄数据学院2 天前
【WEB3.0零基础转行笔记】go编程篇-第12讲:go-zero入门实战
开发语言·笔记·golang·web3·区块链
无心水2 天前
【OpenClaw:赚钱】案例9、模拟盘ROI+1560%:跨平台加密预测市场套利机器人全栈开发指南
机器人·区块链·金融科技·roi·openclaw·openclaw 变现