@@ -15,7 +15,6 @@ import { validateAbstractConfig } from "../environment";
15
15
16
16
import {
17
17
Address ,
18
- createWalletClient ,
19
18
erc20Abi ,
20
19
http ,
21
20
parseEther ,
@@ -25,6 +24,7 @@ import {
25
24
} from "viem" ;
26
25
import { abstractTestnet , mainnet } from "viem/chains" ;
27
26
import { normalize } from "viem/ens" ;
27
+ import { createAbstractClient } from "@abstract-foundation/agw-client" ;
28
28
import { z } from "zod" ;
29
29
import { ValidateContext } from "../utils" ;
30
30
import { ETH_ADDRESS , ERC20_OVERRIDE_INFO } from "../constants" ;
@@ -39,12 +39,14 @@ const TransferSchema = z.object({
39
39
tokenAddress : z . string ( ) ,
40
40
recipient : z . string ( ) ,
41
41
amount : z . string ( ) ,
42
+ useAGW : z . boolean ( ) ,
42
43
} ) ;
43
44
44
45
export interface TransferContent extends Content {
45
46
tokenAddress : string ;
46
47
recipient : string ;
47
48
amount : string | number ;
49
+ useAGW : boolean ;
48
50
}
49
51
50
52
const transferTemplate = `Respond with a JSON markdown block containing only the extracted values. Use null for any values that cannot be determined.
@@ -58,16 +60,21 @@ Example response:
58
60
{
59
61
"tokenAddress": "0x5A7d6b2F92C77FAD6CCaBd7EE0624E64907Eaf3E",
60
62
"recipient": "0xCCa8009f5e09F8C5dB63cb0031052F9CB635Af62",
61
- "amount": "1000"
63
+ "amount": "1000",
64
+ "useAGW": true
62
65
}
63
66
\`\`\`
64
67
65
- {{recentMessages}}
68
+ User message:
69
+ "{{currentMessage}}"
66
70
67
- Given the recent messages , extract the following information about the requested token transfer:
71
+ Given the message , extract the following information about the requested token transfer:
68
72
- Token contract address
69
73
- Recipient wallet address
70
74
- Amount to transfer
75
+ - Whether to use Abstract Global Wallet aka AGW
76
+
77
+ If the user did not specify "global wallet", "AGW", "agw", or "abstract global wallet" in their message, set useAGW to false, otherwise set it to true.
71
78
72
79
Respond with a JSON markdown block containing only the extracted values.` ;
73
80
@@ -104,6 +111,7 @@ export const transferAction: Action = {
104
111
}
105
112
106
113
// Compose transfer context
114
+ state . currentMessage = `${ state . recentMessagesData [ 1 ] . content . text } ` ;
107
115
const transferContext = composeContext ( {
108
116
state,
109
117
template : transferTemplate ,
@@ -138,7 +146,7 @@ export const transferAction: Action = {
138
146
139
147
// Validate transfer content
140
148
if ( ! ValidateContext . transferAction ( content ) ) {
141
- console . error ( "Invalid content for TRANSFER_TOKEN action." ) ;
149
+ elizaLogger . error ( "Invalid content for TRANSFER_TOKEN action." ) ;
142
150
if ( callback ) {
143
151
callback ( {
144
152
text : "Unable to process transfer request. Invalid content provided." ,
@@ -150,40 +158,76 @@ export const transferAction: Action = {
150
158
151
159
try {
152
160
const account = useGetAccount ( runtime ) ;
153
- const walletClient = useGetWalletClient ( ) ;
154
-
155
161
let hash ;
156
-
157
- // Check if the token is native
158
- if (
159
- content . tokenAddress . toLowerCase ( ) !== ETH_ADDRESS . toLowerCase ( )
160
- ) {
161
- // Convert amount to proper token decimals
162
- const tokenInfo =
163
- ERC20_OVERRIDE_INFO [ content . tokenAddress . toLowerCase ( ) ] ;
164
- const decimals = tokenInfo ?. decimals ?? 18 ; // Default to 18 decimals if not specified
165
- const tokenAmount = parseUnits (
166
- content . amount . toString ( ) ,
167
- decimals
168
- ) ;
169
-
170
- // Execute ERC20 transfer
171
- hash = await walletClient . writeContract ( {
172
- account,
162
+ if ( content . useAGW ) {
163
+ const abstractClient = await createAbstractClient ( {
173
164
chain : abstractTestnet ,
174
- address : content . tokenAddress as Address ,
175
- abi : erc20Abi ,
176
- functionName : "transfer" ,
177
- args : [ content . recipient as Address , tokenAmount ] ,
165
+ signer : account ,
178
166
} ) ;
167
+
168
+ // Handle AGW transfer based on token type
169
+ if (
170
+ content . tokenAddress . toLowerCase ( ) !==
171
+ ETH_ADDRESS . toLowerCase ( )
172
+ ) {
173
+ const tokenInfo =
174
+ ERC20_OVERRIDE_INFO [ content . tokenAddress . toLowerCase ( ) ] ;
175
+ const decimals = tokenInfo ?. decimals ?? 18 ;
176
+ const tokenAmount = parseUnits (
177
+ content . amount . toString ( ) ,
178
+ decimals
179
+ ) ;
180
+
181
+ // @ts -ignore - will fix later
182
+ hash = await abstractClient . writeContract ( {
183
+ chain : abstractTestnet ,
184
+ address : content . tokenAddress as Address ,
185
+ abi : erc20Abi ,
186
+ functionName : "transfer" ,
187
+ args : [ content . recipient as Address , tokenAmount ] ,
188
+ } ) ;
189
+ } else {
190
+ // @ts -ignore
191
+ hash = await abstractClient . sendTransaction ( {
192
+ chain : abstractTestnet ,
193
+ to : content . recipient as Address ,
194
+ value : parseEther ( content . amount . toString ( ) ) ,
195
+ kzg : undefined ,
196
+ } ) ;
197
+ }
179
198
} else {
180
- hash = await walletClient . sendTransaction ( {
181
- account : account ,
182
- chain : abstractTestnet ,
183
- to : content . recipient as Address ,
184
- value : parseEther ( content . amount . toString ( ) ) ,
185
- kzg : undefined ,
186
- } ) ;
199
+ const walletClient = useGetWalletClient ( ) ;
200
+
201
+ // Handle regular wallet transfer based on token type
202
+ if (
203
+ content . tokenAddress . toLowerCase ( ) !==
204
+ ETH_ADDRESS . toLowerCase ( )
205
+ ) {
206
+ const tokenInfo =
207
+ ERC20_OVERRIDE_INFO [ content . tokenAddress . toLowerCase ( ) ] ;
208
+ const decimals = tokenInfo ?. decimals ?? 18 ;
209
+ const tokenAmount = parseUnits (
210
+ content . amount . toString ( ) ,
211
+ decimals
212
+ ) ;
213
+
214
+ hash = await walletClient . writeContract ( {
215
+ account,
216
+ chain : abstractTestnet ,
217
+ address : content . tokenAddress as Address ,
218
+ abi : erc20Abi ,
219
+ functionName : "transfer" ,
220
+ args : [ content . recipient as Address , tokenAmount ] ,
221
+ } ) ;
222
+ } else {
223
+ hash = await walletClient . sendTransaction ( {
224
+ account,
225
+ chain : abstractTestnet ,
226
+ to : content . recipient as Address ,
227
+ value : parseEther ( content . amount . toString ( ) ) ,
228
+ kzg : undefined ,
229
+ } ) ;
230
+ }
187
231
}
188
232
189
233
elizaLogger . success (
@@ -233,6 +277,27 @@ export const transferAction: Action = {
233
277
} ,
234
278
} ,
235
279
] ,
280
+ [
281
+ {
282
+ user : "{{user1}}" ,
283
+ content : {
284
+ text : "Send 0.01 ETH to 0x114B242D931B47D5cDcEe7AF065856f70ee278C4 using your abstract global wallet" ,
285
+ } ,
286
+ } ,
287
+ {
288
+ user : "{{agent}}" ,
289
+ content : {
290
+ text : "Sure, I'll send 0.01 ETH to that address now using my AGW." ,
291
+ action : "SEND_TOKEN" ,
292
+ } ,
293
+ } ,
294
+ {
295
+ user : "{{agent}}" ,
296
+ content : {
297
+ text : "Successfully sent 0.01 ETH to 0x114B242D931B47D5cDcEe7AF065856f70ee278C4\nTransaction: 0xdde850f9257365fffffc11324726ebdcf5b90b01c6eec9b3e7ab3e81fde6f14b using my AGW" ,
298
+ } ,
299
+ } ,
300
+ ] ,
236
301
[
237
302
{
238
303
user : "{{user1}}" ,
0 commit comments