|
|
@@ -48,6 +48,9 @@ import { FileService } from 'src/file/file.service'
|
|
|
import axios from 'axios'
|
|
|
import * as randomString from 'randomstring'
|
|
|
import { Account } from '../accounts/entities/account.entity'
|
|
|
+import SyncSwapPoolFactoryAbi from './abi/SyncSwapClassicPoolFactory.json'
|
|
|
+import SyncSwapPoolAbi from './abi/SyncSwapClassicPool.json'
|
|
|
+import SyncSwapRouterAbi from './abi/SyncSwapRouter.json'
|
|
|
|
|
|
@Injectable()
|
|
|
export class Web3Service {
|
|
|
@@ -287,128 +290,87 @@ export class Web3Service {
|
|
|
|
|
|
async addLiquiditySyncSwap(accountId, amount) {
|
|
|
const account = await this.accountService.findById(accountId)
|
|
|
- const chainId =
|
|
|
- web3Config[account.network].ethereumNetwork == 'goerli' ? ChainId.ZkSyncAlphaTest : ChainId.ZkSyncEra
|
|
|
- const provider = new Provider(web3Config[account.network].zksyncRpcUrl)
|
|
|
+ const config = web3Config[account.network]
|
|
|
+ const provider = new Provider(config.zksyncRpcUrl)
|
|
|
const zkWallet = new Wallet(account.privateKey).connect(provider)
|
|
|
- const chain = initialChainTable[chainId]
|
|
|
- const web3 = new Web3(new Web3.providers.HttpProvider(web3Config[account.network].zksyncRpcUrl))
|
|
|
- Logger.log(`address: ${zkWallet.address}`, 'addLiquidity')
|
|
|
-
|
|
|
- const liquidityManagerContract = getLiquidityManagerContract(
|
|
|
- web3Config[account.network].liquidityManagerAddress,
|
|
|
- web3 as any
|
|
|
- )
|
|
|
+ const web3 = new Web3(new Web3.providers.HttpProvider(config.zksyncRpcUrl))
|
|
|
|
|
|
- const tokenA = getGasToken(chainId)
|
|
|
- Logger.log(`tokenA: ${JSON.stringify(tokenA, null, 4)}`, 'addLiquidity')
|
|
|
- const tokenB = await fetchToken(web3Config[account.network].zkUsdcAddress, chain, web3 as any)
|
|
|
- Logger.log(`tokenB: ${JSON.stringify(tokenB, null, 4)}`, 'addLiquidity')
|
|
|
-
|
|
|
- await this.approve(
|
|
|
- tokenB.address,
|
|
|
- web3Config[account.network].liquidityManagerAddress,
|
|
|
- zkWallet,
|
|
|
- account.network
|
|
|
+ Logger.log(`amount: ${amount}`, 'addLiquiditySyncSwap')
|
|
|
+ const poolFactory = new web3.eth.Contract(SyncSwapPoolFactoryAbi, config.syncSwapPoolFactoryAddress)
|
|
|
+ // @ts-ignore
|
|
|
+ const poolAddress = await poolFactory.methods.getPool(config.syncSwapWethAddress, config.zkUsdcAddress).call()
|
|
|
+ Logger.log(`poolAddress: ${poolAddress}`, 'addLiquiditySyncSwap')
|
|
|
+
|
|
|
+ const router = new web3.eth.Contract(SyncSwapRouterAbi, config.syncSwapRouterAddress)
|
|
|
+ const addLiquidity = router.methods.addLiquidity2(
|
|
|
+ // @ts-ignore
|
|
|
+ poolAddress,
|
|
|
+ [
|
|
|
+ [ethers.constants.AddressZero, ethers.utils.parseEther(amount).toString()],
|
|
|
+ [config.zkUsdcAddress, ethers.utils.parseUnits('0', 6).toString()]
|
|
|
+ ],
|
|
|
+ //encode abi
|
|
|
+ ethers.utils.defaultAbiCoder.encode(['uint256'], [zkWallet.address]),
|
|
|
+ 0,
|
|
|
+ ethers.constants.AddressZero,
|
|
|
+ '0x'
|
|
|
)
|
|
|
|
|
|
- const fee = 2000 // 2000 means 0.2%
|
|
|
- const poolAddress = await getPoolAddress(liquidityManagerContract, tokenA, tokenB, fee)
|
|
|
- Logger.log(`poolAddress: ${poolAddress}`, 'addLiquidity')
|
|
|
-
|
|
|
- const poolContract = getPoolContract(poolAddress, web3 as any)
|
|
|
- const state = await getPoolState(poolContract)
|
|
|
- const currentPrice = point2PriceDecimal(tokenA, tokenB, state.currentPoint)
|
|
|
- Logger.log(`current point: ${state.currentPoint}`, 'addLiquidity')
|
|
|
-
|
|
|
- const point1 = priceDecimal2Point(tokenA, tokenB, currentPrice * 0.98, PriceRoundingType.PRICE_ROUNDING_NEAREST)
|
|
|
- const point2 = priceDecimal2Point(tokenA, tokenB, currentPrice * 1.02, PriceRoundingType.PRICE_ROUNDING_NEAREST)
|
|
|
- Logger.log(`point range: ${point1} - ${point2}`, 'addLiquidity')
|
|
|
- let leftPoint = Math.min(point1, point2)
|
|
|
- let rightPoint = Math.max(point1, point2)
|
|
|
- const pointDelta = await getPointDelta(poolContract)
|
|
|
- Logger.log(`point delta: ${pointDelta}`, 'addLiquidity')
|
|
|
- leftPoint = pointDeltaRoundingDown(leftPoint, pointDelta)
|
|
|
- rightPoint = pointDeltaRoundingUp(rightPoint, pointDelta)
|
|
|
-
|
|
|
- const maxTestA = new BigNumber(amount).times(10 ** tokenA.decimal)
|
|
|
- const maxTestB = calciZiLiquidityAmountDesired(
|
|
|
- leftPoint,
|
|
|
- rightPoint,
|
|
|
- state.currentPoint,
|
|
|
- maxTestA,
|
|
|
- true,
|
|
|
- tokenA,
|
|
|
- tokenB
|
|
|
- )
|
|
|
- const mintParams = {
|
|
|
- tokenA: tokenA,
|
|
|
- tokenB: tokenB,
|
|
|
- fee,
|
|
|
- leftPoint,
|
|
|
- rightPoint,
|
|
|
- maxAmountA: maxTestA.toFixed(0),
|
|
|
- maxAmountB: maxTestB.toFixed(0),
|
|
|
- minAmountA: maxTestA.times(0.985).toFixed(0),
|
|
|
- minAmountB: maxTestB.times(0.985).toFixed(0)
|
|
|
- }
|
|
|
+ const gasLimit = await addLiquidity.estimateGas({
|
|
|
+ from: zkWallet.address,
|
|
|
+ value: ethers.utils.parseEther(amount).toString()
|
|
|
+ })
|
|
|
+ const tx = await zkWallet.sendTransaction({
|
|
|
+ // from: wallet.address,
|
|
|
+ to: config.syncSwapRouterAddress,
|
|
|
+ data: addLiquidity.encodeABI(),
|
|
|
+ value: ethers.utils.parseEther(amount).toString(),
|
|
|
+ gasLimit
|
|
|
+ })
|
|
|
+ Logger.log(`transaction sent: ${tx.hash}`, 'addLiquiditySyncSwap')
|
|
|
+ return new Web3Result(account.address, tx.hash, config, true)
|
|
|
+ }
|
|
|
|
|
|
- Logger.log(
|
|
|
- `tokenAtoPay: ${amount2Decimal(new BigNumber(maxTestA), tokenA)}, tokenBtoPay: ${amount2Decimal(
|
|
|
- new BigNumber(maxTestB),
|
|
|
- tokenB
|
|
|
- )}, price: ${point2PriceDecimal(tokenA, tokenB, state.currentPoint)}`,
|
|
|
- 'addLiquidity'
|
|
|
- )
|
|
|
- const balanceA = await zkWallet.getBalance()
|
|
|
- const balanceB = await zkWallet.getBalance(tokenB.address)
|
|
|
- if (new BigNumber(balanceA.toString()).lt(maxTestA)) {
|
|
|
- throw new InternalServerErrorException(
|
|
|
- `${tokenA.symbol}余额不足, 需要${ethers.utils.formatUnits(
|
|
|
- maxTestA.toString(),
|
|
|
- tokenA.decimal
|
|
|
- )}, 当前${ethers.utils.formatUnits(balanceA, tokenA.decimal)}`
|
|
|
- )
|
|
|
- }
|
|
|
- if (new BigNumber(balanceB.toString()).lt(maxTestB)) {
|
|
|
- throw new InternalServerErrorException(
|
|
|
- `${tokenB.symbol}余额不足, 需要${ethers.utils.formatUnits(
|
|
|
- maxTestB.toString(),
|
|
|
- tokenB.decimal
|
|
|
- )}, 当前${ethers.utils.formatUnits(balanceB, tokenB.decimal)}`
|
|
|
- )
|
|
|
- }
|
|
|
+ async removeLiquiditySyncSwap(accountId) {
|
|
|
+ const account = await this.accountService.findById(accountId)
|
|
|
+ const config = web3Config[account.network]
|
|
|
+ const provider = new Provider(config.zksyncRpcUrl)
|
|
|
+ const zkWallet = new Wallet(account.privateKey).connect(provider)
|
|
|
+ const web3 = new Web3(new Web3.providers.HttpProvider(config.zksyncRpcUrl))
|
|
|
|
|
|
- Logger.log(`mintParams: ${JSON.stringify(mintParams, null, 4)}`, 'addLiquidity')
|
|
|
+ const poolFactory = new web3.eth.Contract(SyncSwapPoolFactoryAbi, config.syncSwapPoolFactoryAddress)
|
|
|
+ // @ts-ignore
|
|
|
+ const poolAddress = await poolFactory.methods.getPool(config.syncSwapWethAddress, config.zkUsdcAddress).call()
|
|
|
+ Logger.log(`poolAddress: ${poolAddress}`, 'removeLiquiditySyncSwap')
|
|
|
|
|
|
- const gasPrice = await web3.eth.getGasPrice()
|
|
|
- const { mintCalling, options } = getMintCall(
|
|
|
- liquidityManagerContract,
|
|
|
- zkWallet.address,
|
|
|
- chain,
|
|
|
- mintParams,
|
|
|
- gasPrice.toString()
|
|
|
+ const pool = new web3.eth.Contract(SyncSwapPoolAbi, poolAddress as unknown as string)
|
|
|
+ // @ts-ignore
|
|
|
+ const liquidity = await pool.methods.balanceOf(zkWallet.address).call()
|
|
|
+ Logger.log(`liquidity: ${liquidity}`, 'removeLiquiditySyncSwap')
|
|
|
+
|
|
|
+ const router = new web3.eth.Contract(SyncSwapRouterAbi, config.syncSwapRouterAddress)
|
|
|
+ const burnLiquiditySingle = router.methods.burnLiquiditySingle(
|
|
|
+ // @ts-ignore
|
|
|
+ poolAddress,
|
|
|
+ liquidity,
|
|
|
+ ethers.utils.defaultAbiCoder.encode(
|
|
|
+ ['uint256', 'uint256', 'uint8'],
|
|
|
+ [ethers.constants.AddressZero, zkWallet.address, '0']
|
|
|
+ ),
|
|
|
+ '0',
|
|
|
+ ethers.constants.AddressZero,
|
|
|
+ '0x'
|
|
|
)
|
|
|
- let calling = mintCalling
|
|
|
- if (calling instanceof Array) {
|
|
|
- calling = liquidityManagerContract.methods.multicall(mintCalling)
|
|
|
- }
|
|
|
- const gasLimit = await calling.estimateGas({ from: zkWallet.address })
|
|
|
- Logger.log(`gas limit: ${gasLimit}`, 'addLiquidity')
|
|
|
-
|
|
|
- // sign transaction
|
|
|
+ const gasLimit = await burnLiquiditySingle.estimateGas({
|
|
|
+ from: zkWallet.address
|
|
|
+ })
|
|
|
const tx = await zkWallet.sendTransaction({
|
|
|
- from: options.from,
|
|
|
- value: Web3.utils.numberToHex(options.value),
|
|
|
- to: web3Config[account.network].liquidityManagerAddress,
|
|
|
- data: calling.encodeABI(),
|
|
|
+ to: config.syncSwapRouterAddress,
|
|
|
+ data: burnLiquiditySingle.encodeABI(),
|
|
|
gasLimit
|
|
|
})
|
|
|
- Logger.log(`tx hash: ${tx.hash}`, 'addLiquidity')
|
|
|
- account.addLiuidityNum = (account.addLiuidityNum || 0) + 1
|
|
|
- account.lastAddLiuidity = new Date()
|
|
|
- await this.accountService.save([account])
|
|
|
- return new Web3Result(account.address, tx.hash, web3Config[account.network], true)
|
|
|
+ Logger.log(`transaction sent: ${tx.hash}`, 'removeLiquiditySyncSwap')
|
|
|
+ return new Web3Result(account.address, tx.hash, config, true)
|
|
|
}
|
|
|
|
|
|
async removeLiquidity(accountId) {
|
|
|
@@ -673,6 +635,70 @@ export class Web3Service {
|
|
|
return new Web3Result(account.address, tx.hash, web3Config[account.network], true)
|
|
|
}
|
|
|
|
|
|
+ async swapSyncSwap(accountId, amount, inputToken: 'eth' | 'usdc' = 'usdc') {
|
|
|
+ const account = await this.accountService.findById(accountId)
|
|
|
+ const config = web3Config[account.network]
|
|
|
+ const provider = new Provider(config.zksyncRpcUrl)
|
|
|
+ const zkWallet = new Wallet(account.privateKey).connect(provider)
|
|
|
+ const web3 = new Web3(new Web3.providers.HttpProvider(config.zksyncRpcUrl))
|
|
|
+
|
|
|
+ if (inputToken === 'usdc') {
|
|
|
+ await this.approve(config.zkUsdcAddress, config.syncSwapRouterAddress, zkWallet, account.network)
|
|
|
+ }
|
|
|
+
|
|
|
+ Logger.log(`inputToken: ${inputToken}, amounnt=${amount}`, 'swapSyncSwap')
|
|
|
+ const poolFactory = new web3.eth.Contract(SyncSwapPoolFactoryAbi, config.syncSwapPoolFactoryAddress)
|
|
|
+ // @ts-ignore
|
|
|
+ const poolAddress = await poolFactory.methods.getPool(config.syncSwapWethAddress, config.zkUsdcAddress).call()
|
|
|
+ Logger.log(`poolAddress: ${poolAddress}`, 'addLiquiditySyncSwap')
|
|
|
+
|
|
|
+ const router = new web3.eth.Contract(SyncSwapRouterAbi, config.syncSwapRouterAddress)
|
|
|
+ const value =
|
|
|
+ inputToken === 'eth'
|
|
|
+ ? ethers.utils.parseEther(amount).toString()
|
|
|
+ : ethers.utils.parseUnits(amount, 6).toString()
|
|
|
+ const swap = router.methods.swap(
|
|
|
+ // @ts-ignore
|
|
|
+ [
|
|
|
+ [
|
|
|
+ [
|
|
|
+ [
|
|
|
+ poolAddress,
|
|
|
+ ethers.utils.defaultAbiCoder.encode(
|
|
|
+ ['address', 'address', 'uint8'],
|
|
|
+ [
|
|
|
+ inputToken === 'eth' ? config.syncSwapWethAddress : config.zkUsdcAddress,
|
|
|
+ zkWallet.address,
|
|
|
+ 1
|
|
|
+ ]
|
|
|
+ ),
|
|
|
+ ethers.constants.AddressZero,
|
|
|
+ '0x'
|
|
|
+ ]
|
|
|
+ ],
|
|
|
+ inputToken === 'eth' ? ethers.constants.AddressZero : config.zkUsdcAddress,
|
|
|
+ value
|
|
|
+ ]
|
|
|
+ ],
|
|
|
+ 0,
|
|
|
+ ethers.constants.AddressZero,
|
|
|
+ '0x'
|
|
|
+ )
|
|
|
+
|
|
|
+ const gasLimit = await swap.estimateGas({
|
|
|
+ from: zkWallet.address
|
|
|
+ })
|
|
|
+ const tx = await zkWallet.sendTransaction({
|
|
|
+ // from: wallet.address,
|
|
|
+ to: config.syncSwapRouterAddress,
|
|
|
+ data: swap.encodeABI(),
|
|
|
+ value: value,
|
|
|
+ gasLimit
|
|
|
+ })
|
|
|
+ Logger.log(`transaction sent: ${tx.hash}`, 'swapSyncSwap')
|
|
|
+ return new Web3Result(account.address, tx.hash, config, true)
|
|
|
+ }
|
|
|
+
|
|
|
async mint(accountId) {
|
|
|
// const { data: buffer } = await axios.get('https://cataas.com/cat', {
|
|
|
// responseType: 'arraybuffer'
|