Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions typescript/compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,18 @@ services:
- 3011:3011
restart: unless-stopped

beefy-mcp-server:
build:
context: ./
dockerfile: lib/mcp-tools/beefy-mcp-server/Dockerfile
container_name: vibekit-beefy-mcp-server
env_file:
- path: .env
required: true
ports:
- 3012:3012
restart: unless-stopped

# langgraph-workflow-agent:
# build:
# context: ./
Expand Down
1 change: 1 addition & 0 deletions typescript/lib/ember-schemas/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export * from './pendle.js';
export * from './liquidity.js';
export * from './token.js';
export * from './balance.js';
export * from './vaults.js';
188 changes: 188 additions & 0 deletions typescript/lib/ember-schemas/src/vaults.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
import { z } from 'zod';

import {
TransactionPlanSchema,
type TransactionArtifact,
createTransactionArtifactSchema,
AskEncyclopediaSchema,
type AskEncyclopediaArgs,
TokenIdentifierSchema,
type TokenIdentifier,
} from './common.js';
import { TokenSchema } from './token.js';

//
// Position and Vault Schemas
//

// Schema for vault information
export const VaultInfoSchema = z.object({
id: z.string(),
name: z.string(),
tokenAddress: z.string(),
tokenDecimals: z.number(),
earnedTokenAddress: z.string(),
earnContractAddress: z.string(),
strategy: z.string().optional(),
assets: z.array(z.string()),
apy: z.number().optional(),
tvl: z.number().optional(),
pricePerFullShare: z.string(),
status: z.enum(['active', 'eol']),
risks: z.array(z.string()).optional(),
strategyTypeId: z.string().optional(),
network: z.string(),
chain: z.string(),
});
export type VaultInfo = z.infer<typeof VaultInfoSchema>;

// Schema for user vault position
export const UserVaultPositionSchema = z.object({
vaultId: z.string(),
vaultName: z.string(),
vaultShares: z.string(),
vaultSharesUsd: z.string(),
underlyingBalance: z.string(),
underlyingBalanceUsd: z.string(),
depositToken: TokenSchema,
earnedToken: TokenSchema,
apy: z.number().optional(),
pricePerFullShare: z.string(),
});
export type UserVaultPosition = z.infer<typeof UserVaultPositionSchema>;

export const VaultPositionSchema = z.object({
vaultPositions: z.array(UserVaultPositionSchema),
totalValueUsd: z.string(),
});
export type VaultPosition = z.infer<typeof VaultPositionSchema>;

export const GetWalletVaultPositionsResponseSchema = z.object({
positions: z.array(UserVaultPositionSchema),
});
export type GetWalletVaultPositionsResponse = z.infer<typeof GetWalletVaultPositionsResponseSchema>;

//
// Tool Response Schemas
//

// Schema for the vault deposit tool's nested JSON response
export const VaultDepositResponseSchema = z.object({
vaultId: z.string(),
tokenUid: TokenIdentifierSchema,
amount: z.string(),
expectedVaultShares: z.string(),
walletAddress: z.string(),
transactions: z.array(TransactionPlanSchema),
chainId: z.string(),
});
export type VaultDepositResponse = z.infer<typeof VaultDepositResponseSchema>;

// Schema for the vault withdraw tool's nested JSON response
export const VaultWithdrawResponseSchema = z.object({
vaultId: z.string(),
vaultSharesUid: TokenIdentifierSchema,
amount: z.string(),
expectedTokens: z.string(),
walletAddress: z.string(),
transactions: z.array(TransactionPlanSchema),
chainId: z.string(),
});
export type VaultWithdrawResponse = z.infer<typeof VaultWithdrawResponseSchema>;

// Schema for the vault claim rewards tool's nested JSON response
export const VaultClaimRewardsResponseSchema = z.object({
vaultId: z.string(),
boostId: z.string().optional(),
rewardTokens: z.array(
z.object({
tokenUid: TokenIdentifierSchema,
amount: z.string(),
})
),
walletAddress: z.string(),
transactions: z.array(TransactionPlanSchema),
chainId: z.string(),
});
export type VaultClaimRewardsResponse = z.infer<typeof VaultClaimRewardsResponseSchema>;

// Preview schema for vault transactions
export const VaultPreviewSchema = z.object({
vaultId: z.string(),
vaultName: z.string(),
tokenName: z.string(),
amount: z.string(),
action: z.enum(['deposit', 'withdraw', 'claim-rewards']),
chainId: z.string(),
// Additional fields for specific actions
expectedVaultShares: z.string().optional(),
expectedTokens: z.string().optional(),
apy: z.number().optional(),
});
export type VaultPreview = z.infer<typeof VaultPreviewSchema>;

// Define shared artifact schema for vault transactions
export const VaultTransactionArtifactSchema = createTransactionArtifactSchema(VaultPreviewSchema);
export type VaultTransactionArtifact = TransactionArtifact<VaultPreview>;

//
// Agent Capability Schemas
//

export const VaultCapabilitySchema = z.object({
vaultId: z.string(),
vaultName: z.string(),
currentApy: z.number().optional(),
tvl: z.number().optional(),
underlyingToken: TokenSchema.optional(),
vaultToken: TokenSchema.optional(),
strategyType: z.string().optional(),
riskLevel: z.enum(['low', 'medium', 'high']).optional(),
status: z.enum(['active', 'eol']).optional(),
});
export type VaultCapability = z.infer<typeof VaultCapabilitySchema>;

export const VaultAgentCapabilitySchema = z.object({
vaultCapability: VaultCapabilitySchema.optional(),
});
export type VaultAgentCapability = z.infer<typeof VaultAgentCapabilitySchema>;

export const VaultGetCapabilitiesResponseSchema = z.object({
capabilities: z.array(VaultAgentCapabilitySchema),
});
export type VaultGetCapabilitiesResponse = z.infer<typeof VaultGetCapabilitiesResponseSchema>;

//
// Agent Tool Schemas
//

export const VaultDepositWithdrawSchema = z.object({
vaultId: z.string().describe('The unique identifier of the vault to interact with.'),
tokenName: z
.string()
.describe(
"The symbol of the token (e.g., 'USDC', 'WETH'). Must be one of the available tokens."
),
amount: z
.string()
.describe('The amount of the token to use, as a string representation of a number.'),
});
export type VaultDepositWithdrawArgs = z.infer<typeof VaultDepositWithdrawSchema>;

export const VaultClaimRewardsSchema = z.object({
vaultId: z.string().describe('The unique identifier of the vault to claim rewards from.'),
boostId: z.string().optional().describe('Optional boost ID for claiming specific boost rewards.'),
});
export type VaultClaimRewardsArgs = z.infer<typeof VaultClaimRewardsSchema>;

export const GetWalletVaultPositionsSchema = z.object({});
export type GetWalletVaultPositionsArgs = z.infer<typeof GetWalletVaultPositionsSchema>;

// Define an alias for the vault interface
export { AskEncyclopediaSchema as VaultAskEncyclopediaSchema };
export type VaultAskEncyclopediaArgs = AskEncyclopediaArgs;

// Additional vault-related types
export interface VaultTokenInfo extends TokenIdentifier {
decimals: number;
}
50 changes: 50 additions & 0 deletions typescript/onchain-actions-plugins/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -764,6 +764,56 @@ If what you're trying to integrate is not currently supported by the existing pl
- What changes would your integration enable
- Why this integration would benefit the ecosystem

## Testing

The plugin system includes comprehensive testing capabilities to ensure reliability and functionality:

### Running Tests

```bash
# From the typescript/ directory (monorepo root)
cd typescript

# Run all tests including plugin tests
pnpm test

# Run only plugin-specific tests
pnpm run test:vitest -- onchain-actions-plugins/registry/src/*/test/*.vitest.ts

# Run tests for a specific plugin (e.g., Beefy plugin)
pnpm run test:vitest -- src/beefy-vault-plugin/test/api-integration.vitest.ts
```

### Test Coverage

The test suite includes:

- **API Integration Tests**: Real API calls to protocol endpoints
- **Plugin Registration**: Validation of plugin structure and metadata
- **Action Functionality**: Testing transaction building and token mapping
- **Query Operations**: Data retrieval and position tracking
- **Error Handling**: Network timeouts and validation testing
- **Data Structure Validation**: Ensuring proper data formats

### Plugin-Specific Testing

Each plugin may include its own testing documentation:

- **Beefy Vault Plugin**: See [beefy-vault-plugin/README-TESTING.md](./registry/src/beefy-vault-plugin/README-TESTING.md)
- **AAVE Lending Plugin**: Comprehensive reference implementation with test patterns

### Testing Best Practices

When developing new plugins:

1. **Unit Tests**: Test individual adapter methods with mocks
2. **Integration Tests**: Test plugin registration and action validation
3. **API Tests**: Validate real protocol interactions (when applicable)
4. **Error Scenarios**: Test edge cases and failure conditions
5. **Transaction Validation**: Ensure proper transaction structure

For detailed testing examples, refer to existing plugin implementations in the `registry/src/` directory.

## Contributions

Please checkout our [contribution guidelines](https://github.com/EmberAGI/arbitrum-vibekit/blob/main/CONTRIBUTIONS.md) to get started.
2 changes: 2 additions & 0 deletions typescript/onchain-actions-plugins/registry/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
"zod": "catalog:"
},
"devDependencies": {
"@types/sinon": "^17.0.4",
"sinon": "^20.0.0",
"tsup": "^8.0.0"
},
"license": "MIT",
Expand Down
Loading