-
Notifications
You must be signed in to change notification settings - Fork 51
Added ember package #20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
032efcc
cbf0ca6
d8b5e64
ed98278
3f0d2b1
2465249
90f6680
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @0xTomDaniel changed the order Type, this method is a wrapper included in the ember.service, to follow convention - beihnd the scenes is the same There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see. Sorry I completely overlooked that! |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| import { Router, Request, Response } from "express"; | ||
| import { | ||
| EmberService, | ||
| type AgentSwapAction, | ||
| } from "../services/ember.service.js"; | ||
|
|
||
| const router = Router(); | ||
|
|
||
| /** | ||
| * Initiates the Ember AGI TypeScript SDK | ||
| * https://github.com/EmberAGI/ember-sdk-typescript | ||
| */ | ||
| router.get("/init", async (req: Request, res: Response) => { | ||
| try { | ||
| const ember = await EmberService.getClient(); | ||
|
|
||
| console.log("[Ember Init] initialized ember client:", { query: req.query }); | ||
| res.json({ ok: true, ember }); | ||
| } catch (error) { | ||
| console.error("[Ember Init] Error:", error); | ||
| res.status(500).json({ error: "Ember initialization failed" }); | ||
| } | ||
| }); | ||
|
|
||
| /** | ||
| * Fetches chains from the Ember AGI TypeScript SDK | ||
| */ | ||
| router.get("/chains", async (req: Request, res: Response) => { | ||
| try { | ||
| const ember = await EmberService.getClient(); | ||
| const pageSize = parseInt(req.query.pageSize as string, 10) || 10; | ||
|
|
||
| const chains = await ember.getChains({ | ||
| pageSize, | ||
| filter: "", // Optional filter string | ||
| pageToken: "", // Optional pagination token | ||
| }); | ||
|
|
||
| console.log("[Ember Chains] fetched chains:"); | ||
| res.status(200).json({ ok: true, chains }); | ||
| } catch (error) { | ||
| console.error("[Ember Chains] Error:", error); | ||
| res.status(500).json({ error: "Failed to fetch chains" }); | ||
| } | ||
| }); | ||
|
|
||
| /** | ||
| * Fetches tokens information available to the Ember AGI TypeScript SDK | ||
| */ | ||
| router.get("/tokens", async (req: Request, res: Response) => { | ||
| try { | ||
| const ember = await EmberService.getClient(); | ||
| const pageSize = parseInt(req.query.pageSize as string, 10) || 10; | ||
|
|
||
| const tokens = await ember.getTokens({ | ||
| pageSize, | ||
| filter: "", // Optional filter string | ||
| pageToken: "", // Optional pagination token | ||
| chainId: (req.query.chainId as string) || "1", // Ethereum chain ID | ||
| }); | ||
|
|
||
| console.log("[Ember Chains] fetched chains:"); | ||
| res.status(200).json({ ok: true, tokens }); | ||
| } catch (error) { | ||
| console.error("[Ember Chains] Error:", error); | ||
| res.status(500).json({ error: "Failed to fetch chains" }); | ||
| } | ||
| }); | ||
|
|
||
| /** | ||
| * We're using the ember client to find chains, find a ethereum chain, and perform a swap between two tokens | ||
| * Swaps are used to compensate agents in their network and decentralized applications | ||
| */ | ||
|
|
||
| router.post("/agent/swap", async (req: Request, res: Response) => { | ||
| try { | ||
| const { baseToken, quoteToken, amount, recipient } = req.body; | ||
| const ember = new EmberService(); | ||
|
|
||
| const action: AgentSwapAction = { | ||
| type: "MARKET_BUY", | ||
| params: { | ||
| baseToken, | ||
| quoteToken, | ||
| amount, | ||
| recipient, | ||
| }, | ||
| status: "PENDING", | ||
| }; | ||
|
|
||
| const result = await ember.executeSwap(action); | ||
|
|
||
| res.json({ | ||
| success: true, | ||
| action, | ||
| result, | ||
| }); | ||
| } catch (error) { | ||
| console.error("[Agent Swap] Error:", error); | ||
| res.status(500).json({ | ||
| success: false, | ||
| error: error instanceof Error ? error.message : "Agent swap failed", | ||
| }); | ||
| } | ||
| }); | ||
|
|
||
| export default router; |
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Am I correct in understanding that this is just a proof-of-concept that will be refactored?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @0xTomDaniel yes, this would't be useful released as this waiting for some agent documentation, or someone to refactor into the workflow. but they wanted to check how things are working I was traveling but we'll be around for a few days if we have instructions to execute
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @0xTomDaniel if you understand the flow better, and have that info, we can develop that together. we could find more in the chat and improve the documentation in this repo with some examples and diagrams |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,125 @@ | ||
| import { BaseService } from "./base.service.js"; | ||
| import EmberClient from "@emberai/sdk-typescript"; | ||
| import { OrderType, SwapTokensResponse } from "@emberai/sdk-typescript"; | ||
| import { privateKeyToAccount } from "viem/accounts"; | ||
|
|
||
| export interface AgentSwapAction { | ||
| type: "MARKET_BUY" | "MARKET_SELL"; | ||
| params: { | ||
| baseToken: string; | ||
| quoteToken: string; | ||
| amount: string; | ||
| recipient: string; | ||
| }; | ||
| status: "PENDING" | "EXECUTED" | "FAILED"; | ||
| } | ||
|
|
||
| /** | ||
| * EmberService class - https://www.emberai.xyz/ | ||
| * Bridging the gap between Agents and dApps | ||
| */ | ||
| export class EmberService extends BaseService { | ||
| private static client: EmberClient; | ||
|
|
||
| public constructor() { | ||
| super(); | ||
| } | ||
|
|
||
| public static getClient(): EmberClient { | ||
| if (!EmberService.client) { | ||
| EmberService.client = new EmberClient({ | ||
| endpoint: | ||
| process.env.EMBER_ENDPOINT_URL || "grpc.api.emberai.xyz:50051", | ||
| apiKey: process.env.EMBER_API_KEY || "", | ||
| }); | ||
| } | ||
| return EmberService.client; | ||
| } | ||
|
|
||
| /** | ||
| * executeSwap - Executes a swap between two tokens | ||
| * @param action | ||
| * @returns | ||
| */ | ||
| public async executeSwap( | ||
| action: AgentSwapAction | ||
| ): Promise<SwapTokensResponse | void> { | ||
| this.start(); | ||
|
|
||
| try { | ||
| const client = EmberService.getClient(); | ||
|
|
||
| const { chains } = await client.getChains({ | ||
| pageSize: 10, | ||
| filter: "", | ||
| pageToken: "", | ||
| }); | ||
|
|
||
| const ethereum = chains.find((c) => c.name.toLowerCase() === "ethereum"); | ||
| if (!ethereum) throw new Error("Chain not found"); | ||
|
|
||
| // Get tokens on Ethereum | ||
| const { tokens } = await client.getTokens({ | ||
| chainId: ethereum.chainId, | ||
| pageSize: 100, | ||
| filter: "", | ||
| pageToken: "", | ||
| }); | ||
|
|
||
| // Find USDC and WETH tokens | ||
| const baseToken = tokens.find( | ||
| (token) => token.symbol === action.params.baseToken | ||
| ); | ||
| const quoteToken = tokens.find( | ||
| (token) => token.symbol === action.params.quoteToken | ||
| ); | ||
|
|
||
| if (!baseToken || !quoteToken) { | ||
| throw new Error("Required tokens not found"); | ||
| } | ||
|
|
||
| const account = privateKeyToAccount( | ||
| action.params.recipient as `0x${string}` | ||
| ); | ||
|
|
||
| const swap = await client.swapTokens({ | ||
| orderType: OrderType.MARKET_BUY, | ||
| baseToken: { | ||
| chainId: ethereum.chainId, | ||
| address: baseToken?.tokenId as string, | ||
| }, | ||
| quoteToken: { | ||
| chainId: ethereum.chainId, | ||
| address: quoteToken?.tokenId as string, | ||
| }, | ||
| amount: action.params.amount, | ||
| recipient: account.address, | ||
| }); | ||
|
|
||
| action.status = "EXECUTED"; | ||
| // this.actions.push(action); | ||
|
|
||
| return swap; | ||
| } catch (error) { | ||
| action.status = "FAILED"; | ||
| throw error; | ||
| } | ||
| } | ||
|
|
||
| public async start(): Promise<void> { | ||
| console.log("[EmberService] Starting service..."); | ||
|
|
||
| try { | ||
| if (!EmberService.client) { | ||
| EmberService.client = EmberService.getClient(); | ||
| } | ||
| } catch (error) { | ||
| console.error("[EmberService] Error:", error); | ||
| throw new Error("Ember service failed to start."); | ||
| } | ||
| } | ||
|
|
||
| public async stop(): Promise<void> { | ||
| console.log("[EmberService] Stopping service..."); | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.