Got a cool example to share? Get listed here! Submit it now.

useChainlinkFunctions()

Collection of community submitted examples for Chainlink Functions

Get inspired from quick examples

Chainlink Functions, a new self-service platform that allows anyone to write serverless code to fetch any data from any API and run custom compute on Chainlink's network. Learn from examples created by the community or contribute your own!
Learn more about Chainlink Functions

Fetch the UTC time

Submitted by:
Evan Drake
This function fetches the UTC timestamp from WorldTimeAPI.

1 2 3 4 5 6 7 8 9 const config = { url: "https://worldtimeapi.org/api/timezone/Etc/UTC", }; const response = await Functions.makeHttpRequest(config); const datetime = response.data.utc_datetime; return Functions.encodeString(datetime);

Video or channel verification with an EVM wallet address

Submitted by:
Viet Nguyen
The function returns a result as uint256: 1 if the wallet is found in the video/channel description, and 0 if not found.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 // Begin Function // args = [videoOrChannelId, ownerWalletAddress, type] const videoOrChannelId = args[0]; // video or channel id get from youtube eg. xyFa2amJJoY const ownerWalletAddress = args[1]; // owner wallet address eg. 0x1282401445452436b4094E86619B2Fd2fAD464d8 const type = args[2]; // "video" | "channel" // Youtube API key get from https://console.cloud.google.com/apis/dashboard if (!secrets.apiKey) { throw Error( "YOUTUBE_API_KEY required" ); } // Youtube API request const youtubeRequest = Functions.makeHttpRequest({ url: `https://youtube.googleapis.com/youtube/v3/${type}s`, method: "GET", params: { part: "snippet", id: videoOrChannelId, key: secrets.apiKey }, }); const youtubeResponse = await youtubeRequest; if (youtubeResponse.error) { throw new Error("Youtube error"); } // Checking youtube response if !youtubeResponse.data.items[0] -> Youtube video or channel not found if (youtubeResponse.data && youtubeResponse.data.items && youtubeResponse.data.items[0]) { const description = youtubeResponse.data.items[0].snippet.description.toLowerCase(); const walletIndex = description.indexOf(ownerWalletAddress.toLowerCase()); // If it found owner wallet address return 1, otherwise 0 const resultInt = walletIndex !== -1 ? 1 : 0; return Functions.encodeUint256(resultInt); } else { throw new Error("Youtube video or channel not found"); } // End Function

Entity for an address from the Arkham API

Submitted by:
Arkham Team
This Function returns the entity ID of a given address. The entity ID is a string, and represents a slugified version of the entity's name. For example, Binance -> binance. The address is the only required parameter, and an API key is the only required secret.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 // This Function returns the entity ID of the input address. Entity IDs are strings representing // slugified version of the entity's name. They can be used in other functions to Arkham's API if // you'd like to find more information about the entity and its on-chain footprint. // An Arkham API key is required to use this function. Apply for one here: https://docs.google.com/forms/d/e/1FAIpQLSfJum3MJwq8niPhNkAlNC08wzLKWyNR18vKUN41mnOG3MQkfg/viewform?usp=sf_link const address = args[0] // Validate address input. if (address.length != 42) { throw Error("invalid address") } // Validate required secret. if (!secrets.ARKHAM_API_KEY) { throw Error("api key required") } // Make the request to the /intelligence/address/:address/all endpoint. const url = `https://api.arkhamintelligence.com/intelligence/address/${address}/all` const resp = await Functions.makeHttpRequest({url, headers: {'API-Key': secrets.ARKHAM_API_KEY}}) const data = resp["data"] if (resp.error) { console.error(error) throw Error("Request failed") } // Since we used the /all endpoint, we get data in the form of a chain map (see const declaration). // In very rare cases, an address will have a different entity based on the chain. In those cases, // you can choose which chain you'd like to privilege. let entityId = "" for (const [chain, intel] of Object.entries(data).sort()) { // Sort so that output is deterministic. // Choose the chain with the first non-null arkhamEntity field. if (intel.arkhamEntity !== undefined) { entityId = intel.arkhamEntity.id break } } return Functions.encodeString(entityId)

Weight-Height results from Poke API

Submitted by:
Naman Gautam
This Function returns the Base Experience, Weight, Height of Pokemon. It uses the Poke API. Parameters includes name of pokemon.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 // This function fetches Base Experience, Weight, Height of Pokemon results from Poke API // Args include name of pokemon const pokiURL = "https://pokeapi.co/api/v2/pokemon" const pokemonCharacter = args[0] console.log(`Sending HTTP request to ${pokiURL}/${pokemonCharacter}/`) const pokiRequest = Functions.makeHttpRequest({ url: `${pokiURL}/${pokemonCharacter}`, method: "GET", }) // Execute the API request (Promise) const pokiResponse = await pokiRequest if (pokiResponse.error) { console.error(pokiResponse.error) throw Error("Request failed, try checking the params provided") } console.log(pokiResponse) // gets the Base Experience, Weight, Height of Pokemon const reqData = pokiResponse.data // Gives the whole response from the request console.log(reqData) // result is in JSON object, containing Base Experience, Weight, Height of Pokemon const myData = { base_experience: reqData.base_experience, weight: reqData.weight/10, // The weight of this Pokemon in hectograms which is converted into kilograms by dividing by 10 height: reqData.height/10, // The height of this Pokemon in decimetres which is converted into metres by dividing by 10 } // Use JSON.stringify() to convert from JSON object to JSON string // Finally, use the helper Functions.encodeString() to encode from string to bytes return Functions.encodeString(JSON.stringify(myData))

Latest News Headline from NEWS API

Submitted by:
Shikhar Agarwal
This Function returns the latest news headline for a particular country. It uses the NEWS API to get the news. Parameters include country code and keyword(if user want to filter search on the basis of keyword)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 // This function fetches the latest news headline from a country // Args include country code and keyword(if any) // If user don't want to filter result on the basis of keyword, just pass an empty string for keyword if (!secrets.apiKey) { throw Error("Api Key Not Found") } const url = "https://newsapi.org/v2/top-headlines?" const country = args[0] // Example - "in" for India const keywordSearch = args[1] // Example - "web3" (This arg is optional, leave an empty string) console.log(`Sending HTTP GET Request to ${url}country=${country}&q=${keywordSearch}`) const newsRequest = Functions.makeHttpRequest({ url: url, method: "GET", headers: { "X-Api-Key": secrets.apiKey }, params: { country: country, q: keywordSearch } }) // Execute the API request (Promise) const newsResponse = await newsRequest // check if there was any error during the request if (newsResponse.error) { throw Error("Request failed") } // if there is no news, throw an error with the message if (newsResponse.data.articles.length == 0) { throw Error("No news!") } // get the latest news const newsSelect = newsResponse.data.articles[0] // choosing the required parameters to be uploaded const newsData = { publishTime: newsSelect.publishedAt, title: newsSelect.title } // Use JSON.stringify() to convert from JSON object to JSON string // Finally, use the helper Functions.encodeString() to encode from string to bytes return Functions.encodeString(JSON.stringify(newsData))

Asteroid Data from NASA API

Submitted by:
Naman Gautam
This Function returns the very first current close-approach data for asteroid in the given range of time and max distance

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 // This API provides access to current close-approach data for asteroid and comets in JPL’s SBDB // Args include des, date-min, date-max, dist-max // des - only data for the object matching this designation (e.g., 2015 AB or 141P or 433) // date-min - exclude data earlier than this date YYYY-MM-DD // date-max - exclude data later than this date YYYY-MM-DD // dist-max - exclude data with an approach distance greater than this (in AU) const sbdbURL = "https://ssd-api.jpl.nasa.gov/cad.api?" const des = args[0] const dateMin = args[1] const dateMax = args[2] const maxDist = args[3] console.log(`Sending HTTP request to ${sbdbURL}des=${des}&date-min=${dateMin}&date-max=${dateMax}&dist-max=${maxDist}`) const sbdbRequest = Functions.makeHttpRequest({ url: sbdbURL, method: "GET", params: { des: des, "date-min": dateMin, "date-max": dateMax, "dist-max": maxDist, }, }) // response from sbdb const sbdbResponse = await sbdbRequest if (sbdbResponse.error) { console.error(geoCodingResponse.error) throw Error("Request failed, try checking the params provided") } console.log(sbdbResponse) // getting the very first data of an asteroid const reqData = sbdbResponse.data.data[0] // selecting the required output const myData = { orbitId: reqData[1], closeTimeApproach: reqData[3], dist: reqData[4], relativeVelocity: reqData[7] } // Use JSON.stringify() to convert from JSON object to JSON string // Finally, use the helper Functions.encodeString() to encode from string to bytes return Functions.encodeString(JSON.stringify(myData))

Zerion wallet account $USD balance

Submitted by:
Benjamin
This function returns the USD balance of an account using the Zerion wallet tracker.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 if (!secrets.zerionApiKey) { throw Error('API_KEY'); } async function fetchBalanceFromZerion(address) { const config = { method: 'GET', headers: { accept: 'application/json', authorization: `Basic ${secrets.zerionApiKey}` }, url: `https://api.zerion.io/v1/wallets/${address}/portfolio/?currency=usd` }; const response = await Functions.makeHttpRequest(config); if (response.error) { throw new Error(response.response.data.message); } const upscaledUSDValue = response.data.data.attributes.total.positions * 10 ** 18; return upscaledUSDValue; } const address = args[0]; const balance = await fetchBalanceFromZerion(address); return Functions.encodeUint256(balance); // Gas usage can be reduced by using a minified version. Please remove the code above this line and uncomment the code below. // if(!secrets.zerionApiKey)throw Error("API_KEY");async function fetchBalanceFromZerion(e){let t={method:"GET",headers:{accept:"application/json",authorization:`Basic ${secrets.zerionApiKey}`},url:`https://api.zerion.io/v1/wallets/${e}/portfolio/?currency=usd`},a=await Functions.makeHttpRequest(t);if(a.error)throw Error(a.response.data.message);let o=1e18*a.data.data.attributes.total.positions;return o}const address=args[0],balance=await fetchBalanceFromZerion(address);return Functions.encodeUint256(balance);

Current Flight Status from Aviation Stack API

Submitted by:
Shikhar Agarwal
This Function returns the current flight status for a particular flight. It uses the aviation stack API to get the information of the flight. Parameters include airline iata and flight number

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 // This function fetches the latest flight status for a particular flight // Args include the airline iata and flight number. // Example - for indigo, airline iata is 6E if (!secrets.apiKey) { throw Error("Aviation API Key is not available!") } // make HTTP request const url = 'http://api.aviationstack.com/v1/flights?'; const airlineIata = args[0] // example - "6E" airline iata for indigo const flightNum = args[1] // example - "123" flight number for indigo console.log(`HTTP GET Request to ${url}airline_iata=${airlineIata}&flight_number=${flightNum}`) const flightrequest = Functions.makeHttpRequest({ url: url, method: "GET", params: { airline_iata: airlineIata, flight_number: flightNum, access_key: secrets.apiKey }, }) // Execute the API request (Promise) const flightResponse = await flightrequest if (flightResponse.error) { throw Error("Request failed") } // to get the latest data for flight const latestFlightData = flightResponse.data.data[0] console.log(latestFlightData) // bundle of all the required data in flightData object const flightData = { date: latestFlightData.flight_date, status: latestFlightData.status, departureAirport: latestFlightData.departure.airport, departureTime: latestFlightData.departure.actual || latestFlightData.departure.estimated || latestFlightData.departure.scheduled, arrivalAirport: latestFlightData.arrival.airport, arrivalTime: latestFlightData.arrival.actual || latestFlightData.arrival.estimated || latestFlightData.arrival.scheduled } // Use JSON.stringify() to convert from JSON object to JSON string // Finally, use the helper Functions.encodeString() to encode from string to bytes return Functions.encodeString(JSON.stringify(flightData))

Current Temperature results from openweather API

Submitted by:
Shikhar Agarwal
This Function returns the current temperature in an area. It uses the openweather API. Parameters include zipcode and country code of the location, along with the apiKey in secrets, and units to get the temperature in Kelvin, Celsius or Fahrenheit

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 // This function fetches the latest temperature for a particular area from openweathermap API // Args include the zipcode of your location, ISO 3166 country code // units- unit in which we want the temperature (standard, metric, imperial) if (!secrets.apiKey) { throw Error("Weather API Key is not available!") } const zipCode = `${args[0]},${args[1]}` const geoCodingURL = "http://api.openweathermap.org/geo/1.0/zip?" console.log(`Sending HTTP request to ${geoCodingURL}zip=${zipCode}`) const geoCodingRequest = Functions.makeHttpRequest({ url: geoCodingURL, method: "GET", params: { zip: zipCode, appid: secrets.apiKey } }) const geoCodingResponse = await geoCodingRequest; if (geoCodingResponse.error) { console.error(geoCodingResponse.error) throw Error("Request failed, try checking the params provided") } console.log(geoCodingResponse); const latitude = geoCodingResponse.data.lat const longitude = geoCodingResponse.data.lon const unit = args[2] const url = `https://api.openweathermap.org/data/2.5/weather?` console.log(`Sending HTTP request to ${url}lat=${latitude}&lon=${longitude}&units=${unit}`) const weatherRequest = Functions.makeHttpRequest({ url: url, method: "GET", params: { lat: latitude, lon: longitude, appid: secrets.apiKey, units: unit } }) // Execute the API request (Promise) const weatherResponse = await weatherRequest if (weatherResponse.error) { console.error(weatherResponse.error) throw Error("Request failed, try checking the params provided") } // gets the current temperature const temperature = weatherResponse.data.main.temp // Gives the whole response from the request console.log("Weather response", weatherResponse) // result is in JSON object, containing only temperature const result = { temp: temperature } // Use JSON.stringify() to convert from JSON object to JSON string // Finally, use the helper Functions.encodeString() to encode from string to bytes return Functions.encodeString(JSON.stringify(result))

Get US Treasury Yield of specified maturity and interval

Submitted by:
Justin Gnoh
This example shows how to return the daily, weekly, and monthly US treasury yield of a given maturity timeline from the Alphavantage API. Result is expected to be in percentage.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 // This function retrieves the latest released yield of the US X Year Treasury from the AlphaVantage API given a specific interval or maturity. // Maturity timelines: 3month, 2year, 5year, 7year, 10year, 30year // Interval options: daily, weekly, monthly const maturity = args[0] const interval = args[1] if (!secrets.apiKey) { throw Error("Need to set Alpha Vantage API key"); } // make HTTP request const url = `https://www.alphavantage.co/query?function=TREASURY_YIELD` console.log(`HTTP GET Request to ${url}&interval=${interval}&maturity=${maturity}`) // construct the HTTP Request object. See: https://github.com/smartcontractkit/functions-hardhat-starter-kit#javascript-code // params used for URL query parameters const alphavantageRequest = Functions.makeHttpRequest({ url: url, params: { interval: interval, maturity: maturity, apikey: secrets.apiKey }, }) // Execute the API request (Promise) const alphavantageResponse = await alphavantageRequest if (alphavantageResponse.error) { console.error(alphavantageResponse.error) throw Error("Request failed") } const data = alphavantageResponse["data"] console.log(data); // Gets the latest yield rate in the array of returned data values const floatingRate = data.data[0].value; if (data.Response === "Error") { console.error(data.Message) throw Error(`Functional error. Read message: ${data.Message}`) } // Solidity doesn't support decimals so multiply by 100 and round to the nearest integer // Use Functions.encodeUint256 to encode an unsigned integer to a Buffer return Functions.encodeUint256(Math.round(floatingRate * 100))

Google Maps Distance Matrix API

Submitted by:
Karim Hadni
This function returns the distance and duration of a trip between two locations using the Google Maps Distance Matrix API. The origin and destination are required parameters. A Google Maps API key is also required and must be set as a secret.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 // Define constants for the API endpoint and request parameters const API_ENDPOINT = "https://maps.googleapis.com/maps/api/distancematrix/json" const DEPARTURE_TIME = "now" const RETURN_PROPERTIES = ["distance", "duration", "duration_in_traffic"] // Get the arguments from the request config const origin = args[0] // e.g. "New York City" const destination = args[1] // e.g. "Washington DC" // Get the Google Maps API Key from the environment variables const apiKey = secrets.apiKey if ( !apiKey || apiKey === "Your Google Maps API key (get one: https://developers.google.com/maps/documentation/distance-matrix/start)" ) { throw new Error("GOOGLE_MAPS_API_KEY environment variable not set or invalid") } // build HTTP request object const requestParams = { url: `${API_ENDPOINT}?departure_time=${DEPARTURE_TIME}`, params: { origins: origin, destinations: destination, key: apiKey, }, } // Make the HTTP request to the Google Maps API const googleMapsRequest = Functions.makeHttpRequest(requestParams) let response try { response = await googleMapsRequest } catch (error) { throw new Error(`Google Maps API request failed: ${error.message}`) } // Check if the response status is OK if (response.status !== 200) { throw new Error(`Google Maps API returned an error: ${response.statusText}`) } // Extract the relevant data from the response const data = response.data // Check if the response contains the expected properties if (!data.rows || !data.rows[0].elements || !data.rows[0].elements[0]) { throw new Error("Google Maps API response is missing expected data") } // Extract the distance, standard duration, and duration in traffic from the response const distance = data.rows[0].elements[0].distance.value const stdDuration = data.rows[0].elements[0].duration.value const duration_in_traffic = data.rows[0].elements[0].duration_in_traffic.value // Log the results for debugging purposes console.log(`Distance: ${distance / 1000} km`) console.log(`std duration: ${stdDuration / 60} min`) console.log(`duration_in_traffic: ${duration_in_traffic / 60} min`) console.log(`time in traffic jam: ${(duration_in_traffic - stdDuration) / 60} min`) // Encode and return the distance (in meters), standard duration (in seconds), and duration in traffic (in seconds) as a string which can be parsed and split return Functions.encodeString(`${distance},${stdDuration},${duration_in_traffic}`)

Fetch Discord Upvote Data

Submitted by:
Sam Demaree
This function retrieves the number of upvotes a Discord member has received in the past 24 hours. *Note: ChatGPT was used to demonstrate that non-developers can also participate.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 // This function retrieves the number of upvotes a Discord member has received in the past 24 hours using the Discord API. const getDiscordUpvotes = async (memberId, apiKey, guildId, channelId, timeRangeMs) => { const endpoint = 'https://discord.com/api/v9' const timeRangeSec = Math.round(timeRangeMs / 1000) const time24HoursAgo = Math.round((Date.now() - timeRangeMs) / 1000) const headers = { 'Authorization': `Bot ${apiKey}`, 'Content-Type': 'application/json' } const config = { method: 'GET', headers: headers, url: `${endpoint}/guilds/${guildId}/audit-logs?limit=100&user_id=${memberId}&before=${time24HoursAgo}&action_type=MESSAGE_DELETE` } const response = await Functions.makeHttpRequest(config) if (response.error) { throw new Error(response.response.data.message) } const auditLogs = response.data.audit_log_entries let upvotes = 0 for (let i = 0; i < auditLogs.length; i++) { const log = auditLogs[i] if (log.action_type === 72 && log.target_id === channelId && log.created_at >= time24HoursAgo - timeRangeSec) { upvotes++ } } return Functions.encodeUint256(upvotes) }

US election results from AP (Associated Press) API

Submitted by:
Karen Stepanyan
This Function returns the winner of the US election for a given date. It uses the AP (Associated Press) API to get the results. The date is the only required parameter. API key is the only required secret.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 // Chainlink Function to get election results from AP (Associated Press) API. Date and API key are the only required parameters const getReportingUnit = (reportingUnits, statePostal) => { const level = statePostal === 'US' ? 'national' : 'state' const reportingUnit = reportingUnits.find((ru) => ru.level === level) if (!reportingUnit) { throw new Error('Cannot find reporting unit') } return reportingUnit } const getReportingUnitWinner = (reportingUnit) => { for (const candidate of reportingUnit.candidates) { if (candidate.winner === 'X') { return candidate } } throw new Error('Candidate not found') } const date = args[0] // The date of the election formatted as YYYY-MM-DD const statePostal = args[1] // The state's two-letter code e.g CO. `US` to get the results of a nationwide election const raceID = args[2] // AP-assigned race ID. Should be used with `statePostal` const raceType = args[3] || 'G' // The race type the election is for. The race type can be `D(Dem Primary)`, `R(GOP Primary)`, `G(General)`, `E(Dem Caucus)`, `S(GOP Caucus)`, `X(Open Primary or special use cases)` const resultsType = args[4] || 'L' // The type of results to return. `L` for live results, `T` for test results if (!secrets.apikey) { throw new Error('Missing AP API key') } const params = { level: statePostal === 'US' ? 'national' : 'state', raceTypeID: raceType, format: 'json', winner: 'X', resultsType: resultsType, apikey: secrets.apikey, } if ((statePostal && !raceID) || (!statePostal && raceID)) { throw new Error('Both statePostal and raceID are required if one is provided') } if (statePostal) { params.statePostal = statePostal } if (raceID) { params.raceID = raceID } const config = { url: `https://api.ap.org/v3/elections/${date}`, params } const response = await Functions.makeHttpRequest(config) const races = response.data.races if (races.length === 0) { throw new Error('Could not find any races') } if (races.length > 1) { throw new Error('Finding the winner from multiple races is not supported') } const race = races[0] const reportingUnit = getReportingUnit(race.reportingUnits, statePostal) const raceWinner = getReportingUnitWinner(reportingUnit) return Functions.encodeString(JSON.stringify(raceWinner))

Aggregate the ERC20 balance of an address across multiple chains

Submitted by:
polarzero
Find the balance of a user for a specific ERC20 token across the specified chains, and return the total balance. This balance, for example, could be used immediately in the callback function to approve or deny the user access to specific functions in the contract.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 // https://github.com/polar0/cross-chain-ERC20-balance-verification/blob/main/implementation/verify-balances.js // The address to check the balances of const userAddress = args[0] // The chains to check, formatted as: // name:tokenAddress,name:tokenAddress... const tokens = args[1].split(",").map((tokenAddress) => { const [chain, address] = tokenAddress.split(":") return { chain, address } }) // Verify if there is indeed a secret (RPC URL) for each chain tokens.forEach((token) => { if (!secrets[token.chain]) { throw new Error(`No secret found for chain ${token.chain}`) } }) // Prepare requests for each chain const requests = tokens.map((token, index) => { return Functions.makeHttpRequest({ url: secrets[token.chain], method: "POST", data: { id: index, jsonrpc: "2.0", method: "eth_call", params: [ { to: token.address, // The signature of 'balanceOf(address)' + the user address without the 0x prefix data: "0x70a08231000000000000000000000000" + userAddress.slice(2), }, "latest", ], }, }) }) // Wait for all requests to finish const responses = await Promise.all(requests) // Parse responses const balances = responses.map((response) => { // Convert the result to a number return parseInt(response.data.result, 16) ?? 0 }) // Sum all balances const totalBalance = balances.reduce((a, b) => a + b, 0) // Return the total balance of the user return Functions.encodeUint256(totalBalance)

Find the Best DEX Trade Value for a Given Asset Pair

Submitted by:
Max Melcher
This example shows how to return the best DEX trade value for a give asset pair using Paraswap DEX Aggregator

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 // Decimals can be passed from the token contract decimals() function const srcToken = args[0] // Token source (selling) const srcDecimals = args[1] const destAsset = args[2] //Token destination (buying) const destDecimals = args[3] const amount = args[4] // Amount of source token to trade // Pull from the Paraswap DEX Aggregator router const paraswapRequest = await Functions.makeHttpRequest({ url: `https://apiv5.paraswap.io/prices?srcToken=${srcToken}&srcDecimals=${srcDecimals}&destToken=${destAsset}&destDecimals=${destDecimals}&amount=${amount}&network=1`, }) if (!paraswapRequest.error) { console.log("Optimal trade route found!") console.log( `Swap found to exchange ${ 10 ** -paraswapRequest.data.priceRoute.srcDecimals * parseInt(paraswapRequest.data.priceRoute.srcAmount) } of ${paraswapRequest.data.priceRoute.srcToken} into ${ 10 ** -paraswapRequest.data.priceRoute.destDecimals * parseInt(paraswapRequest.data.priceRoute.destAmount) } of ${paraswapRequest.data.priceRoute.destToken}` ) //Sample Output: "Swap found to exchange 1 of 0x514910771af9ca656af840dff83e8264ecf986ca into 6.732330036871376 of 0x6b175474e89094c44da98b954eedeac495271d0f" console.log(`${paraswapRequest.data.priceRoute.bestRoute.length} best route(s) found:`) //If direct swap is found with one pool return that pool address if (paraswapRequest.data.priceRoute.bestRoute[0].percent == 100) { console.log( `One direct route found through ${paraswapRequest.data.priceRoute.bestRoute[0].swaps[0].swapExchanges[0].exchange}` ) //Sample Output: One direct route found through UniswapV2 console.log(paraswapRequest.data.priceRoute.bestRoute[0].swaps[0].swapExchanges[0].data) /* Sample Output: { router: '0xF9234CB08edb93c0d4a4d4c70cC3FfD070e78e07', path: [ '0x514910771af9ca656af840dff83e8264ecf986ca', '0x6b175474e89094c44da98b954eedeac495271d0f' ], factory: '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f', initCode: '0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f', feeFactor: 10000, pools: [ { address: '0x6D4fd456eDecA58Cf53A8b586cd50754547DBDB2', fee: 30, direction: true } ], gasUSD: '2.735657' } */ } } else { console.log("Paraswap Request error") console.log({ ...paraswapRequest }) } return Functions.encodeUint256(parseInt(paraswapRequest.data.priceRoute.destAmount))

Fetch result of soccer match from Sportsdata.io

Submitted by:
Karen Stepanyan
The function fetches the result of soccer match. Required arguments are match date and abbreviations of team names

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 // Chainlink function to get the winner of soccer match. Possible return values are abbreviations of team names or 'Draw' const date = args[0] // Match date. basic date format YYYY-MM-DD. for example 2023-01-28 let teams = args[1] // competing teams in following format TEAM1/TEAM2. for example AST/LEI if (!secrets.soccerApiKey) { throw Error("Sportsdata.io API KEY is required") } const config = { url: `https://api.sportsdata.io/v3/soccer/scores/json/GamesByDate/${date}?key=${secrets.soccerApiKey}` } const response = await Functions.makeHttpRequest(config) const allMatches = response.data; const match = allMatches.find(match => { const playingTeams = `${match.AwayTeamKey}/${match.HomeTeamKey}`.toUpperCase() const playingTeamsReversed = `${match.HomeTeamKey}/${match.AwayTeamKey}`.toUpperCase() if (teams.toUpperCase() === playingTeams || teams.toUpperCase() === playingTeamsReversed) { return true } }) if (!match) { throw new Error('Match not found for given arguments') } if (match.Winner === 'Scrambled') { throw new Error('Data is scrambled, use production API Key') } let result; if (match.Winner === 'AwayTeam') { result = match.AwayTeamKey } else if (match.Winner === 'HomeTeam') { result = match.HomeTeamKey } else if (match.Winner === 'Draw') { result = 'Draw' } if (!result) { throw new Error('Could not get the winner team.') } return Functions.encodeString(result)

Prompt AI for a response

Submitted by:
Patrick Collins
Ask OpenAI (or any AI model you want to interact with) for information on-chain.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 const prompt = args[0] if ( !secrets.openaiKey ) { throw Error( "Need to set OPENAI_KEY environment variable" ) } // example request: // curl https://api.openai.com/v1/completions -H "Content-Type: application/json" -H "Authorization: Bearer YOUR_API_KEY" -d '{"model": "text-davinci-003", "prompt": "Say this is a test", "temperature": 0, "max_tokens": 7} // example response: // {"id":"cmpl-6jFdLbY08kJobPRfCZL4SVzQ6eidJ","object":"text_completion","created":1676242875,"model":"text-davinci-003","choices":[{"text":"\n\nThis is indeed a test","index":0,"logprobs":null,"finish_reason":"length"}],"usage":{"prompt_tokens":5,"completion_tokens":7,"total_tokens":12}} const openAIRequest = Functions.makeHttpRequest({ url: "https://api.openai.com/v1/completions", method: "POST", headers: { 'Authorization': `Bearer ${secrets.openaiKey}` }, data: { "model": "text-davinci-003", "prompt": prompt, "temperature": 0, "max_tokens": 7 } }) const [openAiResponse] = await Promise.all([ openAIRequest ]) console.log("raw response", openAiResponse) const result = openAiResponse.data.choices[0].text return Functions.encodeString(result)

Read cross-chain information

Submitted by:
Patrick Collins
The function reads the supply APY rate of depositing WETH into AaveV3 on Polygon

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 // This example shows how to make a decentralized price feed using multiple APIs // Arguments can be provided when a request is initated on-chain and used in the request source code as shown below const contractAddress = args[0] const encodedAbiFunctionCall = args[1] if ( !secrets.polygonKey ) { throw Error( "Need to set POLYGON_RPC_URL environment variable" ) } // curl --data '{"method":"eth_call","params":[{"to":"0x794a61358D6845594F94dc1DB02A252b5b4814aD","data":"0x35ea6a750000000000000000000000007ceb23fd6bc0add59e62ac25578270cff1b9f619"},"latest"],"id":1,"jsonrpc":"2.0"}' -H "Content-Type: application/json" -X POST $POLYGON_RPC_URL // example response: // {"jsonrpc":"2.0","id":1,"result":"0x000000000000000000000003e80000069140000039cb03e805122904203a1f400000000000000000000000000000000000000000033e9fbcc201bc653e561a5300000000000000000000000000000000000000000002542e73dd9e8a5aecdb2a0000000000000000000000000000000000000000034895c6e6312a938da89522000000000000000000000000000000000000000000123f39e6ba5158357302ea0000000000000000000000000000000000000000004a723dc6b40b8a9a0000000000000000000000000000000000000000000000000000000000000063e965ca0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000e50fa9b3c56ffb159cb0fca61f5c9d750e8128c8000000000000000000000000d8ad37849950903571df17049516a5cd4cbe55f60000000000000000000000000c84331e39d6658cd6e6b9ba04736cc4c473435100000000000000000000000003733f4e008d36f2e37f0080ff1c8df756622e6f00000000000000000000000000000000000000000000000001e758ee6c676a3f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"} // To make an HTTP request, use the Functions.makeHttpRequest function // Functions.makeHttpRequest function parameters: // - url // - method (optional, defaults to 'GET') // - headers: headers supplied as an object (optional) // - params: URL query parameters supplied as an object (optional) // - data: request body supplied as an object (optional) // - timeout: maximum request duration in ms (optional, defaults to 10000ms) // - responseType: expected response type (optional, defaults to 'json') // Ideally, you'd use multiple RPC URLs so we don't have to trust just one const polygonReadRequest = Functions.makeHttpRequest({ url: secrets.polygonKey, method: "POST", data: { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "to": contractAddress, data: encodedAbiFunctionCall }, "latest" ], "id": 1 } }) // First, execute all the API requests are executed concurrently, then wait for the responses const [polygonResponse] = await Promise.all([ polygonReadRequest ]) console.log("raw response", polygonResponse) // take the "0x" off the front of the hex string const result = polygonResponse.data.result.slice(2) // loop through result and convert each 64 characters to a number const startingIndex = 64 * 2 const supplyApy = "0x" + result.slice(startingIndex, startingIndex + 64) // convert the hex supplyApy to a number const supplyApyNumber = parseInt(supplyApy, 16) // This number is returned as a RAY, so we'd divide by 1e27, or 1e25 to get a percentage console.log("WETH Supply APY on AaveV3 in Polygon: ", (supplyApyNumber / 1e25), "%") // The source code MUST return a Buffer or the request will return an error message // Use one of the following functions to convert to a Buffer representing the response bytes that are returned to the client smart contract: // - Functions.encodeUint256 // - Functions.encodeInt256 // - Functions.encodeString // Or return a custom Buffer for a custom byte encoding // return Functions.encodeUint256(Math.round(medianPrice * 100)) return Functions.encodeUint256(supplyApyNumber)

Fetch outcome of off-chain Snapshot.org vote

Submitted by:
ChainLinkGod
The function fetches the outcome of an off-chain Snapshot.org vote proposal using the GraphQL API. Takes into account if the vote has closed and has met quorum. Gas efficient solution for DAOs.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 const proposalID = args[0] if (!proposalID) { throw Error("Proposal ID is required") } const config = { url: "https://hub.snapshot.org/graphql?", method: "POST", headers: { 'content-type': 'application/json' }, params: { operationName: "Proposal", query: `query Proposal {\n proposal(id:"${proposalID}") {\n id\n votes\n scores\n choices\n state\n scores_total\n quorum\n}\n}`, variables: null, }, } const response = await Functions.makeHttpRequest(config) const state = response.data.data.proposal.state const totalScore = response.data.data.proposal.scores_total const quorum = response.data.data.proposal.quorum if (state !== 'closed') { return Functions.encodeString('Vote not ended') } if (totalScore < quorum) { return Functions.encodeString('Quorum not met') } const scores = response.data.data.proposal.scores const choices = response.data.data.proposal.choices const highestIndex = scores.indexOf(Math.max(...scores)); return Functions.encodeString(choices[highestIndex])

Financial metric data for dApps and blockchains sourced from Token Terminal

Submitted by:
ChainLinkGod
This Function fetches metric data from the Token Terminal API for a specific project. Supported metrics include revenue, fees, earnings, active users, TVL, volume, supply, and more. Projects includes both dApps and blockchains. Optional parameter for specific date. Requires Token Terminal Pro subscription to obtain API key.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 const metric = args[0] // valid metric id that can be found on https://api.tokenterminal.com/v2/metrics const project = args[1] // project id const date = args[2] // optional date. format YYYY-MM-DD. For example 2023-02-10 const apiKey = secrets.API_KEY; if (!apiKey) { throw Error("Tokenterminal API Key is required") } const config = { url: `https://api.tokenterminal.com/v2/metrics/${metric}?project_ids=${project}`, headers: { 'Authorization': `Bearer ${apiKey}` } } const response = await Functions.makeHttpRequest(config) if (response.error) { throw new Error(response.response.data.message) } let data; if (date) { data = response.data.data.find(d => d.timestamp.includes(date)) }else { data = response.data.data[0] } const result = Math.round(data.value * 100) return Functions.encodeUint256(result)

Obtain outcome of off-chain vote

Submitted by:
mykcryptodev
This function fetches the final outcome of an off-chain vote on the Snapshot.org platform

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 const proposalId = args[0] // Use snapshot's graphql API to get the final vote outcome const snapshotRequest = () => Functions.makeHttpRequest({ url: `https://hub.snapshot.org/graphql`, method: "POST", data: { query: `{ proposal(id: "${proposalId}") { choices scores scores_state } }`, }, }) const { data, error } = await snapshotRequest() if (error) { throw Error("Snapshot request failed") } const { proposal } = data.data const { choices, scores, scores_state } = proposal if (scores_state !== "final") { throw Error("Snapshot vote is not final") } const winningChoice = choices[scores.indexOf(Math.max(...scores))] return Functions.encodeString(winningChoice)

Fetch and return available balance of Stripe account

Submitted by:
Karen Stepanyan
This function will fetch Stripe account available balance of particular currency.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 const apiKey = secrets.API_KEY const balanceCurrency = args[0] || 'usd' if (!apiKey) { throw Error("Stripe API Key is required") } const config = { url: `https://${apiKey}@api.stripe.com/v1/balance`, } const response = await Functions.makeHttpRequest(config) const balance = response.data.available.find(c => c.currency.toLowerCase() === balanceCurrency.toLowerCase()) const balanceInCents = Math.round(balance.amount * 100) return Functions.encodeUint256(balanceInCents)

Calculate the median price of a token on Uniswap V2

Submitted by:
moonthoon
This function calculates the median price of a token that is on Uniswap V2. It works by sampling up to 4 prices over a given time period then chooses the median value

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 // Max sample size is 4 due to 5 http request limit const SAMPLE_SIZE = 4 // The number of decimals the price in USD is formatted to const DECIMALS = 18 // A block buffer to take into consideration the synchronization of the subgraph const GRAPH_BLOCK_BUFFER = 50 const AVG_SECONDS_PER_BLOCK = 12 // Token address const token = args[0].toLowerCase(); // Pair address const pair = args[1] // Period in seconds const period = args[2] const blockRange = period / AVG_SECONDS_PER_BLOCK if (!secrets.rpc) { throw Error("\"rpc\" environment variable not set") } const blockNumberResponse = await Functions.makeHttpRequest({ url: secrets.rpc, method: "POST", headers: { "Accept": "application/json", "Content-Type": "application/json", }, data: JSON.stringify({ jsonrpc: "2.0", method: "eth_blockNumber", params: [], id: "1", }), }) if (blockNumberResponse.error) { throw Error("Unable to fetch current block number") } const blockNumber = parseInt(blockNumberResponse.data.result, 16) - GRAPH_BLOCK_BUFFER const fetchPrice = (blockNumber) => Functions.makeHttpRequest({ url: "https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2", method: "POST", data: { query: `{ pair(id: "${pair}", block: {number: ${blockNumber}}) { token0 { id } token1 { id } reserve0 reserve1 reserveUSD } }`, }, }) const stringToBigInt = (str) => { const splitStr = str.split(".") const decimals = splitStr[1].slice(0, DECIMALS).padEnd(DECIMALS, "0") return BigInt(`${splitStr[0]}${decimals}`) } const getPrice = async (blockNumber) => { const { error, data: { errors, data, }, } = await fetchPrice(blockNumber) if (error.error || errors) { throw Error("Unable to fetch price from subgraph") } const { pair: { token0: { id: token0 }, token1: { id: token1 }, reserve0, reserve1, reserveUSD } } = data const token0LC = token0.toLowerCase() const token1LC = token1.toLowerCase() if (token0LC !== token && token1LC !== token) { throw Error("Token not found as part of the pair") } const tokenReserveInUSD = stringToBigInt(reserveUSD) / 2n const tokenReserve = stringToBigInt(token0LC === token ? reserve0 : reserve1) return BigInt(10 ** DECIMALS) * tokenReserveInUSD / tokenReserve } const pickRandomBlock = () => { return blockNumber - Math.round(Math.random() * blockRange) } let prices = [] for (let i = 0; i < SAMPLE_SIZE; i++) { const price = await getPrice(pickRandomBlock()) prices.push(price) } const midpoint = SAMPLE_SIZE % 2 === 0 ? SAMPLE_SIZE / 2 : (SAMPLE_SIZE + 1) / 2 const median = prices[midpoint] return Functions.encodeUint256(median)

Twitter account verification with an Ethereum address

Submitted by:
polarzero
Check if a Twitter account belongs to a specific Ethereum address. This example uses the Twitter API to retrieve a user's recent tweets, and checks if they tweeted a specific message containing their address. It provides the arguments and returns the result via Chainlink Functions, which allows for prior validation of the user's ownership of the address via a signature or other method, thus performing a secure and non-intrusive verification.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 // https://github.com/polar0/twitter-verifier-chainlink-functions/blob/main/implementation/twitter-verification/functions/Functions-request-source.js // Get the arguments from the request config const twitterUsername = args[0]; // e.g. 'TwitterDev' const ethereumAddress = args[1]; // e.g. '0x1234567890123456789012345678901234567890' // The string that must be included in the latest tweets of the user for the verification to pass const requiredStringIncluded = `Verifying my Twitter account for ${ethereumAddress}`; // How many tweets to check (min 5, max 100) const MAX_RESULTS = 10; // Initialize the result to -1 (error) let result = -1; // Get the bearer token from the environment variables if (!secrets.apiKey) { throw Error( 'TWITTER_BEARER_TOKEN environment variable not set for Twitter API. Get a free one: https://developer.twitter.com/en/docs/authentication/oauth-2-0/bearer-tokens', ); } // Don't even try if the username or address is empty if (!twitterUsername || !ethereumAddress) { throw Error('Twitter username or Ethereum address is empty'); } // Prepare the API requests const twitterRequest = { // Get the user id from the provided username userIdByUsername: () => Functions.makeHttpRequest({ url: `https://api.twitter.com/2/users/by/username/${twitterUsername}`, headers: { Authorization: `Bearer ${secrets.apiKey}` }, }), // Get the latest n tweets from the user (n = MAX_RESULTS) lastTweetsByUserId: (userId) => Functions.makeHttpRequest({ url: `https://api.twitter.com/2/users/${userId}/tweets?max_results=${MAX_RESULTS}`, headers: { Authorization: `Bearer ${secrets.apiKey}` }, }), }; // First, request the user id from their username const idRes = await new Promise((resolve, reject) => { twitterRequest.userIdByUsername().then((res) => { if (!res.error) { resolve(res); } else { reject(res); } }); }); if (idRes.error) { throw Error('Twitter API request failed - coult not get user id'); } // Grab the user id const userId = idRes.data.data.id || null; // Let's be extra careful and make sure the user id is not null if (!userId) { throw Error('Twitter API request failed - user id is null'); } // Then, request the latest tweets const tweetsRes = await new Promise((resolve, reject) => { twitterRequest.lastTweetsByUserId(userId).then((res) => { if (!res.error) { resolve(res); } else { reject(res); } }); }); if (tweetsRes.error) { throw Error('Twitter API request failed - coult not get tweets'); } // It'll only get here if the request was successful const tweets = tweetsRes.data.data; const tweetTexts = tweets.map((tweet) => tweet.text); // Check if any of these tweets include the required string const res = tweetTexts.some((text) => text.toLowerCase().includes(requiredStringIncluded.toLowerCase()), ); // If it found the string, return 1, otherwise 0 result = res ? 1 : 0; // `result` can either be: // - 1 (verified) // - 0 (not verified) // - -1 (if by any chance no error was thrown, yet it could not verify) // Return the result along with the username and address, which can be parsed and split return Functions.encodeString( `${result},${twitterUsername},${ethereumAddress}`, );

Price data from multiple sources

Submitted by:
Morgan Kuphal
Retrieve the price of an asset from multiple API sources. Assets could be practially anything, incuding equities, crypto, or commodities. This example pulles from multiple different data providers (APIs) and derrives the median to return on chain via Chainlink Functions.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 const coinMarketCapCoinId = args[0]; const coinGeckoCoinId = args[1]; const coinPaprikaCoinId = args[2]; const badApiCoinId = args[3]; const scalingFactor = parseInt(args[4]); if (!secrets.apiKey) { throw Error('API_KEY environment variable not set for CoinMarketCap API. Get a free key from https://coinmarketcap.com/api/') } // OCR2DR.makeHttpRequest function parameters: // - url // - method (optional, defaults to 'GET') // - headers: headers supplied as an object (optional) // - params: URL query parameters supplied as an object (optional) // - data: request body supplied as an object (optional) // - timeout: maximum request duration in ms (optional, defaults to 10000ms) // - responseType: expected response type (optional, defaults to 'json') // Use multiple APIs & aggregate the results to enhance decentralization const coinMarketCapResponse = await OCR2DR.makeHttpRequest({ url: `https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest?convert=USD&id=${coinMarketCapCoinId}`, // Get a free API key from https://coinmarketcap.com/api/ headers: { 'X-CMC_PRO_API_KEY': secrets.apiKey } }); const coinGeckoResponse = await OCR2DR.makeHttpRequest({ url: `https://api.coingecko.com/api/v3/simple/price?ids=${coinGeckoCoinId}&vs_currencies=usd`, }); const coinPaprikaResponse = await OCR2DR.makeHttpRequest({ url: `https://api.coinpaprika.com/v1/tickers/${coinPaprikaCoinId}` }); const badApiResponse = await OCR2DR.makeHttpRequest({ url: `https://badapi.com/price/symbol/${badApiCoinId}` }); const prices = []; if (!coinMarketCapResponse.error) { prices.push(coinMarketCapResponse.data.data[coinMarketCapCoinId].quote.USD.price); } else { console.log('CoinMarketCap Error'); console.log({ ...coinMarketCapResponse }); } if (!coinGeckoResponse.error) { prices.push(coinGeckoResponse.data[coinGeckoCoinId].usd); } else { console.log('CoinGecko Error'); console.log({ ...coinGeckoResponse }); } if (!coinPaprikaResponse.error) { prices.push(coinPaprikaResponse.data.quotes.USD.price); } else { console.log('CoinPaprika Error'); console.log({ ...coinPaprikaResponse }); } // A single failed API request does not cause the whole request to fail if (!badApiResponse.error) { prices.push(httpResponses[3].data.price.usd); } else { console.log('Bad API request failed. (This message is expected and just for demonstration purposes.)') } // At least 3 prices are needed to aggregate the median price if (prices.length < 3) { // If an error is thrown, it will be returned back to the smart contract throw Error('More than 1 API failed'); } const medianPrice = prices.sort((a, b) => a - b)[Math.round(prices.length / 2)]; console.log(`Median Bitcoin price: $${medianPrice.toFixed(2)}`); // Use the following functions to encode a single value: // - OCR2DR.encodeUint256 // - OCR2DR.encodeInt256 // - OCR2DR.encodeString // Or return a Buffer for a custom byte encoding return OCR2DR.encodeUint256(Math.round(medianPrice * 100));