[chainlink functions] Call an API

채동기·2023년 6월 13일
0

Oracle

목록 보기
12/14

Cryptocompare GET /data/pricemultifull API를 호출하기 위해 탈중앙화 오라클 네트워크에 요청을 보내는 방법을 안내합니다.
OCR이 오프체인 계산과 집계를 완료하면, ETH/USD의 자산 가격을 스마트 계약으로 반환합니다.
HTTP 쿼리 매개변수를 구성하여 다른 자산 가격을 요청하는 방법도 보여줍니다.

시작하기 전에
사전 준비
링크에 있는 내용을 해보고, 준비하셔야 지금 페이지의 내용을 따라 올 수 있습니다.

Chainlink Functions Starter Kit의 tutorials 브랜치로 깃 체크아웃해야합니다.

git checkout tutorials

예제는 /tutorials/2-call-api directory 에 위치해 있습니다.

튜토리얼

이 튜토리얼은 ETH/USD 가격을 가져오도록 구성되어 있습니다. 코드 예제에 대한 자세한 설명은 "설명" 섹션을 읽어보세요.

먼저, config.js 파일을 열어보세요. args 값은 ["ETH", "USD"]로 설정되어 있으며, 이는 현재 ETH/USD 가격을 가져옵니다. 다른 자산 가격을 가져오기 위해 args를 수정할 수 있습니다. 지원되는 심볼 목록을 확인하려면 CryptoCompare API 문서를 참조하세요. 요청 구성 파일에 대한 자세한 설명은 요청 구성 설명을 읽어보세요.

그 다음, source.js를 열어 JavaScript 소스 코드를 분석하세요. 소스 코드에 대한 자세한 설명은 소스 코드 설명을 읽어보세요.

시뮬레이션

Chainlink Functions Hardhat Starter Kit에는 로컬 환경에서 코드를 테스트할 수 있는 시뮬레이터가 포함되어 있습니다. functions-simulate 명령을 사용하면 코드를 로컬에서 실행하고, 엔드 투 엔드 플루필먼트를 시뮬레이션할 수 있습니다. 이를 통해 Decentralized Oracle Network에 함수를 제출하기 전에 문제를 미리 해결할 수 있습니다.

functions-simulate 태스크를 실행하여 소스 코드가 올바르게 작성되었는지 확인해보세요.
이때 config.js와 source.js 파일이 정확하게 작성되어 있는지 확인해야 합니다.

npx hardhat functions-simulate --configpath REPLACE_CONFIG_PATH

Example

$ npx hardhat functions-simulate --configpath tutorials/2-call-api/config.js
secp256k1 unavailable, reverting to browser version

__Compiling Contracts__
Nothing to compile
Duplicate definition of Transfer (Transfer(address,address,uint256,bytes), Transfer(address,address,uint256))

Executing JavaScript request source code locally...

__Console log messages from sandboxed code__
HTTP GET Request to https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD
ETH price is: 1813.50 USD

__Output from sandboxed source code__
Output represented as a hex string: 0x000000000000000000000000000000000000000000000000000000000002c466
Decoded as a uint256: 181350

__Simulated On-Chain Response__
Response returned to client contract represented as a hex string: 0x000000000000000000000000000000000000000000000000000000000002c466
Decoded as a uint256: 181350

Gas used by sendRequest: 367881
Gas used by client callback function: 75029

위의 예시 출력을 읽으면 ETH/USD 가격을 확인할 수 있습니다. 하지만 Solidity는 소수를 지원하지 않기 때문에, 이를 정수처럼 보이도록 소수점을 이동시켜 181350과 같은 정수 형태로 반환합니다. 그런 다음, 콜백에서는 해당 값을 바이트로 인코딩하여 0x000000000000000000000000000000000000000000000000000000000002c466과 같은 값으로 반환합니다. 소스 코드에 대한 자세한 설명은 소스 코드 설명을 참조하세요.

Request

각 튜토리얼은 별도의 Git 브랜치에 있으며 일부는 .env.enc 파일에 고유한 항목이 필요합니다.

Decentralized Oracle Network에 자산 가격을 가져오기 위해 요청을 보내세요. functions-request 작업을 실행하면서 subid (구독 ID)와 계약 매개변수를 함께 전달하세요. 이 작업은 함수 JavaScript 소스 코드, 인수 및 비밀 정보를 배포된 FunctionsConsumer 계약의 executeRequest 함수에 전달합니다. FunctionsConsumer 섹션에서 소비자 계약에 대한 자세한 정보를 확인하세요.

npx hardhat functions-request --subid REPLACE_SUBSCRIPTION_ID --contract REPLACE_CONSUMER_CONTRACT_ADDRESS --network REPLACE_NETWORK --configpath REPLACE_CONFIG_PATH

Example

$ npx hardhat functions-request --subid 443 --contract 0x4B4BA2Fd6b93aDF8d6b6002E10540E58394388Ea --network polygonMumbai --configpath tutorials/2-call-api/config.js
secp256k1 unavailable, reverting to browser version
Estimating cost if the current gas price remains the same...

The transaction to initiate this request will charge the wallet (0x9d087fC03ae39b088326b67fA3C788236645b717):
0.000496339505294288 MATIC, which (using mainnet value) is $0.0005516547067031669

If the request's callback uses all 100,000 gas, this request will charge the subscription:
0.200148503810857266 LINK

Continue? Enter (y) Yes / (n) No
y
Simulating Functions request locally...

__Console log messages from sandboxed code__
HTTP GET Request to https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD
ETH price is: 1813.96 USD

__Output from sandboxed source code__
Output represented as a hex string: 0x000000000000000000000000000000000000000000000000000000000002c494
Decoded as a uint256: 181396

⣾ Request 0x5e89f3e84cbf80d65de53de816052d1b79c50c1f1f9f283aadc3ad36d33d41aa has been initiated. Waiting for fulfillment from the Decentralized Oracle Network...

ℹ Transaction confirmed, see https://mumbai.polygonscan.com/tx/0x36029c2e49d0d890d00a1b554e4bea564444e48c5449f9d5deaed5d42114d91e for more details.

✔ Request 0x5e89f3e84cbf80d65de53de816052d1b79c50c1f1f9f283aadc3ad36d33d41aa fulfilled! Data has been written on-chain.

Response returned to client contract represented as a hex string: 0x000000000000000000000000000000000000000000000000000000000002c48b
Decoded as a uint256: 181387

Actual amount billed to subscription #443:
┌──────────────────────┬─────────────────────────────┐
│         Type         │           Amount            │
├──────────────────────┼─────────────────────────────┤
│  Transmission cost:  │  0.000063268449037502 LINK  │
│      Base fee:       │          0.2 LINK           │
│                      │                             │
│     Total cost:      │  0.200063268449037502 LINK  │
└──────────────────────┴─────────────────────────────┘

위의 예시 출력에서 다음과 같은 정보를 얻을 수 있습니다:

  • FunctionsConsumer 계약에서 executeRequest 함수가 성공적으로 호출되었습니다. 이 예시에서의 트랜잭션은 0x36029c2e49d0d890d00a1b554e4bea564444e48c5449f9d5deaed5d42114d91e입니다.
  • 요청 ID는 0x5e89f3e84cbf80d65de53de816052d1b79c50c1f1f9f283aadc3ad36d33d41aa입니다.
  • Decentralized Oracle Network에서 요청을 성공적으로 완료했습니다. 이를 위해 총 0.200063268449037502 LINK가 소비되었습니다.
  • 컨슈머 계약은 바이트로 된 응답을 수신했으며 값은 0x000000000000000000000000000000000000000000000000000000000002c48b입니다. 이를 오프체인에서 uint256로 디코딩하면 결과값인 181387을 얻을 수 있습니다.

언제든지 contract 매개변수와 함께 functions-read 작업을 실행하여 최신 응답을 확인할 수 있습니다.

npx hardhat functions-read  --contract REPLACE_CONSUMER_CONTRACT_ADDRESS --network REPLACE_NETWORK --configpath REPLACE_CONFIG_PATH

Example

$ npx hardhat functions-read  --contract 0x4B4BA2Fd6b93aDF8d6b6002E10540E58394388Ea  --network polygonMumbai --configpath tutorials/2-call-api/config.js
secp256k1 unavailable, reverting to browser version
Reading data from Functions client contract 0x4B4BA2Fd6b93aDF8d6b6002E10540E58394388Ea on network mumbai

On-chain response represented as a hex string: 0x000000000000000000000000000000000000000000000000000000000002c48b
Decoded as a uint256: 181387

Explanation

FunctionsConsumer.sol

Chainlink Functions 소비자 컨트랙트를 작성하기 위해서는 컨트랙트에서 FunctionsClient.sol을 import해야 합니다. FunctionsClient.sol은 NPM 패키지로 제공되지 않기 때문에 프로젝트 내에서 다운로드하여 import해야 합니다.

import { Functions, FunctionsClient } from "./dev/functions/FunctionsClient.sol";

Chainlink Functions 요청을 생성하는 데 필요한 모든 함수를 사용하기 위해 Functions.sol 라이브러리를 사용합니다. 다음과 같이 Functions 라이브러리를 사용하도록 선언합니다.

using Functions for Functions.Request;

최신 요청 ID, 최신 수신 응답 및 최신 수신 오류(있는 경우)는 상태 변수로 정의됩니다. latestResponse 및 latestError는 동적 크기의 바이트 배열로 인코딩되므로 응답이나 오류를 읽으려면 여전히 디코딩해야 합니다.

bytes32 public latestRequestId;
bytes public latestResponse;
bytes public latestError;

콜백 중에 스마트 컨트랙트에서 발생하는 OCRResponse 이벤트를 정의합니다.

event OCRResponse(bytes32 indexed requestId, bytes result, bytes err);

컨트랙트를 배포할 때 네트워크에 대한 오라클 주소를 전달합니다.

constructor(address oracle) FunctionsClient(oracle)

언제든지 updateOracleAddress 함수를 호출하여 오라클 주소를 변경할 수 있습니다.

남은 두 가지 함수는 다음과 같습니다:

  1. executeRequest: 요청을 보내는 함수입니다. JavaScript 소스 코드, 암호화된 비밀 정보, 소스 코드에 전달할 인수 목록, 구독 ID 및 콜백 가스 제한을 매개변수로 받습니다. 다음과 같은 과정을 거쳐 요청을 초기화하고 전달된 암호화된 비밀 정보나 인수를 추가합니다. 요청 ID는 latestRequestId에 저장됩니다.
Functions.Request memory req;
req.initializeRequest(Functions.Location.Inline, Functions.CodeLanguage.JavaScript, source);
if (secrets.length > 0) {
  req.addRemoteSecrets(secrets);
}
if (args.length > 0) req.addArgs(args);
sendRequest(req, subscriptionId, gasLimit);
latestRequestId = assignedReqID;
  1. fulfillRequest: 콜백 중에 호출되는 함수입니다. 이 함수는 FunctionsClient에서 가상 함수로 정의되어 있으므로 스마트 컨트랙트에서 오버라이딩하여 콜백을 구현해야 합니다. 콜백의 구현은 간단합니다. 컨트랙트는 OCRResponse 이벤트를 발생시키기 전에 최신 응답과 오류를 latestResponse와 latestError에 저장합니다.
function fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err) public override {
  latestResponse = response;
  latestError = err;
  emit OCRResponse(requestId, response, err);
}

config.js

자세한 설정에 대한 설명은 "Request Configuration" 섹션에서 확인할 수 있습니다. 이 예제에서의 설정은 다음과 같습니다:

  • codeLocation: Location.Inline. JavaScript 코드가 요청 내에서 제공됩니다.
  • codeLanguage: CodeLanguage.JavaScript. 소스 코드는 JavaScript 언어로 개발됩니다.
  • source: fs.readFileSync(path.resolve(__dirname, "source.js")).toString(). 소스 코드는 스크립트 객체여야 합니다. 이 예제에서는 fs.readFileSync를 사용하여 source.js를 읽고, toString()을 호출하여 내용을 문자열 객체로 가져옵니다.
  • args: ["ETH", "USD"]. 이러한 인수는 소스 코드로 전달됩니다. 이 예제에서는 ETH/USD 가격을 요청합니다.
  • expectedReturnType: ReturnType.uint256. DON이 받은 응답은 bytes로 인코딩됩니다. 자산 가격이 uint256이므로 ReturnType.uint256를 정의하여 DON이 받은 응답을 해독하는 방법을 사용자에게 알려줍니다.

source.js

예상 API 응답을 확인하려면 다음 URL을 브라우저에 직접 붙여넣거나 터미널에서 curl 명령을 실행할 수 있습니다:

curl -X 'GET' \
  'https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD' \
  -H 'accept: application/json'

응답은 다음 예시와 유사해야 합니다:

{
  "RAW": {
    "ETH": {
      "USD": {
        "TYPE": "5",
        "MARKET": "CCCAGG",
        "FROMSYMBOL": "ETH",
        "TOSYMBOL": "USD",
        "FLAGS": "2049",
        "PRICE": 2867.04,
        "LASTUPDATE": 1650896942,
        "MEDIAN": 2866.2,
        "LASTVOLUME": 0.16533939,
        "LASTVOLUMETO": 474.375243849,
        "LASTTRADEID": "1072154517",
        "VOLUMEDAY": 195241.78281014622,
        "VOLUMEDAYTO": 556240560.4621655,
        "VOLUME24HOUR": 236248.94641103,
        ...
      }
    }
  }
}

가격은 RAW,ETH,USD,PRICE에 위치합니다.

호환 가능한 JavaScript 소스 코드를 작성하는 방법에 대한 자세한 설명은 "JavaScript code" 섹션을 참조하세요. 이 JavaScript 소스 코드는 Functions.makeHttpRequest를 사용하여 HTTP 요청을 보냅니다. ETH/USD 가격을 요청하기 위해 소스 코드는 https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD URL을 호출합니다. Functions.makeHttpRequest 문서를 읽으면 다음 매개변수를 제공해야 함을 알 수 있습니다:

{
  fsyms: fromSymbol,
  tsyms: toSymbol
}

fromSymbol과 toSymbol 값은 args에서 가져옵니다. 자세한 내용은 "request config" 섹션을 참조하세요.

코드는 주석이 달려 있어 각 단계를 이해하는 데 도움이 되며, 자체 설명 가능합니다. 주요 단계는 다음과 같습니다:

  • Functions.makeHttpRequest를 사용하여 cryptoCompareRequest HTTP 객체를 구성합니다.
  • HTTP 호출을 수행합니다.
  • 응답에서 자산 가격을 읽습니다.
  • Functions.encodeUint256 도우미 함수를 사용하여 결과를 버퍼로 반환합니다. Solidity는 소수를 지원하지 않기 때문에 결과를 100으로 곱하고 가장 가까운 정수로 반올림합니다. 참고: Javascript Buffers에 익숙하지 않거나 왜 중요한지 이해하려면 이 문서를 읽어보세요.

참고

https://docs.chain.link/chainlink-functions/tutorials/api-query-parameters#sourcejs

profile
what doesn't kill you makes you stronger

0개의 댓글