Skip to content

Commit

Permalink
convergence plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
uwecerron committed Nov 29, 2024
1 parent 704c7d5 commit 3094df9
Show file tree
Hide file tree
Showing 8 changed files with 394 additions and 0 deletions.
Empty file.
34 changes: 34 additions & 0 deletions packages/plugin-convergence/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"name": "eliza-convergence-plugin-workspace",
"version": "0.1.0",
"private": true,
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc",
"clean": "rimraf dist",
"dev": "tsc -w",
"lint": "eslint src --ext .ts",
"test": "jest"
},
"dependencies": {
"@convergence-rfq/sdk": "^0.1.0",
"@eliza/core": "workspace:*",
"@solana/spl-token": "^0.3.8",
"@solana/web3.js": "^1.78.4",
"bn.js": "^5.2.1",
"decimal.js": "^10.4.3"
},
"devDependencies": {
"@types/bn.js": "^5.1.1",
"@types/jest": "^29.5.3",
"@types/node": "^20.4.5",
"@typescript-eslint/eslint-plugin": "^6.2.0",
"@typescript-eslint/parser": "^6.2.0",
"eslint": "^8.45.0",
"jest": "^29.6.2",
"rimraf": "^5.0.1",
"ts-jest": "^29.1.1",
"typescript": "^5.1.6"
}
}
219 changes: 219 additions & 0 deletions packages/plugin-convergence/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
import { Plugin } from '@eliza/core';
import {
Convergence,
RfqState,
MarketMakerState,
CollateralAccount,
QuoteState
} from '@convergence-rfq/sdk';
import { Connection, PublicKey, Transaction } from '@solana/web3.js';
import { RfqRequest, QuoteMetadata } from './types';

export class ConvergencePlugin implements Plugin {
private convergence: Convergence;

constructor(config: ConvergencePluginConfig) {
const connection = new Connection(config.endpoint, config.commitment);
this.convergence = new Convergence(connection);
}

async onMessage(message: string): Promise<string> {
const parts = message.split(' ');
const command = parts[1]?.toLowerCase();

switch (command) {
// RFQ Management
case 'create':
return this.handleCreateRfq(parts.slice(2));
case 'cancel':
return this.handleCancelRfq(parts.slice(2));
case 'status':
return this.handleStatusCheck(parts[2]);

// Quote Management
case 'respond':
return this.handleRespond(parts.slice(2));
case 'revoke':
return this.handleRevokeQuote(parts.slice(2));
case 'accept':
return this.handleAcceptQuote(parts.slice(2));

// Collateral Management
case 'deposit':
return this.handleDeposit(parts.slice(2));
case 'withdraw':
return this.handleWithdraw(parts.slice(2));
case 'balance':
return this.handleCheckBalance(parts.slice(2));

// Market Maker Management
case 'register':
return this.handleRegisterMM(parts.slice(2));
case 'verify':
return this.handleVerifyIdentity(parts.slice(2));

// Settlement
case 'settle':
return this.handleSettle(parts.slice(2));

default:
return this.getHelpMessage();
}
}

// RFQ Management Methods
private async handleCreateRfq(args: string[]): Promise<string> {
try {
const [baseToken, quoteToken, amount, side, expiryMins, ...options] = args;

const request: RfqRequest = {
baseToken: await this.getTokenInfo(baseToken, parseFloat(amount)),
quoteToken: await this.getTokenInfo(quoteToken, 0),
side: side as 'buy' | 'sell',
expiry: Math.floor(Date.now() / 1000) + (parseInt(expiryMins) * 60),
minCompetitors: options.includes('--min-competitors') ? 3 : undefined,
allowPartialFills: options.includes('--partial-fills'),
requireVerifiedIdentity: options.includes('--verified-only')
};

const rfq = await this.convergence.createRfq(request);
return `RFQ created with ID: ${rfq.id}`;
} catch (error) {
return `Error creating RFQ: ${error.message}`;
}
}

private async handleCancelRfq(args: string[]): Promise<string> {
try {
const [rfqId] = args;
await this.convergence.cancelRfq(rfqId);
return `RFQ ${rfqId} cancelled successfully`;
} catch (error) {
return `Error cancelling RFQ: ${error.message}`;
}
}

// Quote Management Methods
private async handleRespond(args: string[]): Promise<string> {
try {
const [rfqId, price, size] = args;

const quote = await this.convergence.createQuote({
rfqId,
price: parseFloat(price),
size: parseFloat(size),
expiresAt: Math.floor(Date.now() / 1000) + 300 // 5 minutes
});

return `Quote submitted: ${quote.id}`;
} catch (error) {
return `Error submitting quote: ${error.message}`;
}
}

private async handleRevokeQuote(args: string[]): Promise<string> {
try {
const [quoteId] = args;
await this.convergence.revokeQuote(quoteId);
return `Quote ${quoteId} revoked successfully`;
} catch (error) {
return `Error revoking quote: ${error.message}`;
}
}

// Collateral Management Methods
private async handleDeposit(args: string[]): Promise<string> {
try {
const [token, amount] = args;
const tx = await this.convergence.depositCollateral({
mint: new PublicKey(token),
amount: parseFloat(amount)
});
return `Deposit successful: ${tx}`;
} catch (error) {
return `Error depositing collateral: ${error.message}`;
}
}

private async handleWithdraw(args: string[]): Promise<string> {
try {
const [token, amount] = args;
const tx = await this.convergence.withdrawCollateral({
mint: new PublicKey(token),
amount: parseFloat(amount)
});
return `Withdrawal successful: ${tx}`;
} catch (error) {
return `Error withdrawing collateral: ${error.message}`;
}
}

private async handleCheckBalance(args: string[]): Promise<string> {
try {
const [token] = args;
const balance = await this.convergence.getCollateralBalance(new PublicKey(token));
return `Balance: ${balance.amount} ${balance.symbol}`;
} catch (error) {
return `Error checking balance: ${error.message}`;
}
}

// Market Maker Methods
private async handleRegisterMM(args: string[]): Promise<string> {
try {
const [identity] = args;
await this.convergence.registerMarketMaker(identity);
return `Successfully registered as market maker`;
} catch (error) {
return `Error registering as market maker: ${error.message}`;
}
}

private async handleVerifyIdentity(args: string[]): Promise<string> {
try {
const [proof] = args;
await this.convergence.verifyIdentity(proof);
return `Identity verified successfully`;
} catch (error) {
return `Error verifying identity: ${error.message}`;
}
}

// Settlement Methods
private async handleSettle(args: string[]): Promise<string> {
try {
const [rfqId] = args;
const tx = await this.convergence.settleRfq(rfqId);
return `RFQ settled successfully: ${tx}`;
} catch (error) {
return `Error settling RFQ: ${error.message}`;
}
}

private getHelpMessage(): string {
return `
Available commands:
RFQ Management:
/rfq create <base> <quote> <amount> <side> <expiry_mins> [--min-competitors] [--partial-fills] [--verified-only]
/rfq cancel <rfq_id>
/rfq status <rfq_id>
Quote Management:
/rfq respond <rfq_id> <price> <size>
/rfq revoke <quote_id>
/rfq accept <quote_id>
Collateral Management:
/rfq deposit <token> <amount>
/rfq withdraw <token> <amount>
/rfq balance <token>
Market Maker:
/rfq register <identity>
/rfq verify <proof>
Settlement:
/rfq settle <rfq_id>
`;
}
}
31 changes: 31 additions & 0 deletions packages/plugin-convergence/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { PublicKey } from '@solana/web3.js';

export interface TokenInfo {
mint: PublicKey;
amount: number;
decimals: number;
}

export interface RfqRequest {
baseToken: TokenInfo;
quoteToken: TokenInfo;
side: 'buy' | 'sell';
expiry: number;
minCompetitors?: number;
allowPartialFills?: boolean;
requireVerifiedIdentity?: boolean;
}

export interface MarketMakerInfo {
pubkey: PublicKey;
identity: string;
verified: boolean;
}

export interface QuoteMetadata {
rfqId: string;
price: number;
size: number;
expiresAt: number;
marketMaker: MarketMakerInfo;
}
18 changes: 18 additions & 0 deletions packages/plugin-convergence/src/utils/token.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Connection, PublicKey } from '@solana/web3.js';
import { TokenInfo } from '../types';
import { getMint } from '@solana/spl-token';

export async function getTokenInfo(
connection: Connection,
mintAddress: string,
amount: number
): Promise<TokenInfo> {
const mint = new PublicKey(mintAddress);
const mintInfo = await getMint(connection, mint);

return {
mint,
amount,
decimals: mintInfo.decimals
};
}
11 changes: 11 additions & 0 deletions packages/plugin-convergence/tsconfig.base.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { ConvergencePlugin } from '@eliza/plugin-convergence';

export const config = {
plugins: [
new ConvergencePlugin({
endpoint: process.env.SOLANA_RPC_ENDPOINT || 'https://api.mainnet-beta.solana.com',
commitment: 'confirmed'
})
],
// ... other configuration options
};
12 changes: 12 additions & 0 deletions packages/plugin-convergence/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src",
"composite": true
},
"include": ["src/**/*"],
"references": [
{ "path": "../core" }
]
}
Loading

0 comments on commit 3094df9

Please sign in to comment.