@atomiqlabs/chain-starknet 4.0.0-dev.11 → 4.0.0-dev.13
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/dist/starknet/chain/modules/StarknetBlocks.d.ts +1 -1
- package/dist/starknet/chain/modules/StarknetEvents.js +2 -2
- package/dist/starknet/chain/modules/StarknetFees.d.ts +7 -7
- package/dist/starknet/chain/modules/StarknetFees.js +4 -4
- package/dist/starknet/chain/modules/StarknetTokens.js +5 -1
- package/dist/starknet/chain/modules/StarknetTransactions.js +10 -4
- package/dist/starknet/contract/StarknetContractBase.js +5 -1
- package/dist/starknet/contract/modules/StarknetContractEvents.js +1 -1
- package/dist/starknet/events/StarknetChainEventsBrowser.d.ts +1 -2
- package/dist/starknet/events/StarknetChainEventsBrowser.js +8 -6
- package/dist/starknet/swaps/modules/StarknetSwapInit.d.ts +9 -2
- package/dist/starknet/swaps/modules/StarknetSwapInit.js +14 -4
- package/dist/starknet/wallet/StarknetKeypairWallet.js +6 -1
- package/dist/starknet/wallet/StarknetSigner.js +2 -1
- package/dist/utils/Utils.js +0 -1
- package/package.json +9 -3
- package/src/starknet/chain/modules/StarknetBlocks.ts +2 -1
- package/src/starknet/chain/modules/StarknetEvents.ts +2 -2
- package/src/starknet/chain/modules/StarknetFees.ts +4 -4
- package/src/starknet/chain/modules/StarknetTokens.ts +5 -1
- package/src/starknet/chain/modules/StarknetTransactions.ts +13 -5
- package/src/starknet/contract/StarknetContractBase.ts +5 -1
- package/src/starknet/contract/modules/StarknetContractEvents.ts +2 -2
- package/src/starknet/events/StarknetChainEventsBrowser.ts +9 -9
- package/src/starknet/swaps/modules/StarknetSwapInit.ts +18 -5
- package/src/starknet/wallet/StarknetKeypairWallet.ts +6 -1
- package/src/starknet/wallet/StarknetSigner.ts +2 -2
- package/src/utils/Utils.ts +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { StarknetModule } from "../StarknetModule";
|
|
2
|
-
export type StarknetBlockTag = "
|
|
2
|
+
export type StarknetBlockTag = "pre_confirmed" | "latest";
|
|
3
3
|
export declare class StarknetBlocks extends StarknetModule {
|
|
4
4
|
private BLOCK_CACHE_TIME;
|
|
5
5
|
private blockCache;
|
|
@@ -23,8 +23,8 @@ class StarknetEvents extends StarknetModule_1.StarknetModule {
|
|
|
23
23
|
while (result == null || result?.continuation_token != null) {
|
|
24
24
|
result = await this.root.provider.getEvents({
|
|
25
25
|
address: contract,
|
|
26
|
-
from_block: startBlock == null ? "
|
|
27
|
-
to_block: endBlock == null ? "
|
|
26
|
+
from_block: startBlock == null ? "latest" : { block_number: startBlock },
|
|
27
|
+
to_block: endBlock == null ? "latest" : { block_number: endBlock },
|
|
28
28
|
keys,
|
|
29
29
|
chunk_size: this.EVENTS_LIMIT,
|
|
30
30
|
continuation_token: result?.continuation_token
|
|
@@ -57,19 +57,19 @@ export declare class StarknetFees {
|
|
|
57
57
|
version: "0x3";
|
|
58
58
|
resourceBounds: {
|
|
59
59
|
l1_gas: {
|
|
60
|
-
max_amount:
|
|
61
|
-
max_price_per_unit:
|
|
60
|
+
max_amount: bigint;
|
|
61
|
+
max_price_per_unit: bigint;
|
|
62
62
|
};
|
|
63
63
|
l2_gas: {
|
|
64
|
-
max_amount:
|
|
65
|
-
max_price_per_unit:
|
|
64
|
+
max_amount: bigint;
|
|
65
|
+
max_price_per_unit: bigint;
|
|
66
66
|
};
|
|
67
67
|
l1_data_gas: {
|
|
68
|
-
max_amount:
|
|
69
|
-
max_price_per_unit:
|
|
68
|
+
max_amount: bigint;
|
|
69
|
+
max_price_per_unit: bigint;
|
|
70
70
|
};
|
|
71
71
|
};
|
|
72
|
-
tip:
|
|
72
|
+
tip: bigint;
|
|
73
73
|
paymasterData: any[];
|
|
74
74
|
nonceDataAvailabilityMode: "L1" | "L2";
|
|
75
75
|
feeDataAvailabilityMode: "L1" | "L2";
|
|
@@ -100,11 +100,11 @@ class StarknetFees {
|
|
|
100
100
|
return {
|
|
101
101
|
version: "0x3",
|
|
102
102
|
resourceBounds: {
|
|
103
|
-
l1_gas: { max_amount: (
|
|
104
|
-
l2_gas: { max_amount: (
|
|
105
|
-
l1_data_gas: { max_amount: (
|
|
103
|
+
l1_gas: { max_amount: BigInt(gas.l1Gas), max_price_per_unit: BigInt(l1GasCostStr) },
|
|
104
|
+
l2_gas: { max_amount: BigInt(gas.l2Gas), max_price_per_unit: BigInt(l2GasCostStr) },
|
|
105
|
+
l1_data_gas: { max_amount: BigInt(gas.l1DataGas), max_price_per_unit: BigInt(l1DataGasCostStr) }
|
|
106
106
|
},
|
|
107
|
-
tip:
|
|
107
|
+
tip: 0n,
|
|
108
108
|
paymasterData: [],
|
|
109
109
|
nonceDataAvailabilityMode: this.nonceDA,
|
|
110
110
|
feeDataAvailabilityMode: this.feeDA
|
|
@@ -9,7 +9,11 @@ const Utils_1 = require("../../../utils/Utils");
|
|
|
9
9
|
const StarknetAddresses_1 = require("./StarknetAddresses");
|
|
10
10
|
class StarknetTokens extends StarknetModule_1.StarknetModule {
|
|
11
11
|
getContract(address) {
|
|
12
|
-
return new starknet_1.Contract(
|
|
12
|
+
return new starknet_1.Contract({
|
|
13
|
+
abi: ERC20Abi_1.ERC20Abi,
|
|
14
|
+
address: address,
|
|
15
|
+
providerOrAccount: this.root.provider
|
|
16
|
+
}).typedv2(ERC20Abi_1.ERC20Abi);
|
|
13
17
|
}
|
|
14
18
|
/**
|
|
15
19
|
* Action for transferring the erc20 token
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.StarknetTransactions = void 0;
|
|
4
4
|
const StarknetModule_1 = require("../StarknetModule");
|
|
5
|
+
const starknet_1 = require("starknet");
|
|
5
6
|
const Utils_1 = require("../../../utils/Utils");
|
|
7
|
+
const MAX_UNCONFIRMED_TXS = 25;
|
|
6
8
|
class StarknetTransactions extends StarknetModule_1.StarknetModule {
|
|
7
9
|
constructor() {
|
|
8
10
|
super(...arguments);
|
|
@@ -154,7 +156,7 @@ class StarknetTransactions extends StarknetModule_1.StarknetModule {
|
|
|
154
156
|
" waitForConfirmation: " + waitForConfirmation + " parallel: " + parallel);
|
|
155
157
|
const txIds = [];
|
|
156
158
|
if (parallel) {
|
|
157
|
-
|
|
159
|
+
let promises = [];
|
|
158
160
|
for (let i = 0; i < txs.length; i++) {
|
|
159
161
|
const signedTx = txs[i];
|
|
160
162
|
const txId = await this.sendSignedTransaction(signedTx, onBeforePublish, signer);
|
|
@@ -162,6 +164,10 @@ class StarknetTransactions extends StarknetModule_1.StarknetModule {
|
|
|
162
164
|
promises.push(this.confirmTransaction(signedTx, abortSignal));
|
|
163
165
|
txIds.push(txId);
|
|
164
166
|
this.logger.debug("sendAndConfirm(): transaction sent (" + (i + 1) + "/" + txs.length + "): " + signedTx.txId);
|
|
167
|
+
if (promises.length >= MAX_UNCONFIRMED_TXS) {
|
|
168
|
+
await Promise.all(promises);
|
|
169
|
+
promises = [];
|
|
170
|
+
}
|
|
165
171
|
}
|
|
166
172
|
if (promises.length > 0)
|
|
167
173
|
await Promise.all(promises);
|
|
@@ -224,11 +230,11 @@ class StarknetTransactions extends StarknetModule_1.StarknetModule {
|
|
|
224
230
|
});
|
|
225
231
|
if (status == null)
|
|
226
232
|
return "not_found";
|
|
227
|
-
if (status.finality_status ===
|
|
233
|
+
if (status.finality_status === starknet_1.ETransactionStatus.RECEIVED)
|
|
228
234
|
return "pending";
|
|
229
|
-
if (status.finality_status ===
|
|
235
|
+
if (status.finality_status === starknet_1.ETransactionStatus.REJECTED)
|
|
230
236
|
return "rejected";
|
|
231
|
-
if (status.execution_status ===
|
|
237
|
+
if (status.execution_status === starknet_1.ETransactionExecutionStatus.SUCCEEDED) {
|
|
232
238
|
return "success";
|
|
233
239
|
}
|
|
234
240
|
return "reverted";
|
|
@@ -9,7 +9,11 @@ const StarknetContractEvents_1 = require("./modules/StarknetContractEvents");
|
|
|
9
9
|
class StarknetContractBase {
|
|
10
10
|
constructor(chainInterface, contractAddress, contractAbi) {
|
|
11
11
|
this.Chain = chainInterface;
|
|
12
|
-
this.contract = new starknet_1.Contract(
|
|
12
|
+
this.contract = new starknet_1.Contract({
|
|
13
|
+
abi: contractAbi,
|
|
14
|
+
address: contractAddress,
|
|
15
|
+
providerOrAccount: chainInterface.provider
|
|
16
|
+
}).typedv2(contractAbi);
|
|
13
17
|
this.Events = new StarknetContractEvents_1.StarknetContractEvents(chainInterface, this, contractAbi);
|
|
14
18
|
}
|
|
15
19
|
}
|
|
@@ -14,7 +14,7 @@ class StarknetContractEvents extends StarknetEvents_1.StarknetEvents {
|
|
|
14
14
|
const abiEvents = starknet_1.events.getAbiEvents(this.abi);
|
|
15
15
|
const abiStructs = starknet_1.CallData.getAbiStruct(this.abi);
|
|
16
16
|
const abiEnums = starknet_1.CallData.getAbiEnum(this.abi);
|
|
17
|
-
const result = starknet_1.events.parseEvents(blockEvents, abiEvents, abiStructs, abiEnums);
|
|
17
|
+
const result = starknet_1.events.parseEvents(blockEvents, abiEvents, abiStructs, abiEnums, (0, starknet_1.createAbiParser)(this.abi));
|
|
18
18
|
if (result.length !== blockEvents.length)
|
|
19
19
|
throw new Error("Invalid event detected, please check provided ABI");
|
|
20
20
|
return result.map((value, index) => {
|
|
@@ -61,10 +61,9 @@ export declare class StarknetChainEventsBrowser implements ChainEvents<StarknetS
|
|
|
61
61
|
* @param events
|
|
62
62
|
* @param currentBlockNumber
|
|
63
63
|
* @param currentBlockTimestamp
|
|
64
|
-
* @param pendingEventTime
|
|
65
64
|
* @protected
|
|
66
65
|
*/
|
|
67
|
-
protected processEvents(events: (StarknetAbiEvent<EscrowManagerAbiType, "escrow_manager::events::Initialize" | "escrow_manager::events::Refund" | "escrow_manager::events::Claim"> | StarknetAbiEvent<SpvVaultContractAbiType, "spv_swap_vault::events::Opened" | "spv_swap_vault::events::Deposited" | "spv_swap_vault::events::Fronted" | "spv_swap_vault::events::Claimed" | "spv_swap_vault::events::Closed">)[], currentBlockNumber: number, currentBlockTimestamp: number
|
|
66
|
+
protected processEvents(events: (StarknetAbiEvent<EscrowManagerAbiType, "escrow_manager::events::Initialize" | "escrow_manager::events::Refund" | "escrow_manager::events::Claim"> | StarknetAbiEvent<SpvVaultContractAbiType, "spv_swap_vault::events::Opened" | "spv_swap_vault::events::Deposited" | "spv_swap_vault::events::Fronted" | "spv_swap_vault::events::Claimed" | "spv_swap_vault::events::Closed">)[], currentBlockNumber: number, currentBlockTimestamp: number): Promise<void>;
|
|
68
67
|
protected checkEventsEcrowManager(lastTxHash: string, lastBlockNumber?: number, currentBlock?: {
|
|
69
68
|
timestamp: number;
|
|
70
69
|
block_number: number;
|
|
@@ -145,10 +145,9 @@ class StarknetChainEventsBrowser {
|
|
|
145
145
|
* @param events
|
|
146
146
|
* @param currentBlockNumber
|
|
147
147
|
* @param currentBlockTimestamp
|
|
148
|
-
* @param pendingEventTime
|
|
149
148
|
* @protected
|
|
150
149
|
*/
|
|
151
|
-
async processEvents(events, currentBlockNumber, currentBlockTimestamp
|
|
150
|
+
async processEvents(events, currentBlockNumber, currentBlockTimestamp) {
|
|
152
151
|
const blockTimestampsCache = {};
|
|
153
152
|
const getBlockTimestamp = async (blockNumber) => {
|
|
154
153
|
if (blockNumber === currentBlockNumber)
|
|
@@ -188,7 +187,10 @@ class StarknetChainEventsBrowser {
|
|
|
188
187
|
}
|
|
189
188
|
if (parsedEvent == null)
|
|
190
189
|
continue;
|
|
191
|
-
|
|
190
|
+
//We are not trusting pre-confs for events, so this shall never happen
|
|
191
|
+
if (event.blockNumber == null)
|
|
192
|
+
throw new Error("Event block number cannot be null!");
|
|
193
|
+
const timestamp = await getBlockTimestamp(event.blockNumber);
|
|
192
194
|
parsedEvent.meta = {
|
|
193
195
|
blockTime: timestamp,
|
|
194
196
|
txId: event.txHash,
|
|
@@ -213,7 +215,7 @@ class StarknetChainEventsBrowser {
|
|
|
213
215
|
}
|
|
214
216
|
}
|
|
215
217
|
if (events.length > 0) {
|
|
216
|
-
await this.processEvents(events, currentBlock?.block_number, currentBlock?.timestamp
|
|
218
|
+
await this.processEvents(events, currentBlock?.block_number, currentBlock?.timestamp);
|
|
217
219
|
lastTxHash = events[events.length - 1].txHash;
|
|
218
220
|
}
|
|
219
221
|
return lastTxHash;
|
|
@@ -231,14 +233,14 @@ class StarknetChainEventsBrowser {
|
|
|
231
233
|
}
|
|
232
234
|
}
|
|
233
235
|
if (events.length > 0) {
|
|
234
|
-
await this.processEvents(events, currentBlock?.block_number, currentBlock?.timestamp
|
|
236
|
+
await this.processEvents(events, currentBlock?.block_number, currentBlock?.timestamp);
|
|
235
237
|
lastTxHash = events[events.length - 1].txHash;
|
|
236
238
|
}
|
|
237
239
|
return lastTxHash;
|
|
238
240
|
}
|
|
239
241
|
async checkEvents(lastBlockNumber, lastTxHashes) {
|
|
240
242
|
lastTxHashes ?? (lastTxHashes = []);
|
|
241
|
-
const currentBlock = await this.provider.getBlockWithTxHashes(
|
|
243
|
+
const currentBlock = await this.provider.getBlockWithTxHashes(starknet_1.BlockTag.LATEST);
|
|
242
244
|
const currentBlockNumber = currentBlock.block_number;
|
|
243
245
|
lastTxHashes[0] = await this.checkEventsEcrowManager(lastTxHashes[0], lastBlockNumber, currentBlock);
|
|
244
246
|
lastTxHashes[1] = await this.checkEventsSpvVaults(lastTxHashes[1], lastBlockNumber, currentBlock);
|
|
@@ -60,13 +60,20 @@ export declare class StarknetSwapInit extends StarknetSwapModule {
|
|
|
60
60
|
*/
|
|
61
61
|
getSignatureExpiry(timeout: string): Promise<number>;
|
|
62
62
|
/**
|
|
63
|
-
* Checks whether signature is expired
|
|
63
|
+
* Checks whether signature is soft expired, compares the timestamp to the current "pre-confirmed" block timestamp
|
|
64
64
|
*
|
|
65
65
|
* @param timeout
|
|
66
66
|
* @param preFetchData
|
|
67
67
|
* @public
|
|
68
68
|
*/
|
|
69
|
-
|
|
69
|
+
isSignatureSoftExpired(timeout: string, preFetchData?: StarknetPreFetchVerification): Promise<boolean>;
|
|
70
|
+
/**
|
|
71
|
+
* Checks whether signature is expired for good, compares the timestamp to the current "latest" block timestamp
|
|
72
|
+
*
|
|
73
|
+
* @param timeout
|
|
74
|
+
* @public
|
|
75
|
+
*/
|
|
76
|
+
isSignatureExpired(timeout: string): Promise<boolean>;
|
|
70
77
|
/**
|
|
71
78
|
* Creates init transaction with a valid signature from an LP
|
|
72
79
|
*
|
|
@@ -50,7 +50,7 @@ class StarknetSwapInit extends StarknetSwapModule_1.StarknetSwapModule {
|
|
|
50
50
|
}
|
|
51
51
|
async preFetchForInitSignatureVerification() {
|
|
52
52
|
return {
|
|
53
|
-
pendingBlockTime: await this.root.Blocks.getBlockTime(
|
|
53
|
+
pendingBlockTime: await this.root.Blocks.getBlockTime(starknet_1.BlockTag.PRE_CONFIRMED)
|
|
54
54
|
};
|
|
55
55
|
}
|
|
56
56
|
/**
|
|
@@ -121,7 +121,7 @@ class StarknetSwapInit extends StarknetSwapModule_1.StarknetSwapModule {
|
|
|
121
121
|
const isExpired = (timeoutBN - currentTimestamp) < BigInt(this.contract.authGracePeriod);
|
|
122
122
|
if (isExpired)
|
|
123
123
|
throw new base_1.SignatureVerificationError("Authorization expired!");
|
|
124
|
-
if (await this.
|
|
124
|
+
if (await this.isSignatureSoftExpired(timeout, preFetchData))
|
|
125
125
|
throw new base_1.SignatureVerificationError("Authorization expired!");
|
|
126
126
|
const valid = await this.root.Signatures.isValidSignature(signature, signer, Initialize, "Initialize", {
|
|
127
127
|
"Swap hash": "0x" + swapData.getEscrowHash(),
|
|
@@ -167,18 +167,28 @@ class StarknetSwapInit extends StarknetSwapModule_1.StarknetSwapModule {
|
|
|
167
167
|
return timeoutExpiryTime;
|
|
168
168
|
}
|
|
169
169
|
/**
|
|
170
|
-
* Checks whether signature is expired
|
|
170
|
+
* Checks whether signature is soft expired, compares the timestamp to the current "pre-confirmed" block timestamp
|
|
171
171
|
*
|
|
172
172
|
* @param timeout
|
|
173
173
|
* @param preFetchData
|
|
174
174
|
* @public
|
|
175
175
|
*/
|
|
176
|
-
async
|
|
176
|
+
async isSignatureSoftExpired(timeout, preFetchData) {
|
|
177
177
|
if (preFetchData == null || preFetchData.pendingBlockTime == null) {
|
|
178
178
|
preFetchData = await this.preFetchForInitSignatureVerification();
|
|
179
179
|
}
|
|
180
180
|
return preFetchData.pendingBlockTime > parseInt(timeout);
|
|
181
181
|
}
|
|
182
|
+
/**
|
|
183
|
+
* Checks whether signature is expired for good, compares the timestamp to the current "latest" block timestamp
|
|
184
|
+
*
|
|
185
|
+
* @param timeout
|
|
186
|
+
* @public
|
|
187
|
+
*/
|
|
188
|
+
async isSignatureExpired(timeout) {
|
|
189
|
+
const blockTime = await this.root.Blocks.getBlockTime(starknet_1.BlockTag.LATEST);
|
|
190
|
+
return blockTime > parseInt(timeout);
|
|
191
|
+
}
|
|
182
192
|
/**
|
|
183
193
|
* Creates init transaction with a valid signature from an LP
|
|
184
194
|
*
|
|
@@ -12,7 +12,12 @@ class StarknetKeypairWallet extends starknet_1.Account {
|
|
|
12
12
|
// Calculate future address of the account
|
|
13
13
|
const OZaccountConstructorCallData = starknet_1.CallData.compile({ publicKey });
|
|
14
14
|
const OZcontractAddress = starknet_1.hash.calculateContractAddressFromHash(publicKey, OZaccountClassHash, OZaccountConstructorCallData, 0);
|
|
15
|
-
super(
|
|
15
|
+
super({
|
|
16
|
+
provider,
|
|
17
|
+
address: OZcontractAddress,
|
|
18
|
+
signer: privateKey,
|
|
19
|
+
cairoVersion: "1"
|
|
20
|
+
});
|
|
16
21
|
this.publicKey = publicKey;
|
|
17
22
|
}
|
|
18
23
|
getDeploymentData() {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.StarknetSigner = void 0;
|
|
4
|
+
const starknet_1 = require("starknet");
|
|
4
5
|
const Utils_1 = require("../../utils/Utils");
|
|
5
6
|
class StarknetSigner {
|
|
6
7
|
constructor(account) {
|
|
@@ -19,7 +20,7 @@ class StarknetSigner {
|
|
|
19
20
|
//TODO: Introduce proper nonce management!
|
|
20
21
|
async getNonce() {
|
|
21
22
|
try {
|
|
22
|
-
return BigInt(await this.account.getNonceForAddress(this.getAddress(),
|
|
23
|
+
return BigInt(await this.account.getNonceForAddress(this.getAddress(), starknet_1.BlockTag.PRE_CONFIRMED));
|
|
23
24
|
}
|
|
24
25
|
catch (e) {
|
|
25
26
|
if (e.message != null && e.message.includes("20: Contract not found")) {
|
package/dist/utils/Utils.js
CHANGED
|
@@ -117,7 +117,6 @@ function calculateHash(tx) {
|
|
|
117
117
|
return tx.txId = starknet_1.hash.calculateDeployAccountTransactionHash({
|
|
118
118
|
contractAddress: tx.tx.contractAddress,
|
|
119
119
|
classHash: tx.signed.classHash,
|
|
120
|
-
constructorCalldata: deployAccountData,
|
|
121
120
|
compiledConstructorCalldata: deployAccountData,
|
|
122
121
|
salt: tx.signed.addressSalt,
|
|
123
122
|
...commonData
|
package/package.json
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atomiqlabs/chain-starknet",
|
|
3
|
-
"version": "4.0.0-dev.
|
|
3
|
+
"version": "4.0.0-dev.13",
|
|
4
4
|
"description": "Starknet specific base implementation",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
|
-
"types
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"prepublishOnly": "npm run build",
|
|
8
10
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
9
11
|
},
|
|
10
12
|
"files": [
|
|
@@ -21,6 +23,10 @@
|
|
|
21
23
|
],
|
|
22
24
|
"author": "adambor",
|
|
23
25
|
"license": "ISC",
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "git+https://github.com/atomiqlabs/atomiq-chain-starknet.git"
|
|
29
|
+
},
|
|
24
30
|
"dependencies": {
|
|
25
31
|
"@atomiqlabs/base": "^10.0.0-dev.9",
|
|
26
32
|
"@noble/hashes": "^1.7.1",
|
|
@@ -29,7 +35,7 @@
|
|
|
29
35
|
"buffer": "6.0.3"
|
|
30
36
|
},
|
|
31
37
|
"peerDependencies": {
|
|
32
|
-
"starknet": "^
|
|
38
|
+
"starknet": "^8.5.0"
|
|
33
39
|
},
|
|
34
40
|
"devDependencies": {
|
|
35
41
|
"typescript": "4.9.5"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {StarknetModule} from "../StarknetModule";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
// https://github.com/starkware-libs/starknet-specs/blob/c2e93098b9c2ca0423b7f4d15b201f52f22d8c36/api/starknet_api_openrpc.json#L1234
|
|
4
|
+
export type StarknetBlockTag = "pre_confirmed" | "latest";
|
|
4
5
|
|
|
5
6
|
export class StarknetBlocks extends StarknetModule {
|
|
6
7
|
|
|
@@ -29,8 +29,8 @@ export class StarknetEvents extends StarknetModule {
|
|
|
29
29
|
while(result==null || result?.continuation_token!=null) {
|
|
30
30
|
result = await this.root.provider.getEvents({
|
|
31
31
|
address: contract,
|
|
32
|
-
from_block: startBlock==null ? "
|
|
33
|
-
to_block: endBlock==null ? "
|
|
32
|
+
from_block: startBlock==null ? "latest" : {block_number: startBlock},
|
|
33
|
+
to_block: endBlock==null ? "latest" : {block_number: endBlock},
|
|
34
34
|
keys,
|
|
35
35
|
chunk_size: this.EVENTS_LIMIT,
|
|
36
36
|
continuation_token: result?.continuation_token
|
|
@@ -141,11 +141,11 @@ export class StarknetFees {
|
|
|
141
141
|
return {
|
|
142
142
|
version: "0x3" as const,
|
|
143
143
|
resourceBounds: {
|
|
144
|
-
l1_gas: {max_amount:
|
|
145
|
-
l2_gas: {max_amount:
|
|
146
|
-
l1_data_gas: {max_amount:
|
|
144
|
+
l1_gas: {max_amount: BigInt(gas.l1Gas), max_price_per_unit: BigInt(l1GasCostStr)},
|
|
145
|
+
l2_gas: {max_amount: BigInt(gas.l2Gas), max_price_per_unit: BigInt(l2GasCostStr)},
|
|
146
|
+
l1_data_gas: {max_amount: BigInt(gas.l1DataGas), max_price_per_unit: BigInt(l1DataGasCostStr)}
|
|
147
147
|
},
|
|
148
|
-
tip:
|
|
148
|
+
tip: 0n,
|
|
149
149
|
paymasterData: [],
|
|
150
150
|
nonceDataAvailabilityMode: this.nonceDA,
|
|
151
151
|
feeDataAvailabilityMode: this.feeDA
|
|
@@ -17,7 +17,11 @@ export class StarknetTokens extends StarknetModule {
|
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
private getContract(address: string) {
|
|
20
|
-
return new Contract(
|
|
20
|
+
return new Contract({
|
|
21
|
+
abi: ERC20Abi,
|
|
22
|
+
address: address,
|
|
23
|
+
providerOrAccount: this.root.provider
|
|
24
|
+
}).typedv2(ERC20Abi);
|
|
21
25
|
}
|
|
22
26
|
|
|
23
27
|
/**
|
|
@@ -3,7 +3,9 @@ import {
|
|
|
3
3
|
Call,
|
|
4
4
|
DeployAccountContractPayload, DeployAccountContractTransaction,
|
|
5
5
|
Invocation, InvocationsSignerDetails,
|
|
6
|
-
BigNumberish
|
|
6
|
+
BigNumberish,
|
|
7
|
+
ETransactionStatus,
|
|
8
|
+
ETransactionExecutionStatus
|
|
7
9
|
} from "starknet";
|
|
8
10
|
import {StarknetSigner} from "../../wallet/StarknetSigner";
|
|
9
11
|
import {calculateHash, timeoutPromise, toBigInt, toHex, tryWithRetries} from "../../../utils/Utils";
|
|
@@ -21,6 +23,8 @@ export type StarknetTx = ({
|
|
|
21
23
|
txId?: string
|
|
22
24
|
};
|
|
23
25
|
|
|
26
|
+
const MAX_UNCONFIRMED_TXS = 25;
|
|
27
|
+
|
|
24
28
|
export class StarknetTransactions extends StarknetModule {
|
|
25
29
|
|
|
26
30
|
private readonly latestConfirmedNonces: {[address: string]: bigint} = {};
|
|
@@ -178,13 +182,17 @@ export class StarknetTransactions extends StarknetModule {
|
|
|
178
182
|
|
|
179
183
|
const txIds: string[] = [];
|
|
180
184
|
if(parallel) {
|
|
181
|
-
|
|
185
|
+
let promises: Promise<void>[] = [];
|
|
182
186
|
for(let i=0;i<txs.length;i++) {
|
|
183
187
|
const signedTx = txs[i];
|
|
184
188
|
const txId = await this.sendSignedTransaction(signedTx, onBeforePublish, signer);
|
|
185
189
|
if(waitForConfirmation) promises.push(this.confirmTransaction(signedTx, abortSignal));
|
|
186
190
|
txIds.push(txId);
|
|
187
191
|
this.logger.debug("sendAndConfirm(): transaction sent ("+(i+1)+"/"+txs.length+"): "+signedTx.txId);
|
|
192
|
+
if(promises.length >= MAX_UNCONFIRMED_TXS) {
|
|
193
|
+
await Promise.all(promises);
|
|
194
|
+
promises = [];
|
|
195
|
+
}
|
|
188
196
|
}
|
|
189
197
|
if(promises.length>0) await Promise.all(promises);
|
|
190
198
|
} else {
|
|
@@ -247,9 +255,9 @@ export class StarknetTransactions extends StarknetModule {
|
|
|
247
255
|
throw e;
|
|
248
256
|
});
|
|
249
257
|
if(status==null) return "not_found";
|
|
250
|
-
if(status.finality_status===
|
|
251
|
-
if(status.finality_status===
|
|
252
|
-
if(status.execution_status===
|
|
258
|
+
if(status.finality_status===ETransactionStatus.RECEIVED) return "pending";
|
|
259
|
+
if(status.finality_status===ETransactionStatus.REJECTED) return "rejected";
|
|
260
|
+
if(status.execution_status===ETransactionExecutionStatus.SUCCEEDED){
|
|
253
261
|
return "success";
|
|
254
262
|
}
|
|
255
263
|
return "reverted";
|
|
@@ -19,7 +19,11 @@ export class StarknetContractBase<T extends Abi> {
|
|
|
19
19
|
contractAbi: T
|
|
20
20
|
) {
|
|
21
21
|
this.Chain = chainInterface;
|
|
22
|
-
this.contract = new Contract(
|
|
22
|
+
this.contract = new Contract({
|
|
23
|
+
abi: contractAbi,
|
|
24
|
+
address: contractAddress,
|
|
25
|
+
providerOrAccount: chainInterface.provider
|
|
26
|
+
}).typedv2(contractAbi);
|
|
23
27
|
this.Events = new StarknetContractEvents(chainInterface, this, contractAbi);
|
|
24
28
|
}
|
|
25
29
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {Abi} from "abi-wan-kanabi";
|
|
2
2
|
import {EventToPrimitiveType, ExtractAbiEventNames} from "abi-wan-kanabi/dist/kanabi";
|
|
3
3
|
import {StarknetEvent, StarknetEvents} from "../../chain/modules/StarknetEvents";
|
|
4
|
-
import {CallData, events, hash} from "starknet";
|
|
4
|
+
import {CallData, events, hash, createAbiParser} from "starknet";
|
|
5
5
|
import {StarknetContractBase} from "../StarknetContractBase";
|
|
6
6
|
import {toHex} from "../../../utils/Utils";
|
|
7
7
|
import {StarknetChainInterface} from "../../chain/StarknetChainInterface";
|
|
@@ -32,7 +32,7 @@ export class StarknetContractEvents<TAbi extends Abi> extends StarknetEvents {
|
|
|
32
32
|
const abiStructs = CallData.getAbiStruct(this.abi);
|
|
33
33
|
const abiEnums = CallData.getAbiEnum(this.abi);
|
|
34
34
|
|
|
35
|
-
const result = events.parseEvents(blockEvents, abiEvents, abiStructs, abiEnums);
|
|
35
|
+
const result = events.parseEvents(blockEvents, abiEvents, abiStructs, abiEnums, createAbiParser(this.abi));
|
|
36
36
|
if(result.length!==blockEvents.length) throw new Error("Invalid event detected, please check provided ABI");
|
|
37
37
|
return result.map((value, index) => {
|
|
38
38
|
const starknetEvent = blockEvents[index];
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
toHex
|
|
18
18
|
} from "../../utils/Utils";
|
|
19
19
|
import {StarknetSwapContract} from "../swaps/StarknetSwapContract";
|
|
20
|
-
import {BigNumberish, hash, Provider} from "starknet";
|
|
20
|
+
import {BigNumberish, BlockTag, hash, Provider} from "starknet";
|
|
21
21
|
import {StarknetAbiEvent} from "../contract/modules/StarknetContractEvents";
|
|
22
22
|
import {EscrowManagerAbiType} from "../swaps/EscrowManagerAbi";
|
|
23
23
|
import {ExtractAbiFunctionNames} from "abi-wan-kanabi/dist/kanabi";
|
|
@@ -229,7 +229,6 @@ export class StarknetChainEventsBrowser implements ChainEvents<StarknetSwapData>
|
|
|
229
229
|
* @param events
|
|
230
230
|
* @param currentBlockNumber
|
|
231
231
|
* @param currentBlockTimestamp
|
|
232
|
-
* @param pendingEventTime
|
|
233
232
|
* @protected
|
|
234
233
|
*/
|
|
235
234
|
protected async processEvents(
|
|
@@ -241,8 +240,7 @@ export class StarknetChainEventsBrowser implements ChainEvents<StarknetSwapData>
|
|
|
241
240
|
"spv_swap_vault::events::Opened" | "spv_swap_vault::events::Deposited" | "spv_swap_vault::events::Fronted" | "spv_swap_vault::events::Claimed" | "spv_swap_vault::events::Closed"
|
|
242
241
|
>)[],
|
|
243
242
|
currentBlockNumber: number,
|
|
244
|
-
currentBlockTimestamp: number
|
|
245
|
-
pendingEventTime: number
|
|
243
|
+
currentBlockTimestamp: number
|
|
246
244
|
) {
|
|
247
245
|
const blockTimestampsCache: {[blockNumber: string]: number} = {};
|
|
248
246
|
const getBlockTimestamp: (blockNumber: number) => Promise<number> = async (blockNumber: number)=> {
|
|
@@ -283,7 +281,9 @@ export class StarknetChainEventsBrowser implements ChainEvents<StarknetSwapData>
|
|
|
283
281
|
break;
|
|
284
282
|
}
|
|
285
283
|
if(parsedEvent==null) continue;
|
|
286
|
-
|
|
284
|
+
//We are not trusting pre-confs for events, so this shall never happen
|
|
285
|
+
if(event.blockNumber==null) throw new Error("Event block number cannot be null!");
|
|
286
|
+
const timestamp = await getBlockTimestamp(event.blockNumber);
|
|
287
287
|
parsedEvent.meta = {
|
|
288
288
|
blockTime: timestamp,
|
|
289
289
|
txId: event.txHash,
|
|
@@ -315,7 +315,7 @@ export class StarknetChainEventsBrowser implements ChainEvents<StarknetSwapData>
|
|
|
315
315
|
}
|
|
316
316
|
}
|
|
317
317
|
if(events.length>0) {
|
|
318
|
-
await this.processEvents(events, currentBlock?.block_number, currentBlock?.timestamp
|
|
318
|
+
await this.processEvents(events, currentBlock?.block_number, currentBlock?.timestamp);
|
|
319
319
|
lastTxHash = events[events.length-1].txHash;
|
|
320
320
|
}
|
|
321
321
|
return lastTxHash;
|
|
@@ -339,7 +339,7 @@ export class StarknetChainEventsBrowser implements ChainEvents<StarknetSwapData>
|
|
|
339
339
|
}
|
|
340
340
|
}
|
|
341
341
|
if(events.length>0) {
|
|
342
|
-
await this.processEvents(events, currentBlock?.block_number, currentBlock?.timestamp
|
|
342
|
+
await this.processEvents(events, currentBlock?.block_number, currentBlock?.timestamp);
|
|
343
343
|
lastTxHash = events[events.length-1].txHash;
|
|
344
344
|
}
|
|
345
345
|
return lastTxHash;
|
|
@@ -348,8 +348,8 @@ export class StarknetChainEventsBrowser implements ChainEvents<StarknetSwapData>
|
|
|
348
348
|
protected async checkEvents(lastBlockNumber: number, lastTxHashes: string[]): Promise<{txHashes: string[], blockNumber: number}> {
|
|
349
349
|
lastTxHashes ??= [];
|
|
350
350
|
|
|
351
|
-
const currentBlock = await this.provider.getBlockWithTxHashes(
|
|
352
|
-
const currentBlockNumber: number =
|
|
351
|
+
const currentBlock = await this.provider.getBlockWithTxHashes(BlockTag.LATEST);
|
|
352
|
+
const currentBlockNumber: number = currentBlock.block_number;
|
|
353
353
|
|
|
354
354
|
lastTxHashes[0] = await this.checkEventsEcrowManager(lastTxHashes[0], lastBlockNumber, currentBlock as any);
|
|
355
355
|
lastTxHashes[1] = await this.checkEventsSpvVaults(lastTxHashes[1], lastBlockNumber, currentBlock as any);
|
|
@@ -4,7 +4,7 @@ import {Buffer} from "buffer";
|
|
|
4
4
|
import {StarknetSwapData} from "../StarknetSwapData";
|
|
5
5
|
import {StarknetAction} from "../../chain/StarknetAction";
|
|
6
6
|
import {StarknetSwapModule} from "../StarknetSwapModule";
|
|
7
|
-
import {BigNumberish, cairo} from "starknet";
|
|
7
|
+
import {BigNumberish, cairo, BlockTag} from "starknet";
|
|
8
8
|
import {StarknetSigner} from "../../wallet/StarknetSigner";
|
|
9
9
|
import {StarknetFees} from "../../chain/modules/StarknetFees";
|
|
10
10
|
import {StarknetTx} from "../../chain/modules/StarknetTransactions";
|
|
@@ -74,7 +74,7 @@ export class StarknetSwapInit extends StarknetSwapModule {
|
|
|
74
74
|
|
|
75
75
|
public async preFetchForInitSignatureVerification(): Promise<StarknetPreFetchVerification> {
|
|
76
76
|
return {
|
|
77
|
-
pendingBlockTime: await this.root.Blocks.getBlockTime(
|
|
77
|
+
pendingBlockTime: await this.root.Blocks.getBlockTime(BlockTag.PRE_CONFIRMED)
|
|
78
78
|
};
|
|
79
79
|
}
|
|
80
80
|
|
|
@@ -162,7 +162,7 @@ export class StarknetSwapInit extends StarknetSwapModule {
|
|
|
162
162
|
const timeoutBN = BigInt(timeout);
|
|
163
163
|
const isExpired = (timeoutBN - currentTimestamp) < BigInt(this.contract.authGracePeriod);
|
|
164
164
|
if (isExpired) throw new SignatureVerificationError("Authorization expired!");
|
|
165
|
-
if(await this.
|
|
165
|
+
if(await this.isSignatureSoftExpired(timeout, preFetchData)) throw new SignatureVerificationError("Authorization expired!");
|
|
166
166
|
|
|
167
167
|
const valid = await this.root.Signatures.isValidSignature(signature, signer, Initialize, "Initialize", {
|
|
168
168
|
"Swap hash": "0x"+swapData.getEscrowHash(),
|
|
@@ -214,13 +214,13 @@ export class StarknetSwapInit extends StarknetSwapModule {
|
|
|
214
214
|
}
|
|
215
215
|
|
|
216
216
|
/**
|
|
217
|
-
* Checks whether signature is expired
|
|
217
|
+
* Checks whether signature is soft expired, compares the timestamp to the current "pre-confirmed" block timestamp
|
|
218
218
|
*
|
|
219
219
|
* @param timeout
|
|
220
220
|
* @param preFetchData
|
|
221
221
|
* @public
|
|
222
222
|
*/
|
|
223
|
-
public async
|
|
223
|
+
public async isSignatureSoftExpired(
|
|
224
224
|
timeout: string,
|
|
225
225
|
preFetchData?: StarknetPreFetchVerification
|
|
226
226
|
): Promise<boolean> {
|
|
@@ -230,6 +230,19 @@ export class StarknetSwapInit extends StarknetSwapModule {
|
|
|
230
230
|
return preFetchData.pendingBlockTime > parseInt(timeout);
|
|
231
231
|
}
|
|
232
232
|
|
|
233
|
+
/**
|
|
234
|
+
* Checks whether signature is expired for good, compares the timestamp to the current "latest" block timestamp
|
|
235
|
+
*
|
|
236
|
+
* @param timeout
|
|
237
|
+
* @public
|
|
238
|
+
*/
|
|
239
|
+
public async isSignatureExpired(
|
|
240
|
+
timeout: string
|
|
241
|
+
): Promise<boolean> {
|
|
242
|
+
const blockTime = await this.root.Blocks.getBlockTime(BlockTag.LATEST);
|
|
243
|
+
return blockTime > parseInt(timeout);
|
|
244
|
+
}
|
|
245
|
+
|
|
233
246
|
/**
|
|
234
247
|
* Creates init transaction with a valid signature from an LP
|
|
235
248
|
*
|
|
@@ -19,7 +19,12 @@ export class StarknetKeypairWallet extends Account {
|
|
|
19
19
|
OZaccountConstructorCallData,
|
|
20
20
|
0
|
|
21
21
|
);
|
|
22
|
-
super(
|
|
22
|
+
super({
|
|
23
|
+
provider,
|
|
24
|
+
address: OZcontractAddress,
|
|
25
|
+
signer: privateKey,
|
|
26
|
+
cairoVersion: "1"
|
|
27
|
+
});
|
|
23
28
|
this.publicKey = publicKey;
|
|
24
29
|
}
|
|
25
30
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {AbstractSigner} from "@atomiqlabs/base";
|
|
2
|
-
import {Account, DeployAccountContractPayload} from "starknet";
|
|
2
|
+
import {Account, DeployAccountContractPayload, BlockTag} from "starknet";
|
|
3
3
|
import {toHex} from "../../utils/Utils";
|
|
4
4
|
|
|
5
5
|
export class StarknetSigner implements AbstractSigner {
|
|
@@ -27,7 +27,7 @@ export class StarknetSigner implements AbstractSigner {
|
|
|
27
27
|
//TODO: Introduce proper nonce management!
|
|
28
28
|
async getNonce(): Promise<bigint> {
|
|
29
29
|
try {
|
|
30
|
-
return BigInt(await this.account.getNonceForAddress(this.getAddress(),
|
|
30
|
+
return BigInt(await this.account.getNonceForAddress(this.getAddress(), BlockTag.PRE_CONFIRMED));
|
|
31
31
|
} catch (e) {
|
|
32
32
|
if(e.message!=null && e.message.includes("20: Contract not found")) {
|
|
33
33
|
return BigInt(0);
|
package/src/utils/Utils.ts
CHANGED
|
@@ -120,7 +120,6 @@ export function calculateHash(tx: StarknetTx): string {
|
|
|
120
120
|
return tx.txId = hash.calculateDeployAccountTransactionHash({
|
|
121
121
|
contractAddress: tx.tx.contractAddress,
|
|
122
122
|
classHash: tx.signed.classHash,
|
|
123
|
-
constructorCalldata: deployAccountData,
|
|
124
123
|
compiledConstructorCalldata: deployAccountData,
|
|
125
124
|
salt: tx.signed.addressSalt,
|
|
126
125
|
...commonData
|