@entangle-labs/udf-sdk
Version:
SDK for interacting with UDF Oracle
101 lines (100 loc) • 3.83 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
class UdfSdk {
constructor(baseUrl = "https://udfsnap.ent-dx.com") {
this.baseUrl = baseUrl;
}
bytesToHex(bytes) {
return Array.from(bytes)
.map((b) => b.toString(16).padStart(2, "0"))
.join("");
}
decodeVoteValue(base64Value) {
const binaryString = atob(base64Value);
const bytes = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
const hexString = "0x" + this.bytesToHex(bytes);
const value = BigInt(hexString);
return value;
}
processVote(vote) {
return {
feedKey: vote.FeedKey,
value: this.decodeVoteValue(vote.Value),
timestamp: vote.Timestamp,
publisher: vote.Publisher,
signature: vote.Signature,
};
}
async getCallData(feedKeys) {
const response = await this.fetchData(feedKeys);
return response.update_call_data;
}
async getVotes(feedKeys) {
const response = await this.fetchData(feedKeys);
return response.feeds.flatMap((feed) => feed.votes.map((vote) => this.processVote(vote)));
}
async getMedian(feedKey) {
const votes = await this.getVotes([feedKey]);
if (!votes || votes.length === 0) {
throw new Error("No votes provided for median calculation");
}
const sortedValues = votes
.map((v) => v.value)
.filter((v) => !isNaN(Number(v)) && isFinite(Number(v)))
.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
if (sortedValues.length === 0) {
throw new Error("No valid numerical values found in votes");
}
const mid = Math.floor(sortedValues.length / 2);
if (sortedValues.length % 2 === 1) {
return sortedValues[mid];
}
return (sortedValues[mid - 1] + sortedValues[mid]) / 2n;
}
async fetchData(feedKeys) {
const queryParams = new URLSearchParams({ feedKeys: feedKeys.join(",") });
const response = await fetch(`${this.baseUrl}/last_votes?${queryParams}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
}
async getLastVotes(feedKeys) {
const data = await this.fetchData(feedKeys);
const processedFeeds = data.feeds.map((feed) => {
const processedVotes = feed.votes.map((vote) => this.processVote(vote));
const latestTimestamp = Math.max(...processedVotes.map((v) => v.timestamp));
return {
feedKey: feed.feed_key,
votes: processedVotes,
median: this.calculateMedianForVotes(processedVotes),
timestamp: latestTimestamp,
};
});
return {
feeds: processedFeeds,
updateCallData: data.update_call_data,
};
}
calculateMedianForVotes(votes) {
if (!votes || votes.length === 0) {
throw new Error("No votes provided for median calculation");
}
const sortedValues = votes
.map((v) => v.value)
.filter((v) => !isNaN(Number(v)) && isFinite(Number(v)))
.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
if (sortedValues.length === 0) {
throw new Error("No valid numerical values found in votes");
}
const mid = Math.floor(sortedValues.length / 2);
if (sortedValues.length % 2 === 1) {
return sortedValues[mid];
}
return (sortedValues[mid - 1] + sortedValues[mid]) / 2n;
}
}
exports.default = UdfSdk;