Enterprise
The Enterprise interoperability module focuses on Web2.
Consumers can get access to the legacy Web2 world through this module and bring off-chain data of public or permissoned APIs and off-chain computation to their Web3 application in the supported blockchain ecosystems .
As the developer is in full control, they can define their requirement in-code, based specificially on their requirements.


Example Use Cases
- Public API access
- price feeds
- sport results
- weather data
- Permissioned API access
- Verifiable randomness
- Off-chain computation
Examples
Code examples for the Acurast Enterprise interoperability module for off-chain data and computation.
HTTPS GET Request
Request from an API with the result of an asset price.
httpGET(
"https://api.binance.com/api/v3/ticker/price?symbol=BNBBTC",
{},
(response, certificate) => {
console.log("response", response);
const price = JSON.parse(response)["price"] * 10 ** 6;
console.log("price", price);
const payload = { price: price, timestamp: Date.now() / 1000 };
const packedPayload = pack(payload);
const signature = sign(payload);
httpPOST(
"https://oracle.free.beeceptor.com",
JSON.stringify({
signature: signature,
certificate: certificate,
payload: packedPayload,
}),
{},
(response, certificate) => {},
(errorMessage) => {}
);
},
(errorMessage) => {}
);
https://example.com
Verifiable Randomness
Getting a randomized output from the Trusted Execution Environment.
return fulfill(generateSecureRandomHex());
https://example.com
Complete Example
This is a complete example that includes multiple price points and calculations.
- Fetches prices for multiple assets from multiple endpoints
- Does certificate pinning to ensure that the data is coming from the instructed sources
- Calculations for an index with multiple assets
- Calculations for the median
- Defines a minimal amount of sources
const INTERVAL = 900 * 1000;
const MINIMUM_SOURCES_PER_PRICE = 2;
const PREVIOUS_EPOCH_START_MILLIS =
(Math.floor(Date.now() / INTERVAL) - 1) * INTERVAL;
const PREVIOUS_EPOCH_END_MILLIS =
Math.floor(Date.now() / INTERVAL) * INTERVAL - 1;
const PREVIOUS_EPOCH_START_SECONDS = Math.floor(
PREVIOUS_EPOCH_START_MILLIS / 1000
);
const PREVIOUS_EPOCH_END_SECONDS = Math.floor(PREVIOUS_EPOCH_END_MILLIS / 1000);
const PREVIOUS_EPOCH_START_ISO = new Date(
PREVIOUS_EPOCH_START_MILLIS
).toISOString();
const PREVIOUS_EPOCH_END_ISO = new Date(
PREVIOUS_EPOCH_END_MILLIS
).toISOString();
// for index to USDT
const BINANCE_SYMBOLS = [
"UNIUSDT",
"CAKEUSDT",
"LUNAUSDT",
"LINKUSDT",
"AAVEUSDT",
];
const KUCOIN_SYMBOLS = [
"UNI-USDT",
"CAKE-USDT",
"LUNA-USDT",
"LINK-USDT",
"AAVE-USDT",
];
const GATEIO_SYMBOLS = [
"UNI_USDT",
"CAKE_USDT",
"LUNA_USDT",
"LINK_USDT",
"AAVE_USDT",
];
// for USDT<>USD
const COINBASE_SYMBOLS = ["BTC-USD", "XTZ-USD", "USDT-USD"];
const BITFINEX_SYMBOLS = ["BTCUSD", "XTZUSD", "USTUSD"];
const BINANCE_US_SYMBOLS = ["BTCUSD", "XTZUSD", "USDTUSD"];
const PRICE_PRECISION = 10 ** 6;
// for index to USDT
const BINANCE_TEMPLATE = `https://api.binance.com/api/v3/klines?symbol=<<SYMBOL>>&interval=15m&startTime=${PREVIOUS_EPOCH_START_MILLIS}&endTime=${PREVIOUS_EPOCH_END_MILLIS}`;
const KUCOIN_TEMPLATE = `https://api.kucoin.com/api/v1/market/candles?symbol=<<SYMBOL>>&type=15min&startAt=${PREVIOUS_EPOCH_START_SECONDS}&endAt=${PREVIOUS_EPOCH_END_SECONDS}`;
const GATE_IO_TEMPLATE = `https://api.gateio.ws/api/v4/spot/candlesticks/?currency_pair=<<SYMBOL>>&interval=15m&from=${PREVIOUS_EPOCH_START_SECONDS}&to=${PREVIOUS_EPOCH_END_SECONDS}`;
// for USDT<>USD
const BINANCE_US_TEMPLATE = `https://api.binance.us/api/v3/klines?symbol=<<SYMBOL>>&interval=15m&startTime=${PREVIOUS_EPOCH_START_MILLIS}&endTime=${PREVIOUS_EPOCH_END_MILLIS}`;
const COINBASE_TEMPLATE = `https://api.pro.coinbase.com/products/<<SYMBOL>>/candles?granularity=900&start=${PREVIOUS_EPOCH_START_ISO}&end=${PREVIOUS_EPOCH_END_ISO}`;
const BITFINEX_TEMPLATE = `https://api-pub.bitfinex.com/v2/candles/trade:15m:t<<SYMBOL>>/hist?start=${PREVIOUS_EPOCH_START_MILLIS}&end=${PREVIOUS_EPOCH_END_MILLIS}`;
const BINANCE_CONFIG = {
url: BINANCE_TEMPLATE,
exchange_id: "BNN",
timestamp_factor: 1,
timestamp_index: 0,
close_index: 4,
certificate:
"0D:ED:57:7F:B9:1B:4C:8E:B2:36:50:10:4A:BA:08:FF:6C:86:77:75:4E:32:8D:02:09:E1:BE:F3:42:7B:BD:D4",
};
const KUCOIN_CONFIG = {
url: KUCOIN_TEMPLATE,
exchange_id: "KUC",
timestamp_factor: 1000,
timestamp_index: 0,
close_index: 2,
certificate:
"A7:3F:12:F8:0A:A1:87:C0:97:86:B1:E1:0E:03:73:9C:3C:71:73:44:DA:32:C7:77:21:57:0F:48:5C:FC:18:6F",
};
const GATE_IO_CONFIG = {
url: GATE_IO_TEMPLATE,
exchange_id: "GAT",
timestamp_factor: 1000,
timestamp_index: 0,
close_index: 2,
certificate:
"45:8B:33:B8:2F:54:69:32:7B:FB:0B:02:51:29:08:E6:6F:62:BA:2E:93:0A:F7:9E:CB:03:07:C2:E8:E9:DC:74",
};
const BINANCE_US_CONFIG = {
url: BINANCE_US_TEMPLATE,
exchange_id: "BNU",
timestamp_factor: 1,
timestamp_index: 0,
close_index: 4,
certificate:
"9E:94:90:DB:57:6D:B8:17:A4:68:C4:30:9D:83:76:C1:49:04:26:C1:2E:55:93:9D:E0:92:A6:13:16:14:E0:FA",
};
const COINBASE_CONFIG = {
url: COINBASE_TEMPLATE,
exchange_id: "CBP",
timestamp_factor: 1000,
timestamp_index: 0,
close_index: 4,
certificate:
"8B:70:72:2E:AE:DC:63:68:D9:EA:59:6F:B3:30:C1:E7:F8:5F:30:81:8D:7C:90:05:73:BC:64:04:61:D1:03:03",
};
const BITFINEX_CONFIG = {
url: BITFINEX_TEMPLATE,
exchange_id: "BFX",
timestamp_factor: 1,
timestamp_index: 0,
close_index: 2,
certificate:
"57:E3:2B:C3:C5:AC:D8:86:E4:E4:25:9C:CB:A2:40:29:1F:07:7D:E1:61:21:2B:0F:B0:EC:8E:71:4A:82:C8:D1",
};
const INITIAL_PRICES = {
AAVEUSD: 150.8,
CAKEUSD: 6.52,
LINKUSD: 14.76,
LUNAUSD: 94.46,
UNIUSD: 9.36,
};
const WEIGHTS = {
AAVE: 0.0406,
CAKE: 0.0368,
LINK: 0.1335,
LUNA: 0.6654,
UNI: 0.1238,
};
const LAST_REBALANCING_PRICE = 1.21617108;
const internalFetch = (config, symbols) => {
return symbols.map((symbol) => {
return new Promise((resolve, reject) => {
httpGET(
config.url.replace("<<SYMBOL>>", symbol),
{},
(rawResponse, certificate) => {
let response = JSON.parse(rawResponse);
if (config.exchange_id === "KUC") {
response = response["data"];
}
if (certificate === config.certificate) {
const payload = {
symbol: symbol
.replace("-", "")
.replace("_", "")
.replace("UST", "USDT"),
exchange_id: config.exchange_id,
timestamp:
response[0][config.timestamp_index] * config.timestamp_factor,
close: parseFloat(response[0][config.close_index]),
certificate: certificate,
};
resolve(payload);
} else {
reject("certificate does not match");
}
},
(errorMessage) => {
reject(errorMessage);
}
);
});
});
};
const median = (values) => {
values.sort((a, b) => a - b);
if (values.length % 2 == 0) {
return (
(values[Math.floor(values.length / 2)] +
values[Math.floor(values.length / 2) - 1]) /
2.0
);
} else {
return values[Math.floor(values.length / 2)];
}
};
const promises = [
...internalFetch(BINANCE_CONFIG, BINANCE_SYMBOLS),
...internalFetch(KUCOIN_CONFIG, KUCOIN_SYMBOLS),
...internalFetch(GATE_IO_CONFIG, GATEIO_SYMBOLS),
...internalFetch(BINANCE_US_CONFIG, BINANCE_US_SYMBOLS),
...internalFetch(COINBASE_CONFIG, COINBASE_SYMBOLS),
...internalFetch(BITFINEX_CONFIG, BITFINEX_SYMBOLS),
];
Promise.allSettled(promises).then((results) => {
const fulfilledPayloads = results
.filter((result) => result.status === "fulfilled")
.map((result) => result.value)
.filter((item) => item.timestamp === PREVIOUS_EPOCH_START_MILLIS);
const prices = fulfilledPayloads.reduce((previousValue, currentValue) => {
if (currentValue.symbol in previousValue) {
previousValue[currentValue.symbol].push(currentValue.close);
} else {
previousValue[currentValue.symbol] = [currentValue.close];
}
return previousValue;
}, {});
const indexPrice =
(LAST_REBALANCING_PRICE *
PRICE_PRECISION *
(WEIGHTS["UNI"] * (median(prices["UNIUSDT"]) / INITIAL_PRICES["UNIUSD"]) +
WEIGHTS["LINK"] *
(median(prices["LINKUSDT"]) / INITIAL_PRICES["LINKUSD"]) +
WEIGHTS["LUNA"] *
(median(prices["LUNAUSDT"]) / INITIAL_PRICES["LUNAUSD"]) +
WEIGHTS["CAKE"] *
(median(prices["CAKEUSDT"]) / INITIAL_PRICES["CAKEUSD"]) +
WEIGHTS["AAVE"] *
(median(prices["AAVEUSDT"]) / INITIAL_PRICES["AAVEUSD"]))) /
median(prices["USDTUSD"]);
const sources_count = Math.min(
...Object.values(prices).map((values) => values.length)
);
if (sources_count >= MINIMUM_SOURCES_PER_PRICE) {
const oraclePayload = {
timestamp: PREVIOUS_EPOCH_START_SECONDS,
defi_price: Math.round(indexPrice),
xtz_price: Math.round(median(prices["XTZUSD"]) * PRICE_PRECISION),
btc_price: Math.round(median(prices["BTCUSD"]) * PRICE_PRECISION),
};
console.log(fulfill(oraclePayload));
}
});
https://example.com