체인의정석

Nest.js 수정사항 총 정리 03 ) 하나의 API를 2개로 분기시키기 & ether.js 사용하여 이더리움 value값 타입체크하기 본문

개발/backend

Nest.js 수정사항 총 정리 03 ) 하나의 API를 2개로 분기시키기 & ether.js 사용하여 이더리움 value값 타입체크하기

체인의정석 2021. 12. 7. 19:17
728x90
반응형

이더리움 value의 경우 숫자가 커서 빅넘버처리를 안해주면 에러가 나게 된다. 단위가 너무 크기 때문인데 조사해본 결과 빅넘버 처리는 결과 목적에 맞는 모듈을 사용하는것이 정답이라고 한다.

 

타입스크립트도 사용하였으니 한번 유명한 ether.js를 찾아보았다. 처음 써보는데 너무 편리했다.

 

일단 ether.js 에서 사용하는 bignumber의 경우에는 elliptic로직에서 쓰이는것과 같은 방법이기 때문에 가장 안전하다고 한다.

 

오랜기간 서칭을 한 결과 몇가지 케이스에 대한 방안을 알 수 있었다.

 

1.  이더리움 단위로 만들 경우

//ethers.utils.formatEther( value ) ⇒ string

const value = BigNumber.from("1000000000000000000");

formatEther(value);
// '1.0'

2. 특정 단위로 바꿀 때 (빅넘버 형태 리턴)

//ethers.utils.parseUnits( value [ , unit = "ether" ] ) ⇒ BigNumber


parseUnits("1.0");
// { BigNumber: "1000000000000000000" }

parseUnits("1.0", "ether");
// { BigNumber: "1000000000000000000" }

parseUnits("1.0", 18);
// { BigNumber: "1000000000000000000" }

parseUnits("121.0", "gwei");
// { BigNumber: "121000000000" }

parseUnits("121.0", 9);
// { BigNumber: "121000000000" }

 

3. 특정단위로 바꿀 때 (스트링 형태로 바꿀때)

const oneGwei = BigNumber.from("1000000000");
const oneEther = BigNumber.from("1000000000000000000");

formatUnits(oneGwei, 0);
// '1000000000'

formatUnits(oneGwei, "gwei");
// '1.0'

formatUnits(oneGwei, 9);
// '1.0'

formatUnits(oneEther);
// '1.0'

formatUnits(oneEther, 18);
// '1.0'

 

 

4. 코드에 적용하기 ( API 분기 시키기 & 이더리움 value값 bignumber 형태로 타입체크하기)

일반적인 경우라면 상관이 없었지만 나는 ETL 데이터를 가져와서 그걸 타입체크까지 해줘야 했기 때문에 입력값은 string으로 받고 2개의 객체를 생성해서 bigNumber를 따로 class-validator로 검사 해주는데 사용하였다. 코드는 다음과 같다.

      if (searchByRequest.flag == searchTransactionFlag.value) {
        const minValue = ethers.utils.parseUnits(
          pagingSearchByRequest.minValue,
          0,
        );

        const maxValue = ethers.utils.parseUnits(
          pagingSearchByRequest.maxValue,
          0,
        );
        const validValue = new ValidValue(minValue, maxValue);
        const errors = await validate(validValue);
        if (errors.length > 0) {
          this.logger.error(getConstraintsMessage(errors));
          return invalidInputError(errors);
        } else {
          const response_value =
            await this.transactionsService.searchTransactionByValue(
              pagingSearchByRequest,
            );
          return response_value;
        }

여기서는 api를 하나의 입력값으로 받아와서 하나는 시간검색 하나는 value검색으로 구현하였다. 프론트엔드 페이지가 하나이고 리턴 포멧이 같은 경우 다음과 같이 하나의 api로 만드는것이 좋을 수 있다. 이런 경우 flag 변수를 하나 받아와서 분기처리 시켜준다. 여기서 쓴 ParseUnits의 경우는 bignumber 형태로 값을 리턴해주기 때문에 validValue 부분에서 타입체크가 들어가게 된다.

 

export class ValidValue {
  @IsNumber()
  minValue?: BigNumber;

  @IsNumber()
  maxValue?: BigNumber;

  constructor(minValue: BigNumber, maxValue: BigNumber) {
    this.maxValue = maxValue;
    this.minValue = minValue;
  }
}

export enum searchTransactionFlag {
  time = 'time',
  value = 'value',
}

이는 다음과 같이 enum 타입으로 지정하고 validate를 시키기 위한 생성자를 만듦으로서 사용하였다.

 

또한 ether.js에 자체적인 logger가 있고 여기서 숫자를 체크하는 함수가 있었지만 어떠한 이유에서인지 작동하지 않아 결국 calss-validator를 사용하였다. ether.js에서 도 어차피 비슷한 방식으로 체크를 해주기 때문에 큰 상관은 없어보인다.

728x90
반응형
Comments