feat: Add Hardhat config, MockERC20 and tests for Smart Contract

This commit is contained in:
2026-03-12 14:25:18 +03:00
parent 6b40444639
commit e7f9325b1c
5 changed files with 6374 additions and 8 deletions

12
contracts/MockERC20.sol Normal file
View File

@@ -0,0 +1,12 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract MockERC20 is ERC20 {
constructor(string memory name, string memory symbol) ERC20(name, symbol) {}
function mint(address to, uint256 amount) public {
_mint(to, amount);
}
}

22
hardhat.config.ts Normal file
View File

@@ -0,0 +1,22 @@
import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";
const config: HardhatUserConfig = {
solidity: {
version: "0.8.20",
settings: {
optimizer: {
enabled: true,
runs: 200,
},
},
},
paths: {
sources: "./contracts",
tests: "./test",
cache: "./cache",
artifacts: "./artifacts"
},
};
export default config;

6255
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -15,7 +15,6 @@
"@supabase/supabase-js": "^2.90.1",
"clsx": "^2.1.1",
"date-fns": "^4.1.0",
"ethers": "^6.13.5",
"lucide-react": "^0.562.0",
"next": "16.1.1",
"react": "19.2.3",
@@ -25,12 +24,20 @@
"tailwind-merge": "^3.4.0"
},
"devDependencies": {
"@nomicfoundation/hardhat-ethers": "^4.0.6",
"@nomicfoundation/hardhat-toolbox": "^6.1.2",
"@openzeppelin/contracts": "^5.6.1",
"@tailwindcss/postcss": "^4",
"@types/chai": "^5.2.3",
"@types/mocha": "^10.0.10",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"chai": "^6.2.2",
"eslint": "^9",
"eslint-config-next": "16.1.1",
"ethers": "^6.16.0",
"hardhat": "^3.1.12",
"tailwindcss": "^4",
"typescript": "^5"
}

View File

@@ -0,0 +1,84 @@
import { expect } from "chai";
import { ethers } from "hardhat";
import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers";
describe("AyrisSplitter", function () {
async function deploySplitterFixture() {
const [owner, platformAccount, merchantAccount, customerAccount] = await ethers.getSigners();
const Splitter = await ethers.getContractFactory("AyrisSplitter");
const splitter = await Splitter.deploy(platformAccount.address);
const MockERC20 = await ethers.getContractFactory("MockERC20");
const mockToken = await MockERC20.deploy("Tether USD", "USDT");
// Mint 1000 USDT to customer
await mockToken.mint(customerAccount.address, ethers.parseUnits("1000", 18));
return { splitter, mockToken, owner, platformAccount, merchantAccount, customerAccount };
}
describe("Deployment", function () {
it("Should set the right platform address", async function () {
const { splitter, platformAccount } = await loadFixture(deploySplitterFixture);
expect(await splitter.platformAddress()).to.equal(platformAccount.address);
});
});
describe("Native Payments (ETH/MATIC)", function () {
it("Should split native currency exactly 99% to merchant and 1% to platform", async function () {
const { splitter, merchantAccount, platformAccount, customerAccount } = await loadFixture(deploySplitterFixture);
const paymentAmount = ethers.parseEther("1.0"); // 1 ETH/MATIC
const initialMerchantBalance = await ethers.provider.getBalance(merchantAccount.address);
const initialPlatformBalance = await ethers.provider.getBalance(platformAccount.address);
// Customer sends 1 ETH to contract using payNative
await splitter.connect(customerAccount).payNative(merchantAccount.address, { value: paymentAmount });
const finalMerchantBalance = await ethers.provider.getBalance(merchantAccount.address);
const finalPlatformBalance = await ethers.provider.getBalance(platformAccount.address);
// 1 ETH * 1% = 0.01 ETH
const expectedPlatformShare = ethers.parseEther("0.01");
// 1 ETH * 99% = 0.99 ETH
const expectedMerchantShare = ethers.parseEther("0.99");
expect(finalMerchantBalance - initialMerchantBalance).to.equal(expectedMerchantShare);
expect(finalPlatformBalance - initialPlatformBalance).to.equal(expectedPlatformShare);
});
});
describe("Token Payments (USDT/USDC)", function () {
it("Should split ERC20 tokens exactly 99% to merchant and 1% to platform", async function () {
const { splitter, mockToken, merchantAccount, platformAccount, customerAccount } = await loadFixture(deploySplitterFixture);
const paymentAmount = ethers.parseUnits("100", 18); // 100 USDT
// Customer must approve the splitter contract first
await mockToken.connect(customerAccount).approve(await splitter.getAddress(), paymentAmount);
const initialMerchantBalance = await mockToken.balanceOf(merchantAccount.address);
const initialPlatformBalance = await mockToken.balanceOf(platformAccount.address);
// Customer executes payment
await splitter.connect(customerAccount).payToken(
await mockToken.getAddress(),
paymentAmount,
merchantAccount.address
);
const finalMerchantBalance = await mockToken.balanceOf(merchantAccount.address);
const finalPlatformBalance = await mockToken.balanceOf(platformAccount.address);
// 100 USDT * 1% = 1 USDT
const expectedPlatformShare = ethers.parseUnits("1", 18);
// 100 USDT * 99% = 99 USDT
const expectedMerchantShare = ethers.parseUnits("99", 18);
expect(finalMerchantBalance - initialMerchantBalance).to.equal(expectedMerchantShare);
expect(finalPlatformBalance - initialPlatformBalance).to.equal(expectedPlatformShare);
});
});
});