104 lines
3.2 KiB
TypeScript
104 lines
3.2 KiB
TypeScript
import { Injectable, Logger } from '@nestjs/common';
|
|
import { v4 as uuidv4 } from 'uuid';
|
|
|
|
export type GovernanceAction =
|
|
| 'contract_upgrade'
|
|
| 'emergency_freeze'
|
|
| 'gas_parameter_adjustment'
|
|
| 'stablecoin_whitelist'
|
|
| 'validator_admission'
|
|
| 'guarantee_payout';
|
|
|
|
interface GovernanceProposal {
|
|
id: string;
|
|
action: GovernanceAction;
|
|
data: Record<string, any>;
|
|
proposer: string;
|
|
approvers: string[];
|
|
requiredApprovals: number; // 3/5 常规, 4/5 紧急
|
|
status: 'pending' | 'approved' | 'rejected' | 'executed';
|
|
createdAt: Date;
|
|
executedAt?: Date;
|
|
}
|
|
|
|
/** 5 个平台高管/董事签名人 */
|
|
const GOVERNANCE_SIGNERS = [
|
|
'0x1111111111111111111111111111111111111111',
|
|
'0x2222222222222222222222222222222222222222',
|
|
'0x3333333333333333333333333333333333333333',
|
|
'0x4444444444444444444444444444444444444444',
|
|
'0x5555555555555555555555555555555555555555',
|
|
];
|
|
|
|
const EMERGENCY_ACTIONS: GovernanceAction[] = ['emergency_freeze', 'guarantee_payout'];
|
|
|
|
@Injectable()
|
|
export class GovernanceWalletService {
|
|
private readonly logger = new Logger(GovernanceWalletService.name);
|
|
private proposals = new Map<string, GovernanceProposal>();
|
|
|
|
/** 创建治理提案 */
|
|
async createProposal(
|
|
action: GovernanceAction,
|
|
data: Record<string, any>,
|
|
proposer: string,
|
|
): Promise<GovernanceProposal> {
|
|
if (!GOVERNANCE_SIGNERS.includes(proposer)) {
|
|
throw new Error('Only governance signers can create proposals');
|
|
}
|
|
|
|
const isEmergency = EMERGENCY_ACTIONS.includes(action);
|
|
const proposal: GovernanceProposal = {
|
|
id: uuidv4(),
|
|
action,
|
|
data,
|
|
proposer,
|
|
approvers: [proposer],
|
|
requiredApprovals: isEmergency ? 4 : 3, // 紧急 4/5, 常规 3/5
|
|
status: 'pending',
|
|
createdAt: new Date(),
|
|
};
|
|
|
|
this.proposals.set(proposal.id, proposal);
|
|
this.logger.log(`Governance proposal created: ${action} by ${proposer} (${isEmergency ? 'emergency 4/5' : 'normal 3/5'})`);
|
|
return proposal;
|
|
}
|
|
|
|
/** 审批提案 */
|
|
async approveProposal(proposalId: string, signer: string): Promise<GovernanceProposal> {
|
|
const proposal = this.proposals.get(proposalId);
|
|
if (!proposal) throw new Error('Proposal not found');
|
|
if (!GOVERNANCE_SIGNERS.includes(signer)) throw new Error('Not a governance signer');
|
|
if (proposal.status !== 'pending') throw new Error(`Proposal is ${proposal.status}`);
|
|
|
|
if (!proposal.approvers.includes(signer)) {
|
|
proposal.approvers.push(signer);
|
|
}
|
|
|
|
if (proposal.approvers.length >= proposal.requiredApprovals) {
|
|
proposal.status = 'approved';
|
|
await this.executeProposal(proposal);
|
|
}
|
|
|
|
return proposal;
|
|
}
|
|
|
|
/** 查询提案 */
|
|
getProposal(proposalId: string): GovernanceProposal | undefined {
|
|
return this.proposals.get(proposalId);
|
|
}
|
|
|
|
/** 列出所有提案 */
|
|
listProposals(): GovernanceProposal[] {
|
|
return Array.from(this.proposals.values());
|
|
}
|
|
|
|
/** 执行已审批的提案 */
|
|
private async executeProposal(proposal: GovernanceProposal): Promise<void> {
|
|
this.logger.log(`Executing governance proposal: ${proposal.action}`);
|
|
// 实际实现:通过 Gnosis Safe 多签合约执行链上交易
|
|
proposal.status = 'executed';
|
|
proposal.executedAt = new Date();
|
|
}
|
|
}
|