체인의정석

Uniswap V3 - multicall, ethers & typescript로 사용해 보기 본문

블록체인/디파이

Uniswap V3 - multicall, ethers & typescript로 사용해 보기

체인의정석 2023. 7. 20. 15:57
728x90
반응형

유니스왑 V3를 보면 multicall이 내장되어 있다.

따라서 서비스를 만들 때 해당 멀티콜을 써서 다양한 트랜잭션을 보내주거나 조회해 올 수 있는데

ethers와 typescript를 사용해서 멀티콜을 하는 부분을 사용하는 부분을 기록해 두려고 한다.

struct를 encode 하는 부분 참고 소스코드는 다음과 같다.

const a = '0x...';
const b = '123123123123132123123';
const c = true;

const myStructData = ethers.utils.AbiCoder.prototype.encode(
  ['address', 'uint', 'bool'],
  [a, b, c]
);

const tx = await myContract.myFunction(
  myStructData,
  { gasLimit: ethers.utils.parseUnits('1000000', 'wei') }
);

https://github.com/ethers-io/ethers.js/issues/1007

 

Is there a way to encode a struct? · Issue #1007 · ethers-io/ethers.js

Is there a way to encode a struct before passing it as a function argument? I want to be able to do it in JS, preferably using ethers. I couldn't figure it out from the docs and past issues. Thank ...

github.com

그러던 중 찾게된 더 간결한 코드가 있는데 인터페이스로 부터 함수를 인코딩 하는 함수이다.

var abi = [ { name: 'foo', type: 'function', inputs: [ { type: 'uint256' } ], outputs: [ { type: 'uint8' }] } ];
var iface = new ethers.Interface(abi)

// Example
var calldata = iface.functions.foo.encode(42);
// "0x2fbebd38000000000000000000000000000000000000000000000000000000000000002a"

// Parsing call response
var response = "0x000000000000000000000000000000000000000000000000000000000000002b";
var result = iface.functions.foo.decode(response);
// 43

https://github.com/ethers-io/ethers.js/issues/211

 

Using the ABI coder to encode and decode eth_call · Issue #211 · ethers-io/ethers.js

https://github.com/ethjs/ethjs-abi says that it is from ethers.js, but it is fairly out of date and doesn't support structs. I'm using ethers.js elsewhere in my app and would like to leverage its a...

github.com

위 코드들을 참고해서 유니스왑 v3에 적용해보았다.

async function multicall() {
  const signer = await getAllSigners(0);
  const contractAddressNftManager = devAddress.nftPositionManager;

  const nonfungiblePositionManager = await ethers.getContractAt("NonfungiblePositionManager",contractAddressNftManager,signer) as NonfungiblePositionManager;

  const currentBlock = await ethers.provider.getBlockNumber();
  const blockTimestamp = (await ethers.provider.getBlock(currentBlock)).timestamp + 1000000;

  const increaseLiqidityParams: IncreaseLiquidtyParams = {
    tokenId: 19,
    amount0Desired: toEthValue(1,18),
    amount1Desired: toEthValue(1,18),
    amount0Min: 0,
    amount1Min: 0,
    deadline: blockTimestamp
  }

  const decreaseLiquidityParams: DecreaseLiquidtyParams = {
    tokenId: 19,
    liquidity: 1000000,
    amount0Min: 0,
    amount1Min: 0,
    deadline: blockTimestamp
  }

  const calldataIncrease = nonfungiblePositionManager.interface.encodeFunctionData("increaseLiquidity", [increaseLiqidityParams]);
  const calldataDecrease = nonfungiblePositionManager.interface.encodeFunctionData("decreaseLiquidity", [decreaseLiquidityParams]);
  console.log(calldataIncrease);
  console.log(calldataDecrease);

  const increaseAndDecrease = await nonfungiblePositionManager.multicall([calldataIncrease,calldataIncrease,calldataIncrease]);
  console.log(increaseAndDecrease);
}

시행착오 끝에 완성시켰는데 설명을 남기자면

우선 해당 멀티콜이 있는 컨트렉트는 uniswapV3의 nonfungiblePositionManage 인데 이렇게 구조체를 먼저 만들어 주고 해당 구조체를 인터페이스를 가져와서 인코딩 시켜주면 된다.

getContractAt을 통해서 가져온다면 .interface를 통해서 더 쉽게 인터페이스를 가져올 수 있고

그 후에 encodeFunctionData를 사용하게 되면 값들을 인코딩 할 수 있다.

위의 문법들을 참고하면 다중 입력값도 가능할 것이다.

728x90
반응형
Comments