@mimicprotocol/lib-ts 0.0.1-rc.9
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.
- package/README.md +90 -0
- package/index.ts +7 -0
- package/package.json +26 -0
- package/src/chains/Ethereum.ts +12 -0
- package/src/chains/Optimism.ts +12 -0
- package/src/chains/Polygon.ts +12 -0
- package/src/chains/index.ts +3 -0
- package/src/context/Context.ts +29 -0
- package/src/context/index.ts +1 -0
- package/src/environment.ts +126 -0
- package/src/evm.ts +40 -0
- package/src/helpers/constants.ts +9 -0
- package/src/helpers/index.ts +3 -0
- package/src/helpers/serialize.ts +140 -0
- package/src/helpers/strings.ts +103 -0
- package/src/intents/Call.ts +238 -0
- package/src/intents/Intent.ts +79 -0
- package/src/intents/Swap.ts +419 -0
- package/src/intents/Transfer.ts +349 -0
- package/src/intents/index.ts +4 -0
- package/src/queries/Call.ts +16 -0
- package/src/queries/index.ts +1 -0
- package/src/tokens/Token.ts +191 -0
- package/src/tokens/TokenAmount.ts +248 -0
- package/src/tokens/USD.ts +201 -0
- package/src/tokens/index.ts +3 -0
- package/src/types/Address.ts +60 -0
- package/src/types/BigInt.ts +796 -0
- package/src/types/ByteArray.ts +316 -0
- package/src/types/Bytes.ts +137 -0
- package/src/types/ChainId.ts +9 -0
- package/src/types/EvmDecodeParam.ts +30 -0
- package/src/types/EvmEncodeParam.ts +54 -0
- package/src/types/index.ts +7 -0
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
import { environment } from '../environment'
|
|
2
|
+
import { Token, TokenAmount } from '../tokens'
|
|
3
|
+
import { Address, BigInt, ChainId } from '../types'
|
|
4
|
+
|
|
5
|
+
import { Intent, IntentBuilder, OperationType } from './Intent'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Builder for creating Transfer intents with token transfer operations.
|
|
9
|
+
* Supports multiple transfers within a single transaction on the same chain.
|
|
10
|
+
*/
|
|
11
|
+
export class TransferBuilder extends IntentBuilder {
|
|
12
|
+
private chainId: ChainId
|
|
13
|
+
private transfers: TransferData[] = []
|
|
14
|
+
private fee: TokenAmount | null = null
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Creates a TransferBuilder for a specific chain.
|
|
18
|
+
* @param chainId - The blockchain network identifier
|
|
19
|
+
* @returns A new TransferBuilder instance
|
|
20
|
+
*/
|
|
21
|
+
static forChain(chainId: ChainId): TransferBuilder {
|
|
22
|
+
return new TransferBuilder(chainId)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Creates a TransferBuilder for a specific chain with a pre-configured fee.
|
|
27
|
+
* @param chainId - The blockchain network identifier
|
|
28
|
+
* @param fee - The fee token amount for the transfer
|
|
29
|
+
* @returns A new TransferBuilder instance with fee set
|
|
30
|
+
*/
|
|
31
|
+
static forChainWithFee(chainId: ChainId, fee: TokenAmount): TransferBuilder {
|
|
32
|
+
const builder = new TransferBuilder(chainId)
|
|
33
|
+
builder.addFee(fee)
|
|
34
|
+
return builder
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Creates a new TransferBuilder instance.
|
|
39
|
+
* @param chainId - The blockchain network identifier
|
|
40
|
+
*/
|
|
41
|
+
constructor(chainId: ChainId) {
|
|
42
|
+
super()
|
|
43
|
+
this.chainId = chainId
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Adds a transfer to the intent.
|
|
48
|
+
* @param transfer - The transfer data configuration
|
|
49
|
+
* @returns This TransferBuilder instance for method chaining
|
|
50
|
+
*/
|
|
51
|
+
addTransfer(transfer: TransferData): TransferBuilder {
|
|
52
|
+
this.transfers.push(transfer)
|
|
53
|
+
return this
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Adds multiple transfers to the intent.
|
|
58
|
+
* @param transfers - Array of transfer data configurations
|
|
59
|
+
* @returns This TransferBuilder instance for method chaining
|
|
60
|
+
*/
|
|
61
|
+
addTransfers(transfers: TransferData[]): TransferBuilder {
|
|
62
|
+
for (let i = 0; i < transfers.length; i++) this.transfers.push(transfers[i])
|
|
63
|
+
return this
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Adds a transfer from a TokenAmount.
|
|
68
|
+
* @param tokenAmount - The token amount to transfer (must be on same chain)
|
|
69
|
+
* @param recipient - The address to receive the tokens
|
|
70
|
+
* @returns This TransferBuilder instance for method chaining
|
|
71
|
+
*/
|
|
72
|
+
addTransferFromTokenAmount(tokenAmount: TokenAmount, recipient: Address): TransferBuilder {
|
|
73
|
+
if (tokenAmount.token.chainId !== this.chainId) throw new Error('Transfer tokens must be on the same chain')
|
|
74
|
+
return this.addTransfer(TransferData.fromTokenAmount(tokenAmount, recipient))
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Adds a transfer from a 32-bit integer amount.
|
|
79
|
+
* @param token - The token to transfer (must be on same chain)
|
|
80
|
+
* @param amount - The amount as a whole number
|
|
81
|
+
* @param recipient - The address to receive the tokens
|
|
82
|
+
* @returns This TransferBuilder instance for method chaining
|
|
83
|
+
*/
|
|
84
|
+
addTransferFromI32(token: Token, amount: i32, recipient: Address): TransferBuilder {
|
|
85
|
+
if (token.chainId !== this.chainId) throw new Error('Transfer tokens must be on the same chain')
|
|
86
|
+
return this.addTransfer(TransferData.fromI32(token, amount, recipient))
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Adds a transfer from a BigInt amount.
|
|
91
|
+
* @param token - The token to transfer (must be on same chain)
|
|
92
|
+
* @param amount - The amount in the token's smallest unit
|
|
93
|
+
* @param recipient - The address to receive the tokens
|
|
94
|
+
* @returns This TransferBuilder instance for method chaining
|
|
95
|
+
*/
|
|
96
|
+
addTransferFromBigInt(token: Token, amount: BigInt, recipient: Address): TransferBuilder {
|
|
97
|
+
if (token.chainId !== this.chainId) throw new Error('Transfer tokens must be on the same chain')
|
|
98
|
+
return this.addTransfer(TransferData.fromBigInt(token, amount, recipient))
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Adds a transfer from a decimal string amount.
|
|
103
|
+
* @param token - The token to transfer (must be on same chain)
|
|
104
|
+
* @param amount - The amount as a decimal string
|
|
105
|
+
* @param recipient - The address to receive the tokens
|
|
106
|
+
* @returns This TransferBuilder instance for method chaining
|
|
107
|
+
*/
|
|
108
|
+
addTransferFromStringDecimal(token: Token, amount: string, recipient: Address): TransferBuilder {
|
|
109
|
+
if (token.chainId !== this.chainId) throw new Error('Transfer tokens must be on the same chain')
|
|
110
|
+
return this.addTransfer(TransferData.fromStringDecimal(token, amount, recipient))
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Adds multiple transfers from TokenAmounts to the same recipient.
|
|
115
|
+
* @param tokenAmounts - Array of token amounts to transfer (must be on same chain)
|
|
116
|
+
* @param recipient - The address to receive all the tokens
|
|
117
|
+
* @returns This TransferBuilder instance for method chaining
|
|
118
|
+
*/
|
|
119
|
+
addTransfersFromTokenAmounts(tokenAmounts: TokenAmount[], recipient: Address): TransferBuilder {
|
|
120
|
+
for (let i = 0; i < tokenAmounts.length; i++) this.addTransferFromTokenAmount(tokenAmounts[i], recipient)
|
|
121
|
+
return this
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Sets the fee for this transfer intent.
|
|
126
|
+
* @param fee - The fee token amount (must be on same chain)
|
|
127
|
+
* @returns This TransferBuilder instance for method chaining
|
|
128
|
+
*/
|
|
129
|
+
addFee(fee: TokenAmount): TransferBuilder {
|
|
130
|
+
if (fee.token.chainId !== this.chainId) throw new Error('Fee token must be on the same chain')
|
|
131
|
+
this.fee = fee
|
|
132
|
+
return this
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Sets the settler address for this intent.
|
|
137
|
+
* @param settler - The settler address as an Address instance
|
|
138
|
+
* @returns This TransferBuilder instance for method chaining
|
|
139
|
+
*/
|
|
140
|
+
addSettler(settler: Address): TransferBuilder {
|
|
141
|
+
return changetype<TransferBuilder>(super.addSettler(settler))
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Sets the settler address from a string.
|
|
146
|
+
* @param settler - The settler address as a hex string
|
|
147
|
+
* @returns This TransferBuilder instance for method chaining
|
|
148
|
+
*/
|
|
149
|
+
addSettlerAsString(settler: string): TransferBuilder {
|
|
150
|
+
return changetype<TransferBuilder>(super.addSettlerAsString(settler))
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Sets the deadline for this intent.
|
|
155
|
+
* @param deadline - The deadline as a timestamp
|
|
156
|
+
* @returns This TransferBuilder instance for method chaining
|
|
157
|
+
*/
|
|
158
|
+
addDeadline(deadline: BigInt): TransferBuilder {
|
|
159
|
+
return changetype<TransferBuilder>(super.addDeadline(deadline))
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Sets the user address for this intent.
|
|
164
|
+
* @param user - The user address
|
|
165
|
+
* @returns This TransferBuilder instance for method chaining
|
|
166
|
+
*/
|
|
167
|
+
addUser(user: Address): TransferBuilder {
|
|
168
|
+
return changetype<TransferBuilder>(super.addUser(user))
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Sets the user address from a string.
|
|
173
|
+
* @param user - The user address as a hex string
|
|
174
|
+
* @returns This TransferBuilder instance for method chaining
|
|
175
|
+
*/
|
|
176
|
+
addUserAsString(user: string): TransferBuilder {
|
|
177
|
+
return changetype<TransferBuilder>(super.addUserAsString(user))
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Sets the nonce for this intent.
|
|
182
|
+
* @param nonce - A unique identifier to prevent replay attacks
|
|
183
|
+
* @returns This TransferBuilder instance for method chaining
|
|
184
|
+
*/
|
|
185
|
+
addNonce(nonce: string): TransferBuilder {
|
|
186
|
+
return changetype<TransferBuilder>(super.addNonce(nonce))
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Builds and returns the final Transfer intent.
|
|
191
|
+
* @returns A new Transfer instance with all configured parameters
|
|
192
|
+
*/
|
|
193
|
+
build(): Transfer {
|
|
194
|
+
if (!this.fee) throw new Error('Transfer fee must be specified')
|
|
195
|
+
return new Transfer(
|
|
196
|
+
this.chainId,
|
|
197
|
+
this.transfers,
|
|
198
|
+
this.fee as TokenAmount,
|
|
199
|
+
this.settler,
|
|
200
|
+
this.user,
|
|
201
|
+
this.deadline,
|
|
202
|
+
this.nonce
|
|
203
|
+
)
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Represents transfer data for a single token transfer operation.
|
|
209
|
+
* Specifies the token, amount, and recipient for the transfer.
|
|
210
|
+
*/
|
|
211
|
+
@json
|
|
212
|
+
export class TransferData {
|
|
213
|
+
public token: string
|
|
214
|
+
public amount: string
|
|
215
|
+
public recipient: string
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Creates TransferData from a TokenAmount.
|
|
219
|
+
* @param tokenAmount - The token amount to transfer
|
|
220
|
+
* @param recipient - The address to receive the tokens
|
|
221
|
+
* @returns A new TransferData instance
|
|
222
|
+
*/
|
|
223
|
+
static fromTokenAmount(tokenAmount: TokenAmount, recipient: Address): TransferData {
|
|
224
|
+
return new TransferData(tokenAmount.token.address, tokenAmount.amount, recipient)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Creates TransferData from a 32-bit integer amount.
|
|
229
|
+
* @param token - The token to transfer
|
|
230
|
+
* @param amount - The amount as a whole number
|
|
231
|
+
* @param recipient - The address to receive the tokens
|
|
232
|
+
* @returns A new TransferData instance
|
|
233
|
+
*/
|
|
234
|
+
static fromI32(token: Token, amount: i32, recipient: Address): TransferData {
|
|
235
|
+
return this.fromTokenAmount(TokenAmount.fromI32(token, amount), recipient)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Creates TransferData from a BigInt amount.
|
|
240
|
+
* @param token - The token to transfer
|
|
241
|
+
* @param amount - The amount in the token's smallest unit
|
|
242
|
+
* @param recipient - The address to receive the tokens
|
|
243
|
+
* @returns A new TransferData instance
|
|
244
|
+
*/
|
|
245
|
+
static fromBigInt(token: Token, amount: BigInt, recipient: Address): TransferData {
|
|
246
|
+
return this.fromTokenAmount(TokenAmount.fromBigInt(token, amount), recipient)
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Creates TransferData from a decimal string amount.
|
|
251
|
+
* @param token - The token to transfer
|
|
252
|
+
* @param amount - The amount as a decimal string
|
|
253
|
+
* @param recipient - The address to receive the tokens
|
|
254
|
+
* @returns A new TransferData instance
|
|
255
|
+
*/
|
|
256
|
+
static fromStringDecimal(token: Token, amount: string, recipient: Address): TransferData {
|
|
257
|
+
return this.fromTokenAmount(TokenAmount.fromStringDecimal(token, amount), recipient)
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Creates a new TransferData instance.
|
|
262
|
+
* @param token - The token address
|
|
263
|
+
* @param amount - The amount in the token's smallest unit
|
|
264
|
+
* @param recipient - The address to receive the tokens
|
|
265
|
+
*/
|
|
266
|
+
constructor(token: Address, amount: BigInt, recipient: Address) {
|
|
267
|
+
this.token = token.toString()
|
|
268
|
+
this.amount = amount.toString()
|
|
269
|
+
this.recipient = recipient.toString()
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Represents a Transfer intent for sending tokens to recipients on a blockchain network.
|
|
275
|
+
*/
|
|
276
|
+
@json
|
|
277
|
+
export class Transfer extends Intent {
|
|
278
|
+
public chainId: ChainId
|
|
279
|
+
public transfers: TransferData[]
|
|
280
|
+
public feeToken: string
|
|
281
|
+
public feeAmount: string
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Creates a simple single-token transfer intent.
|
|
285
|
+
* @param chainId - The blockchain network identifier
|
|
286
|
+
* @param token - The token address to transfer
|
|
287
|
+
* @param amount - The amount to transfer
|
|
288
|
+
* @param recipient - The address to receive the tokens
|
|
289
|
+
* @param fee - The fee amount for the transfer
|
|
290
|
+
* @param settler - The settler address (optional)
|
|
291
|
+
* @param user - The user address (optional)
|
|
292
|
+
* @param deadline - The deadline timestamp (optional)
|
|
293
|
+
* @param nonce - The nonce for replay protection (optional)
|
|
294
|
+
* @returns A new Transfer instance
|
|
295
|
+
*/
|
|
296
|
+
static create(
|
|
297
|
+
chainId: ChainId,
|
|
298
|
+
token: Address,
|
|
299
|
+
amount: BigInt,
|
|
300
|
+
recipient: Address,
|
|
301
|
+
fee: BigInt,
|
|
302
|
+
settler: Address | null = null,
|
|
303
|
+
user: Address | null = null,
|
|
304
|
+
deadline: BigInt | null = null,
|
|
305
|
+
nonce: string | null = null
|
|
306
|
+
): Transfer {
|
|
307
|
+
const transferToken = Token.fromAddress(token, chainId)
|
|
308
|
+
const transferAmount = TokenAmount.fromBigInt(transferToken, amount)
|
|
309
|
+
const transferData = TransferData.fromTokenAmount(transferAmount, recipient)
|
|
310
|
+
const feeAmount = TokenAmount.fromBigInt(transferToken, fee)
|
|
311
|
+
return new Transfer(chainId, [transferData], feeAmount, settler, user, deadline, nonce)
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Creates a new Transfer intent.
|
|
316
|
+
* @param chainId - The blockchain network identifier
|
|
317
|
+
* @param transfers - Array of transfer data configurations
|
|
318
|
+
* @param fee - The fee token amount for the transfers
|
|
319
|
+
* @param settler - The settler address (optional)
|
|
320
|
+
* @param user - The user address (optional)
|
|
321
|
+
* @param deadline - The deadline timestamp (optional)
|
|
322
|
+
* @param nonce - The nonce for replay protection (optional)
|
|
323
|
+
*/
|
|
324
|
+
constructor(
|
|
325
|
+
chainId: ChainId,
|
|
326
|
+
transfers: TransferData[],
|
|
327
|
+
fee: TokenAmount,
|
|
328
|
+
settler: Address | null = null,
|
|
329
|
+
user: Address | null = null,
|
|
330
|
+
deadline: BigInt | null = null,
|
|
331
|
+
nonce: string | null = null
|
|
332
|
+
) {
|
|
333
|
+
super(OperationType.Transfer, settler, user, deadline, nonce)
|
|
334
|
+
|
|
335
|
+
if (transfers.length === 0) throw new Error('Transfer list cannot be empty')
|
|
336
|
+
|
|
337
|
+
this.transfers = transfers
|
|
338
|
+
this.feeToken = fee.token.address.toString()
|
|
339
|
+
this.feeAmount = fee.amount.toString()
|
|
340
|
+
this.chainId = chainId
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Sends this Transfer intent to the execution environment.
|
|
345
|
+
*/
|
|
346
|
+
send(): void {
|
|
347
|
+
environment.transfer(this)
|
|
348
|
+
}
|
|
349
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Address, ChainId } from '../types'
|
|
2
|
+
|
|
3
|
+
@json
|
|
4
|
+
export class Call {
|
|
5
|
+
public to: string
|
|
6
|
+
public chainId: ChainId
|
|
7
|
+
public timestamp: Date | null
|
|
8
|
+
public data: string
|
|
9
|
+
|
|
10
|
+
constructor(to: Address, chainId: ChainId, timestamp: Date | null, data: string) {
|
|
11
|
+
this.to = to.toString()
|
|
12
|
+
this.chainId = chainId
|
|
13
|
+
this.data = data
|
|
14
|
+
this.timestamp = timestamp
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Call'
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { environment } from '../environment'
|
|
2
|
+
import { evm } from '../evm'
|
|
3
|
+
import { join, NATIVE_ADDRESS, parseCSV, Serializable, serialize } from '../helpers'
|
|
4
|
+
import { Address, ChainId, EvmDecodeParam } from '../types'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Represents a token on a blockchain network including data like symbol, decimals, and address.
|
|
8
|
+
* Supports both ERC-20 and native tokens.
|
|
9
|
+
*/
|
|
10
|
+
export class Token implements Serializable {
|
|
11
|
+
public static readonly EMPTY_DECIMALS: u8 = u8.MAX_VALUE
|
|
12
|
+
public static readonly EMPTY_SYMBOL: string = ''
|
|
13
|
+
private static readonly SERIALIZED_PREFIX: string = 'Token'
|
|
14
|
+
|
|
15
|
+
private _symbol: string
|
|
16
|
+
private _address: Address
|
|
17
|
+
private _chainId: ChainId
|
|
18
|
+
private _decimals: u8
|
|
19
|
+
private _timestamp: Date | null = null
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Creates a Token instance from an Address object.
|
|
23
|
+
* @param address - The contract address of the token
|
|
24
|
+
* @param chainId - The blockchain network identifier
|
|
25
|
+
* @param decimals - Number of decimal places (optional, will be queried if not provided)
|
|
26
|
+
* @param symbol - Token symbol (optional, will be queried if not provided)
|
|
27
|
+
* @param timestamp - Timestamp for historical queries (optional)
|
|
28
|
+
* @returns A new Token instance
|
|
29
|
+
*/
|
|
30
|
+
static fromAddress(
|
|
31
|
+
address: Address,
|
|
32
|
+
chainId: ChainId,
|
|
33
|
+
decimals: u8 = Token.EMPTY_DECIMALS,
|
|
34
|
+
symbol: string = Token.EMPTY_SYMBOL,
|
|
35
|
+
timestamp: Date | null = null
|
|
36
|
+
): Token {
|
|
37
|
+
return new Token(address, chainId, decimals, symbol, timestamp)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Creates a Token instance from a string address.
|
|
42
|
+
* @param address - The contract address as a hex string
|
|
43
|
+
* @param chainId - The blockchain network identifier
|
|
44
|
+
* @param decimals - Number of decimal places (optional, will be queried if not provided)
|
|
45
|
+
* @param symbol - Token symbol (optional, will be queried if not provided)
|
|
46
|
+
* @param timestamp - Timestamp for historical queries (optional)
|
|
47
|
+
* @returns A new Token instance
|
|
48
|
+
*/
|
|
49
|
+
static fromString(
|
|
50
|
+
address: string,
|
|
51
|
+
chainId: ChainId,
|
|
52
|
+
decimals: u8 = Token.EMPTY_DECIMALS,
|
|
53
|
+
symbol: string = Token.EMPTY_SYMBOL,
|
|
54
|
+
timestamp: Date | null = null
|
|
55
|
+
): Token {
|
|
56
|
+
return Token.fromAddress(Address.fromString(address), chainId, decimals, symbol, timestamp)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Creates a Token instance representing the native token of the specified chain.
|
|
61
|
+
* @param chainId - The blockchain network identifier
|
|
62
|
+
* @returns A new Token instance for the native token
|
|
63
|
+
*/
|
|
64
|
+
static native(chainId: ChainId): Token {
|
|
65
|
+
switch (chainId) {
|
|
66
|
+
case ChainId.ETHEREUM:
|
|
67
|
+
case ChainId.OPTIMISM:
|
|
68
|
+
return Token.fromString(NATIVE_ADDRESS, chainId, 18, 'ETH')
|
|
69
|
+
case ChainId.POLYGON:
|
|
70
|
+
return Token.fromString(NATIVE_ADDRESS, chainId, 18, 'POL')
|
|
71
|
+
default:
|
|
72
|
+
throw new Error(`Unsupported chainId: ${chainId}`)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Parses a serialized Token string and creates a Token instance.
|
|
78
|
+
* @param serialized - The serialized token string in format: Token(address,chainId)
|
|
79
|
+
* @returns A new Token instance parsed from the serialized data
|
|
80
|
+
*/
|
|
81
|
+
static parse(serialized: string): Token {
|
|
82
|
+
const isToken = serialized.startsWith(`${Token.SERIALIZED_PREFIX}(`) && serialized.endsWith(')')
|
|
83
|
+
if (!isToken) throw new Error('Invalid serialized token')
|
|
84
|
+
|
|
85
|
+
const elements = parseCSV(serialized.slice(Token.SERIALIZED_PREFIX.length + 1, -1))
|
|
86
|
+
const areNull = elements.some((element) => element === null)
|
|
87
|
+
if (areNull) throw new Error('Invalid serialized token')
|
|
88
|
+
|
|
89
|
+
const address = elements[0]!
|
|
90
|
+
const chainId = i32.parse(elements[1]!)
|
|
91
|
+
|
|
92
|
+
return Token.fromString(address, chainId)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Creates a new Token instance.
|
|
97
|
+
* @param address - The contract address of the token
|
|
98
|
+
* @param chainId - The blockchain network identifier
|
|
99
|
+
* @param decimals - Number of decimal places (optional, will be queried if not provided)
|
|
100
|
+
* @param symbol - Token symbol (optional, will be queried if not provided)
|
|
101
|
+
* @param timestamp - Timestamp for historical queries (optional)
|
|
102
|
+
*/
|
|
103
|
+
constructor(
|
|
104
|
+
address: Address,
|
|
105
|
+
chainId: ChainId,
|
|
106
|
+
decimals: u8 = Token.EMPTY_DECIMALS,
|
|
107
|
+
symbol: string = Token.EMPTY_SYMBOL,
|
|
108
|
+
timestamp: Date | null = null
|
|
109
|
+
) {
|
|
110
|
+
this._address = address
|
|
111
|
+
this._chainId = chainId
|
|
112
|
+
this._timestamp = timestamp
|
|
113
|
+
this._symbol = symbol
|
|
114
|
+
this._decimals = decimals
|
|
115
|
+
// Ensure symbol and decimals are set for native tokens.
|
|
116
|
+
// Since queries return only the address and chainId, missing metadata must be filled
|
|
117
|
+
// to prevent the symbol and decimals getters from failing for native tokens.
|
|
118
|
+
if (
|
|
119
|
+
this._address.equals(Address.fromString(NATIVE_ADDRESS)) &&
|
|
120
|
+
(this._symbol === Token.EMPTY_SYMBOL || this._decimals === Token.EMPTY_DECIMALS)
|
|
121
|
+
) {
|
|
122
|
+
const nativeToken = Token.native(this._chainId)
|
|
123
|
+
if (this._symbol === Token.EMPTY_SYMBOL) {
|
|
124
|
+
this._symbol = nativeToken.symbol
|
|
125
|
+
}
|
|
126
|
+
if (this._decimals === Token.EMPTY_DECIMALS) {
|
|
127
|
+
this._decimals = nativeToken.decimals
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
get address(): Address {
|
|
133
|
+
return this._address.clone()
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
get chainId(): ChainId {
|
|
137
|
+
return this._chainId
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
get symbol(): string {
|
|
141
|
+
if (this._symbol === Token.EMPTY_SYMBOL) {
|
|
142
|
+
const response = environment.contractCall(this.address, this.chainId, this._timestamp, '0x95d89b41')
|
|
143
|
+
this._symbol = evm.decode(new EvmDecodeParam('string', response))
|
|
144
|
+
}
|
|
145
|
+
return this._symbol
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
get decimals(): u8 {
|
|
149
|
+
if (this._decimals == Token.EMPTY_DECIMALS) {
|
|
150
|
+
const result = environment.contractCall(this.address, this.chainId, this._timestamp, '0x313ce567')
|
|
151
|
+
this._decimals = u8.parse(evm.decode(new EvmDecodeParam('uint8', result)))
|
|
152
|
+
}
|
|
153
|
+
return this._decimals
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
set decimals(value: u8) {
|
|
157
|
+
this._decimals = value
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
set symbol(value: string) {
|
|
161
|
+
this._symbol = value
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
set timestamp(value: Date) {
|
|
165
|
+
this._timestamp = value
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Checks if this token is equal to another token.
|
|
170
|
+
* Tokens are considered equal if they have the same address on the same chain.
|
|
171
|
+
* @param other - The token to compare with
|
|
172
|
+
* @returns True if both tokens represent the same asset
|
|
173
|
+
*/
|
|
174
|
+
equals(other: Token): boolean {
|
|
175
|
+
const isSameChain = this.chainId === other.chainId
|
|
176
|
+
const isSameAddress = this.address.equals(other.address)
|
|
177
|
+
return isSameChain && isSameAddress
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Tells the string representation of this token.
|
|
182
|
+
* @returns The token symbol
|
|
183
|
+
*/
|
|
184
|
+
toString(): string {
|
|
185
|
+
return this.symbol
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
serialize(): string {
|
|
189
|
+
return `${Token.SERIALIZED_PREFIX}(${join([serialize(this.address), serialize(this.chainId)])})`
|
|
190
|
+
}
|
|
191
|
+
}
|