UNPKG

@skynetxbt/venice-ai-plugin

Version:

Venice AI Plugin for Skynet Framework - Staking Contract Integration

299 lines (259 loc) 7.76 kB
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) }; } } }