Skip to content

Commit 17215f0

Browse files
Merge pull request #418 from RedBeardEth/unruggable-deploy-token
feat: unruggable on starknet
2 parents bea5567 + 8ff1269 commit 17215f0

File tree

2 files changed

+82
-74
lines changed

2 files changed

+82
-74
lines changed

packages/plugin-starknet/src/actions/unruggable.ts

+80-72
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// TODO: add unruggable
2-
31
import {
42
ActionExample,
53
elizaLogger,
@@ -12,143 +10,153 @@ import {
1210
} from "@ai16z/eliza";
1311
import { composeContext } from "@ai16z/eliza";
1412
import { generateObject } from "@ai16z/eliza";
15-
import {
16-
executeSwap as executeAvnuSwap,
17-
fetchQuotes,
18-
QuoteRequest,
19-
} from "@avnu/avnu-sdk";
2013

21-
import { getStarknetAccount, validateSettings } from "../utils/index.ts";
14+
import {
15+
getStarknetAccount,
16+
getStarknetProvider,
17+
validateSettings,
18+
} from "../utils/index.ts";
19+
import { DeployData, Factory } from "@unruggable_starknet/core";
2220

2321
interface SwapContent {
2422
sellTokenAddress: string;
2523
buyTokenAddress: string;
2624
sellAmount: string;
2725
}
2826

29-
export function isSwapContent(content: SwapContent): content is SwapContent {
27+
export function isDeployTokenContent(
28+
content: DeployData
29+
): content is DeployData {
3030
// Validate types
3131
const validTypes =
32-
typeof content.sellTokenAddress === "string" &&
33-
typeof content.buyTokenAddress === "string" &&
34-
typeof content.sellAmount === "string";
32+
typeof content.name === "string" &&
33+
typeof content.symbol === "string" &&
34+
typeof content.owner === "string" &&
35+
typeof content.initialSupply === "string";
3536
if (!validTypes) {
3637
return false;
3738
}
3839

3940
// Validate addresses (must be 32-bytes long with 0x prefix)
4041
const validAddresses =
41-
content.sellTokenAddress.startsWith("0x") &&
42-
content.sellTokenAddress.length === 66 &&
43-
content.buyTokenAddress.startsWith("0x") &&
44-
content.buyTokenAddress.length === 66;
42+
content.name.length > 2 &&
43+
content.symbol.length > 2 &&
44+
parseInt(content.initialSupply) > 0 &&
45+
content.owner.startsWith("0x") &&
46+
content.owner.length === 66;
4547

4648
return validAddresses;
4749
}
4850

49-
const swapTemplate = `Respond with a JSON markdown block containing only the extracted values. Use null for any values that cannot be determined.
50-
51-
These are known addresses you will get asked to swap, use these addresses for sellTokenAddress and buyTokenAddress:
52-
- BROTHER/brother/$brother: 0x03b405a98c9e795d427fe82cdeeeed803f221b52471e3a757574a2b4180793ee
53-
- BTC/btc: 0x03fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac
54-
- ETH/eth: 0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7
55-
- STRK/strk: 0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d
56-
- LORDS/lords: 0x0124aeb495b947201f5fac96fd1138e326ad86195b98df6dec9009158a533b49
51+
const deployTemplate = `Respond with a JSON markdown block containing only the extracted values. Use null for any values that cannot be determined.
5752
5853
Example response:
5954
\`\`\`json
6055
{
61-
"sellTokenAddress": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
62-
"buyTokenAddress": "0x124aeb495b947201f5fac96fd1138e326ad86195b98df6dec9009158a533b49",
63-
"sellAmount": "1000000000000000000"
56+
"name": "Brother",
57+
"symbol": "BROTHER",
58+
"owner": "0x0000000000000000000000000000000000000000000000000000000000000000",
59+
"initialSupply": "1000000000000000000"
6460
}
6561
\`\`\`
6662
6763
{{recentMessages}}
6864
69-
Extract the following information about the requested token swap:
70-
- Sell token address
71-
- Buy token address
72-
- Amount to sell (in wei)
65+
Extract the following information about the requested token deployment:
66+
- Token Name
67+
- Token Symbol
68+
- Token Owner
69+
- Token initial supply
7370
7471
Respond with a JSON markdown block containing only the extracted values. Use null for any values that cannot be determined.`;
7572

7673
export const deployToken: Action = {
77-
name: "EXECUTE_STARKNET_SWAP",
74+
name: "DEPLOY_STARKNET_UNRUGGABLE_MEME_TOKEN",
7875
similes: [
79-
"STARKNET_SWAP_TOKENS",
80-
"STARKNET_TOKEN_SWAP",
81-
"STARKNET_TRADE_TOKENS",
82-
"STARKNET_EXCHANGE_TOKENS",
76+
"DEPLOY_STARKNET_UNRUGGABLE_TOKEN",
77+
"STARKNET_DEPLOY_MEMECOIN",
78+
"STARKNET_CREATE_MEMECOIN",
8379
],
8480
validate: async (runtime: IAgentRuntime, message: Memory) => {
8581
return validateSettings(runtime);
8682
},
8783
description:
88-
"Perform a token swap on starknet. Use this action when a user asks you to swap tokens anything.",
84+
"Deploy an Unruggable Memecoin on Starknet. Use this action when a user asks you to deploy a new token on Starknet.",
8985
handler: async (
9086
runtime: IAgentRuntime,
9187
message: Memory,
9288
state: State,
9389
_options: { [key: string]: unknown },
9490
callback?: HandlerCallback
9591
): Promise<boolean> => {
96-
elizaLogger.log("Starting EXECUTE_STARKNET_SWAP handler...");
92+
elizaLogger.log(
93+
"Starting DEPLOY_STARKNET_UNRUGGABLE_MEME_TOKEN handler..."
94+
);
9795
if (!state) {
9896
state = (await runtime.composeState(message)) as State;
9997
} else {
10098
state = await runtime.updateRecentMessageState(state);
10199
}
102100

103-
const swapContext = composeContext({
101+
const deployContext = composeContext({
104102
state,
105-
template: swapTemplate,
103+
template: deployTemplate,
106104
});
107105

108106
const response = await generateObject({
109107
runtime,
110-
context: swapContext,
108+
context: deployContext,
111109
modelClass: ModelClass.MEDIUM,
112110
});
111+
elizaLogger.log("init supply." + response.initialSupply);
112+
elizaLogger.log(response);
113113

114-
if (!isSwapContent(response)) {
115-
callback?.({ text: "Invalid swap content, please try again." });
114+
if (!isDeployTokenContent(response)) {
115+
callback?.({
116+
text: "Invalid deployment content, please try again.",
117+
});
116118
return false;
117119
}
118120

119121
try {
120-
// Get quote
121-
const quoteParams: QuoteRequest = {
122-
sellTokenAddress: response.sellTokenAddress,
123-
buyTokenAddress: response.buyTokenAddress,
124-
sellAmount: BigInt(response.sellAmount),
125-
};
126-
127-
const quote = await fetchQuotes(quoteParams);
128-
129-
// Execute swap
130-
const swapResult = await executeAvnuSwap(
131-
getStarknetAccount(runtime),
132-
quote[0],
133-
{
134-
slippage: 0.05, // 5% slippage
135-
executeApprove: true,
136-
}
137-
);
122+
const provider = getStarknetProvider(runtime);
123+
const account = getStarknetAccount(runtime);
124+
125+
const factory = new Factory({
126+
provider,
127+
chainId: await provider.getChainId(),
128+
});
129+
130+
const { tokenAddress, calls } = factory.getDeployCalldata({
131+
name: response.name,
132+
symbol: response.symbol,
133+
owner: response.owner,
134+
initialSupply: response.initialSupply,
135+
});
138136

139137
elizaLogger.log(
140-
"Swap completed successfully!" + swapResult.transactionHash
138+
"Deployment has been initiated for coin: " +
139+
response.name +
140+
" at address: " +
141+
tokenAddress
141142
);
143+
const tx = await account.execute(calls);
144+
142145
callback?.({
143146
text:
144-
"Swap completed successfully! tx: " +
145-
swapResult.transactionHash,
147+
"Token Deployment completed successfully!" +
148+
response.symbol +
149+
" deployed in tx: " +
150+
tx.transaction_hash,
146151
});
147152

148153
return true;
149154
} catch (error) {
150-
elizaLogger.error("Error during token swap:", error);
151-
callback?.({ text: `Error during swap:` });
155+
elizaLogger.error("Error during token deployment:", error);
156+
callback?.({
157+
text: `Error during deployment: ${error.message}`,
158+
content: { error: error.message },
159+
});
152160
return false;
153161
}
154162
},
@@ -157,41 +165,41 @@ export const deployToken: Action = {
157165
{
158166
user: "{{user1}}",
159167
content: {
160-
text: "Swap 10 ETH for LORDS",
168+
text: "Deploy a new token called Lords with the symbol LORDS, owned by 0x024BA6a4023fB90962bDfc2314F3B94372aa382D155291635fc3E6b777657A5B and initial supply of 1000000000000000000 on Starknet",
161169
},
162170
},
163171
{
164172
user: "{{agent}}",
165173
content: {
166-
text: "Ok, I'll swap 10 ETH for LORDS",
174+
text: "Ok, I'll deploy the Lords token to Starknet",
167175
},
168176
},
169177
],
170178
[
171179
{
172180
user: "{{user1}}",
173181
content: {
174-
text: "Swap 100 $lords on starknet",
182+
text: "Deploy the SLINK coin to Starknet",
175183
},
176184
},
177185
{
178186
user: "{{agent}}",
179187
content: {
180-
text: "Ok, I'll swap 100 $lords on starknet",
188+
text: "Ok, I'll deploy your coin on Starknet",
181189
},
182190
},
183191
],
184192
[
185193
{
186194
user: "{{user1}}",
187195
content: {
188-
text: "Swap 0.5 BTC for LORDS",
196+
text: "Create a new coin on Starknet",
189197
},
190198
},
191199
{
192200
user: "{{agent}}",
193201
content: {
194-
text: "Ok, I'll swap 0.5 BTC for LORDS",
202+
text: "Ok, I'll create a new coin for you on Starknet",
195203
},
196204
},
197205
],

packages/plugin-starknet/src/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Plugin } from "@ai16z/eliza";
22
import { executeSwap } from "./actions/swap";
33
import transfer from "./actions/transfer";
4-
4+
import { deployToken } from "./actions/unruggable";
55
export const PROVIDER_CONFIG = {
66
AVNU_API: "https://starknet.impulse.avnu.fi/v1",
77
MAX_RETRIES: 3,
@@ -20,7 +20,7 @@ export const PROVIDER_CONFIG = {
2020
export const starknetPlugin: Plugin = {
2121
name: "starknet",
2222
description: "Starknet Plugin for Eliza",
23-
actions: [transfer, executeSwap],
23+
actions: [transfer, executeSwap, deployToken],
2424
evaluators: [],
2525
providers: [],
2626
};

0 commit comments

Comments
 (0)