@mimicprotocol/lib-ts 0.0.1 → 0.1.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.
@@ -0,0 +1,114 @@
1
+ import { environment } from '../environment'
2
+ import { NULL_ADDRESS } from '../helpers'
3
+ import { Address, Bytes, ChainId } from '../types'
4
+
5
+ export enum OperationType {
6
+ Swap,
7
+ Transfer,
8
+ EvmCall,
9
+ CrossChainSwap,
10
+ EvmDynamicCall,
11
+ SvmCall,
12
+ }
13
+
14
+ /**
15
+ * Represents an operation event.
16
+ * Specifies the topic and data for the event. The topic is an indexed parameter for the EVM events.
17
+ */
18
+ @json
19
+ export class OperationEvent {
20
+ topic: string
21
+ data: string
22
+
23
+ /**
24
+ * Creates a new Operation Event instance.
25
+ * @param topic - the topic that is going to be index in the event
26
+ * @param data - The event data
27
+ */
28
+ constructor(topic: Bytes, data: Bytes) {
29
+ this.topic = topic.toHexString()
30
+ this.data = data.toHexString()
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Base builder for creating operations.
36
+ */
37
+ export abstract class OperationBuilder {
38
+ protected user: Address | null = null
39
+ protected events: OperationEvent[] = []
40
+
41
+ abstract build(): Operation
42
+
43
+ /**
44
+ * Sets the user address for this intent.
45
+ * @param user - The user address
46
+ * @returns This OperationBuilder instance for method chaining
47
+ */
48
+ addUser(user: Address): OperationBuilder {
49
+ this.user = user
50
+ return this
51
+ }
52
+
53
+ /**
54
+ * Sets the user address from a string.
55
+ * @param user - The user address as a hex string
56
+ * @returns This OperationBuilder instance for method chaining
57
+ */
58
+ addUserAsString(user: string): OperationBuilder {
59
+ return this.addUser(Address.fromString(user))
60
+ }
61
+
62
+ /**
63
+ * Sets an event for the intent.
64
+ * @param topic - The topic to be indexed in the event
65
+ * @param data - The event data
66
+ * @returns This OperationBuilder instance for method chaining
67
+ */
68
+ addEvent(topic: Bytes, data: Bytes): OperationBuilder {
69
+ const event = new OperationEvent(topic, data)
70
+ this.events.push(event)
71
+ return this
72
+ }
73
+
74
+ /**
75
+ * Sets multiple events for the intent.
76
+ * @param events - The list of events to be added
77
+ * @returns This OperationBuilder instance for method chaining
78
+ */
79
+ addEvents(events: OperationEvent[]): OperationBuilder {
80
+ for (let i = 0; i < events.length; i++) {
81
+ this.events.push(events[i])
82
+ }
83
+ return this
84
+ }
85
+ }
86
+
87
+ @json
88
+ export abstract class Operation {
89
+ public opType: OperationType
90
+ public chainId: ChainId
91
+ public user: string
92
+ public events: OperationEvent[]
93
+
94
+ /**
95
+ * Creates a new operation.
96
+ * @param opType - The type of operation to be created
97
+ * @param chainId - The source chain id for the operation
98
+ * @param user - The user address (optional)
99
+ * @param events - The list of events for the operation (optional)
100
+ */
101
+ protected constructor(
102
+ opType: OperationType,
103
+ chainId: ChainId,
104
+ user: Address | null,
105
+ events: OperationEvent[] | null
106
+ ) {
107
+ const context = environment.getContext()
108
+ this.opType = opType
109
+ this.chainId = chainId
110
+ this.user = user ? user.toString() : context.user.toString()
111
+ this.events = events || []
112
+ if (!this.user || this.user == NULL_ADDRESS) throw new Error('A user must be specified')
113
+ }
114
+ }
@@ -2,13 +2,14 @@ import { environment } from '../environment'
2
2
  import { Token, TokenAmount } from '../tokens'
3
3
  import { Address, BigInt, Bytes, ChainId } from '../types'
4
4
 
5
- import { Intent, IntentBuilder, IntentEvent, MaxFee, OperationType } from './Intent'
5
+ import { IntentBuilder } from './Intent'
6
+ import { Operation, OperationBuilder, OperationEvent, OperationType } from './Operation'
6
7
 
7
8
  /**
8
9
  * Builder for creating Swap intents with token exchange operations.
9
10
  * Supports both single-chain and cross-chain swaps with multiple input and output tokens.
10
11
  */
11
- export class SwapBuilder extends IntentBuilder {
12
+ export class SwapBuilder extends OperationBuilder {
12
13
  protected sourceChain: ChainId
13
14
  protected destinationChain: ChainId
14
15
  protected tokensIn: SwapTokenIn[] = []
@@ -204,33 +205,6 @@ export class SwapBuilder extends IntentBuilder {
204
205
  return this.addTokenOut(SwapTokenOut.fromStringDecimal(token, amount, recipient))
205
206
  }
206
207
 
207
- /**
208
- * Sets the settler address for this intent.
209
- * @param settler - The settler address as an Address instance
210
- * @returns This SwapBuilder instance for method chaining
211
- */
212
- addSettler(settler: Address): SwapBuilder {
213
- return changetype<SwapBuilder>(super.addSettler(settler))
214
- }
215
-
216
- /**
217
- * Sets the settler address from a string.
218
- * @param settler - The settler address as a hex string
219
- * @returns This SwapBuilder instance for method chaining
220
- */
221
- addSettlerAsString(settler: string): SwapBuilder {
222
- return changetype<SwapBuilder>(super.addSettlerAsString(settler))
223
- }
224
-
225
- /**
226
- * Sets the deadline for this intent.
227
- * @param deadline - The deadline as a timestamp
228
- * @returns This SwapBuilder instance for method chaining
229
- */
230
- addDeadline(deadline: BigInt): SwapBuilder {
231
- return changetype<SwapBuilder>(super.addDeadline(deadline))
232
- }
233
-
234
208
  /**
235
209
  * Sets the user address for this intent.
236
210
  * @param user - The user address
@@ -249,26 +223,6 @@ export class SwapBuilder extends IntentBuilder {
249
223
  return changetype<SwapBuilder>(super.addUserAsString(user))
250
224
  }
251
225
 
252
- /**
253
- * Sets the nonce for this intent.
254
- * @param nonce - A unique identifier to prevent replay attacks
255
- * @returns This SwapBuilder instance for method chaining
256
- */
257
- addNonce(nonce: string): SwapBuilder {
258
- return changetype<SwapBuilder>(super.addNonce(nonce))
259
- }
260
-
261
- /**
262
- * Adds a max fee for this intent.
263
- * @param fee - The max fee token amount (must be on same chain)
264
- * @returns This SwapBuilder instance for method chaining
265
- */
266
- addMaxFee(fee: TokenAmount): SwapBuilder {
267
- if (!fee.token.hasChain(this.destinationChain)) throw new Error('Fee token must be on the destination chain')
268
- this.maxFees.push(fee)
269
- return this
270
- }
271
-
272
226
  /**
273
227
  * Sets an event for the intent.
274
228
  * @param topic - The topic to be indexed in the event
@@ -284,7 +238,7 @@ export class SwapBuilder extends IntentBuilder {
284
238
  * @param events - The list of events to be added
285
239
  * @returns This SwapBuilder instance for method chaining
286
240
  */
287
- addEvents(events: IntentEvent[]): SwapBuilder {
241
+ addEvents(events: OperationEvent[]): SwapBuilder {
288
242
  return changetype<SwapBuilder>(super.addEvents(events))
289
243
  }
290
244
 
@@ -295,18 +249,16 @@ export class SwapBuilder extends IntentBuilder {
295
249
  build(): Swap {
296
250
  if (this.tokensIn.length === 0 || this.tokensOut.length === 0) throw new Error('Tokens in and out are required')
297
251
 
298
- return new Swap(
299
- this.sourceChain,
300
- this.tokensIn,
301
- this.tokensOut,
302
- this.destinationChain,
303
- this.settler,
304
- this.user,
305
- this.deadline,
306
- this.nonce,
307
- this.maxFees,
308
- this.events
309
- )
252
+ return new Swap(this.sourceChain, this.tokensIn, this.tokensOut, this.destinationChain, this.user, this.events)
253
+ }
254
+
255
+ /**
256
+ * Builds this operation and sends it inside an intent with the provided fee data.
257
+ * @param maxFee - The max fee to pay for the intent (optional for swaps)
258
+ * @param feePayer - The fee payer for the intent (optional)
259
+ */
260
+ send(maxFee: TokenAmount | null = null, feePayer: Address | null = null): void {
261
+ this.build().send(maxFee, feePayer)
310
262
  }
311
263
  }
312
264
 
@@ -439,39 +391,7 @@ export class SwapTokenOut {
439
391
  * Represents a Swap intent for exchanging tokens between blockchain networks.
440
392
  */
441
393
  @json
442
- export class Swap extends Intent {
443
- /**
444
- * Creates a simple single-chain swap intent.
445
- * @param chainId - The blockchain network identifier
446
- * @param tokenIn - The input token
447
- * @param amountIn - The amount to swap from
448
- * @param tokenOut - The output token
449
- * @param minAmountOut - The minimum amount to receive
450
- * @param settler - The settler address (optional)
451
- * @param user - The user address (optional)
452
- * @param deadline - The deadline timestamp (optional)
453
- * @param nonce - The nonce for replay protection (optional)
454
- * @returns A new Swap instance
455
- */
456
- static create(
457
- chainId: ChainId,
458
- tokenIn: Token,
459
- amountIn: BigInt,
460
- tokenOut: Token,
461
- minAmountOut: BigInt,
462
- settler: Address | null = null,
463
- user: Address | null = null,
464
- deadline: BigInt | null = null,
465
- nonce: string | null = null,
466
- events: IntentEvent[] | null = null
467
- ): Swap {
468
- const context = environment.getContext()
469
- const recipient = user || context.user
470
- const swapIn = SwapTokenIn.fromBigInt(tokenIn, amountIn)
471
- const swapOut = SwapTokenOut.fromBigInt(tokenOut, minAmountOut, recipient)
472
- return new Swap(chainId, [swapIn], [swapOut], chainId, settler, user, deadline, nonce, [], events)
473
- }
474
-
394
+ export class Swap extends Operation {
475
395
  /**
476
396
  * Creates a new Swap intent.
477
397
  * @param sourceChain - The source blockchain network identifier
@@ -489,23 +409,24 @@ export class Swap extends Intent {
489
409
  public tokensIn: SwapTokenIn[],
490
410
  public tokensOut: SwapTokenOut[],
491
411
  public destinationChain: ChainId,
492
- settler: Address | null = null,
493
412
  user: Address | null = null,
494
- deadline: BigInt | null = null,
495
- nonce: string | null = null,
496
- maxFees: TokenAmount[] | null = null,
497
- events: IntentEvent[] | null = null
413
+ events: OperationEvent[] | null = null
498
414
  ) {
499
- const fees: MaxFee[] = maxFees ? maxFees.map((fee: TokenAmount) => MaxFee.fromTokenAmount(fee)) : []
500
- super(OperationType.Swap, sourceChain, fees, settler, user, deadline, nonce, events)
415
+ const opType = sourceChain == destinationChain ? OperationType.Swap : OperationType.CrossChainSwap
416
+ super(opType, sourceChain, user, events)
501
417
  if (tokensIn.length === 0) throw new Error('TokenIn list cannot be empty')
502
418
  if (tokensOut.length === 0) throw new Error('TokenOut list cannot be empty')
503
419
  }
504
420
 
505
421
  /**
506
422
  * Sends this Swap intent to the execution environment.
507
- */
508
- send(): void {
509
- environment.swap(this)
423
+ * @param maxFee - The max fee to pay for the intent (optional for swaps)
424
+ * @param feePayer - The fee payer for the intent (optional)
425
+ */
426
+ send(maxFee: TokenAmount | null = null, feePayer: Address | null = null): void {
427
+ const intentBuilder = new IntentBuilder().addOperation(this)
428
+ if (maxFee) intentBuilder.addMaxFee(maxFee)
429
+ if (feePayer) intentBuilder.addFeePayer(feePayer)
430
+ environment.sendIntent(intentBuilder.build())
510
431
  }
511
432
  }
@@ -1,14 +1,15 @@
1
1
  import { environment } from '../environment'
2
- import { ERC20Token, Token, TokenAmount } from '../tokens'
2
+ import { Token, TokenAmount } from '../tokens'
3
3
  import { Address, BigInt, Bytes, ChainId } from '../types'
4
4
 
5
- import { Intent, IntentBuilder, IntentEvent, MaxFee, OperationType } from './Intent'
5
+ import { IntentBuilder } from './Intent'
6
+ import { Operation, OperationBuilder, OperationEvent, OperationType } from './Operation'
6
7
 
7
8
  /**
8
9
  * Builder for creating Transfer intents with token transfer operations.
9
10
  * Supports multiple transfers within a single transaction on the same chain.
10
11
  */
11
- export class TransferBuilder extends IntentBuilder {
12
+ export class TransferBuilder extends OperationBuilder {
12
13
  protected chainId: ChainId
13
14
  protected transfers: TransferData[] = []
14
15
 
@@ -135,33 +136,6 @@ export class TransferBuilder extends IntentBuilder {
135
136
  return this
136
137
  }
137
138
 
138
- /**
139
- * Sets the settler address for this intent.
140
- * @param settler - The settler address as an Address instance
141
- * @returns This TransferBuilder instance for method chaining
142
- */
143
- addSettler(settler: Address): TransferBuilder {
144
- return changetype<TransferBuilder>(super.addSettler(settler))
145
- }
146
-
147
- /**
148
- * Sets the settler address from a string.
149
- * @param settler - The settler address as a hex or base58 string accordingly
150
- * @returns This TransferBuilder instance for method chaining
151
- */
152
- addSettlerAsString(settler: string): TransferBuilder {
153
- return changetype<TransferBuilder>(super.addSettlerAsString(settler))
154
- }
155
-
156
- /**
157
- * Sets the deadline for this intent.
158
- * @param deadline - The deadline as a timestamp
159
- * @returns This TransferBuilder instance for method chaining
160
- */
161
- addDeadline(deadline: BigInt): TransferBuilder {
162
- return changetype<TransferBuilder>(super.addDeadline(deadline))
163
- }
164
-
165
139
  /**
166
140
  * Sets the user address for this intent.
167
141
  * @param user - The user address
@@ -180,26 +154,6 @@ export class TransferBuilder extends IntentBuilder {
180
154
  return changetype<TransferBuilder>(super.addUserAsString(user))
181
155
  }
182
156
 
183
- /**
184
- * Sets the nonce for this intent.
185
- * @param nonce - A unique identifier to prevent replay attacks
186
- * @returns This TransferBuilder instance for method chaining
187
- */
188
- addNonce(nonce: string): TransferBuilder {
189
- return changetype<TransferBuilder>(super.addNonce(nonce))
190
- }
191
-
192
- /**
193
- * Adds a max fee for this intent.
194
- * @param fee - The max fee token amount (must be on same chain)
195
- * @returns This TransferBuilder instance for method chaining
196
- */
197
- addMaxFee(fee: TokenAmount): TransferBuilder {
198
- if (!fee.token.hasChain(this.chainId)) throw new Error('Fee token must be on the same chain')
199
- this.maxFees.push(fee)
200
- return this
201
- }
202
-
203
157
  /**
204
158
  * Sets an event for the intent.
205
159
  * @param topic - The topic to be indexed in the event
@@ -215,7 +169,7 @@ export class TransferBuilder extends IntentBuilder {
215
169
  * @param events - The list of events to be added
216
170
  * @returns This TransferBuilder instance for method chaining
217
171
  */
218
- addEvents(events: IntentEvent[]): TransferBuilder {
172
+ addEvents(events: OperationEvent[]): TransferBuilder {
219
173
  return changetype<TransferBuilder>(super.addEvents(events))
220
174
  }
221
175
 
@@ -224,16 +178,16 @@ export class TransferBuilder extends IntentBuilder {
224
178
  * @returns A new Transfer instance with all configured parameters
225
179
  */
226
180
  build(): Transfer {
227
- return new Transfer(
228
- this.chainId,
229
- this.transfers,
230
- this.maxFees,
231
- this.settler,
232
- this.user,
233
- this.deadline,
234
- this.nonce,
235
- this.events
236
- )
181
+ return new Transfer(this.chainId, this.transfers, this.user, this.events)
182
+ }
183
+
184
+ /**
185
+ * Builds this operation and sends it inside an intent with the provided fee data.
186
+ * @param maxFee - The max fee to pay for the intent
187
+ * @param feePayer - The fee payer for the intent (optional)
188
+ */
189
+ send(maxFee: TokenAmount, feePayer: Address | null = null): void {
190
+ this.build().send(maxFee, feePayer)
237
191
  }
238
192
  }
239
193
 
@@ -307,48 +261,9 @@ export class TransferData {
307
261
  * Represents a Transfer intent for sending tokens to recipients on a blockchain network.
308
262
  */
309
263
  @json
310
- export class Transfer extends Intent {
311
- public chainId: ChainId
264
+ export class Transfer extends Operation {
312
265
  public transfers: TransferData[]
313
266
 
314
- /**
315
- * Creates a simple single-token transfer intent.
316
- * @param token - The Token to transfer
317
- * @param amount - The amount to transfer
318
- * @param recipient - The address to receive the tokens
319
- * @param maxFee - The max fee to pay for the transfer intent
320
- * @param settler - The settler address (optional)
321
- * @param user - The user address (optional)
322
- * @param deadline - The deadline timestamp (optional)
323
- * @param nonce - The nonce for replay protection (optional)
324
- * @returns A new Transfer instance
325
- */
326
- static create(
327
- token: Token,
328
- amount: BigInt,
329
- recipient: Address,
330
- maxFee: BigInt,
331
- settler: Address | null = null,
332
- user: Address | null = null,
333
- deadline: BigInt | null = null,
334
- nonce: string | null = null,
335
- events: IntentEvent[] | null = null
336
- ): Transfer {
337
- const transferAmount = TokenAmount.fromBigInt(token, amount)
338
- const transferData = TransferData.fromTokenAmount(transferAmount, recipient)
339
- const maxFees = [TokenAmount.fromBigInt(token, maxFee)]
340
- return new Transfer(
341
- token instanceof ERC20Token ? (token as ERC20Token).chainId : ChainId.SOLANA_MAINNET,
342
- [transferData],
343
- maxFees,
344
- settler,
345
- user,
346
- deadline,
347
- nonce,
348
- events
349
- )
350
- }
351
-
352
267
  /**
353
268
  * Creates a new Transfer intent.
354
269
  * @param chainId - The blockchain network identifier
@@ -362,33 +277,22 @@ export class Transfer extends Intent {
362
277
  constructor(
363
278
  chainId: ChainId,
364
279
  transfers: TransferData[],
365
- maxFees: TokenAmount[],
366
- settler: Address | null = null,
367
280
  user: Address | null = null,
368
- deadline: BigInt | null = null,
369
- nonce: string | null = null,
370
- events: IntentEvent[] | null = null
281
+ events: OperationEvent[] | null = null
371
282
  ) {
372
- const fees: MaxFee[] = maxFees.map((fee: TokenAmount) => MaxFee.fromTokenAmount(fee))
373
- super(OperationType.Transfer, chainId, fees, settler, user, deadline, nonce, events)
283
+ super(OperationType.Transfer, chainId, user, events)
374
284
  if (transfers.length === 0) throw new Error('Transfer list cannot be empty')
375
- if (maxFees.length == 0) throw new Error('At least a max fee must be specified')
376
-
377
285
  this.transfers = transfers
378
- this.chainId = chainId
379
286
  }
380
287
 
381
288
  /**
382
289
  * Sends this Transfer intent to the execution environment.
290
+ * @param maxFee - The max fee to pay for the intent
291
+ * @param feePayer - The fee payer for the intent (optional)
383
292
  */
384
- send(): void {
385
- environment.transfer(this)
386
- }
387
-
388
- /**
389
- * Whether the chainId is Solana or not
390
- */
391
- isSVM(): bool {
392
- return this.chainId === ChainId.SOLANA_MAINNET
293
+ send(maxFee: TokenAmount, feePayer: Address | null = null): void {
294
+ const intentBuilder = new IntentBuilder().addMaxFee(maxFee).addOperation(this)
295
+ if (feePayer) intentBuilder.addFeePayer(feePayer)
296
+ environment.sendIntent(intentBuilder.build())
393
297
  }
394
298
  }
@@ -1,4 +1,5 @@
1
1
  export * from './Call'
2
2
  export * from './Intent'
3
+ export * from './Operation'
3
4
  export * from './Swap'
4
5
  export * from './Transfer'
@@ -2,7 +2,6 @@ import { environment } from '../environment'
2
2
  import { evm } from '../evm'
3
3
  import { MIMIC_HELPER_ADDRESS } from '../helpers'
4
4
  import { EvmCall, EvmCallBuilder } from '../intents'
5
- import { TokenAmount } from '../tokens'
6
5
  import { Address, Bytes, ChainId, EvmDecodeParam, EvmEncodeParam, Result } from '../types'
7
6
 
8
7
  const ADDRESS = Address.fromHexString(MIMIC_HELPER_ADDRESS)
@@ -11,7 +10,6 @@ const DEFAULT_CHAIN_ID = ChainId.OPTIMISM
11
10
  export namespace storage {
12
11
  export function createSetDataCall(
13
12
  smartAccount: Address,
14
- maxFee: TokenAmount,
15
13
  key: string,
16
14
  data: Bytes,
17
15
  chainId: ChainId = DEFAULT_CHAIN_ID
@@ -20,11 +18,7 @@ export namespace storage {
20
18
  '0x1c1bbd37' +
21
19
  evm.encode([EvmEncodeParam.fromValue('string', Bytes.fromUTF8(key)), EvmEncodeParam.fromValue('bytes', data)])
22
20
  )
23
- return EvmCallBuilder.forChain(chainId)
24
- .addUser(smartAccount)
25
- .addMaxFee(maxFee)
26
- .addCall(ADDRESS, encodedData)
27
- .build()
21
+ return EvmCallBuilder.forChain(chainId).addUser(smartAccount).addCall(ADDRESS, encodedData).build()
28
22
  }
29
23
 
30
24
  export function getData(