@b3dotfun/leaderboards
Version:
SDK to interact with leaderboards smart contract
495 lines • 15.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Leaderboard = void 0;
const viem_1 = require("viem");
const accounts_1 = require("viem/accounts");
const LeaderboardABI_1 = require("./abis/LeaderboardABI");
const config_1 = require("./config");
class Leaderboard {
contract;
contractAddress;
chain;
walletKey;
constructor(chainId, walletKey, contractAddress) {
if (walletKey && !walletKey.startsWith("0x")) {
walletKey = `0x${walletKey}`;
}
if (contractAddress && !contractAddress.startsWith("0x")) {
contractAddress = `0x${contractAddress}`;
}
const config = (0, config_1.getConfig)(chainId);
this.chain = config.chain;
this.walletKey = walletKey || "";
this.contractAddress = (contractAddress || "0x");
}
connect(provider) {
try {
const client = (0, viem_1.createWalletClient)({
chain: this.chain,
transport: provider ? (0, viem_1.custom)(provider) : (0, viem_1.http)(),
});
this.contract = (0, viem_1.getContract)({
address: this.contractAddress,
abi: LeaderboardABI_1.LeaderboardABI,
client: client,
});
return true;
}
catch (error) {
console.error("Connection failed:", error);
return false;
}
}
async handleError(error) {
if (error.data === "0xa741a045") {
throw new Error("Score already set for this user");
}
else if (error.data === "0x4456a11e") {
throw new Error("Cannot decrement score below zero");
}
else if (error.data === "0x441dfbd6") {
throw new Error("Score not set for this user");
}
else if (error.data === "0xb8b000dd") {
throw new Error("Leaderboard has not started yet");
}
else if (error.data === "0x9fde1257") {
throw new Error("Leaderboard has ended");
}
else if (error.data === "0x929fcbb9") {
throw new Error("Leaderboard capacity reached");
}
else {
throw error;
}
}
async addAdmin(newAdmin) {
if (!this.walletKey) {
throw new Error("Wallet key not set");
}
try {
return await this.contract.write.addAdmin([newAdmin], {
account: (0, accounts_1.privateKeyToAccount)(this.walletKey),
chain: this.chain,
});
}
catch (error) {
return await this.handleError(error);
}
}
async removeAdmin(admin) {
if (!this.walletKey) {
throw new Error("Wallet key not set");
}
try {
return await this.contract.write.removeAdmin([admin], {
account: (0, accounts_1.privateKeyToAccount)(this.walletKey),
chain: this.chain,
});
}
catch (error) {
return await this.handleError(error);
}
}
async updateLeaderboard(startTime, endTime, title) {
if (!this.walletKey) {
throw new Error("Wallet key not set");
}
try {
return await this.contract.write.updateLeaderboard([BigInt(startTime), BigInt(endTime), title], {
account: (0, accounts_1.privateKeyToAccount)(this.walletKey),
chain: this.chain,
});
}
catch (error) {
return await this.handleError(error);
}
}
async incrementScores(inputs) {
if (!this.walletKey) {
throw new Error("Wallet key not set");
}
// if this is a private leaderboard, filter out users that are not eligible
if (await this.isPrivate()) {
const eligibleUsers = await this.getEligibleUsers();
inputs = inputs.filter((input) => eligibleUsers.includes(input.user));
}
const formattedInputs = inputs.map((input) => ({
user: input.user,
score: BigInt(input.score),
timestamp: BigInt(input.timestamp),
}));
try {
return await this.contract.write.incrementScores([formattedInputs], {
account: (0, accounts_1.privateKeyToAccount)(this.walletKey),
chain: this.chain,
});
}
catch (error) {
return await this.handleError(error);
}
}
async decrementScores(inputs) {
if (!this.walletKey) {
throw new Error("Wallet key not set");
}
// if this is a private leaderboard, filter out users that are not eligible
if (await this.isPrivate()) {
const eligibleUsers = await this.getEligibleUsers();
inputs = inputs.filter((input) => eligibleUsers.includes(input.user));
}
const formattedInputs = inputs.map((input) => ({
user: input.user,
score: BigInt(input.score),
timestamp: BigInt(input.timestamp),
}));
try {
return await this.contract.write.decrementScores([formattedInputs], {
account: (0, accounts_1.privateKeyToAccount)(this.walletKey),
chain: this.chain,
});
}
catch (error) {
return await this.handleError(error);
}
}
async updateScores(inputs) {
if (!this.walletKey) {
throw new Error("Wallet key not set");
}
// if this is a private leaderboard, filter out users that are not eligible
if (await this.isPrivate()) {
const eligibleUsers = await this.getEligibleUsers();
inputs = inputs.filter((input) => eligibleUsers.includes(input.user));
}
const formattedInputs = inputs.map((input) => ({
user: input.user,
score: BigInt(input.score),
timestamp: BigInt(input.timestamp),
}));
try {
return await this.contract.write.updateScores([formattedInputs], {
account: (0, accounts_1.privateKeyToAccount)(this.walletKey),
chain: this.chain,
});
}
catch (error) {
return await this.handleError(error);
}
}
async overwriteScores(inputs) {
if (!this.walletKey) {
throw new Error("Wallet key not set");
}
// if this is a private leaderboard, filter out users that are not eligible
if (await this.isPrivate()) {
const eligibleUsers = await this.getEligibleUsers();
inputs = inputs.filter((input) => eligibleUsers.includes(input.user));
}
const formattedInputs = inputs.map((input) => ({
user: input.user,
score: BigInt(input.score),
timestamp: BigInt(input.timestamp),
}));
try {
return await this.contract.write.overwriteScores([formattedInputs], {
account: (0, accounts_1.privateKeyToAccount)(this.walletKey),
chain: this.chain,
});
}
catch (error) {
return await this.handleError(error);
}
}
async blacklistUsers(users) {
if (!this.walletKey) {
throw new Error("Wallet key not set");
}
try {
return await this.contract.write.blacklistUsers([users], {
account: (0, accounts_1.privateKeyToAccount)(this.walletKey),
chain: this.chain,
});
}
catch (error) {
return await this.handleError(error);
}
}
async unblacklistUser(user) {
if (!this.walletKey) {
throw new Error("Wallet key not set");
}
try {
return await this.contract.write.unblacklistUser([user], {
account: (0, accounts_1.privateKeyToAccount)(this.walletKey),
chain: this.chain,
});
}
catch (error) {
return await this.handleError(error);
}
}
async addEligibleUsers(users) {
if (!this.walletKey) {
throw new Error("Wallet key not set");
}
try {
return await this.contract.write.addEligibleUsers([users], {
account: (0, accounts_1.privateKeyToAccount)(this.walletKey),
chain: this.chain,
});
}
catch (error) {
return await this.handleError(error);
}
}
async removeEligibleUsers(users) {
if (!this.walletKey) {
throw new Error("Wallet key not set");
}
try {
return await this.contract.write.removeEligibleUsers([users], {
account: (0, accounts_1.privateKeyToAccount)(this.walletKey),
chain: this.chain,
});
}
catch (error) {
return await this.handleError(error);
}
}
async increaseUserAttempts(user, amount) {
if (!this.walletKey) {
throw new Error("Wallet key not set");
}
try {
return await this.contract.write.increaseUserAttempts([user, BigInt(amount)], {
account: (0, accounts_1.privateKeyToAccount)(this.walletKey),
chain: this.chain,
});
}
catch (error) {
return await this.handleError(error);
}
}
async decreaseUserAttempts(user, amount) {
if (!this.walletKey) {
throw new Error("Wallet key not set");
}
try {
return await this.contract.write.decreaseUserAttempts([user, BigInt(amount)], {
account: (0, accounts_1.privateKeyToAccount)(this.walletKey),
chain: this.chain,
});
}
catch (error) {
return await this.handleError(error);
}
}
async getUserAttempts(user) {
try {
return Number(await this.contract.read.getUserAttempts([user]));
}
catch (error) {
return undefined;
}
}
/**
* Get all users and their scores, sorted by score in descending order
*/
async getAllScores() {
try {
if (this.contractAddress === "0x") {
return [];
}
const [addresses, scores, timestamps] = (await this.contract.read.getLeaderboard());
// Create array of score objects
const scoreObjects = addresses.map((user, index) => ({
player: user,
score: Number(scores[index]),
timestamp: Number(timestamps[index]),
}));
// Sort by score in descending order
return scoreObjects
.sort((a, b) => b.score - a.score)
.map((score, index) => ({
...score,
rank: index + 1,
}));
}
catch (error) {
return [];
}
}
/**
* Get top N users and their scores
* @param limit Number of top users to return
*/
async getTopScores(limit, startIndex = 0) {
const allScores = await this.getAllScores();
return allScores.slice(startIndex, startIndex + limit);
}
/**
* Get player ranking and score
* @param userAddress Address of the player to look up
*/
async getPlayerRanking(userAddress) {
const allScores = await this.getAllScores();
return allScores.find((score) => score.player.toLowerCase() === userAddress.toLowerCase());
}
async getUserScore(user) {
try {
const [score, lastUpdated] = (await this.contract.read.getUserScore([
user,
]));
return {
score: Number(score),
lastUpdated: Number(lastUpdated),
};
}
catch (error) {
return undefined;
}
}
async getLeaderboardUserCount() {
try {
return Number(await this.contract.read.getLeaderboardUserCount());
}
catch (error) {
return undefined;
}
}
async getLeaderboardStartTime() {
try {
return Number(await this.contract.read.getLeaderboardStartTime());
}
catch (error) {
return undefined;
}
}
async getLeaderboardEndTime() {
try {
return Number(await this.contract.read.getLeaderboardEndTime());
}
catch (error) {
return undefined;
}
}
async isLeaderboardActive() {
try {
return (await this.contract.read.isLeaderboardActive());
}
catch (error) {
return false;
}
}
async isLeaderboardEnded() {
try {
return (await this.contract.read.isLeaderboardEnded());
}
catch (error) {
return false;
}
}
async isPrivate() {
try {
return (await this.contract.read.isPrivate());
}
catch (error) {
return false;
}
}
async isUserBlacklisted(user) {
try {
return (await this.contract.read.isUserBlacklisted([user]));
}
catch (error) {
return false;
}
}
async isUserEligible(user) {
try {
return (await this.contract.read.isUserEligible([user]));
}
catch (error) {
return false;
}
}
async getEligibleUsers() {
try {
return (await this.contract.read.getEligibleUsers());
}
catch (error) {
return [];
}
}
async getAdmins() {
try {
return (await this.contract.read.getAdmins());
}
catch (error) {
return [];
}
}
async getBlacklistUsers() {
try {
return (await this.contract.read.getBlacklistUsers());
}
catch (error) {
return [];
}
}
async getLeaderboardProperties() {
try {
const props = await this.contract.read.getLeaderboardProps();
return {
startTime: Number(props.startTime),
endTime: Number(props.endTime),
hasConcluded: props.hasConcluded,
slug: props.slug,
title: props.title,
isPrivate: props.isPrivate,
useLatestScore: props.useLatestScore,
hasAttemptLimit: props.hasAttemptLimit,
initialAttempts: Number(props.initialAttempts),
isReverseSort: props.isReverseSort,
};
}
catch (error) {
return undefined;
}
}
async getRemainingTime() {
try {
return Number(await this.contract.read.getRemainingTime());
}
catch (error) {
return undefined;
}
}
async getTimeUntilStart() {
try {
return Number(await this.contract.read.getTimeUntilStart());
}
catch (error) {
return undefined;
}
}
async getSlug() {
try {
return await this.contract.read.getSlug();
}
catch (error) {
return undefined;
}
}
async getTitle() {
try {
return await this.contract.read.getTitle();
}
catch (error) {
return undefined;
}
}
}
exports.Leaderboard = Leaderboard;
//# sourceMappingURL=leaderboard.js.map