@skynetxbt/venice-ai-plugin
Version:
Venice AI Plugin for Skynet Framework - Staking Contract Integration
299 lines (259 loc) • 7.76 kB
text/typescript
import { ethers } from "ethers";
import { EventEmitter } from "events";
import {
StakeInfo,
StakingContractConfig,
StakingOperationResult,
StakingStats,
StakingViewResult,
UserStakeInfo
} from "./types";
import { STAKING_CONTRACT_ABI, STAKING_CONTRACT_ADDRESS } from "./constants";
export class StakingContract extends EventEmitter {
private contract: ethers.Contract | null = null;
private provider: ethers.Provider | null = null;
private signer: ethers.Signer | null = null;
private address: string;
constructor(config: StakingContractConfig = {}) {
super();
this.address = config.contractAddress || STAKING_CONTRACT_ADDRESS;
}
public async initialize(provider?: ethers.Provider, signer?: ethers.Signer): Promise<void> {
if (!provider) {
if (!this.provider) {
throw new Error("Provider is required for initialization");
}
} else {
this.provider = provider;
}
if (signer) {
this.signer = signer;
} else if (this.provider) {
// If no signer provided but we have a provider, create a read-only contract
this.contract = new ethers.Contract(
this.address,
STAKING_CONTRACT_ABI,
this.provider
);
return;
}
if (!this.signer) {
throw new Error("Signer is required for write operations");
}
this.contract = new ethers.Contract(
this.address,
STAKING_CONTRACT_ABI,
this.signer
);
}
public async cleanup(): Promise<void> {
this.contract = null;
this.provider = null;
this.signer = null;
}
public async stake(recipient: string, amount: bigint): Promise<StakingOperationResult> {
try {
if (!this.contract || !this.signer) {
throw new Error("Contract not initialized with signer");
}
console.log("Staking with params:", {
recipient,
amount: amount.toString(),
contractAddress: this.address
});
// Debug the exact data being sent
const data = this.contract.interface.encodeFunctionData("stake", [recipient, amount]);
console.log("Amount in BigInt:", amount);
console.log("Encoded transaction data:", data);
const tx = await this.contract.stake(recipient, amount, {
gasLimit: 300000 // Reduced gas limit to a more reasonable value
});
const receipt = await tx.wait();
return {
success: true,
transactionHash: receipt.hash
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : String(error)
};
}
}
public async initiateUnstake(amount: bigint): Promise<StakingOperationResult> {
try {
if (!this.contract || !this.signer) {
throw new Error("Contract not initialized with signer");
}
const tx = await this.contract.initiateUnstake(amount);
const receipt = await tx.wait();
return {
success: true,
transactionHash: receipt.hash
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : String(error)
};
}
}
public async finalizeUnstake(): Promise<StakingOperationResult> {
try {
if (!this.contract || !this.signer) {
throw new Error("Contract not initialized with signer");
}
const tx = await this.contract.finalizeUnstake();
const receipt = await tx.wait();
return {
success: true,
transactionHash: receipt.hash
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : String(error)
};
}
}
public async claim(): Promise<StakingOperationResult> {
try {
if (!this.contract || !this.signer) {
throw new Error("Contract not initialized with signer");
}
const tx = await this.contract.claim();
const receipt = await tx.wait();
return {
success: true,
transactionHash: receipt.hash
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : String(error)
};
}
}
public async getPendingRewards(userAddress: string): Promise<StakingViewResult<bigint>> {
try {
if (!this.contract) {
throw new Error("Contract not initialized");
}
const pendingRewards = await this.contract.pendingRewards(userAddress);
return {
success: true,
data: pendingRewards
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : String(error)
};
}
}
public async getVenicePercentage(): Promise<StakingViewResult<bigint>> {
try {
if (!this.contract) {
throw new Error("Contract not initialized");
}
const percentage = await this.contract.getVenicePercentage();
return {
success: true,
data: percentage
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : String(error)
};
}
}
public async getStakeInfo(userAddress: string): Promise<StakingViewResult<StakeInfo>> {
try {
if (!this.contract) {
throw new Error("Contract not initialized");
}
const stakeInfo = await this.contract.stakes(userAddress);
return {
success: true,
data: {
rewardDebt: stakeInfo[0],
cooldownEnd: stakeInfo[1],
cooldownAmount: stakeInfo[2]
}
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : String(error)
};
}
}
public async getUserStakeInfo(userAddress: string): Promise<StakingViewResult<UserStakeInfo>> {
try {
if (!this.contract) {
throw new Error("Contract not initialized");
}
const [stakeInfoResult, pendingRewardsResult] = await Promise.all([
this.getStakeInfo(userAddress),
this.getPendingRewards(userAddress)
]);
if (!stakeInfoResult.success || !pendingRewardsResult.success) {
throw new Error("Failed to fetch user stake info");
}
// Get the user's staked balance
const stakeAmount = await this.contract.balanceOf(userAddress);
return {
success: true,
data: {
stakeAmount,
pendingRewards: pendingRewardsResult.data!,
stakeInfo: stakeInfoResult.data!
}
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : String(error)
};
}
}
public async getStakingStats(): Promise<StakingViewResult<StakingStats>> {
try {
if (!this.contract) {
throw new Error("Contract not initialized");
}
const [
totalSupply,
emissionRate,
cooldownDuration,
venicePercentage,
accRewardPerShare,
lastRewardTimestamp
] = await Promise.all([
this.contract.totalSupply(),
this.contract.emissionRatePerSecond(),
this.contract.cooldownDuration(),
this.contract.getVenicePercentage(),
this.contract.accRewardPerShare(),
this.contract.lastRewardTimestamp()
]);
return {
success: true,
data: {
totalStaked: totalSupply,
emissionRate,
cooldownDuration,
venicePercentage,
accRewardPerShare,
lastRewardTimestamp
}
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : String(error)
};
}
}
}