# 使用 ethers.js 给智能合约函数“附带 ETH”的最简技巧

By [Untitled](https://paragraph.com/@0x2004418fc71c943473603ebd49a77e449c2a63df) · 2025-09-02

---

场景速描：为什么要“带钱”调用？
----------------

在实际 DApp 开发中，很多 **智能合约** 的函数不仅接受普通参数，也期待“随消息一起汇来”的 **以太币 (ETH)**。例如：

*   NFT 拍卖行的 `bid()` 函数
    
*   质押协议的 `deposit()`
    
*   GameFi 项目的 `purchaseItem()`
    

这些合约会在函数里校验 `msg.value` 是否足额，然后把以太币存储进合约或立即转给受益人。用 **ethers.js** 一行就能触发这类函数，但不少新手容易遗漏 `: { value: … }` 这一关键参数。

* * *

五步实战：从 0 到 1 转 ETH 给函数
----------------------

### 1\. 准备环境

在 `.env` 中写：

    PRIVATE_KEY=xxxxxxxx
    INFURA_KEY=xxxxxxxx
    

为了安全，**不要用明文私钥**。

### 2\. 引入依赖与 RPC

    import { ethers } from 'ethers';
    import dotenv from 'dotenv';
    dotenv.config();
    
    const provider = new ethers.providers.JsonRpcProvider(
      `https://mainnet.infura.io/v3/${process.env.INFURA_KEY}`
    );
    const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);
    

SEO 核心关键词：`ethers.js`, `以太坊主网`, `JsonRpcProvider`

### 3\. 抓取合约对象

    const CONTRACT_ADDRESS = '0x1234...ABCD';
    const abi = [
      'function deposit() external payable',
      // 其他 ABI 片段
    ];
    const contract = new ethers.Contract(CONTRACT_ADDRESS, abi, wallet);
    

> 小贴士：如果合约代码开源，可直接把完整 ABI JSON 扔进去；如果只公开接口，就把所需函数抽出即可。

### 4\. 发送 ETH 同时调用函数

    const ethAmount = '0.23';                    // 用户想存入 0.23 ETH
    const tx = await contract.deposit({
      value: ethers.utils.parseEther(ethAmount)  // 关键！
    });
    console.log(`Tx hash: ${tx.hash}`);
    
    await tx.wait();                             // 等待确认
    console.log('已完成！区块高度:', tx.blockNumber);
    

关键词自然嵌入：**智能合约调用**, **parseEther**

### 5\. 查询结果

    // 如果合约有 getter
    const afterBalance = await provider.getBalance(CONTRACT_ADDRESS);
    console.log('合约余额:', ethers.utils.formatEther(afterBalance), 'ETH');
    

* * *

高频踩坑 & 解决方案
-----------

1.  **Gas估算失败**兼容多数合约的保险写法：`const gasLimit = await contract.estimateGas.deposit({ value })`ethers.js 会基于最新区块状态给出合理预估。
    
2.  **ABI 漏写 payable**如果 ABI 里没有标注 `"payable": true`，ethers.js 会拒绝在调用时附带 `value`。请核对源码重新生成 ABI。
    
3.  **主网 / 测试网地址混用**主网地址放到 Goerli 上调用必定失败，先从区块浏览器确认 **智能合约** 部署在哪一行链。
    

👉 [一图看懂 ethers.js 高级用法，避坑更快更安全！](https://okxdog.com/)

* * *

实战案例：为 NFT 铸造附加 0.08 ETH
------------------------

假设合约规定：

*   每个地址最多买 3 个
    
*   每个 NFT 0.08 ETH
    
*   需要附带 `quantity` 参数
    

    const amount = 2;
    const totalValue = (0.08 * amount).toString();
    const tx = await contract.mint(amount, {
      value: ethers.utils.parseEther(totalValue)
    });
    await tx.wait();
    

链上完成后，用户钱包 NFT 页立刻出现 2 枚新资产，**交易哈希**可直接在浏览器验证。

* * *

FAQ：常见疑问 3 连发
-------------

**Q1：不写** `{ value }` 会如何？A：合约内部的 `msg.value` 为零，若逻辑强制检查则会 revert，提示错误 `not enough eth sent`。

**Q2：用户用浏览器钱包 MetaMask，也需要写** `value` 吗？A：前端 `ethers.js` 调用 `contract.populateTransaction.deposit({ value })` 生成交易体，再由 MetaMask 签名即可。语法不变。

\*\*Q3：可否一次往合约打钱但不调用函数（纯转账）？\*\*A：可以，用 `wallet.sendTransaction({ to: contractAddress, value })`，但这种普通交易会触发合约的 `receive()`；若合约没有 `receive()` 或 `fallback()`，会失败回滚。

👉 [立即体验零门槛区块浏览器交互，查看最新交易池！](https://okxdog.com/)

* * *

结语
--

通过上述 **五步流程** 与 **踩坑清单**，你已能在任何 evm 链上快捷、安全地把 **以太币** 发送到 **智能合约函数**。牢记两点：**ABI 需标** `payable`，**调用参数里加** `value`。如果只想要更清爽的“一条龙”方案，也可以基于 **腾讯云区块链服务 TBaaS** 快速部署测试网节点，无运维烦恼。

---

*Originally published on [Untitled](https://paragraph.com/@0x2004418fc71c943473603ebd49a77e449c2a63df/ethers-js-eth)*
