@elizaos/plugin-wallet 2.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +64 -0
  3. package/auto-enable.ts +76 -0
  4. package/dist/LpManagementService-BWrQ5-cO.mjs +353 -0
  5. package/dist/MockLpService-D_Apn4Fd.mjs +99 -0
  6. package/dist/aerodrome-CfnESC32.mjs +890 -0
  7. package/dist/chunk-hT5z_Zn9.mjs +35 -0
  8. package/dist/index.d.mts +34727 -0
  9. package/dist/index.mjs +21590 -0
  10. package/dist/lib/server-wallet-trade.d.mts +34 -0
  11. package/dist/lib/server-wallet-trade.mjs +306 -0
  12. package/dist/meteora-BPX39hZo.mjs +22640 -0
  13. package/dist/orca-Bybp1HXO.mjs +249 -0
  14. package/dist/pancakeswp-CkEXlXti.mjs +604 -0
  15. package/dist/plugin-ZO_MTyd0.mjs +529 -0
  16. package/dist/raydium-rfaM9yEf.mjs +539 -0
  17. package/dist/sdk/index.d.mts +32492 -0
  18. package/dist/sdk/index.mjs +6415 -0
  19. package/dist/types-D5252NZk.mjs +487 -0
  20. package/dist/uniswap-CReXgXVN.mjs +573 -0
  21. package/dist/wallet-action.d.mts +6 -0
  22. package/dist/wallet-action.mjs +820 -0
  23. package/package.json +152 -0
  24. package/src/actions/failure-codes.ts +79 -0
  25. package/src/actions/index.ts +1 -0
  26. package/src/analytics/birdeye/actions/wallet-search-address.ts +9 -0
  27. package/src/analytics/birdeye/birdeye-task.ts +175 -0
  28. package/src/analytics/birdeye/birdeye.ts +813 -0
  29. package/src/analytics/birdeye/constants.ts +74 -0
  30. package/src/analytics/birdeye/providers/agent-portfolio-provider.ts +18 -0
  31. package/src/analytics/birdeye/providers/market.ts +227 -0
  32. package/src/analytics/birdeye/providers/portfolio-factory.test.ts +138 -0
  33. package/src/analytics/birdeye/providers/portfolio-factory.ts +252 -0
  34. package/src/analytics/birdeye/providers/trending.ts +365 -0
  35. package/src/analytics/birdeye/providers/wallet.ts +14 -0
  36. package/src/analytics/birdeye/search-category.test.ts +207 -0
  37. package/src/analytics/birdeye/search-category.ts +506 -0
  38. package/src/analytics/birdeye/service.ts +992 -0
  39. package/src/analytics/birdeye/tasks/birdeye.ts +232 -0
  40. package/src/analytics/birdeye/types/api/common.ts +305 -0
  41. package/src/analytics/birdeye/types/api/defi.ts +220 -0
  42. package/src/analytics/birdeye/types/api/pair.ts +200 -0
  43. package/src/analytics/birdeye/types/api/search.ts +86 -0
  44. package/src/analytics/birdeye/types/api/token.ts +635 -0
  45. package/src/analytics/birdeye/types/api/trader.ts +76 -0
  46. package/src/analytics/birdeye/types/api/wallet.ts +181 -0
  47. package/src/analytics/birdeye/types/shared.ts +106 -0
  48. package/src/analytics/birdeye/utils.ts +700 -0
  49. package/src/analytics/dexscreener/errors.ts +28 -0
  50. package/src/analytics/dexscreener/index.ts +3 -0
  51. package/src/analytics/dexscreener/search-category.test.ts +49 -0
  52. package/src/analytics/dexscreener/search-category.ts +42 -0
  53. package/src/analytics/dexscreener/service.ts +595 -0
  54. package/src/analytics/dexscreener/types.ts +128 -0
  55. package/src/analytics/lpinfo/index.d.ts +7 -0
  56. package/src/analytics/lpinfo/index.ts +52 -0
  57. package/src/analytics/lpinfo/kamino/README.md +102 -0
  58. package/src/analytics/lpinfo/kamino/index.ts +24 -0
  59. package/src/analytics/lpinfo/kamino/providers/kaminoLiquidityProvider.ts +422 -0
  60. package/src/analytics/lpinfo/kamino/providers/kaminoPoolProvider.ts +365 -0
  61. package/src/analytics/lpinfo/kamino/providers/kaminoProvider.ts +496 -0
  62. package/src/analytics/lpinfo/kamino/services/kaminoLiquidityService.ts +1123 -0
  63. package/src/analytics/lpinfo/kamino/services/kaminoService.ts +758 -0
  64. package/src/analytics/lpinfo/steer/README.md +169 -0
  65. package/src/analytics/lpinfo/steer/index.ts +23 -0
  66. package/src/analytics/lpinfo/steer/providers/steerLiquidityProvider.ts +544 -0
  67. package/src/analytics/lpinfo/steer/services/steerLiquidityService.ts +1690 -0
  68. package/src/analytics/lpinfo/steer/steer-display-types.ts +99 -0
  69. package/src/analytics/news/index.ts +52 -0
  70. package/src/analytics/news/interfaces/types.ts +222 -0
  71. package/src/analytics/news/providers/defiNewsProvider.ts +734 -0
  72. package/src/analytics/news/services/newsDataService.ts +332 -0
  73. package/src/analytics/news/utils/formatters.ts +151 -0
  74. package/src/analytics/token-info/action.ts +240 -0
  75. package/src/analytics/token-info/index.ts +3 -0
  76. package/src/analytics/token-info/params.ts +215 -0
  77. package/src/analytics/token-info/providers.ts +681 -0
  78. package/src/analytics/token-info/service.ts +168 -0
  79. package/src/analytics/token-info/types.ts +74 -0
  80. package/src/audit/audit-log.ts +45 -0
  81. package/src/browser-shim/build-shim.ts +123 -0
  82. package/src/browser-shim/index.ts +5 -0
  83. package/src/browser-shim/shim.template.js +563 -0
  84. package/src/chains/evm/.github/workflows/npm-deploy.yml +112 -0
  85. package/src/chains/evm/LICENSE +21 -0
  86. package/src/chains/evm/README.md +106 -0
  87. package/src/chains/evm/actions/helpers.ts +147 -0
  88. package/src/chains/evm/actions/swap.ts +839 -0
  89. package/src/chains/evm/actions/transfer.ts +254 -0
  90. package/src/chains/evm/biome.json +61 -0
  91. package/src/chains/evm/bridge-router.ts +660 -0
  92. package/src/chains/evm/build.ts +89 -0
  93. package/src/chains/evm/chain-handler.ts +416 -0
  94. package/src/chains/evm/constants.ts +23 -0
  95. package/src/chains/evm/contracts/artifacts/OZGovernor.json +1707 -0
  96. package/src/chains/evm/contracts/artifacts/TimelockController.json +1007 -0
  97. package/src/chains/evm/contracts/artifacts/VoteToken.json +895 -0
  98. package/src/chains/evm/dex/aerodrome/index.ts +34 -0
  99. package/src/chains/evm/dex/aerodrome/services/AerodromeLpService.ts +558 -0
  100. package/src/chains/evm/dex/aerodrome/types.ts +318 -0
  101. package/src/chains/evm/dex/pancakeswp/index.ts +35 -0
  102. package/src/chains/evm/dex/pancakeswp/services/PancakeSwapV3LpService.ts +743 -0
  103. package/src/chains/evm/dex/pancakeswp/types.ts +65 -0
  104. package/src/chains/evm/dex/uniswap/index.ts +35 -0
  105. package/src/chains/evm/dex/uniswap/services/UniswapV3LpService.ts +759 -0
  106. package/src/chains/evm/dex/uniswap/types.ts +390 -0
  107. package/src/chains/evm/generated/specs/spec-helpers.ts +73 -0
  108. package/src/chains/evm/generated/specs/specs.ts +151 -0
  109. package/src/chains/evm/gov-router.ts +250 -0
  110. package/src/chains/evm/index.browser.ts +16 -0
  111. package/src/chains/evm/index.ts +31 -0
  112. package/src/chains/evm/prompts.ts +193 -0
  113. package/src/chains/evm/providers/get-balance.ts +123 -0
  114. package/src/chains/evm/providers/wallet.ts +715 -0
  115. package/src/chains/evm/routes/sign.ts +333 -0
  116. package/src/chains/evm/rpc-providers.ts +410 -0
  117. package/src/chains/evm/service.ts +140 -0
  118. package/src/chains/evm/templates/index.ts +10 -0
  119. package/src/chains/evm/types/index.ts +432 -0
  120. package/src/chains/evm/vitest.config.ts +18 -0
  121. package/src/chains/registry.ts +668 -0
  122. package/src/chains/solana/README.md +367 -0
  123. package/src/chains/wallet-action.ts +533 -0
  124. package/src/chains/wallet-router.test.ts +296 -0
  125. package/src/contracts.ts +65 -0
  126. package/src/core-augmentation.ts +10 -0
  127. package/src/index.ts +71 -0
  128. package/src/lib/server-wallet-trade.ts +192 -0
  129. package/src/lib/wallet-export-guard.ts +330 -0
  130. package/src/lp/actions/liquidity.ts +827 -0
  131. package/src/lp/e2e/real-token-tests.ts +428 -0
  132. package/src/lp/e2e/scenarios.ts +470 -0
  133. package/src/lp/e2e/test-utils.ts +145 -0
  134. package/src/lp/lp-manager-entry.ts +303 -0
  135. package/src/lp/services/ConcentratedLiquidityService.ts +120 -0
  136. package/src/lp/services/DexInteractionService.ts +226 -0
  137. package/src/lp/services/LpManagementService.test.ts +148 -0
  138. package/src/lp/services/LpManagementService.ts +632 -0
  139. package/src/lp/services/UserLpProfileService.ts +163 -0
  140. package/src/lp/services/VaultService.ts +153 -0
  141. package/src/lp/services/YieldOptimizationService.ts +344 -0
  142. package/src/lp/services/__tests__/MockLpService.ts +146 -0
  143. package/src/lp/tasks/LpAutoRebalanceTask.ts +117 -0
  144. package/src/lp/tasks/__tests__/LpAutoRebalanceTask.test.ts +370 -0
  145. package/src/lp/types.ts +582 -0
  146. package/src/lp/utils/solanaClient.ts +143 -0
  147. package/src/plugin.ts +125 -0
  148. package/src/policy/policy.ts +19 -0
  149. package/src/providers/canonical-provider.ts +27 -0
  150. package/src/providers/unified-wallet-provider.ts +79 -0
  151. package/src/register-routes.ts +11 -0
  152. package/src/routes/plugin.ts +47 -0
  153. package/src/routes/wallet-market-overview-route.ts +869 -0
  154. package/src/sdk/abi.ts +258 -0
  155. package/src/sdk/bridge/abis.ts +126 -0
  156. package/src/sdk/bridge/client.ts +518 -0
  157. package/src/sdk/bridge/index.ts +56 -0
  158. package/src/sdk/bridge/solana.ts +604 -0
  159. package/src/sdk/bridge/types.ts +202 -0
  160. package/src/sdk/convenience.ts +347 -0
  161. package/src/sdk/escrow/MutualStakeEscrow.ts +480 -0
  162. package/src/sdk/escrow/types.ts +64 -0
  163. package/src/sdk/escrow/verifiers.ts +73 -0
  164. package/src/sdk/identity/erc8004.ts +692 -0
  165. package/src/sdk/identity/reputation.ts +449 -0
  166. package/src/sdk/identity/uaid.ts +497 -0
  167. package/src/sdk/identity/validation.ts +372 -0
  168. package/src/sdk/index.ts +763 -0
  169. package/src/sdk/policy/SpendingPolicy.ts +260 -0
  170. package/src/sdk/policy/UptoBillingPolicy.ts +320 -0
  171. package/src/sdk/router/PaymentRouter.ts +215 -0
  172. package/src/sdk/router/index.ts +8 -0
  173. package/src/sdk/swap/SwapModule.ts +310 -0
  174. package/src/sdk/swap/abi.ts +117 -0
  175. package/src/sdk/swap/index.ts +34 -0
  176. package/src/sdk/swap/types.ts +135 -0
  177. package/src/sdk/tokens/decimals.ts +140 -0
  178. package/src/sdk/tokens/registry.ts +911 -0
  179. package/src/sdk/tokens/solana.ts +419 -0
  180. package/src/sdk/tokens/transfers.ts +327 -0
  181. package/src/sdk/types.ts +158 -0
  182. package/src/sdk/wallet-core.ts +115 -0
  183. package/src/sdk/x402/budget.ts +168 -0
  184. package/src/sdk/x402/chains/abstract/index.ts +280 -0
  185. package/src/sdk/x402/client.ts +320 -0
  186. package/src/sdk/x402/index.ts +46 -0
  187. package/src/sdk/x402/middleware.ts +92 -0
  188. package/src/sdk/x402/multi-asset.ts +144 -0
  189. package/src/sdk/x402/types.ts +156 -0
  190. package/src/services/wallet-backend-service.ts +328 -0
  191. package/src/types/wallet-router.ts +227 -0
  192. package/src/utils/intent-trajectory.ts +106 -0
  193. package/src/wallet/backend.ts +62 -0
  194. package/src/wallet/errors.ts +49 -0
  195. package/src/wallet/index.ts +27 -0
  196. package/src/wallet/local-eoa-backend.ts +201 -0
  197. package/src/wallet/pending.ts +60 -0
  198. package/src/wallet/select-backend.ts +47 -0
  199. package/src/wallet/steward-backend.ts +161 -0
  200. package/src/wallet-action.ts +1 -0
@@ -0,0 +1,518 @@
1
+ /**
2
+ * @module bridge/client
3
+ * BridgeModule — CCTP V2 cross-chain USDC bridge for AgentWallet (EVM↔EVM).
4
+ *
5
+ * Implements a full EVM-to-EVM USDC bridge using Circle's CCTP V2 protocol.
6
+ * Non-custodial: all signing is done locally via the agent's viem WalletClient.
7
+ *
8
+ * For EVM↔Solana bridging, see bridge/solana.ts.
9
+ *
10
+ * Supported chains: Ethereum, Avalanche, Optimism, Arbitrum, Base, Polygon,
11
+ * Unichain, Linea, Sonic, Worldchain.
12
+ *
13
+ * Flow: approve USDC → depositForBurn → poll Circle IRIS → receiveMessage
14
+ */
15
+ // BridgeModule — CCTP V2 cross-chain USDC bridge for AgentWallet
16
+ // Non-custodial: all signing is done locally via the agent's WalletClient.
17
+ import {
18
+ type Chain,
19
+ createPublicClient,
20
+ getContract,
21
+ type Hash,
22
+ type Hex,
23
+ http,
24
+ keccak256,
25
+ type PublicClient,
26
+ pad,
27
+ type TransactionReceipt,
28
+ type WalletClient,
29
+ } from "viem";
30
+ import {
31
+ arbitrum,
32
+ avalanche,
33
+ base,
34
+ linea,
35
+ mainnet,
36
+ optimism,
37
+ polygon,
38
+ } from "viem/chains";
39
+ import { requireWalletAccount } from "../wallet-core.js";
40
+ import {
41
+ ERC20BridgeAbi,
42
+ MessageTransmitterV2Abi,
43
+ TokenMessengerV2Abi,
44
+ } from "./abis.js";
45
+ import type {
46
+ BridgeChain,
47
+ BridgeOptions,
48
+ BridgeResult,
49
+ BurnResult,
50
+ EVMBridgeChain,
51
+ } from "./types.js";
52
+ import {
53
+ ATTESTATION_POLL_INTERVAL_MS,
54
+ BRIDGE_CHAIN_IDS,
55
+ CCTP_DOMAIN_IDS,
56
+ CIRCLE_ATTESTATION_API,
57
+ FINALITY_THRESHOLD,
58
+ MAX_ATTESTATION_POLLS,
59
+ MESSAGE_TRANSMITTER_V2,
60
+ TOKEN_MESSENGER_V2,
61
+ USDC_CONTRACT,
62
+ } from "./types.js";
63
+
64
+ /**
65
+ * Viem chain definitions for all supported EVM CCTP V2 chains.
66
+ * Chains without built-in viem definitions use custom definitions.
67
+ * Solana is NOT included — use bridge/solana.ts for EVM↔Solana bridging.
68
+ */
69
+ const VIEM_CHAINS: Record<EVMBridgeChain, Chain> = {
70
+ base,
71
+ ethereum: mainnet,
72
+ optimism,
73
+ arbitrum,
74
+ polygon,
75
+ avalanche,
76
+ linea,
77
+ unichain: {
78
+ id: 130,
79
+ name: "Unichain",
80
+ nativeCurrency: { name: "ETH", symbol: "ETH", decimals: 18 },
81
+ rpcUrls: { default: { http: ["https://mainnet.unichain.org"] } },
82
+ },
83
+ sonic: {
84
+ id: 146,
85
+ name: "Sonic",
86
+ nativeCurrency: { name: "S", symbol: "S", decimals: 18 },
87
+ rpcUrls: { default: { http: ["https://rpc.soniclabs.com"] } },
88
+ },
89
+ worldchain: {
90
+ id: 480,
91
+ name: "World Chain",
92
+ nativeCurrency: { name: "ETH", symbol: "ETH", decimals: 18 },
93
+ rpcUrls: {
94
+ default: { http: ["https://worldchain-mainnet.g.alchemy.com/public"] },
95
+ },
96
+ },
97
+ };
98
+
99
+ export class BridgeModule {
100
+ private readonly walletClient: WalletClient;
101
+ private readonly signerAccount: ReturnType<typeof requireWalletAccount>;
102
+ private readonly publicClient: PublicClient;
103
+ private readonly fromChain: EVMBridgeChain;
104
+
105
+ constructor(
106
+ walletClient: WalletClient,
107
+ fromChain: EVMBridgeChain = "base",
108
+ options: { rpcUrl?: string } = {},
109
+ ) {
110
+ this.signerAccount = requireWalletAccount(walletClient);
111
+ this.walletClient = walletClient;
112
+ this.fromChain = fromChain;
113
+ this.publicClient = createPublicClient({
114
+ chain: VIEM_CHAINS[fromChain],
115
+ transport: http(options.rpcUrl),
116
+ }) as PublicClient;
117
+ }
118
+
119
+ async bridge(
120
+ amount: bigint,
121
+ toChain: EVMBridgeChain,
122
+ options: BridgeOptions = {},
123
+ ): Promise<BridgeResult> {
124
+ const startMs = Date.now();
125
+ this.validateBridgeParams(amount, toChain);
126
+ const account = this.signerAccount;
127
+ const recipient = options.destinationAddress ?? account.address;
128
+ const minFinalityThreshold =
129
+ options.minFinalityThreshold ?? FINALITY_THRESHOLD.FAST;
130
+ const maxFee = options.maxFee ?? 0n;
131
+ const attestationApiUrl =
132
+ options.attestationApiUrl ?? CIRCLE_ATTESTATION_API;
133
+
134
+ await this.approveUsdc(amount);
135
+ const burnResult = await this.depositForBurn(
136
+ amount,
137
+ toChain,
138
+ recipient,
139
+ minFinalityThreshold,
140
+ maxFee,
141
+ );
142
+ const attestation = await this.pollForAttestation(
143
+ burnResult.messageHash,
144
+ this.fromChain,
145
+ attestationApiUrl,
146
+ );
147
+ const mintTxHash = await this.receiveMessage(
148
+ burnResult.messageBytes,
149
+ attestation,
150
+ toChain,
151
+ options.destinationRpcUrl,
152
+ );
153
+
154
+ return {
155
+ burnTxHash: burnResult.burnTxHash,
156
+ mintTxHash,
157
+ amount,
158
+ fromChain: this.fromChain,
159
+ toChain,
160
+ recipient,
161
+ nonce: burnResult.nonce,
162
+ elapsedMs: Date.now() - startMs,
163
+ };
164
+ }
165
+
166
+ async burn(
167
+ amount: bigint,
168
+ toChain: EVMBridgeChain,
169
+ options: BridgeOptions = {},
170
+ ): Promise<BurnResult> {
171
+ this.validateBridgeParams(amount, toChain);
172
+ const account = this.signerAccount;
173
+ const recipient = options.destinationAddress ?? account.address;
174
+ const minFinalityThreshold =
175
+ options.minFinalityThreshold ?? FINALITY_THRESHOLD.FAST;
176
+ const maxFee = options.maxFee ?? 0n;
177
+ await this.approveUsdc(amount);
178
+ return this.depositForBurn(
179
+ amount,
180
+ toChain,
181
+ recipient,
182
+ minFinalityThreshold,
183
+ maxFee,
184
+ );
185
+ }
186
+
187
+ async waitForAttestation(
188
+ messageHash: Hex,
189
+ apiUrl: string = CIRCLE_ATTESTATION_API,
190
+ ): Promise<Hex> {
191
+ return this.pollForAttestation(messageHash, this.fromChain, apiUrl);
192
+ }
193
+
194
+ async mint(
195
+ messageBytes: Hex,
196
+ attestation: Hex,
197
+ toChain: EVMBridgeChain,
198
+ destinationRpcUrl?: string,
199
+ ): Promise<Hash> {
200
+ return this.receiveMessage(
201
+ messageBytes,
202
+ attestation,
203
+ toChain,
204
+ destinationRpcUrl,
205
+ );
206
+ }
207
+
208
+ async getUsdcBalance(): Promise<bigint> {
209
+ const account = this.signerAccount;
210
+ const usdc = getContract({
211
+ address: USDC_CONTRACT[this.fromChain],
212
+ abi: ERC20BridgeAbi,
213
+ client: this.publicClient,
214
+ });
215
+ return usdc.read.balanceOf([account.address]) as Promise<bigint>;
216
+ }
217
+
218
+ async getUsdcAllowance(): Promise<bigint> {
219
+ const account = this.signerAccount;
220
+ const usdc = getContract({
221
+ address: USDC_CONTRACT[this.fromChain],
222
+ abi: ERC20BridgeAbi,
223
+ client: this.publicClient,
224
+ });
225
+ return usdc.read.allowance([
226
+ account.address,
227
+ TOKEN_MESSENGER_V2[this.fromChain],
228
+ ]) as Promise<bigint>;
229
+ }
230
+
231
+ private async approveUsdc(amount: bigint): Promise<void> {
232
+ const account = this.signerAccount;
233
+ const spender = TOKEN_MESSENGER_V2[this.fromChain];
234
+ const usdcAddress = USDC_CONTRACT[this.fromChain];
235
+ const usdc = getContract({
236
+ address: usdcAddress,
237
+ abi: ERC20BridgeAbi,
238
+ client: this.publicClient,
239
+ });
240
+ const currentAllowance = (await usdc.read.allowance([
241
+ account.address,
242
+ spender,
243
+ ])) as bigint;
244
+ if (currentAllowance >= amount) return;
245
+
246
+ const usdcWrite = getContract({
247
+ address: usdcAddress,
248
+ abi: ERC20BridgeAbi,
249
+ client: { public: this.publicClient, wallet: this.walletClient },
250
+ });
251
+ const approveTxHash = await usdcWrite.write.approve([spender, amount], {
252
+ account,
253
+ chain: VIEM_CHAINS[this.fromChain],
254
+ });
255
+ const approveReceipt = await this.publicClient.waitForTransactionReceipt({
256
+ hash: approveTxHash,
257
+ });
258
+ if (approveReceipt.status !== "success") {
259
+ throw new BridgeError(
260
+ "INSUFFICIENT_ALLOWANCE",
261
+ `USDC approve failed (tx: ${approveTxHash}).`,
262
+ );
263
+ }
264
+ }
265
+
266
+ private async depositForBurn(
267
+ amount: bigint,
268
+ toChain: EVMBridgeChain,
269
+ recipient: `0x${string}`,
270
+ minFinalityThreshold: number,
271
+ maxFee: bigint,
272
+ ): Promise<BurnResult> {
273
+ const account = this.signerAccount;
274
+ const destinationDomain = CCTP_DOMAIN_IDS[toChain];
275
+ const messengerAddress = TOKEN_MESSENGER_V2[this.fromChain];
276
+ const usdcAddress = USDC_CONTRACT[this.fromChain];
277
+ const mintRecipient = pad(recipient, { size: 32 });
278
+ const destinationCaller = pad("0x0" as Hex, { size: 32 });
279
+
280
+ const messenger = getContract({
281
+ address: messengerAddress,
282
+ abi: TokenMessengerV2Abi,
283
+ client: { public: this.publicClient, wallet: this.walletClient },
284
+ });
285
+
286
+ let burnTxHash: Hash;
287
+ try {
288
+ burnTxHash = await messenger.write.depositForBurn(
289
+ [
290
+ amount,
291
+ destinationDomain,
292
+ mintRecipient,
293
+ usdcAddress,
294
+ destinationCaller,
295
+ maxFee,
296
+ minFinalityThreshold,
297
+ ],
298
+ { account, chain: VIEM_CHAINS[this.fromChain] },
299
+ );
300
+ } catch (err: unknown) {
301
+ const msg = err instanceof Error ? err.message : String(err);
302
+ throw new BridgeError(
303
+ "BURN_FAILED",
304
+ `CCTP depositForBurn failed: ${msg}.`,
305
+ );
306
+ }
307
+
308
+ const receipt = await this.publicClient.waitForTransactionReceipt({
309
+ hash: burnTxHash,
310
+ });
311
+ if (receipt.status !== "success") {
312
+ throw new BridgeError(
313
+ "BURN_FAILED",
314
+ `depositForBurn transaction reverted (tx: ${burnTxHash}).`,
315
+ );
316
+ }
317
+
318
+ const { messageBytes, messageHash, nonce } =
319
+ this.extractMessageSent(receipt);
320
+ return {
321
+ burnTxHash,
322
+ nonce,
323
+ messageHash,
324
+ messageBytes,
325
+ sourceDomain: CCTP_DOMAIN_IDS[this.fromChain],
326
+ destinationDomain,
327
+ };
328
+ }
329
+
330
+ private extractMessageSent(receipt: TransactionReceipt): {
331
+ messageBytes: Hex;
332
+ messageHash: Hex;
333
+ nonce: bigint;
334
+ } {
335
+ const MESSAGE_SENT_TOPIC =
336
+ "0x8c5261668696ce22758910d05bab8f186d6eb247ceac2af2e82c7dc17669b036";
337
+ for (const log of receipt.logs) {
338
+ if (log.topics[0]?.toLowerCase() === MESSAGE_SENT_TOPIC.toLowerCase()) {
339
+ const rawData = log.data;
340
+ if (rawData.length < 130) continue;
341
+ const dataHex = rawData.slice(2);
342
+ const lengthHex = dataHex.slice(64, 128);
343
+ const messageLength = parseInt(lengthHex, 16);
344
+ if (messageLength === 0) continue;
345
+ const messageBytesHex = dataHex.slice(128, 128 + messageLength * 2);
346
+ const messageBytes = `0x${messageBytesHex}` as Hex;
347
+ const messageHash = keccak256(messageBytes);
348
+ const nonceBytesHex = messageBytesHex.slice(24, 40);
349
+ const nonce = BigInt(`0x${nonceBytesHex}`);
350
+ return { messageBytes, messageHash, nonce };
351
+ }
352
+ }
353
+ throw new BridgeError(
354
+ "BURN_FAILED",
355
+ "Could not find MessageSent event in burn transaction receipt.",
356
+ );
357
+ }
358
+
359
+ private async pollForAttestation(
360
+ messageHash: Hex,
361
+ fromChain: EVMBridgeChain,
362
+ apiUrl: string,
363
+ ): Promise<Hex> {
364
+ const sourceDomain = CCTP_DOMAIN_IDS[fromChain];
365
+ const url = `${apiUrl}/v2/messages/${sourceDomain}/${messageHash}`;
366
+
367
+ for (let attempt = 0; attempt < MAX_ATTESTATION_POLLS; attempt++) {
368
+ let response: {
369
+ status: string;
370
+ attestation?: Hex | null;
371
+ error?: string;
372
+ };
373
+ try {
374
+ // @duplicate-component-audit-allow Circle attestation polling is not an LLM generation call.
375
+ const res = await fetch(url, {
376
+ headers: { Accept: "application/json" },
377
+ });
378
+ if (!res.ok) {
379
+ if (res.status === 404) {
380
+ await this.sleep(ATTESTATION_POLL_INTERVAL_MS);
381
+ continue;
382
+ }
383
+ const body = await res.text().catch(() => "");
384
+ throw new BridgeError(
385
+ "ATTESTATION_ERROR",
386
+ `Circle API returned HTTP ${res.status}: ${body}.`,
387
+ );
388
+ }
389
+ response = (await res.json()) as typeof response;
390
+ } catch (err: unknown) {
391
+ if (err instanceof BridgeError) throw err;
392
+ const msg = err instanceof Error ? err.message : String(err);
393
+ throw new BridgeError(
394
+ "ATTESTATION_ERROR",
395
+ `Failed to reach Circle IRIS API: ${msg}.`,
396
+ );
397
+ }
398
+
399
+ if (response.status === "complete" && response.attestation)
400
+ return response.attestation;
401
+ if (response.status === "error") {
402
+ throw new BridgeError(
403
+ "ATTESTATION_ERROR",
404
+ `Circle attestation failed: ${response.error ?? "unknown error"}.`,
405
+ );
406
+ }
407
+ await this.sleep(ATTESTATION_POLL_INTERVAL_MS);
408
+ }
409
+ throw new BridgeError(
410
+ "ATTESTATION_TIMEOUT",
411
+ `Attestation not received after ${MAX_ATTESTATION_POLLS} attempts. Message hash: ${messageHash}.`,
412
+ );
413
+ }
414
+
415
+ private async receiveMessage(
416
+ messageBytes: Hex,
417
+ attestation: Hex,
418
+ toChain: EVMBridgeChain,
419
+ destinationRpcUrl?: string,
420
+ ): Promise<Hash> {
421
+ const account = this.signerAccount;
422
+ const transmitterAddress = MESSAGE_TRANSMITTER_V2[toChain];
423
+ const destChain = VIEM_CHAINS[toChain];
424
+ const destPublicClient = createPublicClient({
425
+ chain: destChain,
426
+ transport: http(destinationRpcUrl),
427
+ }) as PublicClient;
428
+
429
+ const transmitter = getContract({
430
+ address: transmitterAddress,
431
+ abi: MessageTransmitterV2Abi,
432
+ client: { public: destPublicClient, wallet: this.walletClient },
433
+ });
434
+
435
+ let mintTxHash: Hash;
436
+ try {
437
+ mintTxHash = await transmitter.write.receiveMessage(
438
+ [messageBytes, attestation],
439
+ { account, chain: destChain },
440
+ );
441
+ } catch (err: unknown) {
442
+ const msg = err instanceof Error ? err.message : String(err);
443
+ throw new BridgeError(
444
+ "MINT_FAILED",
445
+ `CCTP receiveMessage failed on ${toChain}: ${msg}.`,
446
+ );
447
+ }
448
+
449
+ const mintReceipt = await destPublicClient.waitForTransactionReceipt({
450
+ hash: mintTxHash,
451
+ });
452
+ if (mintReceipt.status !== "success") {
453
+ throw new BridgeError(
454
+ "MINT_FAILED",
455
+ `receiveMessage reverted on ${toChain} (tx: ${mintTxHash}).`,
456
+ );
457
+ }
458
+ return mintTxHash;
459
+ }
460
+
461
+ private validateBridgeParams(amount: bigint, toChain: EVMBridgeChain): void {
462
+ if (amount <= 0n) {
463
+ throw new BridgeError(
464
+ "INVALID_AMOUNT",
465
+ `Bridge amount must be greater than 0. Received: ${amount}.`,
466
+ );
467
+ }
468
+ if (!(toChain in CCTP_DOMAIN_IDS)) {
469
+ throw new BridgeError(
470
+ "UNSUPPORTED_CHAIN",
471
+ `Chain '${toChain}' is not supported.`,
472
+ );
473
+ }
474
+ if (toChain === this.fromChain) {
475
+ throw new BridgeError(
476
+ "UNSUPPORTED_CHAIN",
477
+ `Source and destination chains must be different.`,
478
+ );
479
+ }
480
+ }
481
+
482
+ private sleep(ms: number): Promise<void> {
483
+ return new Promise((resolve) => setTimeout(resolve, ms));
484
+ }
485
+ }
486
+
487
+ export class BridgeError extends Error {
488
+ readonly code: string;
489
+ constructor(code: string, message: string) {
490
+ super(`[BridgeModule:${code}] ${message}`);
491
+ this.code = code;
492
+ this.name = "BridgeError";
493
+ }
494
+ }
495
+
496
+ export function createBridge(
497
+ walletClient: WalletClient,
498
+ fromChain: EVMBridgeChain = "base",
499
+ options: { rpcUrl?: string } = {},
500
+ ): BridgeModule {
501
+ return new BridgeModule(walletClient, fromChain, options);
502
+ }
503
+
504
+ export type {
505
+ BridgeChain,
506
+ BridgeOptions,
507
+ BridgeResult,
508
+ BurnResult,
509
+ EVMBridgeChain,
510
+ };
511
+ export {
512
+ BRIDGE_CHAIN_IDS,
513
+ CCTP_DOMAIN_IDS,
514
+ FINALITY_THRESHOLD,
515
+ MESSAGE_TRANSMITTER_V2,
516
+ TOKEN_MESSENGER_V2,
517
+ USDC_CONTRACT,
518
+ };
@@ -0,0 +1,56 @@
1
+ /**
2
+ * @module bridge
3
+ * Re-exports for the bridge module: EVM↔EVM CCTP V2 bridge and EVM↔Solana bridge.
4
+ *
5
+ * Import from 'agentwallet-sdk/bridge' or 'agentwallet-sdk' (re-exported from root).
6
+ *
7
+ * EVM↔EVM: use BridgeModule or createBridge()
8
+ * EVM↔Solana: use bridgeEVMToSolana() and receiveFromSolanaOnEVM()
9
+ */
10
+
11
+ export {
12
+ ERC20BridgeAbi,
13
+ MessageTransmitterV2Abi,
14
+ TokenMessengerV2Abi,
15
+ } from "./abis.js";
16
+ export {
17
+ BRIDGE_CHAIN_IDS,
18
+ BridgeError,
19
+ BridgeModule,
20
+ CCTP_DOMAIN_IDS,
21
+ createBridge,
22
+ FINALITY_THRESHOLD,
23
+ MESSAGE_TRANSMITTER_V2,
24
+ TOKEN_MESSENGER_V2,
25
+ USDC_CONTRACT,
26
+ } from "./client.js";
27
+ export type {
28
+ EVMToSolanaOptions,
29
+ EVMToSolanaResult,
30
+ SolanaBridgeErrorCode,
31
+ SolanaToEVMBurnParams,
32
+ SolanaToEVMOptions,
33
+ SolanaToEVMResult,
34
+ } from "./solana.js";
35
+
36
+ // ─── Solana Bridge (optional — requires @solana/web3.js for full Solana-side execution) ───
37
+ export {
38
+ bridgeEVMToSolana,
39
+ bytes32ToSolanaPubkey,
40
+ receiveFromSolanaOnEVM,
41
+ SOLANA_CCTP_DOMAIN,
42
+ SOLANA_DEFAULT_RPC,
43
+ SOLANA_MESSAGE_TRANSMITTER,
44
+ SOLANA_TOKEN_MESSENGER,
45
+ SOLANA_USDC_MINT,
46
+ SolanaBridgeError,
47
+ } from "./solana.js";
48
+ export type {
49
+ AttestationResponse,
50
+ AttestationStatus,
51
+ BridgeChain,
52
+ BridgeOptions,
53
+ BridgeResult,
54
+ BurnResult,
55
+ EVMBridgeChain,
56
+ } from "./types.js";