Skip to content

Commit 38716b8

Browse files
init
1 parent ae648b1 commit 38716b8

File tree

11 files changed

+1198
-2
lines changed

11 files changed

+1198
-2
lines changed

packages/adapter-supabase/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"tsup": "^8.3.5"
1313
},
1414
"scripts": {
15-
"build": "echo 'No build step required'",
15+
"build": "tsup --format esm --dts",
1616
"dev": "tsup --watch"
1717
},
1818
"peerDependencies": {

packages/plugin-starknet/package.json

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"name": "@ai16z/plugin-starknet",
3+
"version": "0.0.1",
4+
"main": "dist/index.js",
5+
"type": "module",
6+
"types": "dist/index.d.ts",
7+
"dependencies": {
8+
"@ai16z/eliza": "workspace:*",
9+
"starknet": "^6.11.0",
10+
"tsup": "^8.3.5",
11+
"vitest": "^2.1.4"
12+
},
13+
"scripts": {
14+
"build": "tsup --format esm --dts",
15+
"test": "vitest"
16+
},
17+
"peerDependencies": {
18+
"whatwg-url": "7.1.0"
19+
}
20+
}

packages/plugin-starknet/readme.md

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import {
2+
fetchAvnuQuote,
3+
buildAvnuCallData,
4+
executeAvnuSwap,
5+
} from "../providers/avnu.ts";
6+
import { AvnuQuoteParams } from "../types/token";
7+
import {
8+
ActionExample,
9+
HandlerCallback,
10+
IAgentRuntime,
11+
Memory,
12+
ModelClass,
13+
State,
14+
type Action,
15+
} from "@ai16z/eliza/src/types.ts";
16+
import { composeContext } from "@ai16z/eliza/src/context.ts";
17+
import { generateObject } from "@ai16z/eliza/src/generation.ts";
18+
19+
const swapTemplate = `Respond with a JSON markdown block containing only the extracted values. Use null for any values that cannot be determined.
20+
21+
Example response:
22+
\`\`\`json
23+
{
24+
"sellTokenAddress": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
25+
"buyTokenAddress": "0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8",
26+
"sellAmount": "1000000000000000000"
27+
}
28+
\`\`\`
29+
30+
{{recentMessages}}
31+
32+
Extract the following information about the requested token swap:
33+
- Sell token address
34+
- Buy token address
35+
- Amount to sell (in wei)
36+
37+
Respond with a JSON markdown block containing only the extracted values. Use null for any values that cannot be determined.`;
38+
39+
export const executeSwap: Action = {
40+
name: "EXECUTE_SWAP",
41+
similes: ["SWAP_TOKENS", "TOKEN_SWAP", "TRADE_TOKENS", "EXCHANGE_TOKENS"],
42+
validate: async (runtime: IAgentRuntime, message: Memory) => {
43+
console.log("Message:", message);
44+
return true;
45+
},
46+
description: "Perform a token swap using Avnu.",
47+
handler: async (
48+
runtime: IAgentRuntime,
49+
message: Memory,
50+
state: State,
51+
_options: { [key: string]: unknown },
52+
callback?: HandlerCallback
53+
): Promise<boolean> => {
54+
if (!state) {
55+
state = (await runtime.composeState(message)) as State;
56+
} else {
57+
state = await runtime.updateRecentMessageState(state);
58+
}
59+
60+
const swapContext = composeContext({
61+
state,
62+
template: swapTemplate,
63+
});
64+
65+
const response = await generateObject({
66+
runtime,
67+
context: swapContext,
68+
modelClass: ModelClass.LARGE,
69+
});
70+
71+
console.log("Response:", response);
72+
73+
try {
74+
// Get quote
75+
const quoteParams: AvnuQuoteParams = {
76+
sellTokenAddress: response.sellTokenAddress,
77+
buyTokenAddress: response.buyTokenAddress,
78+
sellAmount: response.sellAmount,
79+
};
80+
81+
const quote = await fetchAvnuQuote(quoteParams);
82+
83+
// Build call data
84+
const callData = await buildAvnuCallData({
85+
quoteId: quote.quoteId,
86+
slippage: 0.05, // 5% slippage
87+
});
88+
89+
// Execute swap
90+
const swapResult = await executeAvnuSwap({
91+
quoteId: quote.quoteId,
92+
calldata: callData.calldata,
93+
});
94+
95+
console.log("Swap completed successfully!");
96+
callback?.({
97+
text:
98+
"Swap completed successfully! tx: " +
99+
swapResult.transactionHash,
100+
});
101+
102+
return true;
103+
} catch (error) {
104+
console.error("Error during token swap:", error);
105+
callback?.({ text: `Error during swap: ${error.message}` });
106+
return false;
107+
}
108+
},
109+
examples: [
110+
[
111+
{
112+
user: "{{user1}}",
113+
content: {
114+
text: "Swap 1 ETH for USDC",
115+
},
116+
},
117+
{
118+
user: "{{user2}}",
119+
content: {
120+
text: "Executing swap...",
121+
action: "TOKEN_SWAP",
122+
},
123+
},
124+
],
125+
] as ActionExample[][],
126+
} as Action;

packages/plugin-starknet/src/index.ts

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { Plugin } from "@ai16z/eliza";
2+
// import { executeSwap } from "./actions/swap.ts";
3+
// import take_order from "./actions/takeOrder";
4+
// import pumpfun from "./actions/pumpfun";
5+
// import { executeSwapForDAO } from "./actions/swapDao";
6+
// import { walletProvider } from "./providers/wallet.ts";
7+
// import { trustScoreProvider } from "./providers/trustScoreProvider.ts";
8+
// import { trustEvaluator } from "./evaluators/trust.ts";
9+
10+
export const starknetPlugin: Plugin = {
11+
name: "Starknet",
12+
description: "Starknet Plugin for Eliza",
13+
actions: [
14+
// executeSwap,
15+
// pumpfun,
16+
// executeSwapForDAO,
17+
// take_order,
18+
],
19+
evaluators: [],
20+
providers: [],
21+
};
22+
23+
export default starknetPlugin;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
import { describe, it, expect, vi, beforeEach } from "vitest";
2+
import { fetchAvnuQuote } from "./avnu";
3+
4+
describe("fetchAvnuQuote", () => {
5+
const mockRuntime = {
6+
getSetting: vi.fn().mockReturnValue("test-api-key"),
7+
};
8+
9+
const mockQuoteResponse = {
10+
quoteId: "test-quote-id",
11+
sellTokenAddress: "0x123",
12+
sellAmount: "1000000000000000000",
13+
sellAmountInUsd: 100,
14+
buyTokenAddress: "0x456",
15+
buyAmount: "2000000000000000000",
16+
buyAmountInUsd: 200,
17+
buyAmountWithoutFees: "1950000000000000000",
18+
buyAmountWithoutFeesInUsd: 195,
19+
estimatedAmount: true,
20+
chainId: "1",
21+
blockNumber: "123456",
22+
expiry: 1234567890,
23+
routes: [],
24+
gasFees: "1000000",
25+
gasFeesInUsd: 1,
26+
avnuFees: "500000",
27+
avnuFeesInUsd: 0.5,
28+
avnuFeesBps: "10",
29+
integratorFees: "0",
30+
integratorFeesInUsd: 0,
31+
integratorFeesBps: "0",
32+
priceRatioUsd: 2,
33+
liquiditySource: "test-source",
34+
sellTokenPriceInUsd: 100,
35+
buyTokenPriceInUsd: 200,
36+
gasless: {
37+
active: false,
38+
gasTokenPrices: [],
39+
},
40+
};
41+
42+
beforeEach(() => {
43+
// Clear all mocks before each test
44+
vi.clearAllMocks();
45+
// Reset fetch mock
46+
global.fetch = vi.fn();
47+
});
48+
49+
it("should successfully fetch a quote", async () => {
50+
// Mock the fetch response
51+
global.fetch = vi.fn().mockResolvedValueOnce({
52+
ok: true,
53+
json: () => Promise.resolve(mockQuoteResponse),
54+
});
55+
56+
const params = {
57+
sellTokenAddress: "0x123",
58+
buyTokenAddress: "0x456",
59+
sellAmount: "1000000000000000000",
60+
};
61+
62+
const result = await fetchAvnuQuote(params);
63+
64+
// Verify the fetch was called with correct parameters
65+
expect(fetch).toHaveBeenCalledWith(
66+
expect.stringContaining(
67+
"https://starknet.api.avnu.fi/swap/v2/quotes"
68+
),
69+
expect.objectContaining({
70+
method: "GET",
71+
headers: {
72+
Accept: "application/json",
73+
Authorization: "Bearer test-api-key",
74+
},
75+
})
76+
);
77+
78+
// Verify the URL contains the correct query parameters
79+
const fetchCall = (fetch as unknown as { mock: { calls: string[][] } })
80+
.mock.calls[0][0];
81+
expect(fetchCall).toContain(
82+
`sellTokenAddress=${params.sellTokenAddress}`
83+
);
84+
expect(fetchCall).toContain(
85+
`buyTokenAddress=${params.buyTokenAddress}`
86+
);
87+
expect(fetchCall).toContain(`sellAmount=${params.sellAmount}`);
88+
89+
// Verify the response
90+
expect(result).toEqual(mockQuoteResponse);
91+
});
92+
93+
it("should handle API errors", async () => {
94+
// Mock a failed response
95+
global.fetch = vi.fn().mockResolvedValueOnce({
96+
ok: false,
97+
text: () => Promise.resolve("API Error"),
98+
});
99+
100+
const params = {
101+
sellTokenAddress: "0x123",
102+
buyTokenAddress: "0x456",
103+
};
104+
105+
await expect(fetchAvnuQuote(params)).rejects.toThrow(
106+
"Failed to fetch Avnu quote: API Error"
107+
);
108+
});
109+
110+
it("should include optional parameters when provided", async () => {
111+
global.fetch = vi.fn().mockResolvedValueOnce({
112+
ok: true,
113+
json: () => Promise.resolve(mockQuoteResponse),
114+
});
115+
116+
const params = {
117+
sellTokenAddress: "0x123",
118+
buyTokenAddress: "0x456",
119+
takerAddress: "0x789",
120+
excludeSources: ["source1", "source2"],
121+
size: 5,
122+
integratorName: "test-integrator",
123+
};
124+
125+
await fetchAvnuQuote(params);
126+
127+
const fetchCall = (fetch as unknown as { mock: { calls: string[][] } })
128+
.mock.calls[0][0];
129+
expect(fetchCall).toContain(`takerAddress=${params.takerAddress}`);
130+
expect(fetchCall).toContain(
131+
`excludeSources=${encodeURIComponent(params.excludeSources.join(","))}`
132+
);
133+
expect(fetchCall).toContain(`size=${params.size}`);
134+
expect(fetchCall).toContain(`integratorName=${params.integratorName}`);
135+
});
136+
});

0 commit comments

Comments
 (0)