O recurso está a ser carregado... Carregamento...

FMZ Quantificação Uniswap V3 Guia de operação relacionado à liquidez do reservatório de câmbio (1)

Autora:Inventor quantificado - sonho pequeno, Criado: 2023-07-14 17:36:55, Atualizado: 2024-11-11 22:38:18

FMZ量化Uniswap V3兑换池流动性相关操作指南(一)

Contrato de Gestor de Posições Não-Fungível no Uniswap V3

Depois de adicionarmos liquidez ao pool de liquidez da Uniswap V3, o contrato NonfungiblePositionManager retornará uma NFT forjada para nós como credencial de adição de liquidez. O primeiro passo é usar um contrato de roteamento para obter o endereço correspondente do contrato do NonfungiblePositionManager, e depois usar o método balanceOf do contrato do NonfungiblePositionManager para obter o número de NFTs de posição do endereço de carteira especificado. Em seguida, o método tokenOfOwnerByIndex é usado para obter o tokenId dessas posições NFT, e com esses tokenId, o método positions pode ser usado para obter mais detalhes sobre essas posições.

O código do teste é o seguinte:

javascript // Uniswap ABI const ABI_UniswapV3Router =[inputs:[{internalType:address,name:_factoryV2,type:address},{internalType:address,type:address},{internalType:address,name:factoryV3,type:address},{internalType:address,name:inputs:address,type:address},{internalType:address,inputs:address,name:positionManager,type:address},{internalType:address,name:type:address,type:address,type:address,typeaddress,typeaddress:address,address,address, const ABI_NonfungiblePositionManager =[{inputs:[{internalType:address,name:_factory,type:address},{internalType:address,name:_WETH9,type:address},{internalType:address,name:tokenDescriptor,type:address}],stateMutability:nonpayable,type:constructor},{indexed:true:false,inputs:[indexed:true,internalType:address,name:owner,type:address},{indexed:true,internalType:address:type:address},{indexed:true,internalType:address:type:address:address},{indexed:true,internalType:address:type:type:address:address},{indexed:true,type:owner:type:type:address:address:address},{indexedindexed ABI_Pool = [\\inputs\:[],\stateMutability:\nonpayable\,\type\:\constructor\,\name\,\anonymous\:\false,\inputs\:[\\indexed\:true,\internalType\:\address\:\stateMutability:\indexed\:true,\internalAddtype\:\int24\,\name\:\tickaddadduplicator\,\indexed\:\type\,\type\,\type\type\,\type\\type\,\type\\\\type\,\type\\\\type\,\type\\\\type\,\type\\\\type\,\type\,\\\\\\\\\ ABI_Factory = [\\inputs\\:[],\stateMutability\:\\nonpayable\,\\type\:\\\addaddconstructor\,\\\anonymous\:\false,\inputs\:[\\\\indexed\:true,\internalType\:\uint24\,\\\name\:\fee\,\\\\\\\\type\:\\uint24\,\\\\indexed\:true,\\\internaladdaddaddtype\:\addtype\:\uint24\,\name\:\anonymous\:\addaddaddtype\:\,\type\:\type\:\type\:\type\:\type\:\type\:\:\type\:\:\"internaladdname\:\,\

// Endereço do contrato Uniswap const UniswapV3RouterAddress = 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45 const ContractV3Factory = 0x1F98431c8aD98523631AE4a59f267346ea31F984

// quantidade usada const TWO = BigInt ((2) const Q192 = (TWO ** BigInt ((96)) ** TWO const Q96 = (TWO ** BigInt ((96))

// Converte-se em quantidade de leitura função toAmount ((s, decimais) { return Number (BigDecimal (BigInt)) / BigDecimal (Math.pow (), decimais))).toString ()) Não.

// Converte inversamente o número de leitura para o número de dados a serem transmitidos e calculados função toInnerAmount ((n, decimais) { return (BigDecimal ((n) * BigDecimal ((Math.pow ((10, decimais))).toFixed ((0) Não.

função main() { // endereço da carteira a ser pesquisado // const walletAddress = exchange.IO ((address bar)) const walletAddress = 0x28df8b987BE232bA33FdFB8Fc5058C1592A3db26

// 获取Uniswap V3的positionManager合约的地址
exchange.IO("abi", UniswapV3RouterAddress, ABI_UniswapV3Router)
const NonfungiblePositionManagerAddress = exchange.IO("api", UniswapV3RouterAddress, "positionManager")
Log("NonfungiblePositionManagerAddress:", NonfungiblePositionManagerAddress)

// 注册positionManager合约的ABI
exchange.IO("abi", NonfungiblePositionManagerAddress, ABI_NonfungiblePositionManager)

// 查询当前账户拥有的Uniswap V3 positions NFT数量
var nftBalance = exchange.IO("api", NonfungiblePositionManagerAddress, "balanceOf", walletAddress)
Log("nftBalance:", nftBalance)

// 查询这些NFT的TokenId
var nftTokenIds = []
for (var i = 0 ; i < nftBalance; i++) {
    var nftTokenId = exchange.IO("api", NonfungiblePositionManagerAddress, "tokenOfOwnerByIndex", walletAddress, i)
    nftTokenIds.push(nftTokenId)
    Log("nftTokenId:", nftTokenId)
}

// 根据positions NFT的tokenId查询流动性头寸详细信息
var positions = []
for (var i = 0; i < nftTokenIds.length; i++) {
    var pos = exchange.IO("api", NonfungiblePositionManagerAddress, "positions", nftTokenIds[i])        
    Log("pos:", pos)

    // 解析头寸数据
    positions.push(parsePosData(pos))
}

var tbl = {
    type : "table",
    title : "LP",
    cols : ["range(token0计价)", "token0", "token1", "fee", "lowerPrice(tickLower)", "upperPrice(tickUpper)", "liquidity", "amount0", "amount1"],
    rows : positions
}
LogStatus("`" + JSON.stringify(tbl) + "`")

}

// Regista as informações sobre os tokens consultados pelo coingecko.com Var tokens = [] função init (()) { // Obter informações de todos os tokens no momento da inicialização, para ser usado para fazer consultas Var res = JSON.parse (httpQuery)https://tokens.coingecko.com/uniswap/all.json”)) Log ((fetch, res.tokens.length, tokens from, res.name) _.each ((res.tokens, função ((token) { Tokens.push (em inglês). nome: token.name, símbolo: token.symbol, decimais: token.decimais, Endereço: token.address - Não. - Não. Log ((tokens:, tokens) - Não.

Função parsePosData ((posData) { /* - O quê? anúncio: 0, operador : 0x000000000000000000000000000000000000 , token1: 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2, taxa: 3000, taxa de crescimento interno0últimoX128: 552824104363438506727784685971981736468, feesGrowthInside1LastX128: 2419576808699564757520565912733367379 tokensDebido0: 0, tokensDebido1: 0, token0: 0x1f9840a85d5af5bf1d1762f925bdaddc4201f984, tickLower: -62160, tickUpper: -41280, liquidez: 19090316141441365693 - Não. */

var token0Symbol = null
var token1Symbol = null
// 根据代币地址判断token,记录token的相关信息
for (var i in tokens) {
    if (tokens[i].address.toLowerCase() == posData.token0.toLowerCase()) {
        token0Symbol = tokens[i]
    } else if (tokens[i].address.toLowerCase() == posData.token1.toLowerCase()) {
        token1Symbol = tokens[i]
    }
}

if (!token0Symbol || !token1Symbol) {
	Log("token0Symbol:", token0Symbol, ", token1Symbol:", token1Symbol)
    throw "token not found"
}

// get Pool ,获取兑换池的相关数据
var poolInfo = getPool(token0Symbol.address, token1Symbol.address, posData.fee)
Log("poolInfo:", poolInfo)
/* 数据范例
{
    "slot0":{
        "sqrtPriceX96":"4403124416947951698847768103","tick":"-57804","observationIndex":136,"observationCardinality":300,
        "observationCardinalityNext":300,"feeProtocol":0,"unlocked":true
    }
}
*/

// 计算token0Amount, token1Amount
var currentTick = parseInt(poolInfo.slot0.tick)
var lowerPrice = 1.0001 ** posData.tickLower
var upperPrice = 1.0001 ** posData.tickUpper
var sqrtRatioA = Math.sqrt(lowerPrice)
var sqrtRatioB = Math.sqrt(upperPrice)
var sqrtPrice = Number(BigFloat(poolInfo.slot0.sqrtPriceX96) / Q96)

var amount0wei = 0
var amount1wei = 0
if (currentTick <= posData.tickLower) {
    amount0wei = Math.floor(posData.liquidity * ((sqrtRatioB - sqrtRatioA) / (sqrtRatioA * sqrtRatioB)))
} else if (currentTick > posData.tickUpper) {
    amount1wei = Math.floor(posData.liquidity * (sqrtRatioB - sqrtRatioA))
} else if (currentTick >= posData.tickLower && currentTick < posData.tickUpper) {
    amount0wei = Math.floor(posData.liquidity * ((sqrtRatioB - sqrtPrice) / (sqrtPrice * sqrtRatioB)))
    amount1wei = Math.floor(posData.liquidity * (sqrtPrice - sqrtRatioA))
}

var rangeToken0 = (1.0001 ** -posData.tickUpper) + " ~ " + (1.0001 ** -posData.tickLower)
var amount0 = toAmount(amount0wei, token0Symbol.decimals)
var amount1 = toAmount(amount1wei, token1Symbol.decimals)

return [rangeToken0, token0Symbol.symbol,

Relacionado

Mais informações

Crypto Joe.É muito forte!