@wasserstoff/tribes-sdk
Version:
SDK for integrating with Tribes by Astrix platform on any EVM compatible chain
501 lines (500 loc) • 19.7 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TribesModule = void 0;
const ethers_1 = require("ethers");
const BaseModule_1 = require("../core/BaseModule");
const core_1 = require("../types/core");
const tribes_1 = require("../types/tribes");
const validation_1 = require("../utils/validation");
// Import TribeController ABI
const TribeController_json_1 = __importDefault(require("../../abis/TribeController.json"));
/**
* Module for managing tribes and tribe membership
*/
class TribesModule extends BaseModule_1.BaseModule {
/**
* Get the TribeController contract
* @param useSigner Whether to use the signer
*/
getTribeControllerContract(useSigner = false) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return this. // eslint-disable-next-line @typescript-eslint/no-explicit-any
getContract(this.config.contracts.tribeController, TribeController_json_1.default, useSigner);
}
/**
* Create a new tribe
* @param params Tribe creation parameters
* @returns Tribe ID of the newly created tribe
*/
async createTribe(params) {
try {
// Validate input
(0, validation_1.validateNonEmptyString)(params.name, 'name');
(0, validation_1.validateNonEmptyString)(params.metadata, 'metadata');
if (params.admins) {
params.admins.forEach((admin, index) => {
(0, validation_1.validateAddress)(admin, `admins[${index}]`);
});
}
if (params.entryFee) {
(0, validation_1.validatePositiveBigInt)(params.entryFee, 'entryFee');
}
const tribeController = this.getTribeControllerContract(true);
const tx = await tribeController.createTribe(params.name, params.metadata, params.admins || [], params.joinType !== undefined ? params.joinType : tribes_1.JoinType.PUBLIC, params.entryFee || 0n, params.nftRequirements || []);
const receipt = await tx.wait();
// Extract tribeId from event
const event = receipt.logs.find((log) => {
return log.topics && log.topics[0] === ethers_1.ethers.id("TribeCreated(uint256,address,string)");
});
if (!event || !event.args) {
throw new Error('Tribe creation event not found or args undefined');
}
const tribeId = Number(event.args[0]);
this.log(`Created tribe`, {
tribeId,
name: params.name,
txHash: receipt.hash
});
return tribeId;
}
catch (error) {
return this.handleError(error, 'Failed to create tribe', core_1.ErrorType.CONTRACT_ERROR);
}
}
/**
* Update tribe configuration
* @param params Tribe configuration update parameters
* @returns Transaction hash
*/
async updateTribeConfig(params) {
try {
if (params.entryFee) {
(0, validation_1.validatePositiveBigInt)(params.entryFee, 'entryFee');
}
const tribeController = this.getTribeControllerContract(true);
const tx = await tribeController.updateTribeConfig(params.tribeId, params.joinType, params.entryFee, params.nftRequirements || []);
const receipt = await tx.wait();
this.log(`Updated tribe configuration`, {
tribeId: params.tribeId,
joinType: params.joinType,
entryFee: params.entryFee?.toString(),
txHash: receipt.hash
});
return receipt.hash;
}
catch (error) {
return this.handleError(error, 'Failed to update tribe configuration', core_1.ErrorType.CONTRACT_ERROR);
}
}
/**
* Update tribe metadata and whitelist
* @param params Tribe update parameters
* @returns Transaction hash
*/
async updateTribe(params) {
try {
(0, validation_1.validateNonEmptyString)(params.newMetadata, 'newMetadata');
if (params.updatedWhitelist) {
params.updatedWhitelist.forEach((address, index) => {
(0, validation_1.validateAddress)(address, `updatedWhitelist[${index}]`);
});
}
const tribeController = this.getTribeControllerContract(true);
const tx = await tribeController.updateTribe(params.tribeId, params.newMetadata, params.updatedWhitelist || []);
const receipt = await tx.wait();
this.log(`Updated tribe`, {
tribeId: params.tribeId,
txHash: receipt.hash
});
return receipt.hash;
}
catch (error) {
return this.handleError(error, 'Failed to update tribe', core_1.ErrorType.CONTRACT_ERROR);
}
}
/**
* Join a tribe
* @param params Join tribe parameters
* @returns Transaction hash
*/
async joinTribe(params) {
try {
const tribeController = this.getTribeControllerContract(true);
const tx = await tribeController.joinTribe(params.tribeId);
const receipt = await tx.wait();
this.log(`Joined tribe`, {
tribeId: params.tribeId,
txHash: receipt.hash
});
return receipt.hash;
}
catch (error) {
return this.handleError(error, 'Failed to join tribe', core_1.ErrorType.CONTRACT_ERROR);
}
}
/**
* Request to join a private tribe
* @param params Request to join parameters
* @returns Transaction hash
*/
async requestToJoinTribe(params) {
try {
if (params.entryFee) {
(0, validation_1.validatePositiveBigInt)(params.entryFee, 'entryFee');
}
const tribeController = this.getTribeControllerContract(true);
const tx = await tribeController.requestToJoinTribe(params.tribeId, { value: params.entryFee || 0n });
const receipt = await tx.wait();
this.log(`Requested to join tribe`, {
tribeId: params.tribeId,
entryFee: params.entryFee?.toString(),
txHash: receipt.hash
});
return receipt.hash;
}
catch (error) {
return this.handleError(error, 'Failed to request to join tribe', core_1.ErrorType.CONTRACT_ERROR);
}
}
/**
* Join a tribe using an invite code
* @param params Join with code parameters
* @returns Transaction hash
*/
async joinTribeWithCode(params) {
try {
(0, validation_1.validateNonEmptyString)(params.inviteCode, 'inviteCode');
const tribeController = this.getTribeControllerContract(true);
const tx = await tribeController.joinTribeWithCode(params.tribeId, params.inviteCode);
const receipt = await tx.wait();
this.log(`Joined tribe with code`, {
tribeId: params.tribeId,
txHash: receipt.hash
});
return receipt.hash;
}
catch (error) {
return this.handleError(error, 'Failed to join tribe with code', core_1.ErrorType.CONTRACT_ERROR);
}
}
/**
* Approve a member's request to join
* @param params Manage member parameters
* @returns Transaction hash
*/
async approveMember(params) {
try {
(0, validation_1.validateAddress)(params.memberAddress, 'memberAddress');
const tribeController = this.getTribeControllerContract(true);
const tx = await tribeController.approveMember(params.tribeId, params.memberAddress);
const receipt = await tx.wait();
this.log(`Approved member`, {
tribeId: params.tribeId,
member: params.memberAddress,
txHash: receipt.hash
});
return receipt.hash;
}
catch (error) {
return this.handleError(error, 'Failed to approve member', core_1.ErrorType.CONTRACT_ERROR);
}
}
/**
* Remove a member from a tribe
* @param params Manage member parameters
* @returns Transaction hash
*/
async removeMember(params) {
try {
(0, validation_1.validateAddress)(params.memberAddress, 'memberAddress');
const tribeController = this.getTribeControllerContract(true);
const tx = await tribeController.removeMember(params.tribeId, params.memberAddress);
const receipt = await tx.wait();
this.log(`Removed member`, {
tribeId: params.tribeId,
member: params.memberAddress,
txHash: receipt.hash
});
return receipt.hash;
}
catch (error) {
return this.handleError(error, 'Failed to remove member', core_1.ErrorType.CONTRACT_ERROR);
}
}
/**
* Ban a member from a tribe
* @param params Manage member parameters
* @returns Transaction hash
*/
async banMember(params) {
try {
(0, validation_1.validateAddress)(params.memberAddress, 'memberAddress');
const tribeController = this.getTribeControllerContract(true);
const tx = await tribeController.banMember(params.tribeId, params.memberAddress);
const receipt = await tx.wait();
this.log(`Banned member`, {
tribeId: params.tribeId,
member: params.memberAddress,
txHash: receipt.hash
});
return receipt.hash;
}
catch (error) {
return this.handleError(error, 'Failed to ban member', core_1.ErrorType.CONTRACT_ERROR);
}
}
/**
* Create an invite code for a tribe
* @param params Create invite code parameters
* @returns Transaction hash
*/
async createInviteCode(params) {
try {
(0, validation_1.validateNonEmptyString)(params.code, 'code');
const tribeController = this.getTribeControllerContract(true);
const tx = await tribeController.createInviteCode(params.tribeId, params.code, params.maxUses, params.expiryTime || 0);
const receipt = await tx.wait();
this.log(`Created invite code`, {
tribeId: params.tribeId,
code: params.code,
maxUses: params.maxUses,
expiryTime: params.expiryTime,
txHash: receipt.hash
});
return receipt.hash;
}
catch (error) {
return this.handleError(error, 'Failed to create invite code', core_1.ErrorType.CONTRACT_ERROR);
}
}
/**
* Get tribe details
* @param tribeId Tribe ID
* @returns Tribe details object
*/
async getTribeDetails(tribeId) {
try {
const tribeController = this.getTribeControllerContract();
const tribeData = await tribeController.getTribeDetails(tribeId);
return {
id: tribeId,
name: tribeData.name,
admin: tribeData.admin,
metadata: tribeData.metadata,
joinType: tribeData.joinType,
entryFee: tribeData.entryFee,
memberCount: Number(tribeData.memberCount),
creationTime: Number(tribeData.creationTime) || 0,
nftRequirements: tribeData.nftRequirements || [],
organization: tribeData.organization || undefined,
isActive: tribeData.isActive || true,
canMerge: tribeData.canMerge || false
};
}
catch (error) {
return this.handleError(error, 'Failed to get tribe details', core_1.ErrorType.CONTRACT_ERROR);
}
}
/**
* Check if an address is a member of a tribe
* @param tribeId Tribe ID
* @param address Address to check
* @returns Member status
*/
async getMemberStatus(tribeId, address) {
try {
(0, validation_1.validateAddress)(address, 'address');
const tribeController = this.getTribeControllerContract();
const status = await tribeController.getMemberStatus(tribeId, address);
return status;
}
catch (error) {
return this.handleError(error, 'Failed to get member status', core_1.ErrorType.CONTRACT_ERROR);
}
}
/**
* Get all members of a tribe
* @param tribeId Tribe ID
* @returns Array of member addresses
*/
async getMembers(tribeId) {
try {
// This function is a placeholder until the contract adds support for it
this.log(`Warning: getMembers function is not yet supported by the contract`, {
tribeId
});
// Return an empty array for now
return [];
// Original implementation (commented out until contract supports it)
// const tribeController = this.getTribeControllerContract();
// const members = await tribeController.getMembers(tribeId);
// return members;
}
catch (error) {
return this.handleError(error, 'Failed to get tribe members', core_1.ErrorType.CONTRACT_ERROR);
}
}
/**
* Get all tribes a user is a member of
* @param address User address
* @returns Array of tribe IDs
*/
async getUserTribes(address) {
try {
(0, validation_1.validateAddress)(address, 'address');
const tribeController = this.getTribeControllerContract();
const tribes = await tribeController.getUserTribes(address);
return tribes.map((tribeId) => Number(tribeId));
}
catch (error) {
return this.handleError(error, 'Failed to get user tribes', core_1.ErrorType.CONTRACT_ERROR);
}
}
/**
* Check if an invite code is valid
* @param tribeId Tribe ID
* @param code Invite code
* @returns True if the code is valid
*/
async isInviteCodeValid(tribeId, code) {
try {
(0, validation_1.validateNonEmptyString)(code, 'code');
const tribeController = this.getTribeControllerContract();
return await tribeController.isInviteCodeValid(tribeId, code);
}
catch (error) {
return this.handleError(error, 'Failed to check invite code validity', core_1.ErrorType.CONTRACT_ERROR);
}
}
/**
* Get all tribes with pagination
* @param offset The starting index for pagination
* @param limit The maximum number of tribes to return
* @returns Object containing tribe IDs and total count
*/
async getAllTribes(offset = 0, limit = 100) {
try {
const tribeController = this.getTribeControllerContract();
const result = await tribeController.getAllTribes(offset, limit);
return {
tribeIds: result.tribeIds.map((id) => Number(id)),
total: Number(result.total)
};
}
catch (error) {
return this.handleError(error, 'Failed to get all tribes', core_1.ErrorType.CONTRACT_ERROR);
}
}
/**
* Check if a tribe exists
* @param tribeId Tribe ID to check
* @returns True if the tribe exists
*/
async tribeExists(tribeId) {
try {
const tribeController = this.getTribeControllerContract();
// Check if the method exists
if (typeof tribeController.tribeExists !== 'function') {
this.log('Warning: tribeExists method not available in contract', {});
// Try to get tribe details as a fallback
try {
await tribeController.getTribeDetails(tribeId);
return true; // If no error, tribe exists
}
catch (detailsError) {
return false; // Error getting details, tribe doesn't exist
}
}
return await tribeController.tribeExists(tribeId);
}
catch (error) {
this.log(`Error checking if tribe ${tribeId} exists, assuming it doesn't`, { error });
return false;
}
}
/**
* Get the total number of tribes
* @returns Total number of tribes
*/
async getTribeCount() {
try {
const tribeController = this.getTribeControllerContract();
// Check if the method exists
if (typeof tribeController.getTribeCount !== 'function') {
this.log('Warning: getTribeCount method not available in contract', {});
return 0;
}
const count = await tribeController.getTribeCount();
return Number(count);
}
catch (error) {
// Return 0 for any errors, indicating no tribes available
this.log('Error in getTribeCount, returning 0', { error });
return 0;
}
}
/**
* Check if a user is an active member of a tribe
* @param tribeId Tribe ID
* @param address User address
* @returns True if the user is an active member
*/
async isActiveMember(tribeId, address) {
try {
const status = await this.getMemberStatus(tribeId, address);
// MemberStatus.ACTIVE = 2
return status === tribes_1.MemberStatus.ACTIVE;
}
catch (error) {
return this.handleError(error, `Failed to check if ${address} is an active member of tribe ${tribeId}`, core_1.ErrorType.CONTRACT_ERROR);
}
}
/**
* Find the first tribe the user is a member of, useful for testing
* @param address User address
* @returns Tribe ID of the first tribe the user is a member of, or 0 if none
*/
async findFirstActiveTribe(address) {
try {
const tribes = await this.getUserTribes(address);
if (tribes.length === 0) {
return 0;
}
// Find the first tribe where the user is an active member
for (const tribeId of tribes) {
const isActive = await this.isActiveMember(tribeId, address);
if (isActive) {
return tribeId;
}
}
return 0;
}
catch (error) {
return this.handleError(error, `Failed to find first active tribe for ${address}`, core_1.ErrorType.CONTRACT_ERROR);
}
}
/**
* Check if a user can post in a tribe
* @param tribeId Tribe ID
* @param address User address
* @returns True if the user can post in the tribe
*/
async canPostInTribe(tribeId, address) {
try {
// First check if the tribe exists
const exists = await this.tribeExists(tribeId);
if (!exists) {
return false;
}
// Then check if the user is an active member
return await this.isActiveMember(tribeId, address);
}
catch (error) {
return this.handleError(error, `Failed to check if ${address} can post in tribe ${tribeId}`, core_1.ErrorType.CONTRACT_ERROR);
}
}
}
exports.TribesModule = TribesModule;