stepanovnikita95-tech/MarketPay-Web2-Web3

GitHub: stepanovnikita95-tech/MarketPay-Web2-Web3

一个为混合 Web2+Web3 电商平台设计的轻量级智能合约支付网关,专注于链上结算验证与事件驱动,将业务逻辑保留在链下。

Stars: 0 | Forks: 0

# MarketPay — 链上支付网关 [![Solidity](https://img.shields.io/badge/Solidity-%5E0.8.30-black?logo=solidity)](https://docs.soliditylang.org/) [![Hardhat](https://img.shields.io/badge/Built%20with-Hardhat-orange)](https://hardhat.org/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Tests & Coverage](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/02b3b151b9080106.svg)](https://github.com/stepanovnikita95-tech/MarketPay-Web2-Web3/actions/workflows/test.yml) [![codecov](https://codecov.io/gh/stepanovnikita95-tech/MarketPay-Web2-Web3/branch/main/graph/badge.svg)](https://codecov.io/gh/stepanovnikita95-tech/MarketPay-Web2-Web3) ## 概述 MarketPay 是建立在现有 MERN 电子商务平台之上的 Web3 扩展层。智能合约充当**验证和结算层**:它接受付款、发出事件,并让后端对其进行索引——而所有业务逻辑都保留在链下。 **设计原则:** - 不在链上存储用户数据——仅存储订单哈希和支付事实 - 合约内部没有定价或订单管理逻辑 - 区块链功能是附加的,不会影响非加密用户 - 稳定币降低了波动性风险;同时也支持 ETH ## 架构 ### 两种合约变体 项目以两种访问控制风格提供相同的支付逻辑: | 合约 | 访问控制 | 最适用于 | |---|---|---| | [`MarketPay.sol`](contracts/MarketPay.sol) | `Ownable` — 单一所有者 | 中心化 / 独立部署 | | [`MarketPayAM.sol`](contracts/MarketPayAM.sol) | `AccessManaged` — 通过 OpenZeppelin AccessManager 进行基于角色的控制 | 多角色 / 团队部署 | [`MarketPayAuthority.sol`](contracts/MarketPayAuthority.sol) 是用于管理 `MarketPayAM` 角色的 AccessManager 合约。 ### 核心支付流程 ``` User approves ERC-20 spend │ ▼ pay() / payBatch() │ ├─ validates orderId (1–64 chars, not duplicate) ├─ validates token is whitelisted ├─ pulls tokens via safeTransferFrom └─ emits PaymentDone / BatchPaymentDone │ ▼ Backend indexes event and updates order status in MongoDB ``` ## 功能 ### 支付方式 | 方式 | 描述 | |---|---| | `pay(orderId, token, amount)` | 单次 ERC-20 支付 | | `payWithETH(orderId)` | 单次 ETH 支付 | | `payBatch(orderIds[], token, amounts[])` | 批量 ERC-20 支付——单笔交易最多 100 个订单 | | `payBatchWithETH(orderIds[], amounts[])` | 批量 ETH 支付——`msg.value` 必须等于金额总和 | ### 管理方法 | 方法 | 描述 | |---|---| | `addTokenApproval(token)` | 将 ERC-20 代币添加到白名单 | | `removeTokenApproval(token)` | 从白名单中移除代币 | | `withdrawal(token, to, amount)` | 部分 ERC-20 提现 | | `withdrawalETH(to, amount)` | 部分 ETH 提现 | | `withdrawalAll(token, to)` | 全额 ERC-20 提取 | | `withdrawalAllETH(to)` | 全额 ETH 提取 | | `pause()` / `unpause()` | 紧急熔断机制 | ### 触发的事件 ``` PaymentDone(string orderId, address indexed customer, address token, uint256 indexed amount) PaymentETHDone(string orderId, address indexed customer, uint256 indexed amountETH) BatchPaymentDone(string[] orderIds, address indexed customer, address token, uint256[] amounts, uint256 indexed totalAmount) BatchWithETHPaymentDone(string[] orderIds, address indexed customer, uint256[] amounts, uint256 indexed totalAmountETH) ``` ## 安全性 | 机制 | 目的 | |---|---| | `ReentrancyGuard` | 防止对所有状态更改函数的重入攻击 | | `SafeERC20` | 防范非标准 ERC-20 实现 | | `Pausable` | 由所有者/授权角色进行紧急暂停 | | `_processedOrders` 映射 | 幂等性——每个 `orderId` 只能支付一次,**适用于所有支付类型(ERC-20 和 ETH)的全局范围** | | `MAX_BATCH_SIZE = 100` | 限制批量大小以防止区块 Gas 限制 DoS 攻击 | | `receive() reverts` | 阻止意外的直接 ETH 转账 | | `orderId` 长度检查(1–64 字节) | 防止订单 ID 为空或过长 | ## 设计说明 ### 紧急提款(预期行为) `withdrawalAll` 和 `withdrawalAllETH` 有意绕过了 `whenNotPaused`。所有者/财务角色始终可以在合约暂停期间提取资金。这是一个深思熟虑的安全阀,用于防止在紧急情况下暂停合约时资金被永久锁定。 **路线图——下个版本:**此模式将被由 Timelock + 多重签名保护的专用 `emergencyWithdraw` 函数取代。常规的 `withdrawalAll` / `withdrawalAllETH` 届时将遵循暂停状态,而紧急提款将需要时间延迟和多方批准。 ### orderId 唯一性 `orderId` 是一个在所有支付方法(ERC-20 和 ETH)中共享的**全局**幂等键。一旦某个 `orderId` 被 `pay`、`payWithETH`、`payBatch` 或 `payBatchWithETH` 中的任何一个处理过,它就永远不能被重复使用。 您的后端**必须生成跨所有支付渠道和货币的全局唯一订单 ID**。将 orderId 重新用于不同的支付类型将导致 `OrderAlreadyProcessed` 回滚。 ## MarketPayAM 部署清单 在部署 `MarketPayAuthority` 和 `MarketPayAM` 之后,在合约可用之前**必须**执行以下步骤。跳过第 3 步将导致所有 `restricted` 函数仅管理员可访问(AccessManager 默认行为)。 **1. 部署合约** ``` npx hardhat run scripts/deploy.ts --network sepolia ``` **2. 授予角色** ``` const TREASURY_ROLE = await authority.TREASURY_ROLE(); // 1 const PAUSER_ROLE = await authority.PAUSER_ROLE(); // 2 const TOKEN_MANAGER_ROLE = await authority.TOKEN_MANAGER_ROLE(); // 3 await authority.grantRole(TREASURY_ROLE, treasuryAddress, 0); await authority.grantRole(PAUSER_ROLE, pauserAddress, 0); await authority.grantRole(TOKEN_MANAGER_ROLE, tokenManagerAddress, 0); ``` **3. 将函数绑定到角色** ``` // Treasury await authority.setTargetFunctionRole(market.target, [ market.interface.getFunction("withdrawal").selector, market.interface.getFunction("withdrawalAll").selector, market.interface.getFunction("withdrawalETH").selector, market.interface.getFunction("withdrawalAllETH").selector, ], TREASURY_ROLE); // Pauser await authority.setTargetFunctionRole(market.target, [ market.interface.getFunction("pause").selector, market.interface.getFunction("unpause").selector, ], PAUSER_ROLE); // Token Manager await authority.setTargetFunctionRole(market.target, [ market.interface.getFunction("addTokenApproval").selector, market.interface.getFunction("removeTokenApproval").selector, ], TOKEN_MANAGER_ROLE); ``` **4. 将至少一个代币列入白名单** ``` await market.connect(tokenManager).addTokenApproval(tokenAddress); ``` ## 技术栈 | 层级 | 技术 | |---|---| | 智能合约 | Solidity `0.8.30`, EVM Cancun | | 框架 | Hardhat `2.x` + TypeScript | | 库 | OpenZeppelin Contracts `v5` | | Ethers | ethers.js `v6` | | 类型安全 | TypeChain (ethers-v6 目标) | | 测试 | Mocha / Chai — **67 个测试** | | 覆盖率 | solidity-coverage | | 测试网 | Sepolia (Alchemy RPC) | ## 快速开始 ### 前置条件 - Node.js `>= 18` - npm `>= 9` ### 安装说明 ``` git clone https://github.com/stepanovnikita95-tech/MarketPay-Web2-Web3.git cd MarketPay-Web2-Web3 npm install ``` ### 环境变量 复制示例文件并填入您的值: ``` cp .env.example .env ``` | 变量 | 描述 | |---|---| | `ALCHEMY_SEPOLIA_URL` | 用于 Sepolia 的 Alchemy RPC 端点 | | `PRIVATE_KEY` | 部署者钱包私钥(无 `0x` 前缀) | | `ETHERSCAN_API_KEY` | 用于在 Etherscan 上进行合约验证 | ## 命令 ``` # Compile contracts npx hardhat compile # Run all tests npx hardhat test # Run a specific test suite npx hardhat test test/MarketPay-test.ts npx hardhat test test/MarketPayAM-test.ts # Code coverage npx hardhat coverage # Gas report REPORT_GAS=true npx hardhat test # Local node npx hardhat node # Deploy to Sepolia npx hardhat run scripts/deploy.ts --network sepolia # Verify on Etherscan npx hardhat verify --network sepolia ``` ## 测试结果 ``` MarketPay.sol ✔ 42 tests — payments, batch, withdrawals, access control, pause MarketPayAM.sol ✔ 25 tests — same coverage + role-based access via AccessManager 67 passing ``` ## 已部署的合约 (Sepolia) | 合约 | 地址 | |---|---| | `MarketPay` | — | | `MarketPayAM` | — | | `MarketPayAuthority` | — | ## 许可证 [MIT](LICENSE)
标签:ERC-20, ETH, Hardhat, MERN, OpenZeppelin, Solidity, Streamlit, Web2.5, Web3, Web3电商, 事件索引, 代币支付, 以太坊, 加密电商, 加密货币支付, 区块链, 去中心化, 去中心化支付, 双重代币支持, 可审计, 后端索引, 安全, 支付网关, 智能合约, 电子商务, 稳定币, 自动化攻击, 订单哈希, 访问控制, 超时处理, 链上结算