@mimicprotocol/lib-ts 0.0.1-rc.9 → 0.1.0

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 (80) hide show
  1. package/CHANGELOG.md +144 -0
  2. package/README.md +7 -7
  3. package/constants.d.ts +1 -0
  4. package/constants.js +1 -0
  5. package/index.ts +3 -0
  6. package/package.json +18 -4
  7. package/src/chains/Arbitrum.ts +14 -0
  8. package/src/chains/Avalanche.ts +15 -0
  9. package/src/chains/BNB.ts +15 -0
  10. package/src/chains/Base.ts +14 -0
  11. package/src/chains/BaseSepolia.ts +7 -0
  12. package/src/chains/Ethereum.ts +7 -7
  13. package/src/chains/Gnosis.ts +14 -0
  14. package/src/chains/Optimism.ts +7 -7
  15. package/src/chains/Polygon.ts +10 -7
  16. package/src/chains/Sonic.ts +13 -0
  17. package/src/chains/index.ts +7 -0
  18. package/src/context/Context.ts +102 -7
  19. package/src/environment.ts +150 -71
  20. package/src/evm.ts +5 -4
  21. package/src/helpers/BorshDeserializer.ts +133 -0
  22. package/src/helpers/consensus.ts +35 -0
  23. package/src/helpers/constants.ts +7 -1
  24. package/src/helpers/index.ts +5 -0
  25. package/src/helpers/math.ts +20 -0
  26. package/src/helpers/serialize.ts +5 -125
  27. package/src/helpers/strings.ts +82 -5
  28. package/src/intents/Call/EvmCall.ts +199 -0
  29. package/src/intents/Call/EvmDynamicCall.ts +272 -0
  30. package/src/intents/Call/SvmCall.ts +204 -0
  31. package/src/intents/Call/index.ts +3 -0
  32. package/src/intents/Intent.ts +347 -35
  33. package/src/intents/Operation.ts +114 -0
  34. package/src/intents/Swap.ts +127 -114
  35. package/src/intents/Transfer.ts +72 -123
  36. package/src/intents/index.ts +1 -0
  37. package/src/log.ts +83 -0
  38. package/src/queries/EvmCallQuery.ts +43 -0
  39. package/src/queries/QueryResponse.ts +26 -0
  40. package/src/queries/RelevantTokensQuery.ts +82 -0
  41. package/src/queries/SubgraphQuery.ts +50 -0
  42. package/src/queries/SvmAccountsInfoQuery.ts +65 -0
  43. package/src/queries/TokenPriceQuery.ts +47 -0
  44. package/src/queries/index.ts +6 -1
  45. package/src/storage/index.ts +1 -0
  46. package/src/storage/storage.ts +40 -0
  47. package/src/svm.ts +27 -0
  48. package/src/tokens/BlockchainToken.ts +108 -0
  49. package/src/tokens/DenominationToken.ts +70 -0
  50. package/src/tokens/ERC20Token.ts +192 -0
  51. package/src/tokens/SPLToken.ts +162 -0
  52. package/src/tokens/Token.ts +55 -155
  53. package/src/tokens/TokenAmount.ts +72 -30
  54. package/src/tokens/TokenProvider.ts +54 -0
  55. package/src/tokens/Tokens.ts +186 -0
  56. package/src/tokens/USD.ts +9 -6
  57. package/src/tokens/index.ts +6 -0
  58. package/src/types/Address.ts +86 -14
  59. package/src/types/BigInt.ts +14 -22
  60. package/src/types/ByteArray.ts +41 -3
  61. package/src/types/Bytes.ts +7 -0
  62. package/src/types/ChainId.ts +9 -1
  63. package/src/types/Option.ts +35 -0
  64. package/src/types/Result.ts +68 -0
  65. package/src/types/TriggerType.ts +4 -0
  66. package/src/types/evm/EvmDecodeParam.ts +7 -0
  67. package/src/types/evm/EvmEncodeParam.ts +31 -0
  68. package/src/types/evm/index.ts +2 -0
  69. package/src/types/index.ts +8 -2
  70. package/src/types/svm/SvmAccountInfo.ts +32 -0
  71. package/src/types/svm/SvmAccountMeta.ts +28 -0
  72. package/src/types/svm/SvmFindProgramAddress.ts +32 -0
  73. package/src/types/svm/SvmMint.ts +44 -0
  74. package/src/types/svm/SvmPdaSeed.ts +19 -0
  75. package/src/types/svm/SvmTokenMetadataData.ts +29 -0
  76. package/src/types/svm/index.ts +5 -0
  77. package/src/intents/Call.ts +0 -238
  78. package/src/queries/Call.ts +0 -16
  79. package/src/types/EvmDecodeParam.ts +0 -30
  80. package/src/types/EvmEncodeParam.ts +0 -54
@@ -1,5 +1,9 @@
1
- export function bytesToString(bytes: Uint8Array): string {
2
- return String.UTF8.decodeUnsafe(bytes.dataStart, bytes.length)
1
+ import { decode, encode } from 'as-base58/assembly/index'
2
+
3
+ import { ByteArray } from '../types'
4
+
5
+ export function bytesToString(bytes: Uint8Array, nullTerminated: bool = false): string {
6
+ return String.UTF8.decodeUnsafe(bytes.dataStart, bytes.length, nullTerminated)
3
7
  }
4
8
 
5
9
  export function bytesToHexString(bytes: Uint8Array): string {
@@ -8,6 +12,59 @@ export function bytesToHexString(bytes: Uint8Array): string {
8
12
  return hex
9
13
  }
10
14
 
15
+ export function bytesToBase58String(bytes: Uint8Array): string {
16
+ return encode(bytes)
17
+ }
18
+
19
+ export function bytesFromBase58String(base58: string): ByteArray {
20
+ assert(isBase58(base58), `input ${base58} is not valid base58`)
21
+ return changetype<ByteArray>(decode(base58))
22
+ }
23
+
24
+ export function stringToBool(str: string): bool {
25
+ if (str !== 'true' && str !== 'false') throw new Error(`Invalid boolean: ${str}`)
26
+ return str === 'true'
27
+ }
28
+
29
+ /**
30
+ * Workaround for json-as boolean bug:
31
+ * Converts JSON boolean values (true/false) into their string equivalents ("true"/"false")
32
+ * without touching occurrences inside JSON strings or keys.
33
+ *
34
+ * This function assumes compact JSON (no newlines between the boolean and the delimiter).
35
+ */
36
+ export function replaceJsonBooleans(json: string): string {
37
+ return (
38
+ json
39
+ // true after ':' (object property values)
40
+ .replaceAll(':true', ':"true"')
41
+ .replaceAll(':true,', ':"true",')
42
+ .replaceAll(':true}', ':"true"}')
43
+ .replaceAll(':true]', ':"true"]')
44
+ .replaceAll(': true,', ': "true",')
45
+ .replaceAll(': true}', ': "true"}')
46
+ .replaceAll(': true]', ': "true"]')
47
+ // true in arrays
48
+ .replaceAll('[true,', '["true",')
49
+ .replaceAll('[true]', '["true"]')
50
+ .replaceAll(',true,', ',"true",')
51
+ .replaceAll(',true]', ',"true"]')
52
+ // false after ':' (object property values)
53
+ .replaceAll(':false', ':"false"')
54
+ .replaceAll(':false,', ':"false",')
55
+ .replaceAll(':false}', ':"false"}')
56
+ .replaceAll(':false]', ':"false"]')
57
+ .replaceAll(': false,', ': "false",')
58
+ .replaceAll(': false}', ': "false"}')
59
+ .replaceAll(': false]', ': "false"]')
60
+ // false in arrays
61
+ .replaceAll('[false,', '["false",')
62
+ .replaceAll('[false]', '["false"]')
63
+ .replaceAll(',false,', ',"false",')
64
+ .replaceAll(',false]', ',"false"]')
65
+ )
66
+ }
67
+
11
68
  export function areAllZeros(str: string): boolean {
12
69
  for (let i = 0; i < str.length; i++) if (str.charCodeAt(i) !== 48) return false
13
70
  return true
@@ -76,12 +133,14 @@ export function normalizeScientificNotation(input: string): string {
76
133
  if (newDecimalPos <= 0) {
77
134
  const zeros = '0'.repeat(-newDecimalPos)
78
135
  return sign + '0.' + zeros + fullDigits
79
- } else if (newDecimalPos >= fullDigits.length) {
136
+ }
137
+
138
+ if (newDecimalPos >= fullDigits.length) {
80
139
  const zeros = '0'.repeat(newDecimalPos - fullDigits.length)
81
140
  return sign + fullDigits + zeros
82
- } else {
83
- return sign + fullDigits.substring(0, newDecimalPos) + '.' + fullDigits.substring(newDecimalPos)
84
141
  }
142
+
143
+ return sign + fullDigits.substring(0, newDecimalPos) + '.' + fullDigits.substring(newDecimalPos)
85
144
  }
86
145
 
87
146
  export function isHex(str: string, strict: boolean = false): boolean {
@@ -101,3 +160,21 @@ export function isHex(str: string, strict: boolean = false): boolean {
101
160
 
102
161
  return true
103
162
  }
163
+
164
+ export function isBase58(str: string): boolean {
165
+ for (let i = 0; i < str.length; i++) {
166
+ const c = str.charCodeAt(i)
167
+
168
+ // Base58 alphabet: digits, letters (not 0IOl)
169
+ if (
170
+ (c >= '1'.charCodeAt(0) && c <= '9'.charCodeAt(0)) ||
171
+ (c >= 'A'.charCodeAt(0) && c <= 'Z'.charCodeAt(0) && c !== 'I'.charCodeAt(0) && c !== 'O'.charCodeAt(0)) ||
172
+ (c >= 'a'.charCodeAt(0) && c <= 'z'.charCodeAt(0) && c !== 'l'.charCodeAt(0))
173
+ ) {
174
+ continue
175
+ }
176
+ return false
177
+ }
178
+
179
+ return true
180
+ }
@@ -0,0 +1,199 @@
1
+ import { environment } from '../../environment'
2
+ import { TokenAmount } from '../../tokens'
3
+ import { Address, BigInt, Bytes, ChainId } from '../../types'
4
+ import { IntentBuilder } from '../Intent'
5
+ import { Operation, OperationBuilder, OperationEvent, OperationType } from '../Operation'
6
+
7
+ /**
8
+ * Builder for creating EVM call operations.
9
+ */
10
+ export class EvmCallBuilder extends OperationBuilder {
11
+ protected chainId: ChainId
12
+ protected calls: EvmCallData[] = []
13
+
14
+ /**
15
+ * Creates an EvmCallBuilder for the specified EVM blockchain network.
16
+ * @param chainId - The blockchain network identifier
17
+ * @returns A new EvmCallBuilder instance
18
+ */
19
+ static forChain(chainId: ChainId): EvmCallBuilder {
20
+ return new EvmCallBuilder(chainId)
21
+ }
22
+
23
+ /**
24
+ * Creates a new EvmCallBuilder instance.
25
+ * @param chainId - The EVM blockchain network identifier
26
+ */
27
+ private constructor(chainId: ChainId) {
28
+ super()
29
+ this.chainId = chainId
30
+ }
31
+
32
+ /**
33
+ * Adds a contract call to the operation.
34
+ * @param target - The contract address to call
35
+ * @param data - The call data
36
+ * @param value - The native token value to send
37
+ * @returns This EvmCallBuilder instance for method chaining
38
+ */
39
+ addCall(target: Address, data: Bytes = Bytes.empty(), value: BigInt = BigInt.zero()): EvmCallBuilder {
40
+ this.calls.push(new EvmCallData(target, data, value))
41
+ return this
42
+ }
43
+
44
+ /**
45
+ * Adds multiple contract calls to the operation.
46
+ * @param calls - The contract calls to add
47
+ * @returns This EvmCallBuilder instance for method chaining
48
+ */
49
+ addCalls(calls: EvmCallData[]): EvmCallBuilder {
50
+ for (let i = 0; i < calls.length; i++)
51
+ this.addCall(
52
+ Address.fromString(calls[i].target),
53
+ Bytes.fromHexString(calls[i].data),
54
+ BigInt.fromString(calls[i].value)
55
+ )
56
+ return this
57
+ }
58
+
59
+ /**
60
+ * Adds the calls from another EvmCallBuilder to this EvmCallBuilder.
61
+ * @param builder - The EvmCallBuilder to add the calls from
62
+ * @returns This EvmCallBuilder instance for method chaining
63
+ */
64
+ addCallsFromBuilder(builder: EvmCallBuilder): EvmCallBuilder {
65
+ return this.addCalls(builder.getCalls())
66
+ }
67
+
68
+ /**
69
+ * Adds the calls from multiple EvmCallBuilders to this EvmCallBuilder.
70
+ * @param builders - The EvmCallBuilders to add the calls from
71
+ * @returns This EvmCallBuilder instance for method chaining
72
+ */
73
+ addCallsFromBuilders(builders: EvmCallBuilder[]): EvmCallBuilder {
74
+ for (let i = 0; i < builders.length; i++) this.addCallsFromBuilder(builders[i])
75
+ return this
76
+ }
77
+
78
+ /**
79
+ * Returns a copy of the calls array.
80
+ * @returns A copy of the calls array
81
+ */
82
+ getCalls(): EvmCallData[] {
83
+ return this.calls.slice(0)
84
+ }
85
+
86
+ /**
87
+ * Sets the user address for this operation.
88
+ * @param user - The user address
89
+ * @returns This EvmCallBuilder instance for method chaining
90
+ */
91
+ addUser(user: Address): EvmCallBuilder {
92
+ return changetype<EvmCallBuilder>(super.addUser(user))
93
+ }
94
+
95
+ /**
96
+ * Sets the user address from a string.
97
+ * @param user - The user address as a hex string
98
+ * @returns This EvmCallBuilder instance for method chaining
99
+ */
100
+ addUserAsString(user: string): EvmCallBuilder {
101
+ return changetype<EvmCallBuilder>(super.addUserAsString(user))
102
+ }
103
+
104
+ /**
105
+ * Sets an event for the operation.
106
+ * @param topic - The topic to be indexed in the event
107
+ * @param data - The event data
108
+ * @returns This EvmCallBuilder instance for method chaining
109
+ */
110
+ addEvent(topic: Bytes, data: Bytes): EvmCallBuilder {
111
+ return changetype<EvmCallBuilder>(super.addEvent(topic, data))
112
+ }
113
+
114
+ /**
115
+ * Sets multiple events for the operation.
116
+ * @param events - The list of events to be added
117
+ * @returns This EvmCallBuilder instance for method chaining
118
+ */
119
+ addEvents(events: OperationEvent[]): EvmCallBuilder {
120
+ return changetype<EvmCallBuilder>(super.addEvents(events))
121
+ }
122
+
123
+ /**
124
+ * Builds and returns the final EvmCall operation.
125
+ * @returns A new EvmCall instance with all configured parameters
126
+ */
127
+ build(): EvmCall {
128
+ return new EvmCall(this.chainId, this.calls, this.user, this.events)
129
+ }
130
+
131
+ /**
132
+ * Builds this operation and sends it inside an intent with the provided fee data.
133
+ * @param maxFee - The max fee to pay for the intent
134
+ * @param feePayer - The fee payer for the intent (optional)
135
+ */
136
+ send(maxFee: TokenAmount, feePayer: Address | null = null): void {
137
+ this.build().send(maxFee, feePayer)
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Represents data for a single contract call within an EVM call operation.
143
+ * Contains the target address, call data, and value to send.
144
+ */
145
+ @json
146
+ export class EvmCallData {
147
+ public target: string
148
+ public data: string
149
+ public value: string
150
+
151
+ /**
152
+ * Creates a new EvmCallData instance.
153
+ * @param target - The contract address to call
154
+ * @param data - The call data
155
+ * @param value - The native token value to send
156
+ */
157
+ constructor(target: Address, data: Bytes = Bytes.empty(), value: BigInt = BigInt.zero()) {
158
+ this.target = target.toString()
159
+ this.data = data.toHexString()
160
+ this.value = value.toString()
161
+ }
162
+ }
163
+
164
+ /**
165
+ * Represents an EVM call operation containing one or more contract calls to be executed.
166
+ */
167
+ @json
168
+ export class EvmCall extends Operation {
169
+ public calls: EvmCallData[]
170
+
171
+ /**
172
+ * Creates a new EvmCall operation.
173
+ * @param chainId - The blockchain network identifier
174
+ * @param calls - Array of contract calls to execute
175
+ * @param user - The user address
176
+ * @param events - The operation events to emit
177
+ */
178
+ constructor(
179
+ chainId: ChainId,
180
+ calls: EvmCallData[],
181
+ user: Address | null = null,
182
+ events: OperationEvent[] | null = null
183
+ ) {
184
+ super(OperationType.EvmCall, chainId, user, events)
185
+ if (calls.length === 0) throw new Error('Call list cannot be empty')
186
+ this.calls = calls
187
+ }
188
+
189
+ /**
190
+ * Sends this EvmCall operation wrapped in an intent.
191
+ * @param maxFee - The max fee to pay for the intent
192
+ * @param feePayer - The fee payer for the intent (optional)
193
+ */
194
+ public send(maxFee: TokenAmount, feePayer: Address | null = null): void {
195
+ const intentBuilder = new IntentBuilder().addMaxFee(maxFee).addOperation(this)
196
+ if (feePayer) intentBuilder.addFeePayer(feePayer)
197
+ environment.sendIntent(intentBuilder.build())
198
+ }
199
+ }
@@ -0,0 +1,272 @@
1
+ import { environment } from '../../environment'
2
+ import { evm } from '../../evm'
3
+ import { TokenAmount } from '../../tokens'
4
+ import { Address, BigInt, Bytes, ChainId, EvmEncodeParam } from '../../types'
5
+ import { IntentBuilder } from '../Intent'
6
+ import { Operation, OperationBuilder, OperationEvent, OperationType } from '../Operation'
7
+
8
+ export enum EvmDynamicArgKind {
9
+ Literal = 0,
10
+ Variable = 1,
11
+ }
12
+
13
+ /**
14
+ * Builder for creating EVM dynamic call operations.
15
+ */
16
+ export class EvmDynamicCallBuilder extends OperationBuilder {
17
+ protected chainId: ChainId
18
+ protected calls: EvmDynamicCallData[] = []
19
+
20
+ /**
21
+ * Creates an EvmDynamicCallBuilder for the specified EVM blockchain network.
22
+ * @param chainId - The blockchain network identifier
23
+ * @returns A new EvmDynamicCallBuilder instance
24
+ */
25
+ static forChain(chainId: ChainId): EvmDynamicCallBuilder {
26
+ return new EvmDynamicCallBuilder(chainId)
27
+ }
28
+
29
+ /**
30
+ * Creates a new EvmDynamicCallBuilder instance.
31
+ * @param chainId - The EVM blockchain network identifier
32
+ */
33
+ private constructor(chainId: ChainId) {
34
+ super()
35
+ this.chainId = chainId
36
+ }
37
+
38
+ /**
39
+ * Adds a dynamic contract call to the operation.
40
+ * @param target - The contract address to call
41
+ * @param selector - The function selector to call
42
+ * @param args - The dynamic call arguments
43
+ * @param value - The native token value to send
44
+ * @returns This EvmDynamicCallBuilder instance for method chaining
45
+ */
46
+ addCall(
47
+ target: Address,
48
+ selector: Bytes,
49
+ args: EvmDynamicArg[] = [],
50
+ value: BigInt = BigInt.zero()
51
+ ): EvmDynamicCallBuilder {
52
+ this.calls.push(new EvmDynamicCallData(target, selector, args, value))
53
+ return this
54
+ }
55
+
56
+ /**
57
+ * Adds multiple dynamic contract calls to the operation.
58
+ * @param calls - The contract calls to add
59
+ * @returns This EvmDynamicCallBuilder instance for method chaining
60
+ */
61
+ addCalls(calls: EvmDynamicCallData[]): EvmDynamicCallBuilder {
62
+ for (let i = 0; i < calls.length; i++) {
63
+ this.addCall(
64
+ Address.fromString(calls[i].target),
65
+ Bytes.fromHexString(calls[i].selector),
66
+ calls[i].arguments,
67
+ BigInt.fromString(calls[i].value)
68
+ )
69
+ }
70
+ return this
71
+ }
72
+
73
+ /**
74
+ * Adds the calls from another EvmDynamicCallBuilder to this EvmDynamicCallBuilder.
75
+ * @param builder - The EvmDynamicCallBuilder to add the calls from
76
+ * @returns This EvmDynamicCallBuilder instance for method chaining
77
+ */
78
+ addCallsFromBuilder(builder: EvmDynamicCallBuilder): EvmDynamicCallBuilder {
79
+ return this.addCalls(builder.getCalls())
80
+ }
81
+
82
+ /**
83
+ * Adds the calls from multiple EvmDynamicCallBuilders to this EvmDynamicCallBuilder.
84
+ * @param builders - The EvmDynamicCallBuilders to add the calls from
85
+ * @returns This EvmDynamicCallBuilder instance for method chaining
86
+ */
87
+ addCallsFromBuilders(builders: EvmDynamicCallBuilder[]): EvmDynamicCallBuilder {
88
+ for (let i = 0; i < builders.length; i++) this.addCallsFromBuilder(builders[i])
89
+ return this
90
+ }
91
+
92
+ /**
93
+ * Returns a copy of the calls array.
94
+ * @returns A copy of the calls array
95
+ */
96
+ getCalls(): EvmDynamicCallData[] {
97
+ return this.calls.slice(0)
98
+ }
99
+
100
+ /**
101
+ * Sets the user address for this operation.
102
+ * @param user - The user address
103
+ * @returns This EvmDynamicCallBuilder instance for method chaining
104
+ */
105
+ addUser(user: Address): EvmDynamicCallBuilder {
106
+ return changetype<EvmDynamicCallBuilder>(super.addUser(user))
107
+ }
108
+
109
+ /**
110
+ * Sets the user address from a string.
111
+ * @param user - The user address as a hex string
112
+ * @returns This EvmDynamicCallBuilder instance for method chaining
113
+ */
114
+ addUserAsString(user: string): EvmDynamicCallBuilder {
115
+ return changetype<EvmDynamicCallBuilder>(super.addUserAsString(user))
116
+ }
117
+
118
+ /**
119
+ * Sets an event for the operation.
120
+ * @param topic - The topic to be indexed in the event
121
+ * @param data - The event data
122
+ * @returns This EvmDynamicCallBuilder instance for method chaining
123
+ */
124
+ addEvent(topic: Bytes, data: Bytes): EvmDynamicCallBuilder {
125
+ return changetype<EvmDynamicCallBuilder>(super.addEvent(topic, data))
126
+ }
127
+
128
+ /**
129
+ * Sets multiple events for the operation.
130
+ * @param events - The list of events to be added
131
+ * @returns This EvmDynamicCallBuilder instance for method chaining
132
+ */
133
+ addEvents(events: OperationEvent[]): EvmDynamicCallBuilder {
134
+ return changetype<EvmDynamicCallBuilder>(super.addEvents(events))
135
+ }
136
+
137
+ /**
138
+ * Builds and returns the final EvmDynamicCall operation.
139
+ * @returns A new EvmDynamicCall instance with all configured parameters
140
+ */
141
+ build(): EvmDynamicCall {
142
+ return new EvmDynamicCall(this.chainId, this.calls, this.user, this.events)
143
+ }
144
+
145
+ /**
146
+ * Builds this operation and sends it inside an intent with the provided fee data.
147
+ * @param maxFee - The max fee to pay for the intent
148
+ * @param feePayer - The fee payer for the intent (optional)
149
+ */
150
+ send(maxFee: TokenAmount, feePayer: Address | null = null): void {
151
+ this.build().send(maxFee, feePayer)
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Represents a single dynamic argument in a dynamic call.
157
+ */
158
+ @json
159
+ export class EvmDynamicArg {
160
+ public kind: EvmDynamicArgKind
161
+ public data: string
162
+ public isDynamic: bool
163
+
164
+ /**
165
+ * Creates a literal dynamic argument from ABI-encoded parameters.
166
+ * @param parameters - The ABI parameters to encode as a literal argument
167
+ * @param isDynamic - Whether the resolved argument is ABI-dynamic
168
+ * @returns A new literal dynamic argument
169
+ */
170
+ static literal(parameters: EvmEncodeParam[], isDynamic: bool): EvmDynamicArg {
171
+ return new EvmDynamicArg(EvmDynamicArgKind.Literal, Bytes.fromHexString(evm.encode(parameters)), isDynamic)
172
+ }
173
+
174
+ /**
175
+ * Creates a variable reference dynamic argument.
176
+ * @param opIndex - The referenced operation index
177
+ * @param subIndex - The referenced output index within the operation
178
+ * @param isDynamic - Whether the resolved argument is ABI-dynamic
179
+ * @returns A new variable dynamic argument
180
+ */
181
+ static variable(opIndex: u32, subIndex: u32, isDynamic: bool): EvmDynamicArg {
182
+ return new EvmDynamicArg(
183
+ EvmDynamicArgKind.Variable,
184
+ Bytes.fromHexString(
185
+ evm.encode([
186
+ EvmEncodeParam.fromValue('uint256', BigInt.fromU32(opIndex)),
187
+ EvmEncodeParam.fromValue('uint256', BigInt.fromU32(subIndex)),
188
+ ])
189
+ ),
190
+ isDynamic
191
+ )
192
+ }
193
+
194
+ /**
195
+ * Creates a new EvmDynamicArg instance.
196
+ * @param kind - The argument resolution strategy
197
+ * @param data - The ABI-encoded argument data
198
+ * @param isDynamic - Whether the resolved argument is ABI-dynamic
199
+ */
200
+ constructor(kind: EvmDynamicArgKind, data: Bytes, isDynamic: bool) {
201
+ this.kind = kind
202
+ this.data = data.toHexString()
203
+ this.isDynamic = isDynamic
204
+ }
205
+ }
206
+
207
+ /**
208
+ * Represents data for a single dynamic contract call within an EVM dynamic call operation.
209
+ */
210
+ @json
211
+ export class EvmDynamicCallData {
212
+ public target: string
213
+ public value: string
214
+ public selector: string
215
+ public arguments: EvmDynamicArg[]
216
+
217
+ /**
218
+ * Creates a new EvmDynamicCallData instance.
219
+ * @param target - The contract address to call
220
+ * @param selector - The function selector to call
221
+ * @param args - The dynamic arguments for the call
222
+ * @param value - The native token value to send
223
+ */
224
+ constructor(target: Address, selector: Bytes, args: EvmDynamicArg[] = [], value: BigInt = BigInt.zero()) {
225
+ if (selector.length !== 4) throw new Error('Selector must be 4 bytes')
226
+ this.target = target.toString()
227
+ this.value = value.toString()
228
+ this.selector = selector.toHexString()
229
+ this.arguments = new Array<EvmDynamicArg>(args.length)
230
+ for (let i = 0; i < args.length; i++) {
231
+ const argument = args[i]
232
+ this.arguments[i] = new EvmDynamicArg(argument.kind, Bytes.fromHexString(argument.data), argument.isDynamic)
233
+ }
234
+ }
235
+ }
236
+
237
+ /**
238
+ * Represents an EVM dynamic call operation containing one or more dynamic contract calls.
239
+ */
240
+ @json
241
+ export class EvmDynamicCall extends Operation {
242
+ public calls: EvmDynamicCallData[]
243
+
244
+ /**
245
+ * Creates a new EvmDynamicCall operation.
246
+ * @param chainId - The blockchain network identifier
247
+ * @param calls - Array of dynamic contract calls to execute
248
+ * @param user - The user address
249
+ * @param events - The operation events to emit
250
+ */
251
+ constructor(
252
+ chainId: ChainId,
253
+ calls: EvmDynamicCallData[],
254
+ user: Address | null = null,
255
+ events: OperationEvent[] | null = null
256
+ ) {
257
+ super(OperationType.EvmDynamicCall, chainId, user, events)
258
+ if (calls.length === 0) throw new Error('Call list cannot be empty')
259
+ this.calls = calls
260
+ }
261
+
262
+ /**
263
+ * Sends this EvmDynamicCall operation wrapped in an intent.
264
+ * @param maxFee - The max fee to pay for the intent
265
+ * @param feePayer - The fee payer for the intent (optional)
266
+ */
267
+ public send(maxFee: TokenAmount, feePayer: Address | null = null): void {
268
+ const intentBuilder = new IntentBuilder().addMaxFee(maxFee).addOperation(this)
269
+ if (feePayer) intentBuilder.addFeePayer(feePayer)
270
+ environment.sendIntent(intentBuilder.build())
271
+ }
272
+ }