@iota/isc-sdk 0.0.0-dev-20251015065834
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/.prettierignore +2 -0
- package/.turbo/turbo-build.log +4 -0
- package/CHANGELOG.md +81 -0
- package/LICENSE +201 -0
- package/README.md +88 -0
- package/dist/cjs/api/EvmRpcClient.d.ts +7 -0
- package/dist/cjs/api/EvmRpcClient.js +57 -0
- package/dist/cjs/api/EvmRpcClient.js.map +7 -0
- package/dist/cjs/api/index.d.ts +1 -0
- package/dist/cjs/api/index.js +19 -0
- package/dist/cjs/api/index.js.map +7 -0
- package/dist/cjs/bcs.d.ts +944 -0
- package/dist/cjs/bcs.js +260 -0
- package/dist/cjs/bcs.js.map +7 -0
- package/dist/cjs/constants.d.ts +2 -0
- package/dist/cjs/constants.js +27 -0
- package/dist/cjs/constants.js.map +7 -0
- package/dist/cjs/enums/contracts.enums.d.ts +76 -0
- package/dist/cjs/enums/contracts.enums.js +113 -0
- package/dist/cjs/enums/contracts.enums.js.map +7 -0
- package/dist/cjs/enums/index.d.ts +1 -0
- package/dist/cjs/enums/index.js +19 -0
- package/dist/cjs/enums/index.js.map +7 -0
- package/dist/cjs/index.d.ts +9 -0
- package/dist/cjs/index.js +27 -0
- package/dist/cjs/index.js.map +7 -0
- package/dist/cjs/isc.d.ts +26 -0
- package/dist/cjs/isc.js +220 -0
- package/dist/cjs/isc.js.map +7 -0
- package/dist/cjs/move_bcs.d.ts +124 -0
- package/dist/cjs/move_bcs.js +70 -0
- package/dist/cjs/move_bcs.js.map +7 -0
- package/dist/cjs/package.json +4 -0
- package/dist/cjs/transaction.d.ts +168 -0
- package/dist/cjs/transaction.js +328 -0
- package/dist/cjs/transaction.js.map +7 -0
- package/dist/cjs/types/assetsResponse.d.ts +37 -0
- package/dist/cjs/types/assetsResponse.js +34 -0
- package/dist/cjs/types/assetsResponse.js.map +7 -0
- package/dist/cjs/types/chainData.d.ts +12 -0
- package/dist/cjs/types/chainData.js +29 -0
- package/dist/cjs/types/chainData.js.map +7 -0
- package/dist/cjs/types/index.d.ts +2 -0
- package/dist/cjs/types/index.js +20 -0
- package/dist/cjs/types/index.js.map +7 -0
- package/dist/cjs/utils/getHname.d.ts +1 -0
- package/dist/cjs/utils/getHname.js +30 -0
- package/dist/cjs/utils/getHname.js.map +7 -0
- package/dist/cjs/utils/index.d.ts +1 -0
- package/dist/cjs/utils/index.js +19 -0
- package/dist/cjs/utils/index.js.map +7 -0
- package/dist/cjs/vite-env.d.js +2 -0
- package/dist/cjs/vite-env.d.js.map +7 -0
- package/dist/esm/api/EvmRpcClient.d.ts +7 -0
- package/dist/esm/api/EvmRpcClient.js +37 -0
- package/dist/esm/api/EvmRpcClient.js.map +7 -0
- package/dist/esm/api/index.d.ts +1 -0
- package/dist/esm/api/index.js +2 -0
- package/dist/esm/api/index.js.map +7 -0
- package/dist/esm/bcs.d.ts +944 -0
- package/dist/esm/bcs.js +240 -0
- package/dist/esm/bcs.js.map +7 -0
- package/dist/esm/constants.d.ts +2 -0
- package/dist/esm/constants.js +7 -0
- package/dist/esm/constants.js.map +7 -0
- package/dist/esm/enums/contracts.enums.d.ts +76 -0
- package/dist/esm/enums/contracts.enums.js +93 -0
- package/dist/esm/enums/contracts.enums.js.map +7 -0
- package/dist/esm/enums/index.d.ts +1 -0
- package/dist/esm/enums/index.js +2 -0
- package/dist/esm/enums/index.js.map +7 -0
- package/dist/esm/index.d.ts +9 -0
- package/dist/esm/index.js +10 -0
- package/dist/esm/index.js.map +7 -0
- package/dist/esm/isc.d.ts +26 -0
- package/dist/esm/isc.js +200 -0
- package/dist/esm/isc.js.map +7 -0
- package/dist/esm/move_bcs.d.ts +124 -0
- package/dist/esm/move_bcs.js +50 -0
- package/dist/esm/move_bcs.js.map +7 -0
- package/dist/esm/package.json +4 -0
- package/dist/esm/transaction.d.ts +168 -0
- package/dist/esm/transaction.js +298 -0
- package/dist/esm/transaction.js.map +7 -0
- package/dist/esm/types/assetsResponse.d.ts +37 -0
- package/dist/esm/types/assetsResponse.js +14 -0
- package/dist/esm/types/assetsResponse.js.map +7 -0
- package/dist/esm/types/chainData.d.ts +12 -0
- package/dist/esm/types/chainData.js +9 -0
- package/dist/esm/types/chainData.js.map +7 -0
- package/dist/esm/types/index.d.ts +2 -0
- package/dist/esm/types/index.js +3 -0
- package/dist/esm/types/index.js.map +7 -0
- package/dist/esm/utils/getHname.d.ts +1 -0
- package/dist/esm/utils/getHname.js +10 -0
- package/dist/esm/utils/getHname.js.map +7 -0
- package/dist/esm/utils/index.d.ts +1 -0
- package/dist/esm/utils/index.js +2 -0
- package/dist/esm/utils/index.js.map +7 -0
- package/dist/esm/vite-env.d.js +10 -0
- package/dist/esm/vite-env.d.js.map +7 -0
- package/dist/tsconfig.esm.tsbuildinfo +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/examples/L1AddressL2funds.ts +72 -0
- package/examples/anchor.ts +72 -0
- package/examples/assetsBag.ts +61 -0
- package/examples/config.ts +81 -0
- package/examples/tokens.ts +96 -0
- package/package.json +57 -0
- package/src/api/EvmRpcClient.ts +48 -0
- package/src/api/index.ts +1 -0
- package/src/bcs.ts +237 -0
- package/src/constants.ts +4 -0
- package/src/enums/contracts.enums.ts +82 -0
- package/src/enums/index.ts +1 -0
- package/src/index.ts +9 -0
- package/src/isc.ts +331 -0
- package/src/move_bcs.ts +47 -0
- package/src/transaction.ts +380 -0
- package/src/types/assetsResponse.ts +13 -0
- package/src/types/chainData.ts +8 -0
- package/src/types/index.ts +2 -0
- package/src/utils/getHname.ts +11 -0
- package/src/utils/index.ts +1 -0
- package/src/vite-env.d.ts +1 -0
- package/tests/L1ToL2Tokens.spec.ts +141 -0
- package/tests/config.ts +81 -0
- package/tests/getHname.spec.ts +78 -0
- package/tests/utils.ts +69 -0
- package/tsconfig.esm.json +7 -0
- package/tsconfig.json +11 -0
- package/vitest.config.ts +10 -0
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
import type { TransactionObjectArgument } from '@iota/iota-sdk/transactions';
|
|
2
|
+
import { Transaction } from '@iota/iota-sdk/transactions';
|
|
3
|
+
import * as isc from './isc.js';
|
|
4
|
+
import type { ChainData } from './types/index.js';
|
|
5
|
+
import { IOTA_TYPE_ARG } from '@iota/iota-sdk/utils';
|
|
6
|
+
import { L2_FROM_L1_GAS_BUDGET } from './constants.js';
|
|
7
|
+
import type { ObjectArgument } from './isc.js';
|
|
8
|
+
|
|
9
|
+
export type Agent = {
|
|
10
|
+
type: 'evm';
|
|
11
|
+
address: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export class IscTransaction {
|
|
15
|
+
#finalized: boolean;
|
|
16
|
+
#transaction: Transaction;
|
|
17
|
+
#chainData: ChainData;
|
|
18
|
+
|
|
19
|
+
constructor(chainData: ChainData, transaction = new Transaction()) {
|
|
20
|
+
this.#finalized = false;
|
|
21
|
+
this.#transaction = transaction;
|
|
22
|
+
this.#chainData = chainData;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
private validateFinalizedStatus() {
|
|
26
|
+
if (this.#finalized) {
|
|
27
|
+
throw Error('Transaction is built.');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Getter for the IOTA MOVE Transaction.
|
|
33
|
+
*/
|
|
34
|
+
transaction(): Transaction {
|
|
35
|
+
return this.#transaction;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Create a bag.
|
|
40
|
+
*/
|
|
41
|
+
newBag(): TransactionObjectArgument {
|
|
42
|
+
this.validateFinalizedStatus();
|
|
43
|
+
return isc.newBag(this.#transaction, this.#chainData);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Get some amount in a coin.
|
|
48
|
+
*/
|
|
49
|
+
coinFromAmount({ amount }: { amount: number | bigint }) {
|
|
50
|
+
this.validateFinalizedStatus();
|
|
51
|
+
return isc.coinFromAmount(this.#transaction, BigInt(amount));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Place a coin in a bag.
|
|
56
|
+
*
|
|
57
|
+
* **Uses the IOTA Coin Type by default.**
|
|
58
|
+
*/
|
|
59
|
+
placeCoinInBag({
|
|
60
|
+
bag,
|
|
61
|
+
coinType = IOTA_TYPE_ARG,
|
|
62
|
+
coin,
|
|
63
|
+
}: {
|
|
64
|
+
coin: ObjectArgument;
|
|
65
|
+
coinType?: string;
|
|
66
|
+
bag: TransactionObjectArgument;
|
|
67
|
+
}) {
|
|
68
|
+
this.validateFinalizedStatus();
|
|
69
|
+
isc.placeCoinInBag(this.#transaction, this.#chainData, bag, coinType, coin);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Finally create and send a request calling the given `contractFunction` with `contractArgs` in `contract`
|
|
74
|
+
*/
|
|
75
|
+
createAndSend({
|
|
76
|
+
bag,
|
|
77
|
+
contract,
|
|
78
|
+
contractFunction,
|
|
79
|
+
contractArgs,
|
|
80
|
+
transfers,
|
|
81
|
+
gasBudget = L2_FROM_L1_GAS_BUDGET,
|
|
82
|
+
}: {
|
|
83
|
+
contractArgs: Uint8Array[];
|
|
84
|
+
contract: number;
|
|
85
|
+
contractFunction: number;
|
|
86
|
+
transfers: Array<[string, number | bigint]>;
|
|
87
|
+
gasBudget?: number | bigint;
|
|
88
|
+
bag: ObjectArgument;
|
|
89
|
+
}) {
|
|
90
|
+
this.validateFinalizedStatus();
|
|
91
|
+
isc.createAndSendRequest(
|
|
92
|
+
this.#transaction,
|
|
93
|
+
this.#chainData,
|
|
94
|
+
contract,
|
|
95
|
+
contractFunction,
|
|
96
|
+
contractArgs,
|
|
97
|
+
bag,
|
|
98
|
+
transfers,
|
|
99
|
+
gasBudget,
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Finally create and send a request calling the given `accountsFunction` in `accountsContract`
|
|
105
|
+
*/
|
|
106
|
+
createAndSendToEvm({
|
|
107
|
+
address,
|
|
108
|
+
accountsContract,
|
|
109
|
+
accountsFunction,
|
|
110
|
+
transfers,
|
|
111
|
+
gasBudget = L2_FROM_L1_GAS_BUDGET,
|
|
112
|
+
bag,
|
|
113
|
+
}: {
|
|
114
|
+
address: string;
|
|
115
|
+
accountsContract: number;
|
|
116
|
+
accountsFunction: number;
|
|
117
|
+
transfers: Array<[string, number | bigint]>;
|
|
118
|
+
gasBudget?: number | bigint;
|
|
119
|
+
bag: ObjectArgument;
|
|
120
|
+
}) {
|
|
121
|
+
const agentID = isc.agentIdForEVM(address);
|
|
122
|
+
this.createAndSend({
|
|
123
|
+
bag,
|
|
124
|
+
gasBudget,
|
|
125
|
+
contract: accountsContract,
|
|
126
|
+
contractFunction: accountsFunction,
|
|
127
|
+
contractArgs: [agentID],
|
|
128
|
+
transfers,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Take out the specified amount of coin from the bag.
|
|
134
|
+
*
|
|
135
|
+
* **Uses the IOTA Coin Type by default.**
|
|
136
|
+
*/
|
|
137
|
+
takeCoinBalanceFromBag({
|
|
138
|
+
bag,
|
|
139
|
+
coinType = IOTA_TYPE_ARG,
|
|
140
|
+
amount,
|
|
141
|
+
}: {
|
|
142
|
+
amount: number | bigint;
|
|
143
|
+
coinType?: string;
|
|
144
|
+
bag: ObjectArgument;
|
|
145
|
+
}) {
|
|
146
|
+
this.validateFinalizedStatus();
|
|
147
|
+
return isc.takeCoinBalanceFromBag(
|
|
148
|
+
this.#transaction,
|
|
149
|
+
this.#chainData,
|
|
150
|
+
bag,
|
|
151
|
+
coinType,
|
|
152
|
+
amount,
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Take out all the coin from the bag.
|
|
158
|
+
*
|
|
159
|
+
* **Uses the IOTA Coin Type by default.**
|
|
160
|
+
*/
|
|
161
|
+
takeAllCoinBalanceFromBag({
|
|
162
|
+
bag,
|
|
163
|
+
coinType = IOTA_TYPE_ARG,
|
|
164
|
+
}: {
|
|
165
|
+
bag: ObjectArgument;
|
|
166
|
+
coinType?: string;
|
|
167
|
+
}) {
|
|
168
|
+
this.validateFinalizedStatus();
|
|
169
|
+
return isc.takeAllCoinBalanceFromBag(this.#transaction, this.#chainData, bag, coinType);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Place a coin balance in the bag.
|
|
174
|
+
*
|
|
175
|
+
* **Uses the IOTA Coin Type by default.**
|
|
176
|
+
*/
|
|
177
|
+
placeCoinBalanceInBag({
|
|
178
|
+
bag,
|
|
179
|
+
coinType = IOTA_TYPE_ARG,
|
|
180
|
+
balance,
|
|
181
|
+
}: {
|
|
182
|
+
balance: ObjectArgument;
|
|
183
|
+
coinType?: string;
|
|
184
|
+
bag: ObjectArgument;
|
|
185
|
+
}) {
|
|
186
|
+
this.validateFinalizedStatus();
|
|
187
|
+
isc.placeCoinBalanceInBag(this.#transaction, this.#chainData, bag, coinType, balance);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Place an asset in the bag.
|
|
192
|
+
*/
|
|
193
|
+
placeAssetInBag({
|
|
194
|
+
bag,
|
|
195
|
+
asset,
|
|
196
|
+
assetType,
|
|
197
|
+
}: {
|
|
198
|
+
asset: ObjectArgument;
|
|
199
|
+
bag: ObjectArgument;
|
|
200
|
+
assetType: string;
|
|
201
|
+
}) {
|
|
202
|
+
this.validateFinalizedStatus();
|
|
203
|
+
isc.placeAssetInBag(this.#transaction, this.#chainData, bag, assetType, asset);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Take an asset from a bag.
|
|
208
|
+
*/
|
|
209
|
+
takeAssetFromBag({
|
|
210
|
+
bag,
|
|
211
|
+
assetType,
|
|
212
|
+
asset,
|
|
213
|
+
}: {
|
|
214
|
+
bag: ObjectArgument;
|
|
215
|
+
assetType: string;
|
|
216
|
+
asset: ObjectArgument;
|
|
217
|
+
}) {
|
|
218
|
+
this.validateFinalizedStatus();
|
|
219
|
+
isc.takeAssetFromBag(this.#transaction, this.#chainData, bag, assetType, asset);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Get the size of the bag.
|
|
224
|
+
*/
|
|
225
|
+
getSizeOfBag({ bag }: { bag: ObjectArgument }) {
|
|
226
|
+
this.validateFinalizedStatus();
|
|
227
|
+
return isc.getSizeOfBag(this.#transaction, this.#chainData, bag);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Destroy the bag.
|
|
232
|
+
*/
|
|
233
|
+
destroyBag({ bag }: { bag: ObjectArgument }) {
|
|
234
|
+
this.validateFinalizedStatus();
|
|
235
|
+
return isc.destroyBag(this.#transaction, this.#chainData, bag);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
startNewChain({ metadata, coin }: { metadata: Uint8Array; coin?: ObjectArgument }) {
|
|
239
|
+
this.validateFinalizedStatus();
|
|
240
|
+
return isc.startNewChain(this.#transaction, this.#chainData, metadata, coin);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
createAnchorWithAssetBag({ bag }: { bag: ObjectArgument }) {
|
|
244
|
+
this.validateFinalizedStatus();
|
|
245
|
+
return isc.createAnchorWithAssetBag(this.#transaction, this.#chainData, bag);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
updateAnchorStateForMigraton({
|
|
249
|
+
anchor,
|
|
250
|
+
metadata,
|
|
251
|
+
stateIndex,
|
|
252
|
+
}: {
|
|
253
|
+
anchor: ObjectArgument;
|
|
254
|
+
metadata: Uint8Array;
|
|
255
|
+
stateIndex: number;
|
|
256
|
+
}) {
|
|
257
|
+
this.validateFinalizedStatus();
|
|
258
|
+
return isc.updateAnchorStateForMigraton(
|
|
259
|
+
this.#transaction,
|
|
260
|
+
this.#chainData,
|
|
261
|
+
anchor,
|
|
262
|
+
metadata,
|
|
263
|
+
stateIndex,
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
destroyAnchor({ anchor }: { anchor: ObjectArgument }) {
|
|
268
|
+
this.validateFinalizedStatus();
|
|
269
|
+
return isc.destroyAnchor(this.#transaction, this.#chainData, anchor);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
borrowAssets({ anchor }: { anchor: ObjectArgument }) {
|
|
273
|
+
this.validateFinalizedStatus();
|
|
274
|
+
return isc.borrowAssets(this.#transaction, this.#chainData, anchor);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
returnAssetsFromBorrow({
|
|
278
|
+
anchor,
|
|
279
|
+
bag,
|
|
280
|
+
borrow,
|
|
281
|
+
}: {
|
|
282
|
+
anchor: ObjectArgument;
|
|
283
|
+
bag: ObjectArgument;
|
|
284
|
+
borrow: ObjectArgument;
|
|
285
|
+
}) {
|
|
286
|
+
this.validateFinalizedStatus();
|
|
287
|
+
return isc.returnAssetsFromBorrow(this.#transaction, this.#chainData, anchor, bag, borrow);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
receiveRequest({ anchor, request }: { anchor: ObjectArgument; request: ObjectArgument }) {
|
|
291
|
+
this.validateFinalizedStatus();
|
|
292
|
+
return isc.receiveRequest(this.#transaction, this.#chainData, anchor, request);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
transition({
|
|
296
|
+
anchor,
|
|
297
|
+
newStateMetadata,
|
|
298
|
+
receipts,
|
|
299
|
+
}: {
|
|
300
|
+
anchor: ObjectArgument;
|
|
301
|
+
newStateMetadata: Uint8Array;
|
|
302
|
+
receipts: ObjectArgument;
|
|
303
|
+
}) {
|
|
304
|
+
this.validateFinalizedStatus();
|
|
305
|
+
return isc.transition(
|
|
306
|
+
this.#transaction,
|
|
307
|
+
this.#chainData,
|
|
308
|
+
anchor,
|
|
309
|
+
newStateMetadata,
|
|
310
|
+
receipts,
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
placeCoinForMigration({
|
|
315
|
+
anchor,
|
|
316
|
+
coinType = IOTA_TYPE_ARG,
|
|
317
|
+
coin,
|
|
318
|
+
}: {
|
|
319
|
+
anchor: ObjectArgument;
|
|
320
|
+
coinType?: string;
|
|
321
|
+
coin: ObjectArgument;
|
|
322
|
+
}) {
|
|
323
|
+
this.validateFinalizedStatus();
|
|
324
|
+
return isc.placeCoinForMigration(
|
|
325
|
+
this.#transaction,
|
|
326
|
+
this.#chainData,
|
|
327
|
+
anchor,
|
|
328
|
+
coinType,
|
|
329
|
+
coin,
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
placeCoinBalanceForMigration({
|
|
334
|
+
anchor,
|
|
335
|
+
coinType = IOTA_TYPE_ARG,
|
|
336
|
+
balance,
|
|
337
|
+
}: {
|
|
338
|
+
anchor: ObjectArgument;
|
|
339
|
+
coinType?: string;
|
|
340
|
+
balance: ObjectArgument;
|
|
341
|
+
}) {
|
|
342
|
+
this.validateFinalizedStatus();
|
|
343
|
+
return isc.placeCoinBalanceForMigration(
|
|
344
|
+
this.#transaction,
|
|
345
|
+
this.#chainData,
|
|
346
|
+
anchor,
|
|
347
|
+
coinType,
|
|
348
|
+
balance,
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
placeAssetForMigration({
|
|
353
|
+
anchor,
|
|
354
|
+
assetType,
|
|
355
|
+
asset,
|
|
356
|
+
}: {
|
|
357
|
+
anchor: ObjectArgument;
|
|
358
|
+
assetType: string;
|
|
359
|
+
asset: ObjectArgument;
|
|
360
|
+
}) {
|
|
361
|
+
this.validateFinalizedStatus();
|
|
362
|
+
return isc.placeAssetForMigration(
|
|
363
|
+
this.#transaction,
|
|
364
|
+
this.#chainData,
|
|
365
|
+
anchor,
|
|
366
|
+
assetType,
|
|
367
|
+
asset,
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Stop building this ISC Transaction and return the IOTA MOVE Transaction.
|
|
373
|
+
* @returns IOTA MOVE Transaction.
|
|
374
|
+
*/
|
|
375
|
+
build(): Transaction {
|
|
376
|
+
this.validateFinalizedStatus();
|
|
377
|
+
this.#finalized = true;
|
|
378
|
+
return this.#transaction;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
export const CoinJSONSchema = z.object({
|
|
4
|
+
balance: z.string(),
|
|
5
|
+
coinType: z.string(),
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
export const AssetsResponseSchema = z.object({
|
|
9
|
+
baseTokens: z.string(),
|
|
10
|
+
nativeTokens: z.array(CoinJSONSchema),
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export type AssetsResponse = z.infer<typeof AssetsResponseSchema>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { blake2b } from '@noble/hashes/blake2';
|
|
2
|
+
|
|
3
|
+
export function getHname(input: string): number {
|
|
4
|
+
// Encode input as UTF-8 and hash it using BLAKE2b (32-byte digest)
|
|
5
|
+
const hash = blake2b(new TextEncoder().encode(input), { dkLen: 32 });
|
|
6
|
+
|
|
7
|
+
// Extract the first 4 bytes and interpret as little-endian uint32
|
|
8
|
+
const value = hash[0] | (hash[1] << 8) | (hash[2] << 16) | (hash[3] << 24);
|
|
9
|
+
|
|
10
|
+
return Number('0x' + (value >>> 0).toString(16).padStart(8, '0')); // Convert to hex with leading zeros
|
|
11
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './getHname.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AccountsContractMethod,
|
|
3
|
+
CoreContract,
|
|
4
|
+
getHname,
|
|
5
|
+
IscTransaction,
|
|
6
|
+
L2_FROM_L1_GAS_BUDGET,
|
|
7
|
+
} from '../src/index';
|
|
8
|
+
import { IOTA_TYPE_ARG } from '@iota/iota-sdk/utils';
|
|
9
|
+
import { Ed25519Keypair } from '@iota/iota-sdk/keypairs/ed25519';
|
|
10
|
+
import { requestIotaFromFaucetV0 } from '@iota/iota-sdk/faucet';
|
|
11
|
+
import { IotaClient } from '@iota/iota-sdk/client';
|
|
12
|
+
import { beforeAll, expect, test } from 'vitest';
|
|
13
|
+
import { CONFIG } from './config';
|
|
14
|
+
import { Wallet } from 'ethers';
|
|
15
|
+
import { bcs } from '@iota/iota-sdk/bcs';
|
|
16
|
+
import { checkL2BalanceWithRetries, requestFunds } from './utils';
|
|
17
|
+
|
|
18
|
+
const { L1 } = CONFIG;
|
|
19
|
+
|
|
20
|
+
let client: IotaClient;
|
|
21
|
+
|
|
22
|
+
beforeAll(async () => {
|
|
23
|
+
client = new IotaClient({
|
|
24
|
+
url: L1.rpcUrl,
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('Send IOTA', async () => {
|
|
29
|
+
const keypair = new Ed25519Keypair();
|
|
30
|
+
const address = keypair.toIotaAddress();
|
|
31
|
+
|
|
32
|
+
await requestIotaFromFaucetV0({
|
|
33
|
+
host: L1.faucetUrl!,
|
|
34
|
+
recipient: address,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const wallet = Wallet.createRandom();
|
|
38
|
+
|
|
39
|
+
// EVM Address
|
|
40
|
+
const recipientAddress = wallet.address;
|
|
41
|
+
// Amount to send (1 IOTAs)
|
|
42
|
+
const amountToSend = BigInt(1 * 1000000000);
|
|
43
|
+
// We also need to place a little more in the bag to cover the L2 gas
|
|
44
|
+
const amountToPlace = amountToSend + L2_FROM_L1_GAS_BUDGET;
|
|
45
|
+
|
|
46
|
+
const iscTx = new IscTransaction(L1);
|
|
47
|
+
|
|
48
|
+
const bag = iscTx.newBag();
|
|
49
|
+
const coin = iscTx.coinFromAmount({ amount: amountToPlace });
|
|
50
|
+
iscTx.placeCoinInBag({ coin, bag });
|
|
51
|
+
iscTx.createAndSendToEvm({
|
|
52
|
+
bag,
|
|
53
|
+
transfers: [[IOTA_TYPE_ARG, amountToSend]],
|
|
54
|
+
address: recipientAddress,
|
|
55
|
+
accountsContract: getHname(CoreContract.Accounts),
|
|
56
|
+
accountsFunction: getHname(AccountsContractMethod.TransferAllowanceTo),
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const transaction = iscTx.build();
|
|
60
|
+
transaction.setSender(address);
|
|
61
|
+
await transaction.build({ client });
|
|
62
|
+
|
|
63
|
+
await client.signAndExecuteTransaction({
|
|
64
|
+
signer: keypair,
|
|
65
|
+
transaction,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const evmBalance = await checkL2BalanceWithRetries(recipientAddress);
|
|
69
|
+
expect(evmBalance?.baseTokens).toEqual(amountToSend.toString());
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test('Send Non-IOTA Tokens', async () => {
|
|
73
|
+
const MNEMONIC =
|
|
74
|
+
'mom program scrap easily doctor seed slender secret mad flat foam hospital cherry seek river you obscure column blood reflect arch pencil cat burst';
|
|
75
|
+
const TOKEN_COIN_TYPE =
|
|
76
|
+
'0xe1e88f4962b3ea96cfad19aee42f666b04bbce4dc4327c3cd63f1b8ff16e13b2::tool_coin::TOOL_COIN';
|
|
77
|
+
|
|
78
|
+
const keypair = Ed25519Keypair.deriveKeypair(MNEMONIC);
|
|
79
|
+
const address = keypair.toIotaAddress();
|
|
80
|
+
const wallet = Wallet.createRandom();
|
|
81
|
+
|
|
82
|
+
await requestFunds(client, L1.faucetUrl!, address);
|
|
83
|
+
|
|
84
|
+
// EVM Address
|
|
85
|
+
const recipientAddress = wallet.address;
|
|
86
|
+
// Amount to send (0.01 IOTAs)
|
|
87
|
+
const amountToSend = BigInt(1 * 1_000_000);
|
|
88
|
+
// Amount to send (1 Boxfish)
|
|
89
|
+
const tokenAmountToSend = BigInt(1);
|
|
90
|
+
// We also need to place a little more in the bag to cover the L2 gas
|
|
91
|
+
const amountToPlace = amountToSend + L2_FROM_L1_GAS_BUDGET;
|
|
92
|
+
|
|
93
|
+
const iscTx = new IscTransaction(L1);
|
|
94
|
+
const tx = iscTx.transaction();
|
|
95
|
+
|
|
96
|
+
const bag = iscTx.newBag();
|
|
97
|
+
|
|
98
|
+
// Place IOTA
|
|
99
|
+
const iotaCoin = iscTx.coinFromAmount({ amount: amountToPlace });
|
|
100
|
+
iscTx.placeCoinInBag({ coin: iotaCoin, bag, coinType: IOTA_TYPE_ARG });
|
|
101
|
+
|
|
102
|
+
// Place Token
|
|
103
|
+
const tokenCoin = tx.splitCoins(
|
|
104
|
+
tx.object('0xf7662ffd9cb079d8e75ab4805ba78fdb0e0fb78cf49aa0fa01ecb7ebdf15d04e'),
|
|
105
|
+
[tx.pure(bcs.U64.serialize(tokenAmountToSend))],
|
|
106
|
+
);
|
|
107
|
+
iscTx.placeCoinInBag({
|
|
108
|
+
bag,
|
|
109
|
+
coin: tokenCoin,
|
|
110
|
+
coinType: TOKEN_COIN_TYPE,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
iscTx.createAndSendToEvm({
|
|
114
|
+
bag,
|
|
115
|
+
transfers: [
|
|
116
|
+
[IOTA_TYPE_ARG, amountToSend],
|
|
117
|
+
[TOKEN_COIN_TYPE, tokenAmountToSend],
|
|
118
|
+
],
|
|
119
|
+
address: recipientAddress,
|
|
120
|
+
accountsContract: getHname(CoreContract.Accounts),
|
|
121
|
+
accountsFunction: getHname(AccountsContractMethod.TransferAllowanceTo),
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
const transaction = iscTx.build();
|
|
125
|
+
transaction.setSender(address);
|
|
126
|
+
await transaction.build({ client });
|
|
127
|
+
|
|
128
|
+
await client.signAndExecuteTransaction({
|
|
129
|
+
signer: keypair,
|
|
130
|
+
transaction,
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
const evmBalance = await checkL2BalanceWithRetries(recipientAddress, TOKEN_COIN_TYPE);
|
|
134
|
+
expect(evmBalance?.baseTokens).toEqual(amountToSend.toString());
|
|
135
|
+
expect(evmBalance?.nativeTokens).toEqual([
|
|
136
|
+
{
|
|
137
|
+
coinType: TOKEN_COIN_TYPE,
|
|
138
|
+
balance: tokenAmountToSend.toString(),
|
|
139
|
+
},
|
|
140
|
+
]);
|
|
141
|
+
});
|
package/tests/config.ts
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// Copyright (c) 2025 IOTA Stiftung
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { config } from 'dotenv';
|
|
6
|
+
|
|
7
|
+
const HEX_REGEX = /^0x[0-9a-fA-F]+$/;
|
|
8
|
+
|
|
9
|
+
const envSchema = z.record(
|
|
10
|
+
z.object({
|
|
11
|
+
L1: z.object({
|
|
12
|
+
networkName: z.string(),
|
|
13
|
+
rpcUrl: z.string().url(),
|
|
14
|
+
faucetUrl: z.string().url().optional(),
|
|
15
|
+
chainId: z.string(),
|
|
16
|
+
packageId: z.string(),
|
|
17
|
+
}),
|
|
18
|
+
L2: z.object({
|
|
19
|
+
chainName: z.string(),
|
|
20
|
+
chainCurrency: z.string(),
|
|
21
|
+
rpcUrl: z.string().url(),
|
|
22
|
+
chainId: z.preprocess(
|
|
23
|
+
(val) => (val !== undefined ? Number(val) : undefined),
|
|
24
|
+
z.number().int().positive(),
|
|
25
|
+
),
|
|
26
|
+
chainDecimals: z.preprocess(
|
|
27
|
+
(val) => (val !== undefined ? Number(val) : undefined),
|
|
28
|
+
z.number().int().positive(),
|
|
29
|
+
),
|
|
30
|
+
chainExplorerName: z.string(),
|
|
31
|
+
chainExplorerUrl: z.string(),
|
|
32
|
+
wagmiAppName: z.string(),
|
|
33
|
+
walletConnectProjectId: z.string(),
|
|
34
|
+
iscContractAddress: z
|
|
35
|
+
.string()
|
|
36
|
+
.regex(
|
|
37
|
+
HEX_REGEX,
|
|
38
|
+
'Must be a valid hex string starting with 0x',
|
|
39
|
+
) as z.ZodType<`0x${string}`>,
|
|
40
|
+
evmRpcUrl: z.string().url(),
|
|
41
|
+
}),
|
|
42
|
+
}),
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
type Config = z.infer<typeof envSchema>;
|
|
46
|
+
|
|
47
|
+
function loadConfig(): Config {
|
|
48
|
+
config();
|
|
49
|
+
const rawEvmBridgeConfig = process.env.VITE_EVM_BRIDGE_CONFIG as string;
|
|
50
|
+
|
|
51
|
+
let evmBridgeConfig: Record<string, unknown> = {};
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
evmBridgeConfig = JSON.parse(rawEvmBridgeConfig);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
throw new Error(
|
|
57
|
+
`Failed to parse IOTA EVM Bridge config JSON env var! ${(error as Error)?.message}`,
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
return envSchema.parse(evmBridgeConfig);
|
|
63
|
+
} catch (error) {
|
|
64
|
+
if (error instanceof z.ZodError) {
|
|
65
|
+
const missingVars = error.issues
|
|
66
|
+
.map((issue) => `${issue.path.join('.')}: ${issue.message}`)
|
|
67
|
+
.join('\n');
|
|
68
|
+
throw new Error(`Missing required configuration:\n${missingVars}`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export const CONFIG = getDefaultNetwork();
|
|
76
|
+
|
|
77
|
+
function getDefaultNetwork() {
|
|
78
|
+
const config = loadConfig();
|
|
79
|
+
const evmBridgeDefaultNetwork = process.env.VITE_EVM_BRIDGE_DEFAULT_NETWORK as string;
|
|
80
|
+
return config[evmBridgeDefaultNetwork];
|
|
81
|
+
}
|