ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [solidity] UniSwapV3Factory 컨트랙트로 event에 대해 알아보기
    solidity 2023. 2. 19. 12:30
    반응형

    유니스왑 코드를 보다가 solidity 에서 indexed 키워드 역할이 궁금해서 찾아보고 실습해보는 목적의 글이다.

    interface IUniswapV3Factory {
        event OwnerChanged(address indexed oldOwner, address indexed newOwner);
        event PoolCreated(
            address indexed token0,
            address indexed token1,
            uint24 indexed fee,
            int24 tickSpacing,
            address pool
        );
        event FeeAmountEnabled(uint24 indexed fee, int24 indexed tickSpacing);
    
        function owner() external view returns (address);
        function feeAmountTickSpacing(uint24 fee) external view returns (int24);
        function getPool(
            address tokenA,
            address tokenB,
            uint24 fee
        ) external view returns (address pool);
        function createPool(
            address tokenA,
            address tokenB,
            uint24 fee
        ) external returns (address pool);
        function setOwner(address _owner) external;
        function enableFeeAmount(uint24 fee, int24 tickSpacing) external;
    }

    위 코드는 유니스왑의 factory contract의 인터페이스 이다.

    이번글에서 보게될 내용은 PoolCreated event 를 직접 조회해보면서 indexed 키워드가 붙어있는 변수와 그렇지 않은 변수의 차이를 살펴볼 생각이다. 미리 이야기 하자면 indexed 키워드는 이후 이벤트를 조회할때 필터기능을 사용할 변수에 붙여주는 키워드 이다.

     

    node.js 와 ethers.js 를 사용해서 이벤트를 조회해보려고 한다.

    require("dotenv").config();
    const ethers = require("ethers");
    
    const FACTORY_ABI = require("./factoryABI.json");
    const FACTORY_ADDR = "0x1F98431c8aD98523631AE4a59f267346ea31F984";
    
    const { ALCHEMY_KEY } = process.env;
    const provider = new ethers.providers.WebSocketProvider("wss://eth-mainnet.g.alchemy.com/v2/${ALCEHMY_KEY}");
    const contract = new ethers.Contract(FACTORY_ADDR, FACTORY_ABI, provider);
    
    async function main() {
    	const filter = contract.filters.PoolCreated(null, "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", 3000, null, null);
    	// const filter = contract.filters.PoolCreated(null, null, null, null, null);
    	const results = await contract.queryFilter(filter, 16605482, "latest").then((res) =>
    		res.map((el) => {
    			return {
    				blockNumber: el.blockNumber,
    				args: el.args,
    			};
    		})
    	);
    	console.log(results, "결과");
    }
    main();

    실제 v3Factory contract에서의 이벤트를 조회하기 위해서 해당 컨트랙트의 주소와 abi가 필요하다.

    해당내용은 유니스왑닥스와 이더스캔 을 통해서 조회할수 있다.

    https://docs.uniswap.org/contracts/v3/reference/deployments

    https://etherscan.io/address/0x1F98431c8aD98523631AE4a59f267346ea31F984#code

    node provider 는 alchemy 를 사용했다.

     

    일단 ethers doc을 보면 event 관련 메서드가 여러개 있는데 그중에서 아래 두개만 보자

    contract.queryFilter( event [ , fromBlockOrBlockHash [ , toBlock ] )  Promise< Array< Event > >
    =>Return Events that match the event.
     

    contract.on( event , listener )  this

    =>Subscribe to event calling listener when the event occurs.

     

    queryfilter는 매치되는 이벤트를 리턴해주고 on 은  특정이벤트를 구독해서 이벤트발생시에 실시간으로 수신하는 방법이다.

    내가 원하는건 특정기간내의 이벤트를 조회해보는방법 이여서 queryfilter를 사용하면 된다.

     

    일단 필터를 정해줘야하는데 특정 filter를 사용하지 않으려면 파라미터자리에 null 값을 넣어주면 된다.

    Poolcreated event를 보면 token0, token1, fee 앞의3개는 indexed 키워드가 있기때문에 필터링을 원하는 값을 넣어줄수 있지만 뒤 2개는 indexed 키워드가 없기 때문에 null 값만 넣어줄수 있다.

    다른값을 넣게 되면 reason: 'cannot filter non-indexed parameters; must be null', 에러가 난다.

     

    queryFilter에는 필터와 같이 블락의 범위도 설정해 줄수있는데 from, to 순서로 넣어주면된다 나는

    16605482 부터 최신블락까지 해당필터를 적용한다는 뜻이다.

    아래그림은 token1 자리에 wrappedeth 와 fee 는 3000 으로 필터링한 값으로 얻은 값이다.

     

     

     

     

     

Designed by Tistory.