name:
함수 toAmount ((s, 소수점) { 반환 번호 (BigDecimal) / BigDecimal (Math.pow), 10개의 소수점 (decimal) ♪ ♪
함수 toInnerAmount ((n, 소수점) { 반환 (BigDecimal(n) * BigDecimal(Math.pow(10, 소수))).toFixed(0) ♪ ♪
function main (() { // 유니스랩 공장 계약에 등록된 ABIexchange.IO("abi", 계약V3Factory주소, abiFactory)
// 注册Uniswap路由合约的ABI
exchange.IO("abi", contractV3SwapRouterV2Address, abiRoute)
// 获取交易对的池地址
var tokenIn = {name : "1INCH", address: "0x111111111117dC0aa78b770fA6A738034120C302", decimals: exchange.IO("api", "0x111111111117dC0aa78b770fA6A738034120C302", "decimals")}
var tokenOut = {name : "WETH", address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", decimals: exchange.IO("api", "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "decimals")}
var poolAddress = exchange.IO("api", contractV3FactoryAddress, "getPool", tokenIn.address, tokenOut.address, 10000)
// 注册池合约ABI
exchange.IO("abi", poolAddress, abiPool)
var slot0 = exchange.IO("api", poolAddress, "slot0")
Log("slot0:", slot0)
}
获取到兑换池的价格信息,打印出代码中```slot0```变量:
```javascript
{
"feeProtocol":0,
"unlocked":true,
"sqrtPriceX96":"1128983883551457130720648561",
"tick":"-85025",
"observationIndex":5,
"observationCardinality":6,
"observationCardinalityNext":6
}
그 중 주요 가격 정보 데이터는sqrtPriceX96
이 필드는 교환 조합의 토큰 정밀 데이터와 함께 교환 풀의 현재 가격을 계산해야 합니다.Uniswap
이 문서는 우리가 계산을 위해 함수를 구현한 것을 설명합니다.
function computePoolPrice(decimals0, decimals1, sqrtPriceX96) {
// sqrtPriceX96 = sqrt(price) * 2^96
[decimals0, decimals1, sqrtPriceX96] = [decimals0, decimals1, sqrtPriceX96].map(BigInt);
const TWO = BigInt(2);
const TEN = BigInt(10);
const SIX_TENTH = BigInt(1000000);
const Q192 = (TWO ** BigInt(96)) ** TWO;
return (
Number((sqrtPriceX96 ** TWO * TEN ** decimals0 * SIX_TENTH) / (Q192 * TEN ** decimals1)) /
Number(SIX_TENTH)
);
}
이 함수를 사용해서1INCH/WETH
function computePoolPrice(decimals0, decimals1, sqrtPriceX96) {
// sqrtPriceX96 = sqrt(price) * 2^96
[decimals0, decimals1, sqrtPriceX96] = [decimals0, decimals1, sqrtPriceX96].map(BigInt);
const TWO = BigInt(2);
const TEN = BigInt(10);
const SIX_TENTH = BigInt(1000000);
const Q192 = (TWO ** BigInt(96)) ** TWO;
return (
Number((sqrtPriceX96 ** TWO * TEN ** decimals0 * SIX_TENTH) / (Q192 * TEN ** decimals1)) /
Number(SIX_TENTH)
);
}
function main() {
var tokenIn = {name : "1INCH", address: "0x111111111117dC0aa78b770fA6A738034120C302", decimals: exchange.IO("api", "0x111111111117dC0aa78b770fA6A738034120C302", "decimals")}
var tokenOut = {name : "WETH", address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", decimals: exchange.IO("api", "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "decimals")}
// 获取的slot0变量中"sqrtPriceX96":"1128983883551457130720648561",
var price = computePoolPrice(tokenIn.decimals, tokenOut.decimals, "1128983883551457130720648561")
Log("price:", price)
}
인쇄 변수price
표시:price: 0.000203
1 인치에 0.000203 WETH가 있습니다.
발명가 양적 거래 플랫폼은 포장 된 것을 공개했습니다.Uniswap
템플릿이 템플릿의 소스 코드를 더 깊이 학습하고 웹 3 방향으로 응용 프로그램을 개발할 수 있습니다.
이 템플릿 라이브러리에는 많은 디자인 세부 사항이 있습니다.
토큰 정보를 자동으로 얻습니다.
예를 들어, 이 템플릿의 변수에서AutoFetchTokens
true로 설정하면 템플릿 프로그램이 자동으로 접속합니다.https://tokens.coingecko.com/uniswap/all.json
링크, 취득 및 자동으로 모든 토큰의 정보를 처리합니다. 이렇게하면 정책 코드에서 수동으로 토큰을 추가하지 않고 사용할 수 있습니다.addToken(name, address)
토큰을 추가합니다.
if (AutoFetchTokens) {
let res = JSON.parse(HttpQuery("https://tokens.coingecko.com/uniswap/all.json"))
Log("fetch", res.tokens.length, "tokens from", res.name)
res.tokens.forEach(function(token) {
if (token.chainId == chainId && token.symbol != "WETH") {
self.tokenInfo[token.symbol] = {
name: token.symbol,
decimals: token.decimals,
address: token.address
}
}
})
}
체인 설정에 따라 다른 계약 주소를 조정합니다
이 템플릿은 설정되었습니다.ChainType
여러 개의 체인 전환을 지원하는 매개 변수:
'https://rpc.ankr.com/eth',
'https://arb1.arbitrum.io/rpc',
'https://mainnet.optimism.io/',
'https://rpc.ankr.com/avalanche',
'https://polygon-rpc.com',
'https://rpc.ankr.com/celo',
if (typeof(ChainType) === 'number') {
let chainRpc = [
'',
'https://rpc.ankr.com/eth',
'https://arb1.arbitrum.io/rpc',
'https://mainnet.optimism.io/',
'https://rpc.ankr.com/avalanche',
'https://polygon-rpc.com',
'https://rpc.ankr.com/celo',
//'https://mainnet.aurora.dev',
//'https://bsc-dataseed.binance.org',
//'https://exchainrpc.okex.org'
][ChainType]
if (chainRpc && chainRpc.length > 0) {
e.IO("base", chainRpc)
Log("change base rpc to", chainRpc)
}
}
에테리움의 RPC 방법eth_chainId
현재 검색chainId
그리고,chainId
이 글은 WETH의 주소와 일치합니다.Uniswap
이 글은 전 세계 유동인물 거래소에서 공개된 글입니다.USDT
이 경우, 다른 체인에서 다른 계약 주소를 가질 수 있습니다.
// https://docs.uniswap.org/contracts/v3/reference/deployments
let WETHAddress = {
1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // Ethereum
3: "0xc778417E063141139Fce010982780140Aa0cD5Ab", // Ropsten
4: "0xc778417E063141139Fce010982780140Aa0cD5Ab", // Rinkeby
5: "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6", // Goerli
42: "0xd0A1E359811322d97991E03f863a0C30C2cF029C", // Kovan
10: "0x4200000000000000000000000000000000000006", // Optimism
69: "0x4200000000000000000000000000000000000006", // Optimistic Kovan
42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1", // Arbitrum One
421611: "0xB47e6A5f8b33b3F17603C83a0535A9dcD7E32681", // Arbitrum Rinkeby
137: "0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270", // Polygon
80001: "0x9c3C9283D3e44854697Cd22D3Faa240Cfb032889", // Polygon Mumbai
}
let chainId = e.IO("api", "ETH", "eth_chainId")
if (chainId) {
chainId = Number(chainId)
Log("chainId: ", chainId)
let addr = WETHAddress[chainId]
if (addr) {
Log("Register WETH address", addr)
self.addToken("ETH", addr)
}
if (chainId == 42220) {
// Celo Address
ContractV3Factory = '0xAfE208a311B21f13EF87E33A90049fC17A7acDEc'
ContractV3SwapRouterV2 = '0x5615CDAb10dc425a742d643d949a7F474C01abc4'
self.addToken('CELO', '0x471ece3750da237f93b8e339c536989b8978a438')
} else if (chainId == 42161) {
self.addToken('USDT', '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9')
}
} else {
panic("get chain Id error")
}
"Uniswap V3 트레이드 클래스 라이브러리"를 이용합니다.
이 템플릿에서$.testUniswap()
함수는 템플릿 함수를 테스트하는 함수이며, 코드는 템플릿을 사용하는 방법에 대한 호출 예제를 제공합니다.
$.testUniswap = function() {
let ex = $.NewUniswapV3()
Log("walletAddress: ", ex.walletAddress)
let tokenAddressMap = {
"USDT": "0xdac17f958d2ee523a2206206994597c13d831ec7",
"1INCH": "0x111111111117dC0aa78b770fA6A738034120C302",
"USDC": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
"DAI": "0x6b175474e89094c44da98b954eedeac495271d0f",
}
for (let name in tokenAddressMap) {
ex.addToken(name, tokenAddressMap[name])
}
Log(ex.getPrice('ETH_USDT'))
Log(ex.getPrice('1INCH_USDT'))
// swap 0.01 ETH to USDT
Log(ex.swapToken('ETH', 0.01, 'USDT'))
let usdtBalance = ex.balanceOf('USDT')
Log("balance of USDT", usdtBalance)
// swap USDT to DAI then DAI to ETH
Log(ex.swapToken('USDT', usdtBalance, 'DAI,ETH'))
Log("balance of ETH", ex.getETHBalance())
// Log(ex.sendETH('0x11111', 0.02))
// ...
}
어떤 정책이 "Uniswap V3 트랜잭션 클래스 라이브러리"를 참조할 때, 이 템플릿 클래스 라이브러리에 포괄된 함수를 호출할 수 있다.
이 프로젝트의 주제는ex
"Uniswap V3 트랜잭션 클래스 라이브러리" 템플릿을 호출하는 변수를 포괄한 인터페이스 함수$.NewUniswapV3()
하나의 객체에 값을 부여하는 것ex
。
let ex = $.NewUniswapV3()
사용ex
객체의 멤버 함수addToken()
이 트로킹은 트로킹에 대한 정보를 추가합니다.
let tokenAddressMap = {
"USDT": "0xdac17f958d2ee523a2206206994597c13d831ec7",
"1INCH": "0x111111111117dC0aa78b770fA6A738034120C302",
"USDC": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
"DAI": "0x6b175474e89094c44da98b954eedeac495271d0f",
}
for (let name in tokenAddressMap) {
ex.addToken(name, tokenAddressMap[name])
}
만약 당신이 거래 쌍의 교환 풀 가격을 얻고 인쇄하려면ex
객체의 멤버 함수getPrice()
이 글은 다음과 같습니다.
Log(ex.getPrice('ETH_USDT'))
Log(ex.getPrice('1INCH_USDT'))
만약 당신이 이식 작업을 수행하고 싶다면ex
객체의 멤버 함수swapToken()
이 모든 것은
// swap 0.01 ETH to USDT
Log(ex.swapToken('ETH', 0.01, 'USDT'))
let usdtBalance = ex.balanceOf('USDT')
Log("balance of USDT", usdtBalance)
// swap USDT to DAI then DAI to ETH
Log(ex.swapToken('USDT', usdtBalance, 'DAI,ETH'))
이 장에서는 발명자의 양적 거래 플랫폼을 사용하여 스마트 계약에 의해 출시되는 이벤트를 읽는 법을 배우게 될 것입니다.
이더리움의 RPC 방법을 사용하는 스마트 계약의 공개 이벤트를 검색합니다.eth_getLogs
에테리움의 RPC 노드를 호출하는 방법에 대한 설명은 이전 강의에서 설명했습니다.
예를 들어,WETH
계약된 이벤트는 FMZ를 사용하여 코드를 작성할 수 있습니다.디뷰팅 도구테스트, 거래소 객체 구성 RPC 노드는 에테리움 네트워크 노드, 호출eth_getLogs
이 방법은 3개의 매개 변수를 지정합니다.fromBlock
、toBlock
、address
우리는 fromBlock와 toBlock를 사용하여 블록 내의 데이터를 제한적으로 검색합니다.
function toAmount(s, decimals) {
return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString())
}
function toInnerAmount(n, decimals) {
return (BigDecimal(n) * BigDecimal(Math.pow(10, decimals))).toFixed(0)
}
function main() {
// getBlockNumber
var blockNumber = exchange.IO("api", "eth", "eth_blockNumber")
Log("blockNumber:", blockNumber)
// get logs
var fromBlock = "0x" + (toAmount(blockNumber, 0) - 1).toString(16)
var toBlock = "0x" + toAmount(blockNumber, 0).toString(16)
var params = {
"fromBlock" : fromBlock,
"toBlock" : toBlock,
"address" : "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" // WETH合约的地址
}
var logs = exchange.IO("api", "eth", "eth_getLogs", params)
// 由于数据量比较大,如果使用Log函数打印,数据会被截断。使用return将完整数据返回在页面「函数结果」编辑框中
return logs
}
로그 데이터에 접근하기 위해, 더 많은 데이터로 인해, 우리는 몇 가지 내용을 생략했습니다:
[{
"data": "0x00000000000000000000000000000000000000000000000001c1a55000000000",
"topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x0000000000000000000000006b75d8af000000e20b7a7ddf000ba900b4009a80", "0x000000000000000000000000bcb095c1f9c3dc02e834976706c87dee5d0f1fb6"],
"transactionHash": "0x27f9bf5abe3148169b4b85a83e1de32bd50eb81ecc52e5af006157d93353e4c4",
"transactionIndex": "0x0",
"removed": false,
"address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
"blockHash": "0x847be24a7b159c292bda030a011dfec89487b70e71eed486969b032d6ef04bad",
"blockNumber": "0x109b1cc",
"logIndex": "0x0"
}, {
"data": "0x00000000000000000000000000000000000000000000000008ea20cdea027c00",
"logIndex": "0x5",
"topics": ["0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c", "0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"],
"address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
"blockHash": "0x847be24a7b159c292bda030a011dfec89487b70e71eed486969b032d6ef04bad",
"blockNumber": "0x109b1cc",
"removed": false,
"transactionHash": "0xace3afa02e8af5d1ef6fc1635fbdf7bee37624547937ea5272c23968dd034c09",
"transactionIndex": "0x1"
},
...
{
"blockNumber": "0x109b1cd",
"address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
"data": "0x00000000000000000000000000000000000000000000000002c053531ab8a000",
"logIndex": "0xd3",
"removed": false,
"topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", "0x000000000000000000000000252ba9b5916171dbdadd2cec7f91875a006955d0"],
"transactionHash": "0x3012b82891f85b077cfe1c12cb9722b93c696ef2c37d67981ccddcc9c3396aca",
"transactionIndex": "0x8d",
"blockHash": "0xcd3d567c9bd02a4549b1de0dc638ab5523e847c3c156b096424f56c633000fd9"
}, {
"topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x00000000000000000000000012b791bb27b3a4ee958b5a435fea7d49ec076e9c", "0x000000000000000000000000ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b"],
"transactionIndex": "0x91",
"logIndex": "0xdb",
"removed": false,
"blockNumber": "0x109b1cd",
"data": "0x0000000000000000000000000000000000000000000000000164f2434262e1cc",
"transactionHash": "0x6aa8d80daf42f442591e7530e31323d05e1d6dd9f9f9b9c102e157d89810c048",
"address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
"blockHash": "0xcd3d567c9bd02a4549b1de0dc638ab5523e847c3c156b096424f56c633000fd9"
}, {
"address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
"blockHash": "0xcd3d567c9bd02a4549b1de0dc638ab5523e847c3c156b096424f56c633000fd9",
"blockNumber": "0x109b1cd",
"logIndex": "0xde",
"removed": false,
"topics": ["0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65", "0x000000000000000000000000ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b"],
"data": "0x0000000000000000000000000000000000000000000000000164f2434262e1cc",
"transactionHash": "0x6aa8d80daf42f442591e7530e31323d05e1d6dd9f9f9b9c102e157d89810c048",
"transactionIndex": "0x91"
}]
로그 데이터에 있는 모든 종류의 이벤트를 볼 수 있습니다Transfer
이 자료를 이용해서Transfer
이 사건은 필터링되어 있습니다.
이더리움 로그는 두 부분으로 나뉘어 있습니다.topics
2 데이터data
。
주제topics
그리고eth_getLogs
이 프로젝트의 주요 목표는 개발자들에 대한 신뢰를 높이고,topics
필드의 데이터는 다음과 같습니다:
"topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x00000000000000000000000012b791bb27b3a4ee958b5a435fea7d49ec076e9c", "0x000000000000000000000000ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b"],
이것은topics
(주제) 필드의 값은 행렬 구조로, 이벤트를 설명하기 위해 사용된다. 그것의 ((열열) 길이가 4을 초과할 수 없도록 규정한다. 첫 번째 요소는 이벤트의 서명 해시 값이다.
우리는 발명가들의 양적 거래 플랫폼을 사용했습니다.Encode
이 함수는 다음과 같은 코드를 사용하여 서명 해시 값을 계산할 수 있습니다.
function main() {
var eventFunction = "Transfer(address,address,uint256)"
var eventHash = Encode("keccak256", "string", "hex", eventFunction)
Log("eventHash:", "0x" + eventHash)
// eventHash: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
}
계산해 보세요.Transfer(address,address,uint256)
이 모든 것은keccak256
해시 값 (hex 코딩) 은0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
。
topics
필드의 값은 배열 구조이며, 두 번째 요소와 세 번째 요소는 다음과 같습니다.
from
to
데이터data
data
필드의 데이터는 다음과 같습니다:
"data": "0x0000000000000000000000000000000000000000000000000164f2434262e1cc",
이 사건의 일부 매개 변수 (스마트 컨트랙트의 솔리디티 코드 내의 매개 변수에는 인덱스 된 선언이 없습니다) 는data
이 부분에는
이 데이터를 분석합니다.0x0000000000000000000000000000000000000000000000000164f2434262e1cc
function toAmount(s, decimals) {
return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString())
}
function main() {
var value = "0x0000000000000000000000000000000000000000000000000164f2434262e1cc"
Log(toAmount(value, 0) / 1e18) // 0.10047146239950075
}
이 자료는 0.10047146239950075입니다.data
이 자료는 송금 금액에 해당합니다.
이 문서의 내용을 설명하고, 연습하고, 준비할 수 있습니다.
function toAmount(s, decimals) {
return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString())
}
function toInnerAmount(n, decimals) {
return (BigDecimal(n) * BigDecimal(Math.pow(10, decimals))).toFixed(0)
}
function main() {
// getBlockNumber
var blockNumber = exchange.IO("api", "eth", "eth_blockNumber")
Log("blockNumber:", blockNumber)
// get logs
var fromBlock = "0x" + (toAmount(blockNumber, 0) - 1).toString(16)
var toBlock = "0x" + toAmount(blockNumber, 0).toString(16)
var params = {
"fromBlock" : fromBlock,
"toBlock" : toBlock,
"address" : "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
}
var logs = exchange.IO("api", "eth", "eth_getLogs", params)
// 遍历logs
var eventFunction = "Transfer(address,address,uint256)"
var eventHash = "0x" + Encode("keccak256", "string", "hex", eventFunction)
Log("eventHash:", eventHash)
var counter = 0
for (var i = logs.length - 1; i >= 0 && counter < 10; i--) {
if (logs[i].topics[0] == eventHash) {
Log("Event Transfer, data:", toAmount(logs[i].data, 0) / 1e18, ", blockNumber:", toAmount(logs[i].blockNumber, 0), ", transactionHash:", logs[i].transactionHash,
", log:", logs[i])
counter++
}
}
}
이쪽에서https://etherscan.io/
이 문서를 검색하세요:
FMZ 디뷰팅 도구에서 테스트 코드가 실행되는 결과:
검색시 필요에 따라 분석할 수도 있습니다.from
,to
필드의 데이터, 예를 들어:
function main() {
var from = "0x00000000000000000000000012b791bb27b3a4ee958b5a435fea7d49ec076e9c"
var address = "0x" + exchange.IO("encodePacked", "address", from)
Log("address:", address)
}
이 프로젝트의 결과는:
주소: 0x12b791bb27b3a4ee958b5a435fea7d49ec076e9c
그 이유는디뷰팅 도구코드는 짧은 시간 동안 테스트 할 수 있으며 코드가 실행된 후에만 출력을 할 수 있으며 실시간으로 표시, 출력 로그를 할 수 없습니다. 이 섹션의 내용은 우리는 발명자의 양적 거래 플랫폼을 사용하여 실제 디스크를 생성하여 테스트합니다.
여기 우리는 에테리움을 사용하고 있습니다.USDT
이 통화 계약은Transfer(address,address,uint256)
우리는 지난 수업에서 배운 내용에 따라 스마트 컨트랙트 이벤트에 대한 지속적인 경청의 예를 작성했습니다.
function toAmount(s, decimals) {
return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString())
}
function toInnerAmount(n, decimals) {
return (BigDecimal(n) * BigDecimal(Math.pow(10, decimals))).toFixed(0)
}
function addEventListener(contractAddress, event, callBack) {
var self = {}
self.eventHash = "0x" + Encode("keccak256", "string", "hex", event)
self.contractAddress = contractAddress
self.latestBlockNumber = 0
self.fromBlockNumber = 0
self.firstBlockNumber = 0
/* TODO: test
self.isFirst = true
*/
self.getBlockNumber = function() {
var maxTry = 10
for (var i = 0; i < maxTry; i++) {
var ret = exchange.IO("api", "eth", "eth_blockNumber")
if (ret) {
return toAmount(ret, 0)
}
Sleep(5000)
}
throw "getBlockNumber failed"
}
self.run = function() {
var currBlockNumber = self.getBlockNumber()
var fromBlock = "0x" + self.fromBlockNumber.toString(16)
var toBlock = "0x" + currBlockNumber.toString(16)
var params = {