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.
- package/.env +47 -0
- package/.gitmodules +3 -0
- package/README.md +158 -0
- package/config/auction.config.ts +40 -0
- package/config/env.config.ts +204 -0
- package/config/uniswap.config.ts +107 -0
- package/config/voucher.config.ts +10 -0
- package/contracts/MutiVoucher.sol +78 -0
- package/contracts/auction/ChainXAuction.sol +177 -0
- package/contracts/auction/ChainXAuctionV2.sol +672 -0
- package/contracts/auction/ChainXWrappedETH.sol +80 -0
- package/contracts/auction/ChainYLiquidityManager.sol +57 -0
- package/contracts/auction/ChainYShadowETH.sol +148 -0
- package/contracts/auction/ChainYVault.sol +195 -0
- package/contracts/auction/ChainYVaultCoinbase.sol +276 -0
- package/contracts/auction/ChainYVaultV2.sol +318 -0
- package/contracts/auction/coinbase-and-stake/README.md +55 -0
- package/contracts/auction/coinbase-and-stake/coinbase.sol +142 -0
- package/contracts/auction/coinbase-and-stake/invokeCoinbase.sol +159 -0
- package/contracts/auction/coinbase-and-stake/invokeStake.sol +82 -0
- package/contracts/auction/coinbase-and-stake/stake.sol +92 -0
- package/contracts/auction/interfaces/IUniswapV2Factory.sol +15 -0
- package/contracts/auction/interfaces/IUniswapV2Pair.sol +53 -0
- package/contracts/auction/interfaces/IUniswapV2Router02.sol +25 -0
- package/contracts/auction/interfaces/IUnlockStrategy.sol +18 -0
- package/contracts/auction/libraries/EventParser.sol +32 -0
- package/contracts/auction/libraries/TransactionParser.sol +70 -0
- package/contracts/auction/strategies/MatchResultWithdrawnStrategy.sol +33 -0
- package/contracts/auction/utils/BytesLib.sol +180 -0
- package/contracts/auction/utils/RLPReader.sol +355 -0
- package/contracts/uniswap/Create2.sol +80 -0
- package/contracts/uniswap/DynamicFee.sol +100 -0
- package/contracts/uniswap/Example.sol +35 -0
- package/contracts/uniswap/HookMiner.sol +52 -0
- package/contracts/uniswap/LimitOrder.sol +486 -0
- package/contracts/uniswap/LiquidPool.sol +179 -0
- package/contracts/uniswap/MockERC20.sol +20 -0
- package/hardhat.config.ts +35 -0
- package/ignition/modules/LimitOrder.ts +33 -0
- package/package.json +32 -0
- package/scripts/auction/deploy.ts +23 -0
- package/scripts/auction/deployCoinbase.ts +21 -0
- package/scripts/auction/deployXAuction.ts +23 -0
- package/scripts/auction/deployYVault.ts +22 -0
- package/scripts/deploy_voucher.ts +20 -0
- package/scripts/uniswap/deploy/deploy.ts +65 -0
- package/scripts/uniswap/deploy/deploy_create2.ts +11 -0
- package/scripts/uniswap/deploy/deploy_example.ts +35 -0
- package/scripts/uniswap/deploy/deploy_hooks.ts +74 -0
- package/scripts/uniswap/deploy/deploy_mockERC20.ts +42 -0
- package/scripts/uniswap/deploy/help.ts +96 -0
- package/scripts/uniswap/deploy/init.ts +70 -0
- package/src/auction/chainXAuction.ts +209 -0
- package/src/auction/chainYVault.ts +153 -0
- package/src/auction/event.ts +19 -0
- package/src/auction/serialize.ts +162 -0
- package/src/auction/type.ts +71 -0
- package/src/lib/signer.ts +20 -0
- package/src/lib/unlock.ts +14 -0
- package/src/uniswap/1-marketprice/addLiquidity.ts +80 -0
- package/src/uniswap/1-marketprice/removeLiquidity.ts +63 -0
- package/src/uniswap/1-marketprice/swap.ts +100 -0
- package/src/uniswap/2-limitorder/kill.ts +70 -0
- package/src/uniswap/2-limitorder/place.ts +93 -0
- package/src/uniswap/2-limitorder/withdraw.ts +78 -0
- package/src/uniswap/3-dynamicfee/dynamicfee.ts +321 -0
- package/src/uniswap/lib/ERC20.ts +49 -0
- package/src/uniswap/lib/contract.ts +18 -0
- package/src/uniswap/lib/limitOrder.ts +40 -0
- package/src/uniswap/lib/liqCalculation.ts +152 -0
- package/src/uniswap/lib/listen.ts +57 -0
- package/src/uniswap/lib/pool.ts +62 -0
- package/src/uniswap/lib/swap.ts +8 -0
- package/src/uniswap/lib/types.ts +21 -0
- package/src/uniswap/lib/utils.ts +26 -0
- package/src/uniswap/playgroud/abiencode.ts +21 -0
- package/src/uniswap/playgroud/amount0.ts +47 -0
- package/src/uniswap/playgroud/errordecode.ts +54 -0
- package/src/uniswap/playgroud/errorsigs.ts +86 -0
- package/src/voucher.ts +122 -0
- package/test/auction/ChainXAuctionV2.test.ts +265 -0
- package/test/auction/ChainYVaultV2.test.js +163 -0
- package/test/auction/ChainYVaultV2.test.ts +183 -0
- package/test/auction/auction.test.ts +106 -0
- package/test/connect_punk.test.ts +26 -0
- package/test/create2.test.ts +44 -0
- package/test/normal.ts +43 -0
- package/test/test-config.ts +18 -0
- package/test/uniswap/example.test.ts +62 -0
- package/test/uniswap/limitOrder.test.ts +184 -0
- package/test/uniswap/mockERC20.test.ts +142 -0
- package/test/voucher_hardhat.test.ts +120 -0
- package/test/voucher_punk.test.ts +83 -0
- package/tsconfig.json +11 -0
package/.env
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# RPC 和 钱包配置。使用hardhat本地测试时候需要注释掉,会使用hardhat默认rpc以及账户
|
|
2
|
+
RPC_URL= "http://127.0.0.1:8666"
|
|
3
|
+
PRIVATE_KEY="0x6c19b85fa2d365e74b4b36556e1369fb9d680789e6e9350f9b62412efe3a76cc"
|
|
4
|
+
ACCOUNT_ADDR="0x9748b3f8B628f11abD2474085DD44F8ffD8EB3e6"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# 地址配置
|
|
8
|
+
Coinbase="0xAa9e62EB6d74d66Ff6720D1A8143c8237067Ff58"
|
|
9
|
+
ChainYVaultV2="0xAa9e62EB6d74d66Ff6720D1A8143c8237067Ff58"
|
|
10
|
+
ChainXAuctionV2="0x88566F811b751Fa527A0816d99d6968E00f2eBef"
|
|
11
|
+
IUnlockStrategy=""
|
|
12
|
+
|
|
13
|
+
Create2= "0x5FbDB2315678afecb367f032d93F642f64180aa3"
|
|
14
|
+
Token0= "0x3E8d9Ad590542AE8731960202CE0334B5c7c317D"
|
|
15
|
+
Token1= "0xF8407E61094a14601a7224AB628152B309788659"
|
|
16
|
+
PoolManager= "0xDB0412DaB8210ccA6d9875eE0be7b580A3c12046"
|
|
17
|
+
LiquidPool= "0x931D3dd4922c67C2C727c2Cf20313c5e541cB7A3"
|
|
18
|
+
LimitOrder= "0x2267dCcfebEa4C2A54A14F7ffa997a089Eb99040"
|
|
19
|
+
DynamicFee= "0x53660445Cda97cAD89c88cA67C099418412AD040"
|
|
20
|
+
|
|
21
|
+
MutiVoucher="0000000000000000000000000000000000000044"
|
|
22
|
+
# ABI配置
|
|
23
|
+
IUnlockStrategy_abi_path='artifacts/contracts/auction/interfaces/IUnlockStrategy.sol/IUnlockStrategy.json'
|
|
24
|
+
ChainYVault_abi_path='artifacts/contracts/auction/ChainYVaultV2.sol/ChainYVaultV2.json'
|
|
25
|
+
ChainXAuction_abi_path='artifacts/contracts/auction/ChainXAuctionV2.sol/ChainXAuctionV2.json'
|
|
26
|
+
Coinbase_abi_path='artifacts/contracts/auction/coinbase-and-stake/coinbase.sol/Coinbase.json'
|
|
27
|
+
|
|
28
|
+
PoolManager_abi_path='artifacts/@uniswap/v4-core/src/PoolManager.sol/PoolManager.json'
|
|
29
|
+
MockERC20_abi_path='artifacts/contracts/uniswap/MockERC20.sol/MockERC20.json'
|
|
30
|
+
LiquidPool_abi_path='artifacts/contracts/uniswap/LiquidPool.sol/LiquidPool.json'
|
|
31
|
+
LimitOrder_abi_path='artifacts/contracts/uniswap/LimitOrder.sol/LimitOrder.json'
|
|
32
|
+
DynamicFee_abi_path='artifacts/contracts/uniswap/DynamicFee.sol/DynamicFee.json'
|
|
33
|
+
Create2_abi_path='artifacts/contracts/uniswap/Create2.sol/Create2.json'
|
|
34
|
+
Example_abi_path='artifacts/contracts/uniswap/Example.sol/Example.json'
|
|
35
|
+
|
|
36
|
+
MutiVoucher_abi_path='artifacts/contracts/MutiVoucher.sol/MutiVoucher.json'
|
|
37
|
+
|
|
38
|
+
# uniswap 全局配置
|
|
39
|
+
# SALT 用于 Create2 部署
|
|
40
|
+
SALT="0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
|
|
41
|
+
SALT_LIMITORDER="0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6"
|
|
42
|
+
# 价格配置 (1 token0 = PRICE_INIT token1)
|
|
43
|
+
PRICE_INIT=1
|
|
44
|
+
PRICE_LIMIT=1.1
|
|
45
|
+
# 初始流动性和供应量 (单位: ETH)
|
|
46
|
+
INITIAL_LIQUIDITY=1000
|
|
47
|
+
INITIAL_SUPPLY=210000000
|
package/.gitmodules
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# Uniswap V4 Hook Deployment & Use cases
|
|
2
|
+
|
|
3
|
+
## 1. Run Uniswap V4 built-in tests
|
|
4
|
+
|
|
5
|
+
In [Uniswap V4 core](https://github.com/Uniswap/v4-core) repo:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx hardhat test
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 2. Compile pool and hook contracts
|
|
12
|
+
|
|
13
|
+
In [Our Uniswap v4 periphery](https://github.com/tofudfy/v4-periphery) repo:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx hardhat compile
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Move the required ABI files from `artifacts/contracts` to [SDK repo](https://github.com/tofudfy/v4-sdk) `scripts/frontend/abi`.
|
|
20
|
+
|
|
21
|
+
## 3. Deploy pool and hook contracts
|
|
22
|
+
|
|
23
|
+
In [Our Uniswap V4 SDK](https://github.com/tofudfy/v4-sdk) repo:
|
|
24
|
+
|
|
25
|
+
1. Start a local blockchain node
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npx hardhat node
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
2. Deploy [Uniswap V4 core](https://github.com/Uniswap/v4-core) contracts
|
|
32
|
+
|
|
33
|
+
3. Configure blockchain networks, wallet, and contract addresses in:
|
|
34
|
+
`scripts/config.ts`
|
|
35
|
+
|
|
36
|
+
4. Run the hook deployment script:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npx hardhat run scripts/depoly/depoly.ts
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
- Limit Order Hook: `contracts/LimitOrder.sol`
|
|
43
|
+
- Dynamic Fee Hook: `contracts/DynamicFee.sol`
|
|
44
|
+
|
|
45
|
+
## 4. Initialize the PoolManager contract
|
|
46
|
+
|
|
47
|
+
Run the initialization script:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npx hardhat run scripts/frontend/init/init.ts
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## 5. Contract interactions
|
|
54
|
+
|
|
55
|
+
### 5.1 Trading at Market Price
|
|
56
|
+
|
|
57
|
+
- Add liquidity:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npx hardhat run scripts/frontend/marketprice/addLiquidity.ts
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
- Swap:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npx hardhat run scripts/frontend/marketprice/swap.ts
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
- Remove liquidity:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npx hardhat run scripts/frontend/marketprice/removeLiquidity.ts
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 5.2 Trading of Limit Order
|
|
76
|
+
|
|
77
|
+
(*Requires `addLiquidity` operation first, otherwise order placement will fail*)
|
|
78
|
+
|
|
79
|
+
- Place order:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
npx hardhat run scripts/frontend/limitorder/place.ts
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
- [Todo] Cancel order:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
npx hardhat run scripts/frontend/limitorder/kill.ts
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
- [Todo] Withdraw liquidity:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
npx hardhat run scripts/frontend/limitorder/withdraw.ts
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### 5.3 Dynamic fee
|
|
98
|
+
|
|
99
|
+
- Adjust fee:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
npx hardhat test scripts/feehook/testfeehook.ts
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## UniswapV4及hook部署使用
|
|
106
|
+
|
|
107
|
+
1. 运行uniswapv4自带测试:
|
|
108
|
+
命令行输入`npx hardhat test`
|
|
109
|
+
2. 合约编译:`npx hardhat compile`
|
|
110
|
+
将必要的abi文件从`artifacts/contracts`移至`scripts/frontend/abi`
|
|
111
|
+
3. 部署uniswapv4合约以及hook合约:
|
|
112
|
+
1. 运行本地区块链节点网络:`npx hardhat node`
|
|
113
|
+
2. 配置文件,配置区块链网络、钱包以及合约地址:`scripts/frontend/lib/address.ts`
|
|
114
|
+
3. hook合约部署脚本:`npx hardhat run scripts/frontend/depoly/depoly.ts`
|
|
115
|
+
+ 限价交易hook:`contracts/LimitOrder.sol`
|
|
116
|
+
+ 动态手续费hook:`contracts/DynamicFee.sol`
|
|
117
|
+
|
|
118
|
+
4. 初始化poolmanager合约:
|
|
119
|
+
运行初始化脚本:`npx hardhat run scripts/frontend/init/init.ts`
|
|
120
|
+
|
|
121
|
+
5. 合约调用:
|
|
122
|
+
1. 市价交易:
|
|
123
|
+
+ 添加流动性:`npx hardhat run scripts/frontend/marketprice/addLiquidity.ts`
|
|
124
|
+
+ 交易:`npx hardhat run scripts/frontend/marketprice/swap.ts`
|
|
125
|
+
+ 撤销流动性:`npx hardhat run scripts/frontend/marketprice/removeLiquidity.ts`
|
|
126
|
+
2. 限价交易:(接`添加流动性`操作,否则无法正常`挂单`)
|
|
127
|
+
+ 挂单:`npx hardhat run scripts/frontend/limitorder/place.ts`
|
|
128
|
+
+ [失败]撤单:`npx hardhat run scripts/frontend/limitorder/kill.ts`
|
|
129
|
+
+ [失败]提取流动性:`npx hardhat run scripts/frontend/limitorder/withdraw.ts`
|
|
130
|
+
3. 动态手续费:
|
|
131
|
+
+ [存疑]调整手续费:`npx hardhat test scripts/feehook/testfeehook.ts`
|
|
132
|
+
## 待完成事项
|
|
133
|
+
|
|
134
|
+
+ 类似挖矿的流动性激励hook合约
|
|
135
|
+
|
|
136
|
+
# lq documents
|
|
137
|
+
|
|
138
|
+
## 部署
|
|
139
|
+
| 依赖 | 版本 |
|
|
140
|
+
| ---- | ---- |
|
|
141
|
+
| nvm | 0.39.7 |
|
|
142
|
+
| npm | v20.19.5 |
|
|
143
|
+
|
|
144
|
+
运行命令:
|
|
145
|
+
```shell
|
|
146
|
+
npm install
|
|
147
|
+
|
|
148
|
+
npx hardhat node # 单独使用命令行执行
|
|
149
|
+
|
|
150
|
+
npx hardhat run scripts/deploy/deploy.ts
|
|
151
|
+
npx hardhat run scripts/deploy/inits.ts
|
|
152
|
+
```
|
|
153
|
+
## 测试
|
|
154
|
+
voucher测试通过
|
|
155
|
+
|
|
156
|
+
```shell
|
|
157
|
+
npx hardhat test test/voucher.ts
|
|
158
|
+
```
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import {
|
|
2
|
+
RPC_URL,
|
|
3
|
+
PRIVATE_KEY,
|
|
4
|
+
config,
|
|
5
|
+
} from "./env.config";
|
|
6
|
+
import {join} from "path";
|
|
7
|
+
|
|
8
|
+
const chainXAuctionV2Addr=config.contracts.auction.chainXAuctionV2;
|
|
9
|
+
const chainYVaultV2Addr=config.contracts.auction.chainYVaultV2;
|
|
10
|
+
const coinbaseAddr=config.contracts.auction.coinbase;
|
|
11
|
+
|
|
12
|
+
const AUCTION_ADDR={
|
|
13
|
+
chainXAuction:chainXAuctionV2Addr,
|
|
14
|
+
chainYVault:chainYVaultV2Addr,
|
|
15
|
+
coinbase:coinbaseAddr,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// ABI路径
|
|
19
|
+
const ABI_PATHS = config.abiPaths.auction;
|
|
20
|
+
function relativePath(filepath:string):string{
|
|
21
|
+
const ROOT = '..';
|
|
22
|
+
return join(ROOT,filepath)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const AUCTION_ABI = {
|
|
26
|
+
coinbase: require(relativePath(ABI_PATHS.coinbase)),
|
|
27
|
+
chainXAuction: require(relativePath(ABI_PATHS.chainXAuction)),
|
|
28
|
+
chainYVault: require(relativePath(ABI_PATHS.chainYVault)),
|
|
29
|
+
} as const;
|
|
30
|
+
|
|
31
|
+
export { RPC_URL, PRIVATE_KEY };
|
|
32
|
+
export { AUCTION_ADDR,AUCTION_ABI};
|
|
33
|
+
|
|
34
|
+
if (require.main === module) {
|
|
35
|
+
console.log("=== Auction 配置验证 ===\n");
|
|
36
|
+
console.log("合约地址:");
|
|
37
|
+
console.log("ChainYVaultV2:", chainYVaultV2Addr);
|
|
38
|
+
console.log("ChainXAuctionV2:", chainXAuctionV2Addr);
|
|
39
|
+
console.log("Coinbase:", coinbaseAddr);
|
|
40
|
+
}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import * as dotenv from "dotenv";
|
|
2
|
+
import { ethers } from "ethers";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
|
|
5
|
+
// 加载环境变量
|
|
6
|
+
dotenv.config({ path: path.resolve(__dirname, "../.env") });
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 环境变量配置接口定义
|
|
10
|
+
*/
|
|
11
|
+
export interface EnvConfig {
|
|
12
|
+
// RPC 和钱包配置
|
|
13
|
+
rpc: {
|
|
14
|
+
url: string;
|
|
15
|
+
};
|
|
16
|
+
wallet: {
|
|
17
|
+
privateKey: string;
|
|
18
|
+
address: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// 合约地址配置
|
|
22
|
+
contracts: {
|
|
23
|
+
mutiVoucher:string;
|
|
24
|
+
auction: {
|
|
25
|
+
chainYVaultV2: string;
|
|
26
|
+
chainXAuctionV2: string;
|
|
27
|
+
coinbase: string;
|
|
28
|
+
};
|
|
29
|
+
uniswap: {
|
|
30
|
+
create2: string;
|
|
31
|
+
token0: string;
|
|
32
|
+
token1: string;
|
|
33
|
+
poolManager: string;
|
|
34
|
+
liquidPool: string;
|
|
35
|
+
limitOrder: string;
|
|
36
|
+
dynamicFee: string;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
// ABI 文件路径配置 (完整路径)
|
|
40
|
+
abiPaths: {
|
|
41
|
+
mutiVoucher:string;
|
|
42
|
+
auction: {
|
|
43
|
+
chainYVault: string;
|
|
44
|
+
chainXAuction: string;
|
|
45
|
+
coinbase:string;
|
|
46
|
+
};
|
|
47
|
+
uniswap: {
|
|
48
|
+
poolManager: string;
|
|
49
|
+
mockERC20: string;
|
|
50
|
+
liquidPool: string;
|
|
51
|
+
limitOrder: string;
|
|
52
|
+
dynamicFee: string;
|
|
53
|
+
create2: string;
|
|
54
|
+
example: string;
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
// Pool 配置
|
|
58
|
+
pool: {
|
|
59
|
+
salt: string;
|
|
60
|
+
saltLimitOrder: string;
|
|
61
|
+
priceInit: number;
|
|
62
|
+
priceLimit: number;
|
|
63
|
+
initialLiquidity: bigint;
|
|
64
|
+
initialSupply: bigint;
|
|
65
|
+
dynamicFeeFlag: number;
|
|
66
|
+
};
|
|
67
|
+
// 路径配置
|
|
68
|
+
paths: {
|
|
69
|
+
abiRootDir: string; // ABI 文件根目录
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 从环境变量中获取值,如果不存在则使用默认值
|
|
75
|
+
*/
|
|
76
|
+
function getEnvValue(key: string, defaultValue: string): string {
|
|
77
|
+
const value = process.env[key];
|
|
78
|
+
if (value === undefined || value === "") {
|
|
79
|
+
return defaultValue;
|
|
80
|
+
}
|
|
81
|
+
return value;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* 从环境变量中获取数字值
|
|
86
|
+
*/
|
|
87
|
+
function getEnvNumber(key: string, defaultValue: number): number {
|
|
88
|
+
const value = process.env[key];
|
|
89
|
+
if (value === undefined || value === "") {
|
|
90
|
+
return defaultValue;
|
|
91
|
+
}
|
|
92
|
+
const parsed = parseFloat(value);
|
|
93
|
+
if (isNaN(parsed)) {
|
|
94
|
+
console.warn(`Warning: ${key} is not a valid number, using default value ${defaultValue}`);
|
|
95
|
+
return defaultValue;
|
|
96
|
+
}
|
|
97
|
+
return parsed;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* 从环境变量中获取 BigInt 值
|
|
102
|
+
*/
|
|
103
|
+
function getEnvBigInt(key: string, defaultValue: string): bigint {
|
|
104
|
+
const value = getEnvValue(key, defaultValue);
|
|
105
|
+
try {
|
|
106
|
+
return ethers.utils.parseEther(value).toBigInt();
|
|
107
|
+
} catch (error) {
|
|
108
|
+
console.warn(`Warning: ${key} is not a valid ether value, using default value ${defaultValue}`);
|
|
109
|
+
return ethers.utils.parseEther(defaultValue).toBigInt();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* 拼接 ABI 文件路径
|
|
115
|
+
* @param rootDir ABI 根目录
|
|
116
|
+
* @param relativePath 相对路径
|
|
117
|
+
* @returns 完整路径
|
|
118
|
+
*/
|
|
119
|
+
function joinAbiPath(rootDir: string, relativePath: string): string {
|
|
120
|
+
// 移除路径中的多余斜杠
|
|
121
|
+
const cleanRoot = rootDir.replace(/\/+$/, "");
|
|
122
|
+
const cleanRelative = relativePath.replace(/^\/+/, "");
|
|
123
|
+
return `${cleanRoot}/${cleanRelative}`;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* 加载并解析环境变量配置
|
|
128
|
+
*/
|
|
129
|
+
function loadConfig(): EnvConfig {
|
|
130
|
+
// 获取 ABI 根目录
|
|
131
|
+
const abiRootDir = getEnvValue("ABI_ROOT_DIR", "chain-core/ABI");
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
rpc: {
|
|
135
|
+
url: getEnvValue("RPC_URL", "http://127.0.0.1:8545/"),
|
|
136
|
+
},
|
|
137
|
+
wallet: {
|
|
138
|
+
privateKey: getEnvValue(
|
|
139
|
+
"PRIVATE_KEY",
|
|
140
|
+
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
|
|
141
|
+
),
|
|
142
|
+
address: getEnvValue(
|
|
143
|
+
"ACCOUNT_ADDR",
|
|
144
|
+
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
|
|
145
|
+
),
|
|
146
|
+
},
|
|
147
|
+
contracts: {
|
|
148
|
+
mutiVoucher:getEnvValue("MutiVoucher",""),
|
|
149
|
+
auction: {
|
|
150
|
+
chainYVaultV2: getEnvValue("ChainYVaultV2", ""),
|
|
151
|
+
chainXAuctionV2: getEnvValue("ChainXAuctionV2", ""),
|
|
152
|
+
coinbase: getEnvValue("Coinbase", ""),
|
|
153
|
+
},
|
|
154
|
+
uniswap: {
|
|
155
|
+
create2: getEnvValue("Create2", "0x5FbDB2315678afecb367f032d93F642f64180aa3"),
|
|
156
|
+
token0: getEnvValue("Token0", "0x3e7B83B8bb8eE2D4d74ec805aeb1465e65E15E24"),
|
|
157
|
+
token1: getEnvValue("Token1", "0xF4DB8B5cC187B286Eb54Bf76c6b041286a46E4Ee"),
|
|
158
|
+
poolManager: getEnvValue("PoolManager", "0xDB0412DaB8210ccA6d9875eE0be7b580A3c12046"),
|
|
159
|
+
liquidPool: getEnvValue("LiquidPool", "0xBFd16A06062060FA08EFca22e3b6d334EcF3E2f0"),
|
|
160
|
+
limitOrder: getEnvValue("LimitOrder", "0x7982Cd1B4162c145e6c1a0f7fD3De4676950D040"),
|
|
161
|
+
dynamicFee: getEnvValue("DynamicFee", "0x541eEcD8E9A59476E436A766123B27330e149040"),
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
abiPaths: {
|
|
165
|
+
mutiVoucher: getEnvValue("MutiVoucher_abi_path", "MutiVoucher.json"),
|
|
166
|
+
auction: {
|
|
167
|
+
chainYVault: getEnvValue("ChainYVault_abi_path", "ChainYVaultV2.json"),
|
|
168
|
+
chainXAuction: getEnvValue("ChainXAuction_abi_path", "ChainXAuctionV2.json"),
|
|
169
|
+
coinbase: getEnvValue("Coinbase_abi_path", "Coinbase.json"),
|
|
170
|
+
},
|
|
171
|
+
uniswap: {
|
|
172
|
+
poolManager: getEnvValue("PoolManager_abi_path", "PoolManager.json"),
|
|
173
|
+
mockERC20: getEnvValue("MockERC20_abi_path", "MockERC20.json"),
|
|
174
|
+
liquidPool: getEnvValue("LiquidPool_abi_path", "LiquidPool.json"),
|
|
175
|
+
limitOrder: getEnvValue("LimitOrder_abi_path", "LimitOrder.json"),
|
|
176
|
+
dynamicFee: getEnvValue("DynamicFee_abi_path", "DynamicFee.json"),
|
|
177
|
+
create2: getEnvValue("Create2_abi_path", "Create2.json"),
|
|
178
|
+
example: getEnvValue("Example_abi_path", "Example.json"),
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
pool: {
|
|
182
|
+
salt: getEnvValue("SALT", ethers.utils.keccak256("0x00")),
|
|
183
|
+
saltLimitOrder: getEnvValue("SALT_LIMITORDER", ethers.utils.keccak256("0x01")),
|
|
184
|
+
priceInit: getEnvNumber("PRICE_INIT", 1),
|
|
185
|
+
priceLimit: getEnvNumber("PRICE_LIMIT", 1.1),
|
|
186
|
+
initialLiquidity: getEnvBigInt("INITIAL_LIQUIDITY", "1000"),
|
|
187
|
+
initialSupply: getEnvBigInt("INITIAL_SUPPLY", "210000000"),
|
|
188
|
+
dynamicFeeFlag: 0x800000,
|
|
189
|
+
},
|
|
190
|
+
paths: {
|
|
191
|
+
abiRootDir,
|
|
192
|
+
},
|
|
193
|
+
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* 导出配置对象
|
|
199
|
+
*/
|
|
200
|
+
export const config: EnvConfig = loadConfig();
|
|
201
|
+
export const RPC_URL = config.rpc.url;
|
|
202
|
+
export const PRIVATE_KEY = config.wallet.privateKey;
|
|
203
|
+
export const ACCOUNT_ADDR = config.wallet.address;
|
|
204
|
+
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// 从集中的配置解析器导入所有配置
|
|
2
|
+
import {
|
|
3
|
+
config,
|
|
4
|
+
RPC_URL,
|
|
5
|
+
PRIVATE_KEY,
|
|
6
|
+
} from "./env.config";
|
|
7
|
+
import {join} from "path";
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
// ============================== 导出配置供其他模块使用 ======================================
|
|
12
|
+
export { RPC_URL, PRIVATE_KEY };
|
|
13
|
+
export { CONTRACT_ADDRESSES,CONTRACTS_ABI,POOL_KEYS};
|
|
14
|
+
export { SALT, SALT_LIMITORDER, PRICE_INIT, PRICE_LIMIT, INITIAL_LIQUIDITY, INITIAL_SUPPLY };
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
// ============================== Contract Address ============================================
|
|
19
|
+
const CONTRACT_ADDRESSES = {
|
|
20
|
+
Create2: config.contracts.uniswap.create2,
|
|
21
|
+
Token0: config.contracts.uniswap.token0,
|
|
22
|
+
Token1: config.contracts.uniswap.token1,
|
|
23
|
+
PoolManager: config.contracts.uniswap.poolManager,
|
|
24
|
+
LiquidPool: config.contracts.uniswap.liquidPool,
|
|
25
|
+
LimitOrder: config.contracts.uniswap.limitOrder,
|
|
26
|
+
DynamicFee: config.contracts.uniswap.dynamicFee,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// ============================== Contract ABIs ============================================
|
|
30
|
+
function relativePath(filepath:string):string{
|
|
31
|
+
const ROOT = '..';
|
|
32
|
+
return join(ROOT,filepath)
|
|
33
|
+
}
|
|
34
|
+
// Uniswap ABI 路径
|
|
35
|
+
const ABI_PATHS = config.abiPaths.uniswap;
|
|
36
|
+
|
|
37
|
+
const CONTRACTS_ABI={
|
|
38
|
+
PoolManager: require(relativePath(ABI_PATHS.poolManager)),
|
|
39
|
+
MockERC20: require(relativePath(ABI_PATHS.mockERC20)),
|
|
40
|
+
LiquidPool: require(relativePath(ABI_PATHS.liquidPool)),
|
|
41
|
+
LimitOrder: require(relativePath(ABI_PATHS.limitOrder)),
|
|
42
|
+
DynamicFee: require(relativePath(ABI_PATHS.dynamicFee)),
|
|
43
|
+
Create2: require(relativePath(ABI_PATHS.create2)),
|
|
44
|
+
Example: require(relativePath(ABI_PATHS.example)),
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// ============================== Pool Keys ================================================
|
|
48
|
+
// Pool 配置
|
|
49
|
+
const SALT = config.pool.salt;
|
|
50
|
+
const SALT_LIMITORDER = config.pool.saltLimitOrder;
|
|
51
|
+
const PRICE_INIT = config.pool.priceInit;
|
|
52
|
+
const PRICE_LIMIT = config.pool.priceLimit;
|
|
53
|
+
const INITIAL_LIQUIDITY = config.pool.initialLiquidity;
|
|
54
|
+
const INITIAL_SUPPLY = config.pool.initialSupply;
|
|
55
|
+
const DYNAMIC_FEE_FLAG = config.pool.dynamicFeeFlag;
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
const POOL_KEYS = {
|
|
59
|
+
limitOrderPoolKey: {
|
|
60
|
+
currency0: CONTRACT_ADDRESSES.Token0,
|
|
61
|
+
currency1: CONTRACT_ADDRESSES.Token1,
|
|
62
|
+
fee: 60,
|
|
63
|
+
tickSpacing: 60,
|
|
64
|
+
hooks: CONTRACT_ADDRESSES.LimitOrder,
|
|
65
|
+
},
|
|
66
|
+
dynamicFeePoolKey: {
|
|
67
|
+
currency0: CONTRACT_ADDRESSES.Token0,
|
|
68
|
+
currency1: CONTRACT_ADDRESSES.Token1,
|
|
69
|
+
fee: DYNAMIC_FEE_FLAG,
|
|
70
|
+
tickSpacing: 60,
|
|
71
|
+
hooks: CONTRACT_ADDRESSES.DynamicFee,
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
if (require.main === module) {
|
|
77
|
+
console.log("=== Uniswap 配置验证 ===\n");
|
|
78
|
+
|
|
79
|
+
console.log("ABI 路径:");
|
|
80
|
+
console.log("- PoolManager:", ABI_PATHS.poolManager);
|
|
81
|
+
console.log("- MockERC20:", ABI_PATHS.mockERC20);
|
|
82
|
+
console.log("- LiquidPool:", ABI_PATHS.liquidPool);
|
|
83
|
+
console.log("- LimitOrder:", ABI_PATHS.limitOrder);
|
|
84
|
+
console.log("- DynamicFee:", ABI_PATHS.dynamicFee);
|
|
85
|
+
console.log("- Create2:", ABI_PATHS.create2);
|
|
86
|
+
console.log("- Example:", ABI_PATHS.example);
|
|
87
|
+
|
|
88
|
+
console.log("\n合约地址:");
|
|
89
|
+
console.log("- Token0:", CONTRACT_ADDRESSES.Token0);
|
|
90
|
+
console.log("- Token1:", CONTRACT_ADDRESSES.Token1);
|
|
91
|
+
console.log("- PoolManager:", CONTRACT_ADDRESSES.PoolManager);
|
|
92
|
+
console.log("- LiquidPool:", CONTRACT_ADDRESSES.LiquidPool);
|
|
93
|
+
console.log("- LimitOrder:", CONTRACT_ADDRESSES.LimitOrder);
|
|
94
|
+
console.log("- DynamicFee:", CONTRACT_ADDRESSES.DynamicFee);
|
|
95
|
+
console.log("- Create2:", CONTRACT_ADDRESSES.Create2);
|
|
96
|
+
|
|
97
|
+
console.log("\nPool 配置:");
|
|
98
|
+
console.log("- SALT:", SALT.toString());
|
|
99
|
+
console.log("- SALT_LIMITORDER:", SALT_LIMITORDER.toString());
|
|
100
|
+
console.log("- PRICE_INIT:", PRICE_INIT);
|
|
101
|
+
console.log("- PRICE_LIMIT:", PRICE_LIMIT);
|
|
102
|
+
console.log("- INITIAL_LIQUIDITY:", INITIAL_LIQUIDITY.toString());
|
|
103
|
+
console.log("- INITIAL_SUPPLY:", INITIAL_SUPPLY.toString());
|
|
104
|
+
console.log("- DYNAMIC_FEE_FLAG:", DYNAMIC_FEE_FLAG.toString(16));
|
|
105
|
+
|
|
106
|
+
console.log("poolKeys:", POOL_KEYS);
|
|
107
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { config } from "./env.config";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
// MutiVoucher 相关
|
|
4
|
+
function relativePath(filepath:string):string{
|
|
5
|
+
const ROOT = '..';
|
|
6
|
+
return join(ROOT,filepath)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const MUTI_VOUCHER_ADDR=config.contracts.mutiVoucher
|
|
10
|
+
export const MUTI_VOUCHER_ABI = require(relativePath(config.abiPaths.mutiVoucher));
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.15;
|
|
3
|
+
|
|
4
|
+
// import "./utils/ownable.sol";
|
|
5
|
+
|
|
6
|
+
contract MutiVoucher {
|
|
7
|
+
struct Voucher {
|
|
8
|
+
uint256 conversionRate; // exchange rate with ETH
|
|
9
|
+
mapping(address => uint256) balances;
|
|
10
|
+
}
|
|
11
|
+
bytes32[] private voucherNames;
|
|
12
|
+
mapping(bytes32 => Voucher) private vouchers;
|
|
13
|
+
|
|
14
|
+
event VoucherCreated(bytes32 voucherName, uint256 conversionRate);
|
|
15
|
+
event VoucherPurchased(address buyer, bytes32 voucherName, uint256 amount);
|
|
16
|
+
event VoucherUsed(address user, bytes32 voucherName, uint256 amount);
|
|
17
|
+
|
|
18
|
+
// Create new voucher and store in vouchers
|
|
19
|
+
function createVoucher(
|
|
20
|
+
bytes32 name,
|
|
21
|
+
uint256 conversionRate
|
|
22
|
+
) external {
|
|
23
|
+
require(
|
|
24
|
+
conversionRate > 0,
|
|
25
|
+
"Conversion rate must be greater than zero"
|
|
26
|
+
);
|
|
27
|
+
require(vouchers[name].conversionRate == 0, "Voucher already exist");
|
|
28
|
+
|
|
29
|
+
// Create new voucher
|
|
30
|
+
Voucher storage newVoucher = vouchers[name];
|
|
31
|
+
newVoucher.conversionRate = conversionRate;
|
|
32
|
+
voucherNames.push(name);
|
|
33
|
+
|
|
34
|
+
emit VoucherCreated(name, conversionRate);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function getVoucherInfo(
|
|
38
|
+
bytes32 name
|
|
39
|
+
) external view returns (uint256 conversionRate) {
|
|
40
|
+
require(vouchers[name].conversionRate > 0, "Voucher doesn't exist");
|
|
41
|
+
return vouchers[name].conversionRate;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function buy(bytes32 name) external payable {
|
|
45
|
+
require(vouchers[name].conversionRate > 0, "Voucher doesn't exist");
|
|
46
|
+
require(msg.value > 0, "Message value must be greater than zero");
|
|
47
|
+
// Attention the unit of value is wei
|
|
48
|
+
uint256 expectedAmount = msg.value * vouchers[name].conversionRate;
|
|
49
|
+
vouchers[name].balances[msg.sender] += expectedAmount;
|
|
50
|
+
emit VoucherPurchased(msg.sender, name, expectedAmount);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function use(bytes32 name, uint256 amount) external {
|
|
54
|
+
require(vouchers[name].conversionRate > 0, "Voucher doesn't exist");
|
|
55
|
+
require(amount > 0, "Amount must be greater than zero");
|
|
56
|
+
require(
|
|
57
|
+
vouchers[name].balances[msg.sender] >= amount,
|
|
58
|
+
"Insufficient balance"
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
// Reduce balance
|
|
62
|
+
vouchers[name].balances[msg.sender] -= amount;
|
|
63
|
+
emit VoucherUsed(msg.sender, name, amount);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Query balance of an address in voucher
|
|
67
|
+
function balanceOf(
|
|
68
|
+
bytes32 name,
|
|
69
|
+
address user
|
|
70
|
+
) external view returns (uint256) {
|
|
71
|
+
require(vouchers[name].conversionRate > 0, "Voucher doesn't exist");
|
|
72
|
+
return vouchers[name].balances[user];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function getAllVouchers() external view returns (bytes32[] memory) {
|
|
76
|
+
return voucherNames;
|
|
77
|
+
}
|
|
78
|
+
}
|