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
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { ethers } from "hardhat";
|
|
2
|
+
import type { Contract } from "ethers";
|
|
3
|
+
import { PoolKey, SwapParams, ModifyPositionParams } from "../lib/types";
|
|
4
|
+
|
|
5
|
+
let provider = new ethers.providers.JsonRpcProvider('http://localhost:8545');
|
|
6
|
+
let wallet = new ethers.Wallet("0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", provider)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
function calculateTickFromPrice(price: number, tickSpacing = 60): number {
|
|
11
|
+
let unroundedTick = Math.floor(Math.log(price) / Math.log(1.0001));
|
|
12
|
+
return Math.round(unroundedTick / tickSpacing) * tickSpacing;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async function checkAllowance(contract: Contract, ownerAddress: string, spenderAddress: string) {
|
|
16
|
+
// Check the amount of tokens that an owner allowed to a spender
|
|
17
|
+
let allowance = await contract.allowance(ownerAddress, spenderAddress);
|
|
18
|
+
console.log(`Allowance: ${allowance.toString()}`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function isdepolyed(address: string) {
|
|
22
|
+
let code = await provider.getCode(address);
|
|
23
|
+
if (code !== "0x") {
|
|
24
|
+
console.log(`The contract ${address} has been deployed.`);
|
|
25
|
+
} else {
|
|
26
|
+
console.log(`The contract ${address} has not been deployed. `);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function donate(contract: Contract, poolKey: PoolKey, amount0: bigint, amount1: bigint) {
|
|
31
|
+
// Donate
|
|
32
|
+
console.log("begin donate")
|
|
33
|
+
let to0params = {
|
|
34
|
+
tickLower: 840000, // lower price 0.5
|
|
35
|
+
tickUpper: 876600, // upper price 1.5
|
|
36
|
+
liquidityDelta: 0
|
|
37
|
+
}
|
|
38
|
+
let tx1 = await contract.setPositionParameters(poolKey, to0params);
|
|
39
|
+
await tx1.wait();
|
|
40
|
+
let swapParams = {
|
|
41
|
+
zeroForOne: false,
|
|
42
|
+
amountSpecified: 0,
|
|
43
|
+
sqrtPriceLimitX96: 0
|
|
44
|
+
}
|
|
45
|
+
let tx2 = await contract.setSwapParameters(poolKey, swapParams);
|
|
46
|
+
await tx2.wait();
|
|
47
|
+
|
|
48
|
+
let tx3 = await contract.setDonateParameters(poolKey, amount0, amount1);
|
|
49
|
+
await tx3.wait();
|
|
50
|
+
|
|
51
|
+
let tx4 = await contract.donate();
|
|
52
|
+
await tx4.wait();
|
|
53
|
+
|
|
54
|
+
console.log("donate successfully");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function modifyPosition(contract: Contract, poolKey: PoolKey, modifyPositionParams: ModifyPositionParams) {
|
|
58
|
+
// Set position parameters
|
|
59
|
+
let tx = await contract.setPositionParameters(poolKey, modifyPositionParams);
|
|
60
|
+
await tx.wait();
|
|
61
|
+
console.log("Position parameters set successfully");
|
|
62
|
+
// Add liquidity
|
|
63
|
+
tx = await contract.addLiquidity();
|
|
64
|
+
await tx.wait();
|
|
65
|
+
}
|
|
66
|
+
//function kill(IPoolManager.PoolKey calldata key, int24 tickLower, bool zeroForOne, address to)
|
|
67
|
+
async function killLimitOrder(contract: Contract, poolKey: PoolKey, tickLower: number, zeroForOne: boolean, to: string) {
|
|
68
|
+
let tx = await contract.kill(poolKey, tickLower, zeroForOne, to);
|
|
69
|
+
await tx.wait();
|
|
70
|
+
console.log("kill successfully");
|
|
71
|
+
//emit Kill(msg.sender, epoch, key, tickLower, zeroForOne, liquidity);
|
|
72
|
+
await contract.on("Kill", (owner, epoch, key, tickLower, zeroForOne, liquidity, event) => {
|
|
73
|
+
console.log("Kill event emitted:");
|
|
74
|
+
console.log("Owner: ", owner);
|
|
75
|
+
console.log("Epoch: ", epoch.toString());
|
|
76
|
+
console.log("Key: ", key);
|
|
77
|
+
console.log("TickLower: ", tickLower.toString());
|
|
78
|
+
console.log("ZeroForOne: ", zeroForOne);
|
|
79
|
+
console.log("Liquidity: ", liquidity.toString());
|
|
80
|
+
|
|
81
|
+
// Handle event here
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function placeLimitOrder(contract: Contract, poolKey: PoolKey, tickLower: number, zeroForOne: boolean, liquidity: number) {
|
|
86
|
+
let tx = await contract.place(poolKey, tickLower, zeroForOne, liquidity);
|
|
87
|
+
await tx.wait();
|
|
88
|
+
console.log("limit order set successfully");
|
|
89
|
+
|
|
90
|
+
await contract.on("Place", (owner, epoch, key, tickLower, zeroForOne, liquidity, event) => {
|
|
91
|
+
console.log("Place event emitted:");
|
|
92
|
+
console.log("Owner: ", owner);
|
|
93
|
+
console.log("Epoch: ", epoch.toString());
|
|
94
|
+
console.log("Key: ", key);
|
|
95
|
+
console.log("TickLower: ", tickLower.toString());
|
|
96
|
+
console.log("ZeroForOne: ", zeroForOne);
|
|
97
|
+
console.log("Liquidity: ", liquidity.toString());
|
|
98
|
+
|
|
99
|
+
// Handle event here
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function withdrawLimitOrder(contract: Contract, epoch: number, to: string) {
|
|
104
|
+
let tx = await contract.withdraw(epoch, to);
|
|
105
|
+
await tx.wait();
|
|
106
|
+
console.log("limit order withdraw successfully");
|
|
107
|
+
await contract.on("Withdraw", (owner, epoch, liquidity, event) => {
|
|
108
|
+
console.log("Withdraw event emitted:");
|
|
109
|
+
console.log("Owner: ", owner);
|
|
110
|
+
console.log("Epoch: ", epoch.toString());
|
|
111
|
+
console.log("Liquidity: ", liquidity.toString());
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async function initialize(contract: Contract, key: PoolKey, sqrtPriceX96: bigint) {
|
|
116
|
+
let tick = await contract.initialize(key, sqrtPriceX96);
|
|
117
|
+
console.log(`Returned tick: ${JSON.stringify(tick)}`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async function approveERC20(contract: Contract, toAddress: string, amount: bigint) {
|
|
121
|
+
let tx = await contract.approve(toAddress, amount);
|
|
122
|
+
let receipt = await tx.wait();
|
|
123
|
+
console.log(`Transaction hash: ${receipt.transactionHash}`);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function getPoolId(poolKey: PoolKey): string {
|
|
127
|
+
return ethers.utils.solidityKeccak256(
|
|
128
|
+
["bytes"],
|
|
129
|
+
[ethers.utils.defaultAbiCoder.encode(
|
|
130
|
+
["address", "address", "uint24", "int24", "address"],
|
|
131
|
+
[poolKey.currency0, poolKey.currency1, poolKey.fee, poolKey.tickSpacing, poolKey.hooks]
|
|
132
|
+
)]
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async function getSlot0(contract: Contract, poolKey: PoolKey) {
|
|
137
|
+
let poolId = getPoolId(poolKey);
|
|
138
|
+
console.log(`PoolId: ${poolId}`);
|
|
139
|
+
let slot0 = await contract.getSlot0(poolId);
|
|
140
|
+
console.log(`Returned slot0: ${JSON.stringify(slot0)}`);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async function getLiquidity(contract: Contract, poolKey: PoolKey) {
|
|
144
|
+
let poolId = getPoolId(poolKey);
|
|
145
|
+
console.log(`PoolId: ${poolId}`);
|
|
146
|
+
//let liq0 = await contract.getLiquidity(poolId);
|
|
147
|
+
let liq0 = await contract.functions['getLiquidity(bytes32)'](poolId);
|
|
148
|
+
|
|
149
|
+
console.log(`Returned liquidity: ${liq0}`);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async function getERC20Balance(contract: Contract, address: string) {
|
|
153
|
+
// 查询ERC20余额
|
|
154
|
+
let balance = await contract.balanceOf(address);
|
|
155
|
+
console.log(`ERC20 Balance: ${balance.toString()}`);
|
|
156
|
+
return balance;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async function executeSwap(contract: Contract, poolKey: PoolKey, swapParams: SwapParams) {
|
|
160
|
+
|
|
161
|
+
// Set position parameters
|
|
162
|
+
console.log("begin swap")
|
|
163
|
+
let to0params = {
|
|
164
|
+
tickLower: 840000, // lower price 0.5
|
|
165
|
+
tickUpper: 876600, // upper price 1.5
|
|
166
|
+
liquidityDelta: 0
|
|
167
|
+
}
|
|
168
|
+
let tx1 = await contract.setPositionParameters(poolKey, to0params);
|
|
169
|
+
await tx1.wait();
|
|
170
|
+
let tx2 = await contract.setSwapParameters(poolKey, swapParams);
|
|
171
|
+
console.log("begin swap1")
|
|
172
|
+
await tx2.wait();
|
|
173
|
+
console.log("Position parameters set successfully");
|
|
174
|
+
// swap
|
|
175
|
+
let tx3 = await contract.executeSwap();
|
|
176
|
+
await tx3.wait();
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async function depolyContract(contractName: string, params?: any): Promise<Contract> {
|
|
180
|
+
const Factory = await ethers.getContractFactory(contractName);
|
|
181
|
+
let contract;
|
|
182
|
+
if (params === undefined) {
|
|
183
|
+
contract = await Factory.deploy();
|
|
184
|
+
} else {
|
|
185
|
+
console.log(`params: ${JSON.stringify(params)}`);
|
|
186
|
+
contract = await Factory.deploy(params);
|
|
187
|
+
//depolyContract("depoly1");
|
|
188
|
+
}
|
|
189
|
+
await contract.deployed();
|
|
190
|
+
console.log(`${contractName} deployed to ${contract.address}`);
|
|
191
|
+
return contract;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
async function delay(milliseconds: any) {
|
|
195
|
+
// 这个新的 Promise 将在指定的毫秒数后 resolve
|
|
196
|
+
return new Promise(resolve => setTimeout(resolve, milliseconds));
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
describe("PoolManager", function () {
|
|
200
|
+
it("Should return the new greeting once it's changed", async function () {
|
|
201
|
+
const token0 = await depolyContract("Token0");
|
|
202
|
+
const token1 = await depolyContract("Token1");
|
|
203
|
+
// await isdepolyed(token0.address);
|
|
204
|
+
// await isdepolyed(token1.address);
|
|
205
|
+
const totalSupply0 = await token0.totalSupply();
|
|
206
|
+
console.log(`Token0 deployed to ${token0.address} with an initial supply ${totalSupply0}`);
|
|
207
|
+
const totalSupply1 = await token1.totalSupply();
|
|
208
|
+
console.log(`Token1 deployed to ${token1.address} with an initial supply ${totalSupply1}`);
|
|
209
|
+
getERC20Balance(token0, wallet.address);
|
|
210
|
+
getERC20Balance(token1, wallet.address);
|
|
211
|
+
const token0Address = token0.address < token1.address ? token0.address : token1.address;
|
|
212
|
+
const token1Address = token0.address > token1.address ? token0.address : token1.address;
|
|
213
|
+
//await isdepolyed(token0Address);
|
|
214
|
+
//await isdepolyed(token1Address);
|
|
215
|
+
|
|
216
|
+
//depoly poolManager
|
|
217
|
+
const poolManager = await depolyContract("PoolManager", 88888888888);
|
|
218
|
+
// const Factory = await ethers.getContractFactory("PoolManager");
|
|
219
|
+
// const controllerGasLimit = 88888888888;
|
|
220
|
+
// const contractpm = await Factory.deploy(controllerGasLimit);
|
|
221
|
+
// await contractpm.deployed();
|
|
222
|
+
const poolManagerAddress = poolManager.address;
|
|
223
|
+
//console.log("PoolManager Contract deployed to:", poolManagerAddress);
|
|
224
|
+
await isdepolyed(poolManagerAddress);
|
|
225
|
+
|
|
226
|
+
//depoly hook
|
|
227
|
+
// 部署 LimitOrder 合约
|
|
228
|
+
const dynamicFee = await depolyContract("DynamicFee", poolManagerAddress);
|
|
229
|
+
console.log("LimitOrder Contract deployed to:", dynamicFee.address);
|
|
230
|
+
// await isdepolyed(limitOrder.address);
|
|
231
|
+
|
|
232
|
+
//initial poolManager
|
|
233
|
+
let sqrtPriceX96 = BigInt("792281625142643375935439503360")// price = 100 token1/token0
|
|
234
|
+
const DYNAMIC_FEE_FLAG = 0x800000;
|
|
235
|
+
let poolKey: PoolKey = {
|
|
236
|
+
currency0: token0Address,
|
|
237
|
+
currency1: token1Address,
|
|
238
|
+
fee: DYNAMIC_FEE_FLAG,
|
|
239
|
+
tickSpacing: 60,
|
|
240
|
+
hooks: dynamicFee.address,
|
|
241
|
+
};
|
|
242
|
+
//await getSlot0(poolManager, poolKey);
|
|
243
|
+
await initialize(poolManager, poolKey, sqrtPriceX96);
|
|
244
|
+
//await getSlot0(poolManager, poolKey);
|
|
245
|
+
|
|
246
|
+
//approve ERC20 token to limitOrder
|
|
247
|
+
//await approveERC20(token0,poolManager.address,ethers.utils.parseUnits("21000000", 18))
|
|
248
|
+
//await approveERC20(token1,poolManager.address,ethers.utils.parseUnits("21000000", 18))
|
|
249
|
+
|
|
250
|
+
const MyLiquidityProvider = await depolyContract("MyLiquidityProvider", poolManagerAddress);
|
|
251
|
+
//approve ERC20 token to MyLiquidityProvider
|
|
252
|
+
const wei = ethers.utils.parseUnits("21000000", 18).toBigInt();
|
|
253
|
+
await approveERC20(token0, MyLiquidityProvider.address, wei);
|
|
254
|
+
await approveERC20(token1, MyLiquidityProvider.address, wei);
|
|
255
|
+
|
|
256
|
+
//add liquidity
|
|
257
|
+
let modifyPositionParams: ModifyPositionParams = {
|
|
258
|
+
tickLower: 45000, // lower price 90
|
|
259
|
+
tickUpper: 46980, // upper price 110
|
|
260
|
+
//liquidityDelta: 194868329805051412324060
|
|
261
|
+
liquidityDelta: BigInt('10000000000000000000000')// 10000token0 10000token1
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
//console.log(`modifyPositionParams: ${JSON.stringify(modifyPositionParams)}`);
|
|
265
|
+
//console.log(`Poolkey: ${JSON.stringify(poolKey)}`);
|
|
266
|
+
await getERC20Balance(token0, wallet.address);
|
|
267
|
+
await getERC20Balance(token1, wallet.address);
|
|
268
|
+
|
|
269
|
+
await modifyPosition(MyLiquidityProvider, poolKey, modifyPositionParams);
|
|
270
|
+
console.log("Liquidity added successfully");
|
|
271
|
+
|
|
272
|
+
await getERC20Balance(token0, wallet.address);
|
|
273
|
+
await getERC20Balance(token1, wallet.address);
|
|
274
|
+
//swap
|
|
275
|
+
let sqrtpricelimit = ethers.BigNumber.from('7922816251426433759354395033600').toBigInt();
|
|
276
|
+
let amountswap = ethers.BigNumber.from('1083456789101112134000').toBigInt();
|
|
277
|
+
console.log("amountswap:", amountswap.toString())
|
|
278
|
+
|
|
279
|
+
let swapParams: SwapParams = {
|
|
280
|
+
zeroForOne: false,
|
|
281
|
+
amountSpecified: amountswap,
|
|
282
|
+
sqrtPriceLimitX96: sqrtpricelimit
|
|
283
|
+
}
|
|
284
|
+
//console.log("sprtprice to price",sqrtPricetoPrice(pricetoSqrtPrice(110)))
|
|
285
|
+
|
|
286
|
+
let token0beforswap = await getERC20Balance(token0, wallet.address);
|
|
287
|
+
let token1beforswap = await getERC20Balance(token1, wallet.address);
|
|
288
|
+
|
|
289
|
+
//await getSlot0(poolManager, poolKey);
|
|
290
|
+
await executeSwap(MyLiquidityProvider, poolKey, swapParams);
|
|
291
|
+
//await getSlot0(poolManager, poolKey);
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
console.log("swap successfully");
|
|
295
|
+
let token0afterswap = await getERC20Balance(token0, wallet.address);
|
|
296
|
+
let token1afterswap = await getERC20Balance(token1, wallet.address);
|
|
297
|
+
|
|
298
|
+
console.log("token0 change:", token0afterswap.sub(token0beforswap).toString())
|
|
299
|
+
console.log("token1 change:", token1afterswap.sub(token1beforswap).toString())
|
|
300
|
+
//price=token0 change/token1 change
|
|
301
|
+
console.log("price:", token1afterswap.sub(token1beforswap).toString() / token0afterswap.sub(token0beforswap).toString())
|
|
302
|
+
|
|
303
|
+
token0beforswap = await getERC20Balance(token0, wallet.address);
|
|
304
|
+
token1beforswap = await getERC20Balance(token1, wallet.address);
|
|
305
|
+
|
|
306
|
+
//await getSlot0(poolManager, poolKey);
|
|
307
|
+
await executeSwap(MyLiquidityProvider, poolKey, swapParams);
|
|
308
|
+
//await getSlot0(poolManager, poolKey);
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
console.log("swap successfully");
|
|
312
|
+
token0afterswap = await getERC20Balance(token0, wallet.address);
|
|
313
|
+
token1afterswap = await getERC20Balance(token1, wallet.address);
|
|
314
|
+
|
|
315
|
+
console.log("token0 change:", token0afterswap.sub(token0beforswap).toString())
|
|
316
|
+
console.log("token1 change:", token1afterswap.sub(token1beforswap).toString())
|
|
317
|
+
//price=token0 change/token1 change
|
|
318
|
+
console.log("price:", token1afterswap.sub(token1beforswap).toString() / token0afterswap.sub(token0beforswap).toString())
|
|
319
|
+
|
|
320
|
+
})
|
|
321
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Contract } from "ethers";
|
|
2
|
+
// Check if the spender is approved to spend at least 'amount' tokens from ownerAddress
|
|
3
|
+
export async function isApproved(contract: Contract, ownerAddress: string, spenderAddress: string, amount: bigint) {
|
|
4
|
+
let allowance = await contract.allowance(ownerAddress, spenderAddress);
|
|
5
|
+
if (allowance >= amount) {
|
|
6
|
+
return true;
|
|
7
|
+
}
|
|
8
|
+
else {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function approveERC20(contract: Contract, spenderAddress: string, amount: bigint) {
|
|
14
|
+
let tx = await contract.approve(spenderAddress, amount);
|
|
15
|
+
await tx.wait();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function getAllowance(contract: Contract, ownerAddress: string, spenderAddress: string): Promise<bigint> {
|
|
19
|
+
const allowance = await contract.allowance(ownerAddress, spenderAddress);
|
|
20
|
+
return allowance;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function checkAndApproveERC20(contract: Contract, ownerAddress: string, spenderAddress: string, amount: bigint) {
|
|
24
|
+
const allowance = await getAllowance(contract, ownerAddress, spenderAddress);
|
|
25
|
+
|
|
26
|
+
if (allowance >= amount) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const tx = await contract.approve(spenderAddress, amount);
|
|
31
|
+
const receipt = await tx.wait();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function getERC20Balance(contract: Contract, address: string): Promise<bigint> {
|
|
35
|
+
const balance: bigint = BigInt(await contract.balanceOf(address));
|
|
36
|
+
// console.log(`ERC20 Balance: ${balance.toString()}`);
|
|
37
|
+
return balance;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function transferERC20(contract: Contract, toAddress: string, amount: bigint) {
|
|
41
|
+
const tx = await contract.transfer(toAddress, amount);
|
|
42
|
+
const receipt = await tx.wait();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
export async function mintERC20(contract: Contract, toAddress: string, amount: bigint) {
|
|
47
|
+
const tx = await contract.mint(toAddress, amount);
|
|
48
|
+
await tx.wait();
|
|
49
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {Wallet , Contract} from "ethers";
|
|
2
|
+
import { CONTRACT_ADDRESSES , CONTRACTS_ABI} from "../../../config/uniswap.config";
|
|
3
|
+
import { ethers } from "hardhat";
|
|
4
|
+
|
|
5
|
+
export async function getContract(wallet:Wallet, name:string): Promise<Contract> {
|
|
6
|
+
switch(name){
|
|
7
|
+
case "Token0":
|
|
8
|
+
return new ethers.Contract(CONTRACT_ADDRESSES.Token0,CONTRACTS_ABI.MockERC20,wallet);
|
|
9
|
+
case "Token1":
|
|
10
|
+
return new ethers.Contract(CONTRACT_ADDRESSES.Token1,CONTRACTS_ABI.MockERC20,wallet);
|
|
11
|
+
case "LiquidPool":
|
|
12
|
+
return new ethers.Contract(CONTRACT_ADDRESSES.LiquidPool,CONTRACTS_ABI.LiquidPool,wallet);
|
|
13
|
+
case "LimitOrder":
|
|
14
|
+
return new ethers.Contract(CONTRACT_ADDRESSES.LimitOrder,CONTRACTS_ABI.LimitOrder,wallet);
|
|
15
|
+
default:
|
|
16
|
+
throw new Error(`Contract(${name}) initial method not defined`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Contract, providers, Wallet } from "ethers";
|
|
2
|
+
import { PoolKey } from "./types";
|
|
3
|
+
import { getPoolId } from "./pool";
|
|
4
|
+
import { RPC_URL, PRIVATE_KEY, POOL_KEYS } from "../../../config/uniswap.config";
|
|
5
|
+
import {ethers} from "hardhat";
|
|
6
|
+
import { getContract } from "./contract";
|
|
7
|
+
|
|
8
|
+
export async function getTickLowerLast(contract:Contract, poolKey: PoolKey): Promise<bigint> {
|
|
9
|
+
const poolId = getPoolId(poolKey);
|
|
10
|
+
return contract.getTickLowerLast(poolId);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// epoach is uint232 in solidity
|
|
14
|
+
export async function getEpoch(contract:Contract, poolKey: PoolKey, tickLower: bigint, zeroForOne: boolean): Promise<bigint> {
|
|
15
|
+
const poolId = getPoolId(poolKey);
|
|
16
|
+
return contract.getEpoch(poolId, tickLower, zeroForOne);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// uint256
|
|
20
|
+
export async function getEpochLiquidity(contract:Contract, epoch: bigint, ownerAddress:string): Promise<bigint> {
|
|
21
|
+
return contract.getEpochLiquidity(epoch, ownerAddress);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function getTick(contract:Contract, poolKey: PoolKey): Promise<bigint> {
|
|
25
|
+
const poolId = getPoolId(poolKey);
|
|
26
|
+
return contract.getTick(poolId);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function test(){
|
|
30
|
+
const provider = new ethers.providers.JsonRpcProvider(RPC_URL);
|
|
31
|
+
const wallet = new ethers.Wallet(PRIVATE_KEY, provider);
|
|
32
|
+
let contract= await getContract(wallet,"LiquidPool");
|
|
33
|
+
|
|
34
|
+
let zeroForOne=true;
|
|
35
|
+
let tickLower=BigInt(-60);
|
|
36
|
+
let epoch=getEpoch(contract, POOL_KEYS.limitOrderPoolKey,tickLower,zeroForOne);
|
|
37
|
+
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
test();
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// Constants
|
|
2
|
+
const MAX_TICK = BigInt('887272');
|
|
3
|
+
const q32 = BigInt(2) ** BigInt(32);
|
|
4
|
+
const q96 = BigInt(2) ** BigInt(96);
|
|
5
|
+
const q128 = BigInt(2) ** BigInt(128);
|
|
6
|
+
const q256 = BigInt(2) ** BigInt(256);
|
|
7
|
+
|
|
8
|
+
// Function to calculate tick from price with optional spacing
|
|
9
|
+
export function calculateTickFromPriceWithSpacing(price: number, tickSpacing = 60): number {
|
|
10
|
+
const unroundedTick = calculateTickFromPrice(price);
|
|
11
|
+
return Math.floor(unroundedTick / tickSpacing) * tickSpacing;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Function to calculate tick from price without spacing
|
|
15
|
+
export function calculateTickFromPrice(price: number): number {
|
|
16
|
+
return Math.floor(Math.log(price) / Math.log(1.0001));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function getAbsTick(tick: bigint): bigint {
|
|
20
|
+
// Ensure tick is within the int24 range
|
|
21
|
+
const int24Max: bigint = BigInt(2) ** BigInt(23) - BigInt(1);
|
|
22
|
+
const int24Min: bigint = BigInt(-2) ** BigInt(23);
|
|
23
|
+
if (tick > int24Max || tick < int24Min) {
|
|
24
|
+
throw new Error('tick is out of int24 range');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Determine the mask: 0 if tick >= 0, -1 if tick < 0
|
|
28
|
+
const mask: bigint = tick < BigInt(0) ? BigInt(-1) : BigInt(0);
|
|
29
|
+
|
|
30
|
+
// Calculate absTick
|
|
31
|
+
const absTick: bigint = (mask ^ (tick + mask));
|
|
32
|
+
|
|
33
|
+
return absTick;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function getSqrtPriceAtTick(tick: number): bigint {
|
|
37
|
+
const absTick: bigint = getAbsTick(BigInt(tick));
|
|
38
|
+
|
|
39
|
+
if (absTick > MAX_TICK) {
|
|
40
|
+
throw new Error("Invalid tick");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let price = (absTick & BigInt(1)) === BigInt(0)
|
|
44
|
+
? q128
|
|
45
|
+
: BigInt("0xfffcb933bd6fad37aa2d162d1a594001");
|
|
46
|
+
|
|
47
|
+
if (absTick & BigInt(2)) price = (price * BigInt("0xfff97272373d413259a46990580e213a")) >> BigInt(128);
|
|
48
|
+
if (absTick & BigInt(4)) price = (price * BigInt("0xfff2e50f5f656932ef12357cf3c7fdcc")) >> BigInt(128);
|
|
49
|
+
if (absTick & BigInt(8)) price = (price * BigInt("0xffe5caca7e10e4e61c3624eaa0941cd0")) >> BigInt(128);
|
|
50
|
+
if (absTick & BigInt(16)) price = (price * BigInt("0xffcb9843d60f6159c9db58835c926644")) >> BigInt(128);
|
|
51
|
+
if (absTick & BigInt(32)) price = (price * BigInt("0xff973b41fa98c081472e6896dfb254c0")) >> BigInt(128);
|
|
52
|
+
if (absTick & BigInt(64)) price = (price * BigInt("0xff2ea16466c96a3843ec78b326b52861")) >> BigInt(128);
|
|
53
|
+
if (absTick & BigInt(128)) price = (price * BigInt("0xfe5dee046a99a2a811c461f1969c3053")) >> BigInt(128);
|
|
54
|
+
if (absTick & BigInt(256)) price = (price * BigInt("0xfcbe86c7900a88aedcffc83b479aa3a4")) >> BigInt(128);
|
|
55
|
+
if (absTick & BigInt(512)) price = (price * BigInt("0xf987a7253ac413176f2b074cf7815e54")) >> BigInt(128);
|
|
56
|
+
if (absTick & BigInt(1024)) price = (price * BigInt("0xf3392b0822b70005940c7a398e4b70f3")) >> BigInt(128);
|
|
57
|
+
if (absTick & BigInt(2048)) price = (price * BigInt("0xe7159475a2c29b7443b29c7fa6e889d9")) >> BigInt(128);
|
|
58
|
+
if (absTick & BigInt(4096)) price = (price * BigInt("0xd097f3bdfd2022b8845ad8f792aa5825")) >> BigInt(128);
|
|
59
|
+
if (absTick & BigInt(8192)) price = (price * BigInt("0xa9f746462d870fdf8a65dc1f90e061e5")) >> BigInt(128);
|
|
60
|
+
if (absTick & BigInt(16384)) price = (price * BigInt("0x70d869a156d2a1b890bb3df62baf32f7")) >> BigInt(128);
|
|
61
|
+
if (absTick & BigInt(32768)) price = (price * BigInt("0x31be135f97d08fd981231505542fcfa6")) >> BigInt(128);
|
|
62
|
+
if (absTick & BigInt(65536)) price = (price * BigInt("0x9aa508b5b7a84e1c677de54f3e99bc9")) >> BigInt(128);
|
|
63
|
+
if (absTick & BigInt(131072)) price = (price * BigInt("0x5d6af8dedb81196699c329225ee604")) >> BigInt(128);
|
|
64
|
+
if (absTick & BigInt(262144)) price = (price * BigInt("0x2216e584f5fa1ea926041bedfe98")) >> BigInt(128);
|
|
65
|
+
if (absTick & BigInt(524288)) price = (price * BigInt("0x48a170391f7dc42444e8fa2")) >> BigInt(128);
|
|
66
|
+
|
|
67
|
+
if (tick > 0) {
|
|
68
|
+
price = (q256 - BigInt(1)) / price;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return (price + q32 - BigInt(1)) >> BigInt(32); // Convert from Q128.128 to Q128.96 and round up
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Function to calculate price from tick
|
|
75
|
+
export function calculatePriceFromTick(tick: number): number {
|
|
76
|
+
return Math.exp(tick * Math.log(1.0001));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Function to convert price to sqrtPriceX96
|
|
80
|
+
export function priceToSqrtPrice(price: number): bigint {
|
|
81
|
+
return BigInt(Math.floor(Math.sqrt(price) * Number(q96)));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Function to convert sqrtPriceX96 to price
|
|
85
|
+
function sqrtPricetoPrice(sqrtprice: bigint): number {
|
|
86
|
+
return (Number(sqrtprice) ** 2) / Number(q96 ** BigInt(2));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Liquidity calculations for amount0 and amount1
|
|
90
|
+
export function liquidity0(amount: bigint, pa: bigint, pb: bigint): bigint {
|
|
91
|
+
if (pa > pb) {
|
|
92
|
+
[pa, pb] = [pb, pa];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return (amount * pa * pb) / (q96 * (pb - pa));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function liquidity1(amount: bigint, pa: bigint, pb: bigint): bigint {
|
|
99
|
+
if (pa > pb) {
|
|
100
|
+
[pa, pb] = [pb, pa];
|
|
101
|
+
}
|
|
102
|
+
return (amount * q96) / (pb - pa);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function divRoundingUp(a: bigint, b: bigint): bigint {
|
|
106
|
+
const remainder = a % b;
|
|
107
|
+
const quotient = a / b;
|
|
108
|
+
return remainder === BigInt(0) ? quotient : quotient + BigInt(1);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Amount calculations for liquidity0 and liquidity1
|
|
112
|
+
export function amount0(liquidity0: bigint, pa: bigint, pb: bigint): bigint {
|
|
113
|
+
if (pa > pb) {
|
|
114
|
+
[pa, pb] = [pb, pa];
|
|
115
|
+
}
|
|
116
|
+
const diff = pb - pa;
|
|
117
|
+
return divRoundingUp((liquidity0 * q96 * diff), pa * pb);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function amount1(liquidity1: bigint, pa: bigint, pb: bigint): bigint {
|
|
121
|
+
if (pa > pb) {
|
|
122
|
+
[pa, pb] = [pb, pa];
|
|
123
|
+
}
|
|
124
|
+
const diff = pb - pa;
|
|
125
|
+
return divRoundingUp(liquidity1 * diff, q96);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Simplified version to calculate liquidity delta
|
|
129
|
+
/// @liquidity delta, @amount0 used, @amount1 used
|
|
130
|
+
export function calculateLiqDelta(ticklow: number, sqrt_cur: bigint, tickupp: number, amt0: bigint, amt1: bigint): [bigint, bigint, bigint] {
|
|
131
|
+
const sqrt_low = getSqrtPriceAtTick(ticklow);
|
|
132
|
+
const sqrt_upp = getSqrtPriceAtTick(tickupp);
|
|
133
|
+
// console.log(`sqrt_low: ${sqrt_low}, sqrt_upp: ${sqrt_upp}, sqrt_cur: ${sqrt_cur}`);
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
if (sqrt_low > sqrt_cur) {
|
|
137
|
+
// 当前价格比最低价格还要小,流动性按照token0数量计算
|
|
138
|
+
const liq0 = liquidity0(amt0, sqrt_low, sqrt_upp);
|
|
139
|
+
return [liq0, amount0(liq0, sqrt_low, sqrt_upp), BigInt(0)];
|
|
140
|
+
} else if (sqrt_cur > sqrt_upp) {
|
|
141
|
+
// 当前价格比最高价格还要高,流动性按照token1数量计算
|
|
142
|
+
const liq1 = liquidity1(amt1, sqrt_upp, sqrt_low);
|
|
143
|
+
return [liq1, BigInt(0), amount1(liq1, sqrt_low, sqrt_upp)];
|
|
144
|
+
} else {
|
|
145
|
+
// 按照流动性最高的来计算
|
|
146
|
+
const liq0 = liquidity0(amt0, sqrt_cur, sqrt_upp);
|
|
147
|
+
const liq1 = liquidity1(amt1, sqrt_cur, sqrt_low);
|
|
148
|
+
|
|
149
|
+
const liq = liq0 < liq1 ? liq1 : liq0;
|
|
150
|
+
return [liq, amount0(liq, sqrt_cur, sqrt_upp), amount1(liq, sqrt_low, sqrt_cur)];
|
|
151
|
+
}
|
|
152
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Contract } from "ethers";
|
|
2
|
+
|
|
3
|
+
export async function listenAllEvents(hook: Contract): Promise<void> {
|
|
4
|
+
hook.on('*', (event) => {
|
|
5
|
+
console.log(`${event.event} event emitted:`);
|
|
6
|
+
for (const key in event.args) {
|
|
7
|
+
if (event.args.hasOwnProperty(key)) {
|
|
8
|
+
console.log(`${key}: ${event.args[key].toString()}`);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function listenPlaceEvent(contract: Contract): Promise<void> {
|
|
15
|
+
contract.once("Place", (owner, epoch, key, tickLower, zeroForOne, liquidity) => {
|
|
16
|
+
console.log("Place event emitted:");
|
|
17
|
+
console.log("Owner: ", owner);
|
|
18
|
+
console.log("Epoch: ", epoch.toString());
|
|
19
|
+
console.log("Key: ", key);
|
|
20
|
+
console.log("TickLower: ", tickLower.toString());
|
|
21
|
+
console.log("ZeroForOne: ", zeroForOne);
|
|
22
|
+
console.log("Liquidity: ", liquidity.toString());
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export async function listenKillEvent(contract: Contract): Promise<void> {
|
|
27
|
+
contract.once("Kill", (owner, epoch, key, tickLower, zeroForOne, liquidity) => {
|
|
28
|
+
console.log("Kill event emitted:");
|
|
29
|
+
console.log("Owner: ", owner);
|
|
30
|
+
console.log("Epoch: ", epoch.toString());
|
|
31
|
+
console.log("Key: ", key);
|
|
32
|
+
console.log("TickLower: ", tickLower.toString());
|
|
33
|
+
console.log("ZeroForOne: ", zeroForOne);
|
|
34
|
+
console.log("Liquidity: ", liquidity.toString());
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export async function listenWithdrawEvent(contract: Contract): Promise<void> {
|
|
39
|
+
contract.once("Withdraw", (owner, epoch, liquidity) => {
|
|
40
|
+
console.log("Withdraw event emitted:");
|
|
41
|
+
console.log("Owner: ", owner);
|
|
42
|
+
console.log("Epoch: ", epoch.toString());
|
|
43
|
+
console.log("Liquidity: ", liquidity.toString());
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function listenFillEvent(contract: Contract): Promise<void> {
|
|
48
|
+
contract.once("Fill", (owner, epoch, key, tickLower, zeroForOne, liquidity) => {
|
|
49
|
+
console.log("Fill event emitted:");
|
|
50
|
+
console.log("Owner: ", owner);
|
|
51
|
+
console.log("Epoch: ", epoch.toString());
|
|
52
|
+
console.log("Key: ", key);
|
|
53
|
+
console.log("TickLower: ", tickLower.toString());
|
|
54
|
+
console.log("ZeroForOne: ", zeroForOne);
|
|
55
|
+
console.log("Liquidity: ", liquidity.toString());
|
|
56
|
+
});
|
|
57
|
+
}
|