如何在Solidity里怎么实现安全的代币转账。Solidity是Ethereum区块链的智能合约开发语言,写代币合约是区块链开发的常见场景,但转账逻辑如果不小心,可能会被黑客钻空子,比如重入攻击、溢出问题,或者权限管理不当。本文把Solidity的代币转账核心机制讲清楚,基于ERC-20标准,结合
如何在Solidity里怎么实现安全的代币转账。Solidity是Ethereum区块链的智能合约开发语言,写代币合约是区块链开发的常见场景,但转账逻辑如果不小心,可能会被黑客钻空子,比如重入攻击、溢出问题,或者权限管理不当。本文把Solidity的代币转账核心机制讲清楚,基于ERC-20标准,结合OpenZeppelin库,从简单的转账到复杂的多签和权限控制,配合完整代码和Hardhat测试,一步步带你搞定安全的代币转账。重点是干货,少废话,直接上技术细节,帮你把Solidity代币转账写得稳如磐石!
先搞清楚几个关键点:
transfer
、transferFrom
、approve
等接口,方便钱包和交易所交互。咱们用Solidity 0.8.x(自带溢出检查)和OpenZeppelin,结合Hardhat和TypeScript,展示安全的代币转账实现。
用Hardhat搭建开发环境,写和测试合约。
mkdir token-demo
cd token-demo
npm init -y
npm install --save-dev hardhat @nomicfoundation/hardhat-toolbox @openzeppelin/contracts
npm install ethers
初始化Hardhat:
npx hardhat init
选择TypeScript项目,安装依赖:
npm install --save-dev ts-node typescript @types/node @types/mocha
目录结构:
token-demo/
├── contracts/
│ ├── Token.sol
│ ├── AdvancedToken.sol
├── scripts/
│ ├── deploy.ts
├── test/
│ ├── Token.test.ts
├── hardhat.config.ts
├── tsconfig.json
├── package.json
tsconfig.json
:
{
"compilerOptions": {
"target": "ES2020",
"module": "CommonJS",
"strict": true,
"esModuleInterop": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"outDir": "./dist",
"rootDir": "./"
},
"include": ["hardhat.config.ts", "scripts", "test"]
}
hardhat.config.ts
:
import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";
const config: HardhatUserConfig = {
solidity: "0.8.20",
networks: {
hardhat: {
chainId: 1337,
},
},
};
export default config;
跑本地节点:
npx hardhat node
实现一个简单的ERC-20代币,包含transfer
和transferFrom
。
contracts/Token.sol
:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract Token is ERC20 {
constructor(string memory name, string memory symbol, uint256 initialSupply) ERC20(name, symbol) {
_mint(msg.sender, initialSupply);
}
}
ERC20
,实现标准接口:
transfer(address to, uint256 amount)
:转账。transferFrom(address from, address to, uint256 amount)
:授权转账。approve(address spender, uint256 amount)
:授权。balanceOf(address account)
:查询余额。totalSupply()
:总供应量。allowance(address owner, address spender)
:授权额度。initialSupply
代币给部署者。SafeMath
(0.8.x前)内置于编译器。transfer
和transferFrom
检查余额和授权。test/Token.test.ts
:
import { ethers } from "hardhat";
import { expect } from "chai";
import { Token } from "../typechain-types";
describe("Token", function () {
let token: Token;
let owner: any, addr1: any, addr2: any;
beforeEach(async function () {
[owner, addr1, addr2] = await ethers.getSigners();
const TokenFactory = await ethers.getContractFactory("Token");
token = await TokenFactory.deploy("MyToken", "MTK", ethers.parseEther("1000"));
await token.deployed();
});
it("should deploy with initial supply", async function () {
const balance = await token.balanceOf(owner.address);
expect(balance).to.equal(ethers.parseEther("1000"));
});
it("should transfer tokens", async function () {
await token.transfer(addr1.address, ethers.parseEther("100"));
expect(await token.balanceOf(addr1.address)).to.equal(ethers.parseEther("100"));
expect(await token.balanceOf(owner.address)).to.equal(ethers.parseEther("900"));
});
it("should fail if insufficient balance", async function () {
await expect(token.transfer(addr1.address, ethers.parseEther("1001"))).to.be.revertedWith(
"ERC20: transfer amount exceeds balance"
);
});
it("should handle transferFrom", async function () {
await token.approve(addr1.address, ethers.parseEther("100"));
await token.connect(addr1).transferFrom(owner.address, addr2.address, ethers.parseEther("50"));
expect(await token.balanceOf(addr2.address)).to.equal(ethers.parseEther("50"));
expect(await token.allowance(owner.address, addr1.address)).to.equal(ethers.parseEther("50"));
});
it("should fail if insufficient allowance", async function () {
await token.approve(addr1.address, ethers.parseEther("50"));
await expect(
токен.connect(addr1).transferFrom(owner.address, addr2.address, ethers.parseEther("51"))
).to.be.revertedWith("ERC20: insufficient allowance");
});
});
跑测试:
npx hardhat test
owner
。owner
转100 MTK到addr1
,检查余额。owner
授权addr1
100 MTK,addr1
转50 MTK到addr2
。transfer amount exceeds balance
。insufficient allowance
。Transfer
和Approval
事件自动触发,记录日志。重入攻击是转账中的常见风险,外部合约可能在转账完成前重复调用。
contracts/VulnerableToken.sol
:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract VulnerableToken {
mapping(address => uint256) public balances;
constructor(uint256 initialSupply) {
balances[msg.sender] = initialSupply;
}
function transfer(address to, uint256 amount) public {
require(balances[msg.sender] >= amount, "Insufficient balance");
balances[msg.sender] -= amount;
(bool success, ) = to.call{value: 0}("");
require(success, "Transfer failed");
balances[to] += amount;
}
}
攻击合约:
contracts/Attacker.sol
:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "./VulnerableToken.sol";
contract Attacker {
VulnerableToken public token;
uint256 public count;
constructor(address _token) {
token = VulnerableToken(_token);
}
receive() external payable {
if (count < 2) {
count++;
token.transfer(address(this), 100);
}
}
function attack() external {
token.transfer(address(this), 100);
}
}
测试:
test/VulnerableToken.test.ts
:
import { ethers } from "hardhat";
import { expect } from "chai";
import { VulnerableToken, Attacker } from "../typechain-types";
describe("VulnerableToken", function () {
let token: VulnerableToken;
let attacker: Attacker;
let owner: any, attackerAddr: any;
beforeEach(async function () {
[owner, attackerAddr] = await ethers.getSigners();
const TokenFactory = await ethers.getContractFactory("VulnerableToken");
token = await TokenFactory.deploy(ethers.parseEther("1000"));
await token.deployed();
const AttackerFactory = await ethers.getContractFactory("Attacker");
attacker = await AttackerFactory.deploy(token.address);
await attacker.deployed();
await token.transfer(attacker.address, ethers.parseEther("200"));
});
it("should be vulnerable to reentrancy", async function () {
await attacker.connect(attackerAddr).attack();
expect(await token.balances(attacker.address)).to.equal(ethers.parseEther("300"));
});
});
transfer
在更新balances[to]
前调用to.call
,攻击合约通过receive
重复调用,窃取代币。OpenZeppelin的ReentrancyGuard
防止重入攻击。
contracts/SafeToken.sol
:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract SafeToken is ERC20, ReentrancyGuard {
constructor(string memory name, string memory symbol, uint256 initialSupply) ERC20(name, symbol) {
_mint(msg.sender, initialSupply);
}
function transfer(address to, uint256 amount) public virtual override nonReentrant returns (bool) {
return super.transfer(to, amount);
}
function transferFrom(address from, address to, uint256 amount) public virtual override nonReentrant returns (bool) {
return super.transferFrom(from, to, amount);
}
}
测试:
test/SafeToken.test.ts
:
import { ethers } from "hardhat";
import { expect } from "chai";
import { SafeToken, Attacker } from "../typechain-types";
describe("SafeToken", function () {
let token: SafeToken;
let attacker: Attacker;
let owner: any, attackerAddr: any;
beforeEach(async function () {
[owner, attackerAddr] = await ethers.getSigners();
const TokenFactory = await ethers.getContractFactory("SafeToken");
token = await TokenFactory.deploy("SafeToken", "STK", ethers.parseEther("1000"));
await token.deployed();
const AttackerFactory = await ethers.getContractFactory("Attacker");
attacker = await AttackerFactory.deploy(token.address);
await attacker.deployed();
await token.transfer(attacker.address, ethers.parseEther("200"));
});
it("should prevent reentrancy", async function () {
await expect(attacker.connect(attackerAddr).attack()).to.be.revertedWith("ReentrancyGuard: reentrant call");
expect(await token.balanceOf(attacker.address)).to.equal(ethers.parseEther("200"));
});
});
nonReentrant
修饰符,设置锁状态,防止重复调用。实现多签机制,只有多个管理者同意才能转账大额代币。
contracts/MultiSigToken.sol
:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract MultiSigToken is ERC20, ReentrancyGuard {
address[] public owners;
uint256 public required;
mapping(uint256 => Transaction) public transactions;
mapping(uint256 => mapping(address => bool)) public confirmations;
uint256 public transactionCount;
struct Transaction {
address to;
uint256 amount;
bool executed;
uint256 confirmationCount;
}
event SubmitTransaction(uint256 indexed txId, address indexed to, uint256 amount);
event ConfirmTransaction(uint256 indexed txId, address indexed owner);
event ExecuteTransaction(uint256 indexed txId);
event RevokeConfirmation(uint256 indexed txId, address indexed owner);
modifier onlyOwner() {
bool isOwner = false;
for (uint256 i = 0; i < owners.length; i++) {
if (owners[i] == msg.sender) {
isOwner = true;
break;
}
}
require(isOwner, "Not owner");
_;
}
constructor(
string memory name,
string memory symbol,
uint256 initialSupply,
address[] memory _owners,
uint256 _required
) ERC20(name, symbol) {
require(_owners.length > 0 && _required > 0 && _required <= _owners.length, "Invalid params");
owners = _owners;
required = _required;
_mint(msg.sender, initialSupply);
}
function submitTransaction(address to, uint256 amount) public onlyOwner {
require(balanceOf(address(this)) >= amount, "Insufficient contract balance");
uint256 txId = transactionCount++;
transactions[txId] = Transaction({
to: to,
amount: amount,
executed: false,
confirmationCount: 0
});
emit SubmitTransaction(txId, to, amount);
}
function confirmTransaction(uint256 txId) public onlyOwner nonReentrant {
Transaction storage transaction = transactions[txId];
require(!transaction.executed, "Transaction already executed");
require(!confirmations[txId][msg.sender], "Already confirmed");
confirmations[txId][msg.sender] = true;
transaction.confirmationCount++;
emit ConfirmTransaction(txId, msg.sender);
if (transaction.confirmationCount >= required) {
executeTransaction(txId);
}
}
function executeTransaction(uint256 txId) internal nonReentrant {
Transaction storage transaction = transactions[txId];
require(!transaction.executed, "Transaction already executed");
require(transaction.confirmationCount >= required, "Insufficient confirmations");
transaction.executed = true;
_transfer(address(this), transaction.to, transaction.amount);
emit ExecuteTransaction(txId);
}
function revokeConfirmation(uint256 txId) public onlyOwner {
Transaction storage transaction = transactions[txId];
require(!transaction.executed, "Transaction already executed");
require(confirmations[txId][msg.sender], "Not confirmed");
confirmations[txId][msg.sender] = false;
transaction.confirmationCount--;
emit RevokeConfirmation(txId, msg.sender);
}
function transfer(address to, uint256 amount) public virtual override returns (bool) {
if (amount > 100 ether) {
_transfer(msg.sender, address(this), amount);
submitTransaction(to, amount);
return true;
}
return super.transfer(to, amount);
}
}
owners
:管理者地址列表。required
:需要的最少确认数。transactions
:存储转账请求。confirmations
:记录每个管理者的确认状态。super.transfer
。submitTransaction
:提交转账请求。confirmTransaction
:管理者确认,达到required
后自动执行。executeTransaction
:执行转账。revokeConfirmation
:撤销确认。nonReentrant
防止重入。onlyOwner
限制操作者。test/MultiSigToken.test.ts
:
import { ethers } from "hardhat";
import { expect } from "chai";
import { MultiSigToken } from "../typechain-types";
describe("MultiSigToken", function () {
let token: MultiSigToken;
let owner: any, addr1: any, addr2: any, addr3: any;
beforeEach(async function () {
[owner, addr1, addr2, addr3] = await ethers.getSigners();
const TokenFactory = await ethers.getContractFactory("MultiSigToken");
token = await TokenFactory.deploy(
"MultiSigToken",
"MST",
ethers.parseEther("1000"),
[owner.address, addr1.address, addr2.address],
2
);
await token.deployed();
});
it("should deploy with initial supply", async function () {
expect(await token.balanceOf(owner.address)).to.equal(ethers.parseEther("1000"));
});
it("should handle small transfers", async function () {
await token.transfer(addr3.address, ethers.parseEther("50"));
expect(await token.balanceOf(addr3.address)).to.equal(ethers.parseEther("50"));
});
it("should handle multisig transfer", async function () {
await token.transfer(addr3.address, ethers.parseEther("200"));
expect(await token.balanceOf(address(token))).to.equal(ethers.parseEther("200"));
await token.connect(addr1).confirmTransaction(0);
expect(await token.balanceOf(addr3.address)).to.equal(ethers.parseEther("0"));
await token.connect(addr2).confirmTransaction(0);
expect(await token.balanceOf(addr3.address)).to.equal(ethers.parseEther("200"));
});
it("should fail if insufficient confirmations", async function () {
await token.transfer(addr3.address, ethers.parseEther("200"));
await token.connect(addr1).confirmTransaction(0);
expect(await token.balanceOf(addr3.address)).to.equal(ethers.parseEther("0"));
});
it("should allow revoking confirmation", async function () {
await token.transfer(addr3.address, ethers.parseEther("200"));
await token.connect(addr1).confirmTransaction(0);
await token.connect(addr1).revokeConfirmation(0);
await token.connect(addr2).confirmTransaction(0);
expect(await token.balanceOf(addr3.address)).to.equal(ethers.parseEther("0"));
});
});
nonReentrant
和状态检查防止攻击。实现账户冻结和管理员权限。
contracts/AdvancedToken.sol
:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract AdvancedToken is ERC20, ReentrancyGuard, Ownable {
mapping(address => bool) public frozenAccounts;
event FreezeAccount(address indexed account);
event UnfreezeAccount(address indexed account);
constructor(string memory name, string memory symbol, uint256 initialSupply) ERC20(name, symbol) Ownable() {
_mint(msg.sender, initialSupply);
}
function freezeAccount(address account) public onlyOwner {
frozenAccounts[account] = true;
emit FreezeAccount(account);
}
function unfreezeAccount(address account) public onlyOwner {
frozenAccounts[account] = false;
emit UnfreezeAccount(account);
}
function transfer(address to, uint256 amount) public virtual override nonReentrant returns (bool) {
require(!frozenAccounts[msg.sender], "Account is frozen");
require(!frozenAccounts[to], "Recipient account is frozen");
return super.transfer(to, amount);
}
function transferFrom(address from, address to, uint256 amount) public virtual override nonReentrant returns (bool) {
require(!frozenAccounts[from], "Account is frozen");
require(!frozenAccounts[to], "Recipient account is frozen");
return super.transferFrom(from, to, amount);
}
}
Ownable
,onlyOwner
限制管理员操作。frozenAccounts
:记录账户冻结状态。freezeAccount
/unfreezeAccount
:管理员控制。transfer
和transferFrom
检查账户状态。nonReentrant
防止重入。onlyOwner
限制冻结权限。test/AdvancedToken.test.ts
:
import { ethers } from "hardhat";
import { expect } from "chai";
import { AdvancedToken } from "../typechain-types";
describe("AdvancedToken", function () {
let token: AdvancedToken;
let owner: any, addr1: any, addr2: any;
beforeEach(async function () {
[owner, addr1, addr2] = await ethers.getSigners();
const TokenFactory = await ethers.getContractFactory("AdvancedToken");
token = await TokenFactory.deploy("AdvancedToken", "ATK", ethers.parseEther("1000"));
await token.deployed();
});
it("should deploy with initial supply", async function () {
expect(await token.balanceOf(owner.address)).to.equal(ethers.parseEther("1000"));
});
it("should allow transfer when not frozen", async function () {
await token.transfer(addr1.address, ethers.parseEther("100"));
expect(await token.balanceOf(addr1.address)).to.equal(ethers.parseEther("100"));
});
it("should prevent transfer when sender frozen", async function () {
await token.freezeAccount(addr1.address);
await token.transfer(addr1.address, ethers.parseEther("100"));
await expect(
token.connect(addr1).transfer(addr2.address, ethers.parseEther("50"))
).to.be.revertedWith("Account is frozen");
});
it("should prevent transfer to frozen recipient", async function () {
await token.freezeAccount(addr2.address);
await expect(
token.transfer(addr2.address, ethers.parseEther("100"))
).to.be.revertedWith("Recipient account is frozen");
});
it("should allow unfreezing and transfer", async function () {
await token.freezeAccount(addr1.address);
await token.unfreezeAccount(addr1.address);
await token.transfer(addr1.address, ethers.parseEther("100"));
await token.connect(addr1).transfer(addr2.address, ethers.parseEther("50"));
expect(await token.balanceOf(addr2.address)).to.equal(ethers.parseEther("50"));
});
it("should restrict freeze to owner", async function () {
await expect(
token.connect(addr1).freezeAccount(addr2.address)
).to.be.revertedWith("Ownable: caller is not the owner");
});
});
实现限额转账和黑名单功能。
contracts/AdvancedToken.sol
(更新):
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract AdvancedToken is ERC20, ReentrancyGuard, Ownable {
mapping(address => bool) public frozenAccounts;
mapping(address => bool) public blacklisted;
uint256 public transferLimit;
event FreezeAccount(address indexed account);
event UnfreezeAccount(address indexed account);
event BlacklistAccount(address indexed account);
event UnblacklistAccount(address indexed account);
event SetTransferLimit(uint256 limit);
constructor(string memory name, string memory symbol, uint256 initialSupply) ERC20(name, symbol) Ownable() {
_mint(msg.sender, initialSupply);
transferLimit = 500 ether;
}
function setTransferLimit(uint256 limit) public onlyOwner {
transferLimit = limit;
emit SetTransferLimit(limit);
}
function freezeAccount(address account) public onlyOwner {
frozenAccounts[account] = true;
emit FreezeAccount(account);
}
function unfreezeAccount(address account) public onlyOwner {
frozenAccounts[account] = false;
emit UnfreezeAccount(account);
}
function blacklistAccount(address account) public onlyOwner {
blacklisted[account] = true;
emit BlacklistAccount(account);
}
function unblacklistAccount(address account) public onlyOwner {
blacklisted[account] = false;
emit UnblacklistAccount(account);
}
function transfer(address to, uint256 amount) public virtual override nonReentrant returns (bool) {
require(!frozenAccounts[msg.sender], "Account is frozen");
require(!frozenAccounts[to], "Recipient account is frozen");
require(!blacklisted[msg.sender], "Sender is blacklisted");
require(!blacklisted[to], "Recipient is blacklisted");
require(amount <= transferLimit, "Amount exceeds transfer limit");
return super.transfer(to, amount);
}
function transferFrom(address from, address to, uint256 amount) public virtual override nonReentrant returns (bool) {
require(!frozenAccounts[from], "Account is frozen");
require(!frozenAccounts[to], "Recipient account is frozen");
require(!blacklisted[from], "Sender is blacklisted");
require(!blacklisted[to], "Recipient is blacklisted");
require(amount <= transferLimit, "Amount exceeds transfer limit");
return super.transferFrom(from, to, amount);
}
}
transferLimit
限制单次转账金额,管理员可调整。blacklisted
阻止特定账户转账。onlyOwner
限制限额和黑名单操作。nonReentrant
防止重入。test/AdvancedToken.test.ts
(更新):
import { ethers } from "hardhat";
import { expect } from "chai";
import { AdvancedToken } from "../typechain-types";
describe("AdvancedToken", function () {
let token: AdvancedToken;
let owner: any, addr1: any, addr2: any;
beforeEach(async function () {
[owner, addr1, addr2] = await ethers.getSigners();
const TokenFactory = await ethers.getContractFactory("AdvancedToken");
token = await TokenFactory.deploy("AdvancedToken", "ATK", ethers.parseEther("1000"));
await token.deployed();
});
it("should deploy with initial supply", async function () {
expect(await token.balanceOf(owner.address)).to.equal(ethers.parseEther("1000"));
});
it("should enforce transfer limit", async function () {
await expect(
token.transfer(addr1.address, ethers.parseEther("501"))
).to.be.revertedWith("Amount exceeds transfer limit");
await token.transfer(addr1.address, ethers.parseEther("500"));
expect(await token.balanceOf(addr1.address)).to.equal(ethers.parseEther("500"));
});
it("should allow owner to change transfer limit", async function () {
await token.setTransferLimit(ethers.parseEther("100"));
await expect(
token.transfer(addr1.address, ethers.parseEther("101"))
).to.be.revertedWith("Amount exceeds transfer limit");
await token.transfer(addr1.address, ethers.parseEther("100"));
expect(await token.balanceOf(addr1.address)).to.equal(ethers.parseEther("100"));
});
it("should prevent blacklisted sender", async function () {
await token.blacklistAccount(addr1.address);
await token.transfer(addr1.address, ethers.parseEther("100"));
await expect(
token.connect(addr1).transfer(addr2.address, ethers.parseEther("50"))
).to.be.revertedWith("Sender is blacklisted");
});
it("should prevent blacklisted recipient", async function () {
await token.blacklistAccount(addr2.address);
await expect(
token.transfer(addr2.address, ethers.parseEther("100"))
).to.be.revertedWith("Recipient is blacklisted");
});
it("should allow unblacklisting", async function () {
await token.blacklistAccount(addr1.address);
await token.unblacklistAccount(addr1.address);
await token.transfer(addr1.address, ethers.parseEther("100"));
await token.connect(addr1).transfer(addr2.address, ethers.parseEther("50"));
expect(await token.balanceOf(addr2.address)).to.equal(ethers.parseEther("50"));
});
it("should restrict blacklist to owner", async function () {
await expect(
token.connect(addr1).blacklistAccount(addr2.address)
).to.be.revertedWith("Ownable: caller is not the owner");
});
});
scripts/deploy.ts
:
import { ethers } from "hardhat";
async function main() {
const [owner, addr1, addr2] = await ethers.getSigners();
const TokenFactory = await ethers.getContractFactory("AdvancedToken");
const token = await TokenFactory.deploy("AdvancedToken", "ATK", ethers.parseEther("1000"));
await token.deployed();
console.log(`Token deployed to: ${token.address}`);
const MultiSigFactory = await ethers.getContractFactory("MultiSigToken");
const multiSigToken = await MultiSigFactory.deploy(
"MultiSigToken",
"MST",
ethers.parseEther("1000"),
[owner.address, addr1.address, addr2.address],
2
);
await multiSigToken.deployed();
console.log(`MultiSigToken deployed to: ${multiSigToken.address}`);
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
跑部署:
npx hardhat run scripts/deploy.ts --network hardhat
AdvancedToken
和MultiSigToken
,记录合约地址。如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!