punkkit-sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/.env +47 -0
  2. package/.gitmodules +3 -0
  3. package/README.md +158 -0
  4. package/config/auction.config.ts +40 -0
  5. package/config/env.config.ts +204 -0
  6. package/config/uniswap.config.ts +107 -0
  7. package/config/voucher.config.ts +10 -0
  8. package/contracts/MutiVoucher.sol +78 -0
  9. package/contracts/auction/ChainXAuction.sol +177 -0
  10. package/contracts/auction/ChainXAuctionV2.sol +672 -0
  11. package/contracts/auction/ChainXWrappedETH.sol +80 -0
  12. package/contracts/auction/ChainYLiquidityManager.sol +57 -0
  13. package/contracts/auction/ChainYShadowETH.sol +148 -0
  14. package/contracts/auction/ChainYVault.sol +195 -0
  15. package/contracts/auction/ChainYVaultCoinbase.sol +276 -0
  16. package/contracts/auction/ChainYVaultV2.sol +318 -0
  17. package/contracts/auction/coinbase-and-stake/README.md +55 -0
  18. package/contracts/auction/coinbase-and-stake/coinbase.sol +142 -0
  19. package/contracts/auction/coinbase-and-stake/invokeCoinbase.sol +159 -0
  20. package/contracts/auction/coinbase-and-stake/invokeStake.sol +82 -0
  21. package/contracts/auction/coinbase-and-stake/stake.sol +92 -0
  22. package/contracts/auction/interfaces/IUniswapV2Factory.sol +15 -0
  23. package/contracts/auction/interfaces/IUniswapV2Pair.sol +53 -0
  24. package/contracts/auction/interfaces/IUniswapV2Router02.sol +25 -0
  25. package/contracts/auction/interfaces/IUnlockStrategy.sol +18 -0
  26. package/contracts/auction/libraries/EventParser.sol +32 -0
  27. package/contracts/auction/libraries/TransactionParser.sol +70 -0
  28. package/contracts/auction/strategies/MatchResultWithdrawnStrategy.sol +33 -0
  29. package/contracts/auction/utils/BytesLib.sol +180 -0
  30. package/contracts/auction/utils/RLPReader.sol +355 -0
  31. package/contracts/uniswap/Create2.sol +80 -0
  32. package/contracts/uniswap/DynamicFee.sol +100 -0
  33. package/contracts/uniswap/Example.sol +35 -0
  34. package/contracts/uniswap/HookMiner.sol +52 -0
  35. package/contracts/uniswap/LimitOrder.sol +486 -0
  36. package/contracts/uniswap/LiquidPool.sol +179 -0
  37. package/contracts/uniswap/MockERC20.sol +20 -0
  38. package/hardhat.config.ts +35 -0
  39. package/ignition/modules/LimitOrder.ts +33 -0
  40. package/package.json +32 -0
  41. package/scripts/auction/deploy.ts +23 -0
  42. package/scripts/auction/deployCoinbase.ts +21 -0
  43. package/scripts/auction/deployXAuction.ts +23 -0
  44. package/scripts/auction/deployYVault.ts +22 -0
  45. package/scripts/deploy_voucher.ts +20 -0
  46. package/scripts/uniswap/deploy/deploy.ts +65 -0
  47. package/scripts/uniswap/deploy/deploy_create2.ts +11 -0
  48. package/scripts/uniswap/deploy/deploy_example.ts +35 -0
  49. package/scripts/uniswap/deploy/deploy_hooks.ts +74 -0
  50. package/scripts/uniswap/deploy/deploy_mockERC20.ts +42 -0
  51. package/scripts/uniswap/deploy/help.ts +96 -0
  52. package/scripts/uniswap/deploy/init.ts +70 -0
  53. package/src/auction/chainXAuction.ts +209 -0
  54. package/src/auction/chainYVault.ts +153 -0
  55. package/src/auction/event.ts +19 -0
  56. package/src/auction/serialize.ts +162 -0
  57. package/src/auction/type.ts +71 -0
  58. package/src/lib/signer.ts +20 -0
  59. package/src/lib/unlock.ts +14 -0
  60. package/src/uniswap/1-marketprice/addLiquidity.ts +80 -0
  61. package/src/uniswap/1-marketprice/removeLiquidity.ts +63 -0
  62. package/src/uniswap/1-marketprice/swap.ts +100 -0
  63. package/src/uniswap/2-limitorder/kill.ts +70 -0
  64. package/src/uniswap/2-limitorder/place.ts +93 -0
  65. package/src/uniswap/2-limitorder/withdraw.ts +78 -0
  66. package/src/uniswap/3-dynamicfee/dynamicfee.ts +321 -0
  67. package/src/uniswap/lib/ERC20.ts +49 -0
  68. package/src/uniswap/lib/contract.ts +18 -0
  69. package/src/uniswap/lib/limitOrder.ts +40 -0
  70. package/src/uniswap/lib/liqCalculation.ts +152 -0
  71. package/src/uniswap/lib/listen.ts +57 -0
  72. package/src/uniswap/lib/pool.ts +62 -0
  73. package/src/uniswap/lib/swap.ts +8 -0
  74. package/src/uniswap/lib/types.ts +21 -0
  75. package/src/uniswap/lib/utils.ts +26 -0
  76. package/src/uniswap/playgroud/abiencode.ts +21 -0
  77. package/src/uniswap/playgroud/amount0.ts +47 -0
  78. package/src/uniswap/playgroud/errordecode.ts +54 -0
  79. package/src/uniswap/playgroud/errorsigs.ts +86 -0
  80. package/src/voucher.ts +122 -0
  81. package/test/auction/ChainXAuctionV2.test.ts +265 -0
  82. package/test/auction/ChainYVaultV2.test.js +163 -0
  83. package/test/auction/ChainYVaultV2.test.ts +183 -0
  84. package/test/auction/auction.test.ts +106 -0
  85. package/test/connect_punk.test.ts +26 -0
  86. package/test/create2.test.ts +44 -0
  87. package/test/normal.ts +43 -0
  88. package/test/test-config.ts +18 -0
  89. package/test/uniswap/example.test.ts +62 -0
  90. package/test/uniswap/limitOrder.test.ts +184 -0
  91. package/test/uniswap/mockERC20.test.ts +142 -0
  92. package/test/voucher_hardhat.test.ts +120 -0
  93. package/test/voucher_punk.test.ts +83 -0
  94. package/tsconfig.json +11 -0
@@ -0,0 +1,106 @@
1
+
2
+ import { anyValue } from "@nomicfoundation/hardhat-chai-matchers/withArgs";
3
+ import { getAuctionID, buildAuctionCreatedReceipt, buildAuctionCreatedTx } from "../../src/auction/serialize";
4
+
5
+
6
+ import { expect } from "chai";
7
+ import { ethers, network } from "hardhat";
8
+ import { Contract, Wallet, Transaction, ContractTransaction, ContractReceipt } from "ethers";
9
+
10
+
11
+ interface AuctionValue{
12
+ value: bigint;
13
+ salt: string;
14
+ hashSecret: string;
15
+ }
16
+
17
+ describe("auction", function () {
18
+ let chainXAuction: Contract;
19
+ let chainYVault:Contract;
20
+ let coinBase:Contract;
21
+
22
+ let owner: any;
23
+ let seller: any;
24
+ let sellerWallet: Wallet;
25
+ let bidder1: any;
26
+ let bidder2: any;
27
+ let configId: bigint = BigInt(0);
28
+ let abiCoder=new ethers.utils.AbiCoder();
29
+
30
+ let auctionValue={
31
+ value: BigInt(100),
32
+ salt:ethers.utils.hexZeroPad("0x1234", 32),
33
+ hashSecret: ethers.utils.solidityKeccak256(
34
+ ["uint256", "bytes32"],
35
+ [BigInt(100), ethers.utils.hexZeroPad("0x1234", 32)]
36
+ )
37
+ };
38
+
39
+ // 测试数据
40
+ const auctionType = 0x00000000; // 密封竞标
41
+ const baseAmount = ethers.utils.parseEther("1.0");
42
+
43
+ const chainXId = 31337;
44
+ const chainYId = 22445;
45
+
46
+ const gasPrice = ethers.utils.parseUnits("1", "gwei").toBigInt();
47
+ const gasLimit = BigInt(52_200);
48
+
49
+
50
+
51
+ beforeEach(async function () {
52
+ [owner, bidder1, bidder2] = await ethers.getSigners();
53
+ seller = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266";
54
+ let sellerPk = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80";
55
+ sellerWallet = new ethers.Wallet(sellerPk);
56
+
57
+ const coinBaseFactory=await ethers.getContractFactory("CoinBase");
58
+ coinBase=await coinBaseFactory.deploy();
59
+ await coinBase.deployed();
60
+
61
+
62
+ const ChainYVaultFactory=await ethers.getContractFactory("ChainYVaultV2");
63
+ chainYVault=await ChainYVaultFactory.deploy(coinBase.address);
64
+ await chainYVault.deployed();
65
+
66
+
67
+ const ChainXAuctionV2 = await ethers.getContractFactory("ChainXAuctionV2");
68
+ chainXAuction = await ChainXAuctionV2.deploy(chainYVault.address);
69
+ await chainXAuction.deployed();
70
+ });
71
+
72
+ describe("punk链(Y链) 创建拍卖配置", function () {
73
+
74
+
75
+ it ("创建拍卖配置",async function(){
76
+ configId = await chainYVault.getActiveConfigsCount();
77
+ await chainYVault.createAuctionConfig(
78
+ auctionType,
79
+ baseAmount,
80
+ 86400 // 1天的扩展时间
81
+ );
82
+ });
83
+
84
+ it ("Y链创建拍卖",async function(){
85
+ const expiration = Math.floor(Date.now() / 1000) + 3600;
86
+ let auctionCreateTx:ContractTransaction = await chainYVault.connect(seller).createAucion(configId,auctionValue.hashSecret,expiration,{value:baseAmount})
87
+ let auctionCreateReceipt: ContractReceipt=await auctionCreateTx.wait();
88
+ const event = auctionCreateReceipt.events?.find(
89
+ (e: any) => e.event === "AuctionCreated"
90
+ );
91
+
92
+ expect(event).to.not.be.undefined;
93
+ const auctionId = event.args.auctionId;
94
+ const auction = await chainYVault.auctions(auctionId);
95
+ expect(auction.auctionType).to.equal(auctionType);
96
+ expect(auction.baseAmount).to.equal(baseAmount);
97
+ });
98
+
99
+ it ("X链创建拍卖",async function(){
100
+ const crossChainMessage=ethers.utils.defaultAbiCoder.encode(
101
+ ["tuple(uint256 sourceChainId, bytes rawTransaction, bytes rawRecpt)"],
102
+ [[chainYId, auctionCreateTx.rawTransaction, ]]
103
+ );
104
+ });
105
+ });
106
+ });
@@ -0,0 +1,26 @@
1
+
2
+ import { utils } from "ethers";
3
+ import { ethers } from "hardhat";
4
+ import { MUTI_VOUCHER_ADDR } from "../config/voucher.config";
5
+ import { RPC_URL} from "../config/env.config"
6
+
7
+ async function getCode(address:string){
8
+ const provider = new ethers.providers.JsonRpcProvider(RPC_URL);
9
+ const code = await provider.getCode(address);
10
+ if (code === "0x"){
11
+ console.log(`Contract ${address} is not deployed`);
12
+ }else{
13
+ console.log("contract code:",code)
14
+ }
15
+ }
16
+
17
+ // 判断是否链接到punk链
18
+ // npx hardhat run test/connect_punk.test.ts --network punk 命令可以执行
19
+ // TODO: 转化为test风格
20
+ function main(){
21
+ getCode(MUTI_VOUCHER_ADDR);
22
+ }
23
+
24
+ if (require.main === module){
25
+ main();
26
+ }
@@ -0,0 +1,44 @@
1
+ import { ethers } from "hardhat";
2
+ import { expect } from "chai";
3
+ import { Contract, BigNumber } from "ethers";
4
+ import { CONTRACT_ADDRESSES } from "../config/uniswap.config";
5
+
6
+ describe("create2 test", function () {
7
+ let value = BigInt(1000);
8
+ let create2: Contract;
9
+
10
+ beforeEach(async () => {
11
+ let [deployer] = await ethers.getSigners();
12
+ let Factory = await ethers.getContractFactory("Create2", deployer);
13
+ create2 = await Factory.deploy();
14
+ await create2.deployed();
15
+ });
16
+
17
+ it("deploy example.sol", async function () {
18
+
19
+ const Contract = await ethers.getContractFactory("Example");
20
+ const contract = await Contract.deploy(BigInt(1000));
21
+ await contract.deployed();
22
+
23
+ const storedValue: BigNumber = await contract.getValue();
24
+ expect(storedValue.toBigInt()).to.equal(value);
25
+
26
+ const newValue = BigInt(2000);
27
+ const tx = await contract.setValue(newValue);
28
+ await tx.wait();
29
+
30
+ const updatedValue: BigNumber = await contract.getValue();
31
+ expect(updatedValue.toBigInt()).to.equal(newValue);
32
+ });
33
+
34
+ it("judge address", async function () {
35
+ const tokenName = "Token0";
36
+ let tokenAddress = CONTRACT_ADDRESSES[tokenName];
37
+ tokenAddress = "0xa8aAB7BbAfC9bb277332b25B3C5BCA74534Df4A7"
38
+ if (await ethers.provider.getCode(tokenAddress) != "0x") {
39
+ console.log(`${tokenName} is deployed at address: ${tokenAddress}`);
40
+ } else {
41
+ console.log(`${tokenName} is not deployed`);
42
+ }
43
+ });
44
+ });
package/test/normal.ts ADDED
@@ -0,0 +1,43 @@
1
+
2
+ import { utils } from "ethers";
3
+ import { ethers } from "hardhat";
4
+ import { RPC_URL,CONTRACTS, CONTRACT_ADDRESSES } from "../config/uniswap.config";
5
+
6
+ async function getCode(address:string){
7
+ const provider = new ethers.providers.JsonRpcProvider(RPC_URL);
8
+ const code = await provider.getCode(address);
9
+ if (code === "0x"){
10
+ console.log(`Contract ${address} is not deployed`);
11
+ }
12
+ }
13
+
14
+ async function ConvertBytes32(){
15
+ const voucherName="BitCoin"
16
+ const voucherNameByte32=ethers.utils.formatBytes32String(voucherName);
17
+ console.log("voucherNameByte32:",voucherNameByte32);
18
+
19
+ let parseNameString=ethers.utils.parseBytes32String(voucherNameByte32);
20
+ console.log("parseNameString:",parseNameString);
21
+ }
22
+
23
+
24
+ function main(){
25
+ const name = "InvalidTickLower()";
26
+ const selector = utils.id(name).substring(0, 10)
27
+ console.log("%s abi encode:%s",name,selector);
28
+
29
+ ConvertBytes32()
30
+ // const encoded = utils.defaultAbiCoder.encode(["string"], [name]);
31
+ // console.log(encoded);
32
+ // getCode(CONTRACT_ADDRESSES.Create2);
33
+ // getCode(CONTRACT_ADDRESSES.Token0);
34
+ // getCode(CONTRACT_ADDRESSES.Token1);
35
+ // getCode(CONTRACT_ADDRESSES.PoolManager);
36
+ // getCode(CONTRACT_ADDRESSES.LiquidPool);
37
+ // getCode(CONTRACT_ADDRESSES.LimitOrder);
38
+ // getCode(CONTRACT_ADDRESSES.DynamicFee);
39
+ }
40
+
41
+ if (require.main === module){
42
+ main();
43
+ }
@@ -0,0 +1,18 @@
1
+ import { config } from "../config/env.config";
2
+
3
+ console.log("=== 配置验证 ===\n");
4
+
5
+ console.log("ABI 根目录:", config.paths.abiRootDir);
6
+ console.log("\n完整 ABI 路径:");
7
+ console.log("- PoolManager:", config.abiPaths.uniswap.poolManager);
8
+ console.log("- MockERC20:", config.abiPaths.uniswap.mockERC20);
9
+ console.log("- ChainYVault:", config.abiPaths.auction.chainYVault);
10
+ console.log("- ChainXAuction:", config.abiPaths.auction.chainXAuction);
11
+
12
+ console.log("\n合约地址:");
13
+ console.log("- Token0:", config.contracts.uniswap.token0);
14
+ console.log("- PoolManager:", config.contracts.uniswap.poolManager);
15
+
16
+ console.log("\nPool 配置:");
17
+ console.log("- PRICE_INIT:", config.pool.priceInit);
18
+ console.log("- INITIAL_LIQUIDITY:", config.pool.initialLiquidity.toString());
@@ -0,0 +1,62 @@
1
+ import { ethers } from "hardhat";
2
+ import { expect } from "chai";
3
+ import { Contract, BigNumber } from "ethers";
4
+
5
+ describe("Example", function () {
6
+ let value=BigInt(1000);
7
+ let contract: Contract;
8
+
9
+ beforeEach(async () => {
10
+ let [deployer, addr1, addr2] = await ethers.getSigners();
11
+ let Factory = await ethers.getContractFactory("Example", deployer);
12
+ contract = await Factory.deploy(value);
13
+ await contract.deployed();
14
+ });
15
+
16
+ it("initial and store",async function() {
17
+ const storedValue: BigNumber = await contract.getValue();
18
+ expect(storedValue.toBigInt()).to.equal(value);
19
+
20
+ const newValue = BigInt(2000);
21
+ const tx = await contract.setValue(newValue);
22
+ await tx.wait();
23
+
24
+ const updatedValue: BigNumber = await contract.getValue();
25
+ expect(updatedValue.toBigInt()).to.equal(newValue);
26
+ });
27
+ });
28
+
29
+ describe("Example2", function () {
30
+ let value="Hello World!";
31
+ let contract: Contract;
32
+ let contractNmae="Example2";
33
+
34
+ beforeEach(async () => {
35
+ let [deployer] = await ethers.getSigners();
36
+ let Factory = await ethers.getContractFactory(contractNmae, deployer);
37
+ contract = await Factory.deploy();
38
+ await contract.deployed();
39
+ });
40
+
41
+ it("initial and store",async function() {
42
+ const storedValue = await contract.getName();
43
+ console.log(storedValue);
44
+ expect(storedValue).to.equal(value);
45
+
46
+ const tx = await contract.setName(value);
47
+ await tx.wait();
48
+
49
+ const updatedValue = await contract.getName();
50
+ console.log(updatedValue);
51
+ expect(updatedValue).to.equal(value);
52
+ });
53
+ });
54
+
55
+ describe("normal test", function () {
56
+ it("hex concat example", function () {
57
+ const hex1 = "0x1111";
58
+ const hex2 = "0x2222";
59
+ const result = ethers.utils.hexConcat([hex1, hex2]);
60
+ console.log(`result: ${result}`);
61
+ });
62
+ });
@@ -0,0 +1,184 @@
1
+ import { ethers } from "hardhat";
2
+ import { expect } from "chai";
3
+ // LoadFixture is used to set up a fresh blockchain state for each test
4
+ import { loadFixture } from "@nomicfoundation/hardhat-network-helpers";
5
+
6
+ describe("LimitOrder", function () {
7
+ const TICK_SPACING = 10;
8
+ const SWAP_FEE = 3000;
9
+ const sqrtPriceX96 = ethers.utils.parseEther("1");
10
+
11
+ async function deployFixture() {
12
+ const [deployer, user] = await ethers.getSigners();
13
+
14
+ const MockERC20Factory = await ethers.getContractFactory("MockERC20", deployer);
15
+ const token0 = await MockERC20Factory.deploy("Token0", "T0", 18);
16
+ const token1 = await MockERC20Factory.deploy("Token1", "T1", 18);
17
+
18
+ // Ensure token0 is "less than" token1 for pool key purposes
19
+ const [sortedToken0, sortedToken1] =
20
+ (token0.address).toLowerCase() < (token1.address).toLowerCase()
21
+ ? [token0, token1]
22
+ : [token1, token0];
23
+
24
+ const PoolManagerFactory = await ethers.getContractFactory("PoolManager", deployer);
25
+ const PoolManager = await PoolManagerFactory.deploy(user.address);
26
+
27
+ const LimitOrderFactory = await ethers.getContractFactory("LimitOrder", deployer);
28
+ const limitOrder = await LimitOrderFactory.deploy(PoolManager.address);
29
+
30
+ const poolKey = {
31
+ currency0: sortedToken0.address,
32
+ currency1: sortedToken1.address,
33
+ fee: SWAP_FEE,
34
+ tickSpacing: TICK_SPACING,
35
+ hooks: limitOrder.address,
36
+ };
37
+
38
+ // Mint some tokens for the user
39
+ const initialAmount = ethers.utils.parseEther("1000");
40
+ await sortedToken0.mint(user.address, initialAmount);
41
+ await sortedToken1.mint(user.address, initialAmount);
42
+
43
+ // User approves PoolManager contract to spend their tokens, as it's the one pulling funds
44
+ await sortedToken0.connect(user).approve(PoolManager.address, ethers.constants.MaxUint256);
45
+ await sortedToken1.connect(user).approve(PoolManager.address, ethers.constants.MaxUint256);
46
+
47
+ // Initialize PoolManager's pool state (mock)
48
+ await PoolManager.initialize(poolKey, sqrtPriceX96);
49
+
50
+ // Initialize add liquidity
51
+ const modifyPositionParams={
52
+ tickLower: -TICK_SPACING * 10,
53
+ tickUpper: TICK_SPACING * 10,
54
+ liquidityDelta: ethers.utils.parseEther("1000"),
55
+ };
56
+ const tx = await PoolManager.addLiquidity(modifyPositionParams, "");
57
+ await tx.wait();
58
+
59
+ return {
60
+ deployer,
61
+ user,
62
+ token0: sortedToken0,
63
+ token1: sortedToken1,
64
+ PoolManager,
65
+ limitOrder,
66
+ poolKey,
67
+ };
68
+ }
69
+
70
+ describe("Placing a limit order", function () {
71
+ it("Should allow a user to place a limit order", async function () {
72
+ const { user, limitOrder, poolKey, token0, PoolManager } = await loadFixture(deployFixture);
73
+ const orderAmount = ethers.utils.parseEther("10");
74
+ const tickLower = -10;
75
+ const zeroForOne = true;
76
+ const initialUserBalance = await token0.balanceOf(user.address);
77
+
78
+ await expect(limitOrder.connect(user).place(poolKey, tickLower, zeroForOne, orderAmount))
79
+ .to.emit(limitOrder, "Place");
80
+
81
+ const finalUserBalance = await token0.balanceOf(user.address);
82
+ const poolManagerBalance = await token0.balanceOf(PoolManager.address);
83
+
84
+ // User's balance decreases
85
+ expect(finalUserBalance).to.be.lt(initialUserBalance);
86
+ // PoolManager's balance increases
87
+ expect(poolManagerBalance).to.be.gt(0);
88
+ });
89
+ });
90
+
91
+ describe("Filling a limit order", function () {
92
+ it("Should fill a limit order after a swap", async function () {
93
+ const { user, limitOrder, PoolManager, poolKey, token0, token1 } = await loadFixture(deployFixture);
94
+ const orderAmount = ethers.utils.parseEther("10");
95
+ const tickLower = -10;
96
+ const zeroForOne = true;
97
+
98
+ // Place order
99
+ await limitOrder.connect(user).place(poolKey, tickLower, zeroForOne, orderAmount);
100
+ const epoch = await limitOrder.getEpoch(poolKey, tickLower, zeroForOne);
101
+
102
+ // Simulate a swap that crosses the tick
103
+ // Set current tick on mock pool manager to be past the order's tick
104
+ await PoolManager.setTick(tickLower - TICK_SPACING);
105
+
106
+ const swapParams = {
107
+ zeroForOne: false, // Swap direction is opposite of limit order direction
108
+ amountSpecified: ethers.utils.parseEther("-1"), // negative for exact output
109
+ sqrtPriceLimitX96: 0,
110
+ };
111
+
112
+ const salt = ethers.utils.formatBytes32String("test");
113
+ const hookData = ethers.utils.defaultAbiCoder.encode(["bytes32"], [salt]);
114
+
115
+ // The pool manager would call this hook after a swap
116
+ await limitOrder.afterSwap(user.address, poolKey, swapParams, "0x", hookData);
117
+
118
+ const epochInfo = await limitOrder.epochInfos(epoch);
119
+ expect(epochInfo.filled).to.be.true;
120
+
121
+ // The limit order contract should now hold the filled tokens (token1 in this case)
122
+ const contractToken1Balance = await token1.balanceOf(limitOrder.address);
123
+ expect(contractToken1Balance).to.be.gt(0);
124
+ });
125
+ });
126
+
127
+ describe("Killing/cancelling a limit order", function () {
128
+ it("Should allow a user to cancel their limit order", async function () {
129
+ const { user, limitOrder, poolKey, token0 } = await loadFixture(deployFixture);
130
+ const orderAmount = ethers.utils.parseEther("10");
131
+ const tickLower = -10;
132
+ const zeroForOne = true;
133
+ const initialUserBalance = await token0.balanceOf(user.address);
134
+
135
+ // Place order
136
+ await limitOrder.connect(user).place(poolKey, tickLower, zeroForOne, orderAmount);
137
+
138
+ const balanceAfterPlace = await token0.balanceOf(user.address);
139
+ expect(balanceAfterPlace).to.be.lt(initialUserBalance);
140
+
141
+ // Kill order
142
+ await expect(limitOrder.connect(user).kill(poolKey, tickLower, zeroForOne, user.address))
143
+ .to.emit(limitOrder, "Kill");
144
+
145
+ // User should get their tokens back
146
+ const finalUserBalance = await token0.balanceOf(user.address);
147
+ expect(finalUserBalance).to.equal(initialUserBalance);
148
+ });
149
+ });
150
+
151
+ describe("Withdrawing from a filled limit order", function () {
152
+ it("Should allow a user to withdraw from a filled order", async function () {
153
+ const { user, limitOrder, PoolManager, poolKey, token1 } = await loadFixture(deployFixture);
154
+ const orderAmount = ethers.utils.parseEther("10");
155
+ const tickLower = -10;
156
+ const zeroForOne = true;
157
+
158
+ // Place order
159
+ await limitOrder.connect(user).place(poolKey, tickLower, zeroForOne, orderAmount);
160
+ const epoch = await limitOrder.getEpoch(poolKey, tickLower, zeroForOne);
161
+
162
+ // Simulate swap and fill
163
+ await PoolManager.setTick(tickLower - TICK_SPACING);
164
+ const swapParams = { zeroForOne: false, amountSpecified: ethers.utils.parseEther("-1"), sqrtPriceLimitX96: 0 };
165
+ const salt = ethers.utils.formatBytes32String("test");
166
+ const hookData = ethers.utils.defaultAbiCoder.encode(["bytes32"], [salt]);
167
+ await limitOrder.afterSwap(user.address, poolKey, swapParams, "0x", hookData);
168
+
169
+ const initialUserToken1Balance = await token1.balanceOf(user.address);
170
+
171
+ // Withdraw
172
+ await expect(limitOrder.connect(user).withdraw(epoch, user.address))
173
+ .to.emit(limitOrder, "Withdraw");
174
+
175
+ // User should have received the filled tokens
176
+ const finalUserToken1Balance = await token1.balanceOf(user.address);
177
+ expect(finalUserToken1Balance).to.be.gt(initialUserToken1Balance);
178
+
179
+ // Contract should have no more of the filled tokens for this order
180
+ const contractToken1Balance = await token1.balanceOf(limitOrder.address);
181
+ expect(contractToken1Balance).to.equal(0);
182
+ });
183
+ });
184
+ });
@@ -0,0 +1,142 @@
1
+ import { ethers } from "hardhat";
2
+ import { expect } from "chai";
3
+ import { Contract, Signer, BigNumber } from "ethers";
4
+ import { CONTRACTS, CONTRACT_ADDRESSES, PRIVATE_KEY, RPC_URL } from "../../config/uniswap.config";
5
+
6
+ describe("MockERC20", function () {
7
+ let token: Contract;
8
+ let owner: Signer;
9
+ let addr1: Signer;
10
+ let addr2: Signer;
11
+
12
+ const tokenName = "Mock Token";
13
+ const tokenSymbol = "MCK";
14
+ // 初始供应量为 1000 个代币 (假设18位小数)
15
+ const initialSupply = ethers.utils.parseEther("1000");
16
+
17
+ beforeEach(async function () {
18
+ // 获取测试账户
19
+ [owner, addr1, addr2] = await ethers.getSigners();
20
+
21
+ // 部署合约
22
+ const MockERC20Factory = await ethers.getContractFactory("MockERC20", owner);
23
+ token = await MockERC20Factory.deploy(tokenName, tokenSymbol, initialSupply);
24
+ await token.deployed();
25
+ });
26
+
27
+ describe("Deployment", function () {
28
+ it("Should set the right name and symbol", async function () {
29
+ expect(await token.name()).to.equal(tokenName);
30
+ expect(await token.symbol()).to.equal(tokenSymbol);
31
+ });
32
+
33
+ it("Should assign the total supply of tokens to the owner", async function () {
34
+ const ownerAddress = await owner.getAddress();
35
+ const ownerBalance = await token.balanceOf(ownerAddress);
36
+ expect(await token.totalSupply()).to.equal(ownerBalance);
37
+ expect(ownerBalance).to.equal(initialSupply);
38
+ });
39
+ });
40
+
41
+ describe("Transactions", function () {
42
+ it("Should transfer tokens between accounts", async function () {
43
+ const ownerAddress = await owner.getAddress();
44
+ const addr1Address = await addr1.getAddress();
45
+ const transferAmount = ethers.utils.parseEther("50");
46
+
47
+ // 从 owner 转 50 个代币到 addr1
48
+ await token.connect(owner).transfer(addr1Address, transferAmount);
49
+ const addr1Balance = await token.balanceOf(addr1Address);
50
+ expect(addr1Balance).to.equal(transferAmount);
51
+
52
+ // 从 addr1 转 20 个代币到 addr2
53
+ const addr2Address = await addr2.getAddress();
54
+ const transferAmount2 = ethers.utils.parseEther("20");
55
+ await token.connect(addr1).transfer(addr2Address, transferAmount2);
56
+ const addr2Balance = await token.balanceOf(addr2Address);
57
+ expect(addr2Balance).to.equal(transferAmount2);
58
+ });
59
+
60
+ it("Should fail if sender doesn’t have enough tokens", async function () {
61
+ const ownerAddress = await owner.getAddress();
62
+ const addr1Address = await addr1.getAddress();
63
+ const initialOwnerBalance = await token.balanceOf(ownerAddress);
64
+
65
+ // 尝试从 addr1 (余额为0) 转账
66
+ const value = 1;
67
+ await expect(token.connect(addr1).transfer(ownerAddress, value))
68
+ .to.be.revertedWithCustomError(token, "ERC20InsufficientBalance")
69
+ .withArgs(addr1Address, 0, value); // address,balance,transfer amount
70
+
71
+ // 确认 owner 余额未变
72
+ expect(await token.balanceOf(ownerAddress)).to.equal(initialOwnerBalance);
73
+ });
74
+ });
75
+
76
+ describe("Approval", function () {
77
+ it("Should allow a spender to transfer tokens after approval", async function () {
78
+ const ownerAddress = await owner.getAddress();
79
+ const addr1Address = await addr1.getAddress();
80
+ const addr2Address = await addr2.getAddress();
81
+ const amountToApprove = ethers.utils.parseEther("100");
82
+
83
+ // Owner 授权 addr1 可以动用 100 个代币
84
+ await token.connect(owner).approve(addr1Address, amountToApprove);
85
+ const allowance = await token.allowance(ownerAddress, addr1Address);
86
+ expect(allowance).to.equal(amountToApprove);
87
+
88
+ // Addr1 使用 transferFrom 将 owner 的 50 个代币转给 addr2
89
+ const amountToTransfer = ethers.utils.parseEther("50");
90
+ await token.connect(addr1).transferFrom(ownerAddress, addr2Address, amountToTransfer);
91
+
92
+ // 检查余额
93
+ expect(await token.balanceOf(ownerAddress)).to.equal(initialSupply.sub(amountToTransfer));
94
+ expect(await token.balanceOf(addr2Address)).to.equal(amountToTransfer);
95
+
96
+ // 检查剩余授权额度
97
+ const remainingAllowance = await token.allowance(ownerAddress, addr1Address);
98
+ expect(remainingAllowance).to.equal(amountToApprove.sub(amountToTransfer));
99
+ });
100
+ });
101
+
102
+ describe("Minting", function () {
103
+ it("Should allow minting new tokens to any address", async function () {
104
+ const addr1Address = await addr1.getAddress();
105
+ const mintAmount = ethers.utils.parseEther("200");
106
+ const initialTotalSupply = await token.totalSupply();
107
+
108
+ // 给 addr1 增发 200 个代ar币
109
+ await token.connect(owner).mint(addr1Address, mintAmount);
110
+
111
+ // 检查 addr1 余额和总供应量
112
+ expect(await token.balanceOf(addr1Address)).to.equal(mintAmount);
113
+ expect(await token.totalSupply()).to.equal(initialTotalSupply.add(mintAmount));
114
+ });
115
+ });
116
+ });
117
+
118
+ describe("Deterministic deployment of MockERC20", function () {
119
+ const tokenName = "BitCoin"
120
+ const tokenSymbol = "BTC"
121
+ const initialSupply = ethers.utils.parseUnits("2100000", 18).toBigInt();
122
+ let walletAddress = "0x";
123
+ let token0Address = CONTRACT_ADDRESSES["Token0"];
124
+ let wallet: Signer;
125
+ let token: Contract;
126
+
127
+ beforeEach(async function () {
128
+ const provider = new ethers.providers.JsonRpcProvider(RPC_URL);
129
+ wallet = new ethers.Wallet(PRIVATE_KEY, provider);
130
+ walletAddress = await wallet.getAddress();
131
+ });
132
+
133
+ it("Owner", async function () {
134
+ const token = await ethers.getContractAt("MockERC20", token0Address, wallet);
135
+ let res: bigint = await token.balanceOf(walletAddress);
136
+ console.log(res.toString());
137
+
138
+ res = await token.balanceOf(CONTRACT_ADDRESSES["Create2"]);
139
+ console.log(res.toString())
140
+ });
141
+
142
+ });