@atomiqlabs/chain-evm 2.1.12 → 2.1.14
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 +75 -0
- package/dist/chains/EVMOptions.d.ts +66 -0
- package/dist/chains/EVMOptions.js +2 -0
- package/dist/chains/alpen/AlpenInitializer.d.ts +3 -30
- package/dist/chains/alpen/AlpenInitializer.js +3 -3
- package/dist/chains/botanix/BotanixInitializer.d.ts +3 -30
- package/dist/chains/botanix/BotanixInitializer.js +3 -3
- package/dist/chains/citrea/CitreaBtcRelay.d.ts +5 -0
- package/dist/chains/citrea/CitreaBtcRelay.js +7 -2
- package/dist/chains/citrea/CitreaFees.d.ts +3 -5
- package/dist/chains/citrea/CitreaFees.js +3 -5
- package/dist/chains/citrea/CitreaInitializer.d.ts +3 -29
- package/dist/chains/citrea/CitreaInitializer.js +3 -3
- package/dist/chains/citrea/CitreaSpvVaultContract.d.ts +5 -0
- package/dist/chains/citrea/CitreaSpvVaultContract.js +7 -2
- package/dist/chains/citrea/CitreaSwapContract.d.ts +7 -2
- package/dist/chains/citrea/CitreaSwapContract.js +10 -5
- package/dist/chains/citrea/CitreaTokens.d.ts +5 -0
- package/dist/chains/citrea/CitreaTokens.js +5 -0
- package/dist/chains/goat/GoatInitializer.d.ts +3 -30
- package/dist/chains/goat/GoatInitializer.js +3 -3
- package/dist/evm/btcrelay/EVMBtcRelay.d.ts +41 -10
- package/dist/evm/btcrelay/EVMBtcRelay.js +50 -18
- package/dist/evm/btcrelay/headers/EVMBtcHeader.d.ts +53 -7
- package/dist/evm/btcrelay/headers/EVMBtcHeader.js +43 -5
- package/dist/evm/btcrelay/headers/EVMBtcStoredHeader.d.ts +53 -8
- package/dist/evm/btcrelay/headers/EVMBtcStoredHeader.js +41 -1
- package/dist/evm/chain/EVMChainInterface.d.ts +57 -2
- package/dist/evm/chain/EVMChainInterface.js +7 -7
- package/dist/evm/chain/EVMModule.d.ts +5 -0
- package/dist/evm/chain/EVMModule.js +6 -1
- package/dist/evm/chain/modules/EVMBlocks.d.ts +7 -0
- package/dist/evm/chain/modules/EVMBlocks.js +2 -0
- package/dist/evm/chain/modules/EVMEvents.js +19 -19
- package/dist/evm/chain/modules/EVMFees.d.ts +41 -5
- package/dist/evm/chain/modules/EVMFees.js +24 -5
- package/dist/evm/chain/modules/EVMTokens.d.ts +1 -1
- package/dist/evm/chain/modules/EVMTokens.js +1 -1
- package/dist/evm/chain/modules/EVMTransactions.d.ts +20 -2
- package/dist/evm/chain/modules/EVMTransactions.js +11 -8
- package/dist/evm/contract/EVMContractBase.d.ts +28 -10
- package/dist/evm/contract/EVMContractBase.js +9 -18
- package/dist/evm/contract/EVMContractModule.d.ts +5 -0
- package/dist/evm/contract/EVMContractModule.js +5 -0
- package/dist/evm/contract/modules/EVMContractEvents.d.ts +7 -1
- package/dist/evm/contract/modules/EVMContractEvents.js +23 -3
- package/dist/evm/events/EVMChainEvents.d.ts +8 -0
- package/dist/evm/events/EVMChainEvents.js +8 -0
- package/dist/evm/events/EVMChainEventsBrowser.d.ts +87 -19
- package/dist/evm/events/EVMChainEventsBrowser.js +53 -18
- package/dist/evm/providers/JsonRpcProviderWithRetries.d.ts +9 -0
- package/dist/evm/providers/JsonRpcProviderWithRetries.js +9 -0
- package/dist/evm/providers/ReconnectingWebSocketProvider.d.ts +5 -0
- package/dist/evm/providers/ReconnectingWebSocketProvider.js +5 -0
- package/dist/evm/providers/WebSocketProviderWithRetries.d.ts +9 -0
- package/dist/evm/providers/WebSocketProviderWithRetries.js +9 -0
- package/dist/evm/spv_swap/EVMSpvVaultContract.d.ts +46 -21
- package/dist/evm/spv_swap/EVMSpvVaultContract.js +61 -23
- package/dist/evm/spv_swap/EVMSpvVaultData.d.ts +57 -2
- package/dist/evm/spv_swap/EVMSpvVaultData.js +57 -2
- package/dist/evm/spv_swap/EVMSpvWithdrawalData.d.ts +12 -0
- package/dist/evm/spv_swap/EVMSpvWithdrawalData.js +12 -0
- package/dist/evm/swaps/EVMSwapContract.d.ts +58 -13
- package/dist/evm/swaps/EVMSwapContract.js +81 -54
- package/dist/evm/swaps/EVMSwapData.d.ts +27 -6
- package/dist/evm/swaps/EVMSwapData.js +26 -0
- package/dist/evm/swaps/EVMSwapModule.d.ts +5 -0
- package/dist/evm/swaps/EVMSwapModule.js +5 -0
- package/dist/evm/swaps/handlers/IHandler.d.ts +5 -0
- package/dist/evm/swaps/handlers/claim/ClaimHandlers.d.ts +15 -0
- package/dist/evm/swaps/handlers/claim/ClaimHandlers.js +5 -0
- package/dist/evm/swaps/handlers/claim/btc/BitcoinNoncedOutputClaimHandler.d.ts +5 -0
- package/dist/evm/swaps/handlers/claim/btc/BitcoinOutputClaimHandler.d.ts +10 -0
- package/dist/evm/swaps/handlers/claim/btc/BitcoinTxIdClaimHandler.d.ts +5 -0
- package/dist/evm/swaps/handlers/claim/btc/IBitcoinClaimHandler.d.ts +15 -0
- package/dist/evm/swaps/handlers/claim/btc/IBitcoinClaimHandler.js +7 -2
- package/dist/evm/swaps/modules/EVMLpVault.d.ts +5 -0
- package/dist/evm/swaps/modules/EVMLpVault.js +9 -4
- package/dist/evm/swaps/modules/EVMSwapClaim.d.ts +7 -2
- package/dist/evm/swaps/modules/EVMSwapClaim.js +11 -6
- package/dist/evm/swaps/modules/EVMSwapInit.d.ts +10 -0
- package/dist/evm/swaps/modules/EVMSwapInit.js +11 -6
- package/dist/evm/swaps/modules/EVMSwapRefund.d.ts +5 -0
- package/dist/evm/swaps/modules/EVMSwapRefund.js +9 -4
- package/dist/evm/wallet/EVMBrowserSigner.d.ts +22 -2
- package/dist/evm/wallet/EVMBrowserSigner.js +40 -2
- package/dist/evm/wallet/EVMPersistentSigner.d.ts +13 -2
- package/dist/evm/wallet/EVMPersistentSigner.js +13 -1
- package/dist/evm/wallet/EVMSigner.d.ts +30 -1
- package/dist/evm/wallet/EVMSigner.js +34 -1
- package/dist/index.d.ts +71 -0
- package/dist/index.js +70 -0
- package/dist/node/index.d.ts +10 -0
- package/dist/node/index.js +15 -0
- package/dist/utils/Utils.d.ts +50 -0
- package/dist/utils/Utils.js +45 -0
- package/node/index.d.ts +1 -0
- package/node/index.js +3 -0
- package/package.json +4 -3
- package/src/chains/EVMOptions.ts +70 -0
- package/src/chains/alpen/AlpenInitializer.ts +5 -27
- package/src/chains/botanix/BotanixChainType.ts +5 -5
- package/src/chains/botanix/BotanixInitializer.ts +5 -27
- package/src/chains/citrea/CitreaBtcRelay.ts +8 -3
- package/src/chains/citrea/CitreaFees.ts +3 -6
- package/src/chains/citrea/CitreaInitializer.ts +5 -27
- package/src/chains/citrea/CitreaSpvVaultContract.ts +7 -2
- package/src/chains/citrea/CitreaSwapContract.ts +11 -6
- package/src/chains/citrea/CitreaTokens.ts +6 -1
- package/src/chains/goat/GoatChainType.ts +5 -5
- package/src/chains/goat/GoatInitializer.ts +3 -25
- package/src/evm/btcrelay/EVMBtcRelay.ts +54 -22
- package/src/evm/btcrelay/headers/EVMBtcHeader.ts +60 -13
- package/src/evm/btcrelay/headers/EVMBtcStoredHeader.ts +55 -10
- package/src/evm/chain/EVMChainInterface.ts +66 -14
- package/src/evm/chain/EVMModule.ts +6 -1
- package/src/evm/chain/modules/EVMBlocks.ts +7 -0
- package/src/evm/chain/modules/EVMEvents.ts +19 -19
- package/src/evm/chain/modules/EVMFees.ts +41 -5
- package/src/evm/chain/modules/EVMTokens.ts +1 -1
- package/src/evm/chain/modules/EVMTransactions.ts +27 -8
- package/src/evm/contract/EVMContractBase.ts +29 -24
- package/src/evm/contract/EVMContractModule.ts +5 -0
- package/src/evm/contract/modules/EVMContractEvents.ts +27 -8
- package/src/evm/events/EVMChainEvents.ts +8 -0
- package/src/evm/events/EVMChainEventsBrowser.ts +103 -29
- package/src/evm/providers/JsonRpcProviderWithRetries.ts +10 -1
- package/src/evm/providers/ReconnectingWebSocketProvider.ts +6 -1
- package/src/evm/providers/WebSocketProviderWithRetries.ts +10 -1
- package/src/evm/spv_swap/EVMSpvVaultContract.ts +72 -32
- package/src/evm/spv_swap/EVMSpvVaultData.ts +57 -2
- package/src/evm/spv_swap/EVMSpvWithdrawalData.ts +12 -0
- package/src/evm/swaps/EVMSwapContract.ts +108 -63
- package/src/evm/swaps/EVMSwapData.ts +27 -1
- package/src/evm/swaps/EVMSwapModule.ts +5 -0
- package/src/evm/swaps/handlers/IHandler.ts +5 -0
- package/src/evm/swaps/handlers/claim/ClaimHandlers.ts +15 -0
- package/src/evm/swaps/handlers/claim/btc/BitcoinNoncedOutputClaimHandler.ts +5 -0
- package/src/evm/swaps/handlers/claim/btc/BitcoinOutputClaimHandler.ts +10 -0
- package/src/evm/swaps/handlers/claim/btc/BitcoinTxIdClaimHandler.ts +5 -0
- package/src/evm/swaps/handlers/claim/btc/IBitcoinClaimHandler.ts +17 -2
- package/src/evm/swaps/modules/EVMLpVault.ts +10 -5
- package/src/evm/swaps/modules/EVMSwapClaim.ts +12 -7
- package/src/evm/swaps/modules/EVMSwapInit.ts +17 -7
- package/src/evm/swaps/modules/EVMSwapRefund.ts +9 -4
- package/src/evm/wallet/EVMBrowserSigner.ts +44 -5
- package/src/evm/wallet/EVMPersistentSigner.ts +14 -2
- package/src/evm/wallet/EVMSigner.ts +37 -1
- package/src/index.ts +72 -0
- package/src/node/index.ts +10 -0
- package/src/utils/Utils.ts +50 -1
|
@@ -8,11 +8,21 @@ import {keccak256} from "ethers";
|
|
|
8
8
|
import {Buffer} from "buffer";
|
|
9
9
|
import {EVMSwapData} from "../../../EVMSwapData";
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Common commitment fields used by all bitcoin-based claim handlers.
|
|
13
|
+
*
|
|
14
|
+
* @category Internal/Handlers
|
|
15
|
+
*/
|
|
11
16
|
export type BitcoinCommitmentData = {
|
|
12
17
|
btcRelay: EVMBtcRelay<any>,
|
|
13
18
|
confirmations: number
|
|
14
19
|
}
|
|
15
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Common witness input for bitcoin-based claim handlers.
|
|
23
|
+
*
|
|
24
|
+
* @category Internal/Handlers
|
|
25
|
+
*/
|
|
16
26
|
export type BitcoinWitnessData = {
|
|
17
27
|
tx: { blockhash: string, confirmations: number, txid: string, hex: string, height: number },
|
|
18
28
|
requiredConfirmations: number,
|
|
@@ -23,6 +33,11 @@ export type BitcoinWitnessData = {
|
|
|
23
33
|
|
|
24
34
|
const logger = getLogger("IBitcoinClaimHandler: ");
|
|
25
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Shared base implementation for bitcoin-backed claim handlers.
|
|
38
|
+
*
|
|
39
|
+
* @category Internal/Handlers
|
|
40
|
+
*/
|
|
26
41
|
export abstract class IBitcoinClaimHandler<C, W extends BitcoinWitnessData> implements IClaimHandler<C & BitcoinCommitmentData, W> {
|
|
27
42
|
|
|
28
43
|
public readonly address: string;
|
|
@@ -38,7 +53,7 @@ export abstract class IBitcoinClaimHandler<C, W extends BitcoinWitnessData> impl
|
|
|
38
53
|
protected serializeCommitment(data: BitcoinCommitmentData): Buffer {
|
|
39
54
|
const buffer = Buffer.alloc(24);
|
|
40
55
|
buffer.writeUint32BE(data.confirmations, 0);
|
|
41
|
-
Buffer.from(data.btcRelay.
|
|
56
|
+
Buffer.from(data.btcRelay._contractAddress.substring(2), "hex").copy(buffer, 4, 0, 20);
|
|
42
57
|
return buffer;
|
|
43
58
|
}
|
|
44
59
|
|
|
@@ -68,7 +83,7 @@ export abstract class IBitcoinClaimHandler<C, W extends BitcoinWitnessData> impl
|
|
|
68
83
|
|
|
69
84
|
if(!swapData.isClaimData(commitmentHash)) throw new Error("Invalid commit data");
|
|
70
85
|
|
|
71
|
-
const merkleProof = await btcRelay.
|
|
86
|
+
const merkleProof = await btcRelay._bitcoinRpc.getMerkleProof(tx.txid, tx.blockhash);
|
|
72
87
|
if(merkleProof==null) throw new Error(`Failed to generate merkle proof for tx: ${tx.txid}!`);
|
|
73
88
|
logger.debug("getWitness(): merkle proof computed: ", merkleProof);
|
|
74
89
|
|
|
@@ -4,6 +4,11 @@ import {TransactionRequest} from "ethers";
|
|
|
4
4
|
import {EVMFees} from "../../chain/modules/EVMFees";
|
|
5
5
|
import {EVMTx} from "../../chain/modules/EVMTransactions";
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* LP vault helper for intermediary balances, reputation and LP deposit/withdraw transactions.
|
|
9
|
+
*
|
|
10
|
+
* @category Internal/Swaps
|
|
11
|
+
*/
|
|
7
12
|
export class EVMLpVault extends EVMSwapModule {
|
|
8
13
|
|
|
9
14
|
private static readonly GasCosts = {
|
|
@@ -71,13 +76,13 @@ export class EVMLpVault extends EVMSwapModule {
|
|
|
71
76
|
* @param token
|
|
72
77
|
*/
|
|
73
78
|
public async getIntermediaryReputation(address: string, token: string): Promise<IntermediaryReputationType> {
|
|
74
|
-
const filter = Object.keys(this.contract.
|
|
79
|
+
const filter = Object.keys(this.contract._claimHandlersByAddress).map(claimHandler => ({owner: address, token, claimHandler}));
|
|
75
80
|
const resp = await this.swapContract.getReputation(filter);
|
|
76
81
|
if(resp.length!==filter.length) throw new Error("getIntermediaryReputation(): Invalid response length");
|
|
77
82
|
|
|
78
83
|
const result: any = {};
|
|
79
|
-
Object.keys(this.contract.
|
|
80
|
-
const handler = this.contract.
|
|
84
|
+
Object.keys(this.contract._claimHandlersByAddress).forEach((address, index) => {
|
|
85
|
+
const handler = this.contract._claimHandlersByAddress[address.toLowerCase()];
|
|
81
86
|
const handlerResp = resp[index];
|
|
82
87
|
result[handler.getType()] = {
|
|
83
88
|
successVolume: handlerResp[0].amount,
|
|
@@ -140,7 +145,7 @@ export class EVMLpVault extends EVMSwapModule {
|
|
|
140
145
|
|
|
141
146
|
//Approve first
|
|
142
147
|
if(token.toLowerCase()!==this.root.getNativeCurrencyAddress().toLowerCase()) {
|
|
143
|
-
const approveTx = await this.root.Tokens.checkAndGetApproveTx(signer, token, amount, this.contract.
|
|
148
|
+
const approveTx = await this.root.Tokens.checkAndGetApproveTx(signer, token, amount, this.contract._contractAddress, feeRate);
|
|
144
149
|
if(approveTx!=null) txs.push(approveTx);
|
|
145
150
|
}
|
|
146
151
|
|
|
@@ -152,4 +157,4 @@ export class EVMLpVault extends EVMSwapModule {
|
|
|
152
157
|
return txs;
|
|
153
158
|
}
|
|
154
159
|
|
|
155
|
-
}
|
|
160
|
+
}
|
|
@@ -10,6 +10,11 @@ import {EVMFees} from "../../chain/modules/EVMFees";
|
|
|
10
10
|
import {EVMTx} from "../../chain/modules/EVMTransactions";
|
|
11
11
|
import {EVMBtcStoredHeader} from "../../btcrelay/headers/EVMBtcStoredHeader";
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Swap claim helper for HTLC and BTC on-chain claim paths.
|
|
15
|
+
*
|
|
16
|
+
* @category Internal/Swaps
|
|
17
|
+
*/
|
|
13
18
|
export class EVMSwapClaim extends EVMSwapModule {
|
|
14
19
|
|
|
15
20
|
private static readonly GasCosts = {
|
|
@@ -67,7 +72,7 @@ export class EVMSwapClaim extends EVMSwapModule {
|
|
|
67
72
|
throw new SwapDataVerificationError("Not enough time to reliably pay the invoice");
|
|
68
73
|
}
|
|
69
74
|
|
|
70
|
-
const claimHandler: IClaimHandler<Buffer, string> = this.contract.
|
|
75
|
+
const claimHandler: IClaimHandler<Buffer, string> = this.contract._claimHandlersByAddress[swapData.claimHandler.toLowerCase()];
|
|
71
76
|
if(claimHandler==null) throw new SwapDataVerificationError("Unknown claim handler!");
|
|
72
77
|
if(claimHandler.getType()!==ChainSwapType.HTLC) throw new SwapDataVerificationError("Invalid claim handler!");
|
|
73
78
|
|
|
@@ -89,7 +94,7 @@ export class EVMSwapClaim extends EVMSwapModule {
|
|
|
89
94
|
* @param tx bitcoin transaction that satisfies the swap condition
|
|
90
95
|
* @param requiredConfirmations
|
|
91
96
|
* @param vout vout of the bitcoin transaction that satisfies the swap condition
|
|
92
|
-
* @param commitedHeader
|
|
97
|
+
* @param commitedHeader committed header data from BTC relay (fetched internally if null)
|
|
93
98
|
* @param synchronizer optional synchronizer to use in case we need to sync up the btc relay ourselves
|
|
94
99
|
* @param feeRate fee rate to be used for the transactions
|
|
95
100
|
*/
|
|
@@ -103,7 +108,7 @@ export class EVMSwapClaim extends EVMSwapModule {
|
|
|
103
108
|
synchronizer?: RelaySynchronizer<EVMBtcStoredHeader, EVMTx, any>,
|
|
104
109
|
feeRate?: string
|
|
105
110
|
): Promise<EVMTx[]> {
|
|
106
|
-
const claimHandler: IClaimHandler<any, BitcoinOutputWitnessData | BitcoinWitnessData> = this.contract.
|
|
111
|
+
const claimHandler: IClaimHandler<any, BitcoinOutputWitnessData | BitcoinWitnessData> = this.contract._claimHandlersByAddress[swapData.claimHandler.toLowerCase()];
|
|
107
112
|
if(claimHandler==null) throw new SwapDataVerificationError("Unknown claim handler!");
|
|
108
113
|
if(
|
|
109
114
|
claimHandler.getType()!==ChainSwapType.CHAIN_NONCED &&
|
|
@@ -118,7 +123,7 @@ export class EVMSwapClaim extends EVMSwapModule {
|
|
|
118
123
|
vout,
|
|
119
124
|
requiredConfirmations,
|
|
120
125
|
commitedHeader,
|
|
121
|
-
btcRelay: this.contract.
|
|
126
|
+
btcRelay: this.contract._btcRelay,
|
|
122
127
|
synchronizer,
|
|
123
128
|
}, feeRate);
|
|
124
129
|
const claimTx = await this.Claim(signer, swapData, witness, feeRate, claimHandler.getGas(swapData));
|
|
@@ -156,7 +161,7 @@ export class EVMSwapClaim extends EVMSwapModule {
|
|
|
156
161
|
}
|
|
157
162
|
|
|
158
163
|
/**
|
|
159
|
-
*
|
|
164
|
+
* Returns the estimated fee of the claim transaction.
|
|
160
165
|
*/
|
|
161
166
|
public async getClaimFee(swapData: EVMSwapData, feeRate?: string): Promise<bigint> {
|
|
162
167
|
feeRate ??= await this.root.Fees.getFeeRate();
|
|
@@ -164,10 +169,10 @@ export class EVMSwapClaim extends EVMSwapModule {
|
|
|
164
169
|
//TODO: Claim with success action not supported yet!
|
|
165
170
|
let gasRequired = this.getClaimGas(swapData);
|
|
166
171
|
|
|
167
|
-
const claimHandler: IClaimHandler<any, any> = this.contract.
|
|
172
|
+
const claimHandler: IClaimHandler<any, any> = this.contract._claimHandlersByAddress[swapData.claimHandler.toLowerCase()];
|
|
168
173
|
if(claimHandler!=null) gasRequired += claimHandler.getGas(swapData);
|
|
169
174
|
|
|
170
175
|
return EVMFees.getGasFee(gasRequired, feeRate);
|
|
171
176
|
}
|
|
172
177
|
|
|
173
|
-
}
|
|
178
|
+
}
|
|
@@ -6,6 +6,11 @@ import {EVMFees} from "../../chain/modules/EVMFees";
|
|
|
6
6
|
import {EVMSigner} from "../../wallet/EVMSigner";
|
|
7
7
|
import {EVMTx} from "../../chain/modules/EVMTransactions";
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Prefetched values used for initialization signature verification.
|
|
11
|
+
*
|
|
12
|
+
* @category Internal/Swaps
|
|
13
|
+
*/
|
|
9
14
|
export type EVMPreFetchVerification = {
|
|
10
15
|
safeBlockTime: number
|
|
11
16
|
};
|
|
@@ -31,6 +36,11 @@ const Initialize = [
|
|
|
31
36
|
{ name: "extraDataHash", type: "bytes32" }
|
|
32
37
|
];
|
|
33
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Swap initialization helper handling authorization signatures and init transaction construction.
|
|
41
|
+
*
|
|
42
|
+
* @category Internal/Swaps
|
|
43
|
+
*/
|
|
34
44
|
export class EVMSwapInit extends EVMSwapModule {
|
|
35
45
|
|
|
36
46
|
private static readonly GasCosts = {
|
|
@@ -76,7 +86,7 @@ export class EVMSwapInit extends EVMSwapModule {
|
|
|
76
86
|
|
|
77
87
|
public async preFetchForInitSignatureVerification(): Promise<EVMPreFetchVerification> {
|
|
78
88
|
return {
|
|
79
|
-
safeBlockTime: await this.root.Blocks.getBlockTime(this.root.
|
|
89
|
+
safeBlockTime: await this.root.Blocks.getBlockTime(this.root._config.safeBlockTag)
|
|
80
90
|
};
|
|
81
91
|
}
|
|
82
92
|
|
|
@@ -96,7 +106,7 @@ export class EVMSwapInit extends EVMSwapModule {
|
|
|
96
106
|
): Promise<{prefix: string, timeout: string, signature: string}> {
|
|
97
107
|
const authExpiry = Math.floor(Date.now()/1000)+authorizationTimeout;
|
|
98
108
|
|
|
99
|
-
const signature = await this.root.Signatures.signTypedMessage(this.contract.
|
|
109
|
+
const signature = await this.root.Signatures.signTypedMessage(this.contract._contractAddress, signer, Initialize, "Initialize", {
|
|
100
110
|
"swapHash": "0x"+swapData.getEscrowHash(),
|
|
101
111
|
"offerer": swapData.offerer,
|
|
102
112
|
"claimer": swapData.claimer,
|
|
@@ -156,11 +166,11 @@ export class EVMSwapInit extends EVMSwapModule {
|
|
|
156
166
|
|
|
157
167
|
const currentTimestamp = BigInt(Math.floor(Date.now() / 1000));
|
|
158
168
|
const timeoutBN = BigInt(timeout);
|
|
159
|
-
const isExpired = (timeoutBN - currentTimestamp) < BigInt(this.contract.
|
|
169
|
+
const isExpired = (timeoutBN - currentTimestamp) < BigInt(this.contract._authGracePeriod);
|
|
160
170
|
if (isExpired) throw new SignatureVerificationError("Authorization expired!");
|
|
161
171
|
if(await this.isSignatureExpired(timeout, preFetchData)) throw new SignatureVerificationError("Authorization expired!");
|
|
162
172
|
|
|
163
|
-
const valid = await this.root.Signatures.isValidSignature(this.contract.
|
|
173
|
+
const valid = await this.root.Signatures.isValidSignature(this.contract._contractAddress, signature, signer, Initialize, "Initialize", {
|
|
164
174
|
"swapHash": "0x"+swapData.getEscrowHash(),
|
|
165
175
|
"offerer": swapData.offerer,
|
|
166
176
|
"claimer": swapData.claimer,
|
|
@@ -196,7 +206,7 @@ export class EVMSwapInit extends EVMSwapModule {
|
|
|
196
206
|
timeout: string
|
|
197
207
|
): Promise<number> {
|
|
198
208
|
const now = Date.now();
|
|
199
|
-
const timeoutExpiryTime = (parseInt(timeout)-this.contract.
|
|
209
|
+
const timeoutExpiryTime = (parseInt(timeout)-this.contract._authGracePeriod)*1000;
|
|
200
210
|
|
|
201
211
|
if(timeoutExpiryTime<now) return 0;
|
|
202
212
|
|
|
@@ -272,7 +282,7 @@ export class EVMSwapInit extends EVMSwapModule {
|
|
|
272
282
|
}
|
|
273
283
|
|
|
274
284
|
const requiredApprovalTxns = await Promise.all(
|
|
275
|
-
Object.keys(requiredApprovals).map(token => this.root.Tokens.checkAndGetApproveTx(sender, token, requiredApprovals[token], this.contract.
|
|
285
|
+
Object.keys(requiredApprovals).map(token => this.root.Tokens.checkAndGetApproveTx(sender, token, requiredApprovals[token], this.contract._contractAddress, feeRate))
|
|
276
286
|
);
|
|
277
287
|
requiredApprovalTxns.forEach(tx => tx!=null && txs.push(tx));
|
|
278
288
|
|
|
@@ -324,4 +334,4 @@ export class EVMSwapInit extends EVMSwapModule {
|
|
|
324
334
|
|
|
325
335
|
return totalFee;
|
|
326
336
|
}
|
|
327
|
-
}
|
|
337
|
+
}
|
|
@@ -13,6 +13,11 @@ const Refund = [
|
|
|
13
13
|
{ name: "timeout", type: "uint256" }
|
|
14
14
|
];
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Swap refund helper for timeout and cooperative refund flows.
|
|
18
|
+
*
|
|
19
|
+
* @category Internal/Swaps
|
|
20
|
+
*/
|
|
16
21
|
export class EVMSwapRefund extends EVMSwapModule {
|
|
17
22
|
|
|
18
23
|
private static readonly GasCosts = {
|
|
@@ -77,7 +82,7 @@ export class EVMSwapRefund extends EVMSwapModule {
|
|
|
77
82
|
const authPrefix = "refund";
|
|
78
83
|
const authTimeout = Math.floor(Date.now()/1000)+authorizationTimeout;
|
|
79
84
|
|
|
80
|
-
const signature = await this.root.Signatures.signTypedMessage(this.contract.
|
|
85
|
+
const signature = await this.root.Signatures.signTypedMessage(this.contract._contractAddress, signer, Refund, "Refund", {
|
|
81
86
|
"swapHash": "0x"+swapData.getEscrowHash(),
|
|
82
87
|
"timeout": BigInt(authTimeout)
|
|
83
88
|
});
|
|
@@ -100,10 +105,10 @@ export class EVMSwapRefund extends EVMSwapModule {
|
|
|
100
105
|
const expiryTimestamp = BigInt(timeout);
|
|
101
106
|
const currentTimestamp = BigInt(Math.floor(Date.now() / 1000));
|
|
102
107
|
|
|
103
|
-
const isExpired = (expiryTimestamp - currentTimestamp) < BigInt(this.contract.
|
|
108
|
+
const isExpired = (expiryTimestamp - currentTimestamp) < BigInt(this.contract._authGracePeriod);
|
|
104
109
|
if(isExpired) throw new SignatureVerificationError("Authorization expired!");
|
|
105
110
|
|
|
106
|
-
const valid = await this.root.Signatures.isValidSignature(this.contract.
|
|
111
|
+
const valid = await this.root.Signatures.isValidSignature(this.contract._contractAddress, signature, swapData.claimer, Refund, "Refund", {
|
|
107
112
|
"swapHash": "0x"+swapData.getEscrowHash(),
|
|
108
113
|
"timeout": BigInt(expiryTimestamp)
|
|
109
114
|
});
|
|
@@ -131,7 +136,7 @@ export class EVMSwapRefund extends EVMSwapModule {
|
|
|
131
136
|
feeRate?: string,
|
|
132
137
|
witnessData?: T
|
|
133
138
|
): Promise<EVMTx[]> {
|
|
134
|
-
const refundHandler: IHandler<any, T> = this.contract.
|
|
139
|
+
const refundHandler: IHandler<any, T> = this.contract._refundHandlersByAddress[swapData.refundHandler.toLowerCase()];
|
|
135
140
|
if(refundHandler==null) throw new Error("Invalid refund handler");
|
|
136
141
|
|
|
137
142
|
if(check && !await this.contract.isRequestRefundable(swapData.offerer.toString(), swapData)) {
|
|
@@ -1,18 +1,57 @@
|
|
|
1
|
-
import {Signer, TransactionRequest, TransactionResponse} from "ethers";
|
|
1
|
+
import {Signer, TransactionRequest, TransactionResponse, verifyMessage} from "ethers";
|
|
2
2
|
import {EVMSigner} from "./EVMSigner";
|
|
3
3
|
|
|
4
|
-
|
|
5
4
|
/**
|
|
6
|
-
* Browser-based EVM signer for external
|
|
5
|
+
* Browser-based EVM signer, intended for injected/external wallets. This ensures no explicit
|
|
6
|
+
* `signTransaction()` flow is required and transaction submission goes through `sendTransaction()`.
|
|
7
|
+
*
|
|
7
8
|
* @category Wallets
|
|
8
9
|
*/
|
|
9
10
|
export class EVMBrowserSigner extends EVMSigner {
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
private usesECDSADN?: boolean;
|
|
13
|
+
|
|
14
|
+
getReproducibleEntropy?: (appName: string) => Promise<Buffer>;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @param account Signer account to request signatures and send transaction through
|
|
18
|
+
* @param address Signer address
|
|
19
|
+
* @param usesECDSADN Optional flag indicating whether the signer supports signing using ECDSA-DN (deterministic
|
|
20
|
+
* nonce) algorithm, this allows the wallet to produce reproducible entropy. Only pass `true` here if you are
|
|
21
|
+
* 100% sure that the signer supports this!
|
|
22
|
+
*/
|
|
23
|
+
constructor(account: Signer, address: string, usesECDSADN?: boolean) {
|
|
12
24
|
super(account, address, false);
|
|
25
|
+
this.usesECDSADN = usesECDSADN;
|
|
13
26
|
this.signTransaction = undefined;
|
|
27
|
+
if(this.usesECDSADN!==false) {
|
|
28
|
+
this.getReproducibleEntropy = async (appName: string) => {
|
|
29
|
+
if(this.usesECDSADN===false) throw new Error("This wallet doesn't support generating recoverable entropy!");
|
|
30
|
+
|
|
31
|
+
const message = EVMSigner.getReproducibleEntropyMessage(appName);
|
|
32
|
+
const signature = await account.signMessage(message);
|
|
33
|
+
if(this.usesECDSADN!==true) {
|
|
34
|
+
const secondSignature = await account.signMessage(message);
|
|
35
|
+
if(signature!==secondSignature) {
|
|
36
|
+
this.usesECDSADN = false;
|
|
37
|
+
this.getReproducibleEntropy = undefined;
|
|
38
|
+
throw new Error("This wallet doesn't support generating recoverable entropy!");
|
|
39
|
+
}
|
|
40
|
+
this.usesECDSADN = true;
|
|
41
|
+
}
|
|
42
|
+
if(verifyMessage(message, signature)!==address) throw new Error("Invalid wallet signature provided!");
|
|
43
|
+
return Buffer.from(signature.substring(2), "hex");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
14
46
|
}
|
|
15
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Signs and sends the provided EVM transaction.
|
|
50
|
+
* Maps common wallet rejection errors to a consistent user-facing message.
|
|
51
|
+
*
|
|
52
|
+
* @param transaction A transaction to sign and send
|
|
53
|
+
* @param onBeforePublish Optional callback called after signing and before broadcast when available
|
|
54
|
+
*/
|
|
16
55
|
async sendTransaction(transaction: TransactionRequest, onBeforePublish?: (txId: string, rawTx: string) => Promise<void>): Promise<TransactionResponse> {
|
|
17
56
|
try {
|
|
18
57
|
return await super.sendTransaction(transaction, onBeforePublish);
|
|
@@ -23,4 +62,4 @@ export class EVMBrowserSigner extends EVMSigner {
|
|
|
23
62
|
}
|
|
24
63
|
}
|
|
25
64
|
|
|
26
|
-
}
|
|
65
|
+
}
|
|
@@ -16,9 +16,15 @@ const WAIT_BEFORE_BUMP = 15*1000;
|
|
|
16
16
|
const MIN_FEE_INCREASE_ABSOLUTE = 1n*1_000_000_000n; //1GWei
|
|
17
17
|
const MIN_FEE_INCREASE_PPM = 100_000n; // +10%
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* A robust EVM signer implementation with internal nonce management, automatic rebroadcasting and fee bumping.
|
|
21
|
+
* Uses Node.js `fs` to persist transaction data across restarts, so it is intended for backend runtimes.
|
|
22
|
+
*
|
|
23
|
+
* @category Wallets
|
|
24
|
+
*/
|
|
19
25
|
export class EVMPersistentSigner extends EVMSigner {
|
|
20
26
|
|
|
21
|
-
readonly safeBlockTag: EVMBlockTag;
|
|
27
|
+
private readonly safeBlockTag: EVMBlockTag;
|
|
22
28
|
|
|
23
29
|
private pendingTxs: Map<number, {
|
|
24
30
|
txs: Transaction[],
|
|
@@ -58,7 +64,7 @@ export class EVMPersistentSigner extends EVMSigner {
|
|
|
58
64
|
this.minFeeIncreaseAbsolute = minFeeIncreaseAbsolute ?? MIN_FEE_INCREASE_ABSOLUTE;
|
|
59
65
|
this.minFeeIncreasePpm = minFeeIncreasePpm ?? MIN_FEE_INCREASE_PPM;
|
|
60
66
|
this.waitBeforeBump = waitBeforeBumpMillis ?? WAIT_BEFORE_BUMP;
|
|
61
|
-
this.safeBlockTag = chainInterface.
|
|
67
|
+
this.safeBlockTag = chainInterface._config.safeBlockTag;
|
|
62
68
|
this.logger = getLogger("EVMPersistentSigner("+address+"): ");
|
|
63
69
|
}
|
|
64
70
|
|
|
@@ -247,6 +253,9 @@ export class EVMPersistentSigner extends EVMSigner {
|
|
|
247
253
|
}
|
|
248
254
|
}
|
|
249
255
|
|
|
256
|
+
/**
|
|
257
|
+
* @inheritDoc
|
|
258
|
+
*/
|
|
250
259
|
async init(): Promise<void> {
|
|
251
260
|
try {
|
|
252
261
|
await fs.mkdir(this.directory)
|
|
@@ -261,6 +270,9 @@ export class EVMPersistentSigner extends EVMSigner {
|
|
|
261
270
|
this.startFeeBumper();
|
|
262
271
|
}
|
|
263
272
|
|
|
273
|
+
/**
|
|
274
|
+
* @inheritDoc
|
|
275
|
+
*/
|
|
264
276
|
stop(): Promise<void> {
|
|
265
277
|
this.stopped = true;
|
|
266
278
|
if(this.feeBumper!=null) {
|
|
@@ -2,16 +2,46 @@ import {AbstractSigner} from "@atomiqlabs/base";
|
|
|
2
2
|
import {getAddress, Signer, Transaction, TransactionRequest, TransactionResponse} from "ethers";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* EVM signer implementation wrapping an ethers Signer
|
|
5
|
+
* EVM signer implementation wrapping an ethers {@link Signer}, for browser-based wallet use
|
|
6
|
+
* {@link EVMBrowserSigner}.
|
|
7
|
+
*
|
|
6
8
|
* @category Wallets
|
|
7
9
|
*/
|
|
8
10
|
export class EVMSigner implements AbstractSigner {
|
|
11
|
+
/**
|
|
12
|
+
* A static message, which should be signed by the EVM wallets to generate reproducible entropy. Works when
|
|
13
|
+
* wallets use signing with deterministic nonce, such that signature over the same message always yields the
|
|
14
|
+
* same signature (same entropy).
|
|
15
|
+
*/
|
|
16
|
+
private static readonly EVM_REPRODUCIBLE_ENTROPY_MESSAGE =
|
|
17
|
+
"Signing this messages generates a reproducible secret to be used on %APPNAME%.\n\nPLEASE DOUBLE CHECK THAT YOU"+
|
|
18
|
+
" ARE ON THE %APPNAME% WEBSITE BEFORE SIGNING THE MESSAGE, SIGNING THIS MESSAGE ON ANY OTHER WEBSITE MIGHT LEAD TO"+
|
|
19
|
+
" LOSS OF FUNDS!";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Returns a static message, which should be signed by the EVM wallets to generate reproducible entropy. Works when
|
|
23
|
+
* wallets use signing with deterministic nonce, such that signature over the same message always yields the
|
|
24
|
+
* same signature (same entropy).
|
|
25
|
+
*
|
|
26
|
+
* @param appName Application name to differentiate reproducible entropy generated across different apps
|
|
27
|
+
*/
|
|
28
|
+
public static getReproducibleEntropyMessage(appName: string): string {
|
|
29
|
+
return EVMSigner.EVM_REPRODUCIBLE_ENTROPY_MESSAGE.replace(new RegExp("%APPNAME%", 'g'), appName);
|
|
30
|
+
}
|
|
31
|
+
|
|
9
32
|
type = "AtomiqAbstractSigner" as const;
|
|
10
33
|
|
|
11
34
|
account: Signer;
|
|
12
35
|
public readonly address: string;
|
|
13
36
|
public readonly isManagingNoncesInternally: boolean;
|
|
14
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Constructs a signer wrapping an ethers {@link Signer}.
|
|
40
|
+
*
|
|
41
|
+
* @param account
|
|
42
|
+
* @param address
|
|
43
|
+
* @param isManagingNoncesInternally
|
|
44
|
+
*/
|
|
15
45
|
constructor(account: Signer, address: string, isManagingNoncesInternally: boolean = false) {
|
|
16
46
|
this.account = account;
|
|
17
47
|
this.address = address;
|
|
@@ -25,10 +55,16 @@ export class EVMSigner implements AbstractSigner {
|
|
|
25
55
|
return getAddress(this.address);
|
|
26
56
|
}
|
|
27
57
|
|
|
58
|
+
/**
|
|
59
|
+
* @inheritDoc
|
|
60
|
+
*/
|
|
28
61
|
async signTransaction?(transaction: TransactionRequest): Promise<string> {
|
|
29
62
|
return this.account.signTransaction(transaction);
|
|
30
63
|
}
|
|
31
64
|
|
|
65
|
+
/**
|
|
66
|
+
* @inheritDoc
|
|
67
|
+
*/
|
|
32
68
|
async sendTransaction(transaction: TransactionRequest, onBeforePublish?: (txId: string, rawTx: string) => Promise<void>): Promise<TransactionResponse> {
|
|
33
69
|
const txResponse = await this.account.sendTransaction(transaction);
|
|
34
70
|
if(onBeforePublish!=null) await onBeforePublish(txResponse.hash, Transaction.from({
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* # @atomiqlabs/chain-evm
|
|
3
|
+
*
|
|
4
|
+
* `@atomiqlabs/chain-evm` is the EVM integration package for the Atomiq protocol.
|
|
5
|
+
*
|
|
6
|
+
* Within the Atomiq stack, this library provides the EVM-side building blocks used for Bitcoin-aware swaps and SPV-backed vault flows on supported EVM-compatible chains. It includes:
|
|
7
|
+
*
|
|
8
|
+
* - chain initializers for Atomiq-supported EVM networks
|
|
9
|
+
* - the `EVMChainInterface` used to talk to chain RPCs
|
|
10
|
+
* - BTC relay, escrow swap, and SPV vault contract wrappers
|
|
11
|
+
* - browser and server-side EVM signer helpers
|
|
12
|
+
* - event utilities for tracking swap and vault activity
|
|
13
|
+
*
|
|
14
|
+
* This package is intended for direct protocol integrations and for higher-level Atomiq SDK layers that need EVM chain support.
|
|
15
|
+
*
|
|
16
|
+
* ## Installation
|
|
17
|
+
*
|
|
18
|
+
* Install the package with its `ethers` peer dependency:
|
|
19
|
+
*
|
|
20
|
+
* ```bash
|
|
21
|
+
* npm install @atomiqlabs/chain-evm ethers
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* ## Supported Chains
|
|
25
|
+
*
|
|
26
|
+
* The package currently exports chain initializers for:
|
|
27
|
+
*
|
|
28
|
+
* - Botanix via `BotanixInitializer`
|
|
29
|
+
* - Citrea via `CitreaInitializer`
|
|
30
|
+
* - Alpen via `AlpenInitializer`
|
|
31
|
+
* - GOAT Network via `GoatInitializer`
|
|
32
|
+
*
|
|
33
|
+
* Canonical deployments currently defined in this package:
|
|
34
|
+
*
|
|
35
|
+
* | Chain | Canonical deployments included |
|
|
36
|
+
* | --- | --- |
|
|
37
|
+
* | Botanix | `MAINNET`, `TESTNET` |
|
|
38
|
+
* | Citrea | `MAINNET`, `TESTNET4` |
|
|
39
|
+
* | Alpen | `TESTNET`, `TESTNET4` |
|
|
40
|
+
* | GOAT Network | `TESTNET`, `TESTNET4` |
|
|
41
|
+
*
|
|
42
|
+
* For Alpen and GOAT Network, `MAINNET` chain types exist in the API, but default mainnet contract addresses are not populated in this package yet. In those cases, pass explicit contract addresses if you want to use non-canonical deployments.
|
|
43
|
+
*
|
|
44
|
+
* ## SDK Example
|
|
45
|
+
*
|
|
46
|
+
* Initialize the atomiq SDK with Citrea network support:
|
|
47
|
+
*
|
|
48
|
+
* ```ts
|
|
49
|
+
* import {CitreaInitializer, CitreaInitializerType} from "@atomiqlabs/chain-evm";
|
|
50
|
+
* import {BitcoinNetwork, SwapperFactory, TypedSwapper} from "@atomiqlabs/sdk";
|
|
51
|
+
*
|
|
52
|
+
* //Define chains that you want to support here
|
|
53
|
+
* const chains = [CitreaInitializer] as const;
|
|
54
|
+
* type SupportedChains = typeof chains; //It's helpful that we also get the type of the chains array
|
|
55
|
+
*
|
|
56
|
+
* const Factory = new SwapperFactory<SupportedChains>(chains); //Create swapper factory
|
|
57
|
+
*
|
|
58
|
+
* const swapper: TypedSwapper<SupportedChains> = Factory.newSwapper({
|
|
59
|
+
* chains: {
|
|
60
|
+
* CITREA: {
|
|
61
|
+
* rpcUrl: citreaRpc, //You can also pass JsonApiProvider object here
|
|
62
|
+
* }
|
|
63
|
+
* },
|
|
64
|
+
* bitcoinNetwork: BitcoinNetwork.MAINNET //or BitcoinNetwork.TESTNET3, BitcoinNetwork.TESTNET4 - this also sets the deployment to use for EVM chains
|
|
65
|
+
* });
|
|
66
|
+
* ```
|
|
67
|
+
*
|
|
68
|
+
* @packageDocumentation
|
|
69
|
+
*/
|
|
70
|
+
export * from "./chains/EVMOptions";
|
|
71
|
+
|
|
1
72
|
export * from "./chains/citrea/CitreaInitializer";
|
|
2
73
|
export * from "./chains/citrea/CitreaChainType";
|
|
3
74
|
export * from "./chains/citrea/CitreaFees";
|
|
@@ -17,6 +88,7 @@ export {EVMBtcRelay} from "./evm/btcrelay/EVMBtcRelay";
|
|
|
17
88
|
|
|
18
89
|
export * from "./evm/chain/EVMChainInterface";
|
|
19
90
|
export * from "./evm/chain/modules/EVMFees";
|
|
91
|
+
export {EVMTx, SignedEVMTx} from "./evm/chain/modules/EVMTransactions";
|
|
20
92
|
|
|
21
93
|
export * from "./evm/events/EVMChainEventsBrowser";
|
|
22
94
|
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node.js-only entrypoint for filesystem-backed EVM helpers.
|
|
3
|
+
*
|
|
4
|
+
* Import from `@atomiqlabs/chain-evm/node` when you need runtime features
|
|
5
|
+
* that depend on Node's `fs` module.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
export {EVMChainEvents} from "../evm/events/EVMChainEvents";
|
|
10
|
+
export {EVMPersistentSigner} from "../evm/wallet/EVMPersistentSigner";
|
package/src/utils/Utils.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Logger interface used across EVM modules.
|
|
4
|
+
*
|
|
5
|
+
* @category Internal/Utils
|
|
6
|
+
*/
|
|
3
7
|
export type LoggerType = {
|
|
4
8
|
debug: (msg: string, ...args: any[]) => void,
|
|
5
9
|
info: (msg: string, ...args: any[]) => void,
|
|
@@ -7,6 +11,11 @@ export type LoggerType = {
|
|
|
7
11
|
error: (msg: string, ...args: any[]) => void,
|
|
8
12
|
}
|
|
9
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Returns a promise that resolves after `timeoutMillis` unless aborted first.
|
|
16
|
+
*
|
|
17
|
+
* @category Internal/Utils
|
|
18
|
+
*/
|
|
10
19
|
export function timeoutPromise(timeoutMillis: number, abortSignal?: AbortSignal): Promise<void> {
|
|
11
20
|
return new Promise((resolve, reject) => {
|
|
12
21
|
const timeout = setTimeout(resolve, timeoutMillis)
|
|
@@ -17,6 +26,11 @@ export function timeoutPromise(timeoutMillis: number, abortSignal?: AbortSignal)
|
|
|
17
26
|
});
|
|
18
27
|
}
|
|
19
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Wraps an async executor so it runs once at a time and reuses the same promise.
|
|
31
|
+
*
|
|
32
|
+
* @category Internal/Utils
|
|
33
|
+
*/
|
|
20
34
|
export function onceAsync<T>(executor: () => Promise<T>): () => Promise<T> {
|
|
21
35
|
let promise: Promise<T>;
|
|
22
36
|
|
|
@@ -30,6 +44,11 @@ export function onceAsync<T>(executor: () => Promise<T>): () => Promise<T> {
|
|
|
30
44
|
}
|
|
31
45
|
}
|
|
32
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Creates a prefixed logger that honors the global `atomiqLogLevel`.
|
|
49
|
+
*
|
|
50
|
+
* @category Internal/Utils
|
|
51
|
+
*/
|
|
33
52
|
export function getLogger(prefix: string): LoggerType {
|
|
34
53
|
return {
|
|
35
54
|
debug: (msg, ...args) => (global as any).atomiqLogLevel >= 3 && console.debug(prefix+msg, ...args),
|
|
@@ -41,6 +60,11 @@ export function getLogger(prefix: string): LoggerType {
|
|
|
41
60
|
|
|
42
61
|
const logger = getLogger("Utils: ");
|
|
43
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Retries an async function using the provided retry policy.
|
|
65
|
+
*
|
|
66
|
+
* @category Internal/Utils
|
|
67
|
+
*/
|
|
44
68
|
export async function tryWithRetries<T>(func: () => Promise<T>, retryPolicy?: {
|
|
45
69
|
maxRetries?: number, delay?: number, exponential?: boolean
|
|
46
70
|
}, errorAllowed?: (e: any) => boolean, abortSignal?: AbortSignal): Promise<T> {
|
|
@@ -72,6 +96,11 @@ export async function tryWithRetries<T>(func: () => Promise<T>, retryPolicy?: {
|
|
|
72
96
|
throw err;
|
|
73
97
|
}
|
|
74
98
|
|
|
99
|
+
/**
|
|
100
|
+
* Reverses byte order of a 32-bit unsigned integer.
|
|
101
|
+
*
|
|
102
|
+
* @category Internal/Utils
|
|
103
|
+
*/
|
|
75
104
|
export function uint32ReverseEndianness(value: number): number {
|
|
76
105
|
const valueBN = BigInt(value);
|
|
77
106
|
return Number(((valueBN & 0xFFn) << 24n) |
|
|
@@ -80,10 +109,20 @@ export function uint32ReverseEndianness(value: number): number {
|
|
|
80
109
|
((valueBN >> 24n) & 0xFFn));
|
|
81
110
|
}
|
|
82
111
|
|
|
112
|
+
/**
|
|
113
|
+
* Returns the greater of two bigint values.
|
|
114
|
+
*
|
|
115
|
+
* @category Internal/Utils
|
|
116
|
+
*/
|
|
83
117
|
export function bigIntMax(a: bigint, b: bigint) {
|
|
84
118
|
return a>b ? a : b;
|
|
85
119
|
}
|
|
86
120
|
|
|
121
|
+
/**
|
|
122
|
+
* Ethers.js error codes considered recoverable for retry logic.
|
|
123
|
+
*
|
|
124
|
+
* @category Internal/Utils
|
|
125
|
+
*/
|
|
87
126
|
export const allowedEthersErrorCodes: Set<string> = new Set([
|
|
88
127
|
"NOT_IMPLEMENTED", "UNSUPPORTED_OPERATION", "BAD_DATA",
|
|
89
128
|
"NUMERIC_FAULT",
|
|
@@ -91,6 +130,11 @@ export const allowedEthersErrorCodes: Set<string> = new Set([
|
|
|
91
130
|
"CALL_EXCEPTION", "NONCE_EXPIRED", "REPLACEMENT_UNDERPRICED", "TRANSACTION_REPLACED", "UNCONFIGURED_NAME", "OFFCHAIN_FAULT", "ACTION_REJECTED"
|
|
92
131
|
]);
|
|
93
132
|
|
|
133
|
+
/**
|
|
134
|
+
* JSON-RPC error numbers considered recoverable for retry logic.
|
|
135
|
+
*
|
|
136
|
+
* @category Internal/Utils
|
|
137
|
+
*/
|
|
94
138
|
export const allowedEthersErrorNumbers: Set<number> = new Set([
|
|
95
139
|
3, //Revertion during eth_getAccessList call
|
|
96
140
|
-32700, //Invalid JSON
|
|
@@ -107,6 +151,11 @@ export const allowedEthersErrorNumbers: Set<number> = new Set([
|
|
|
107
151
|
-32006 //JSON-RPC version not supported
|
|
108
152
|
]);
|
|
109
153
|
|
|
154
|
+
/**
|
|
155
|
+
* RPC error messages considered recoverable for retry logic.
|
|
156
|
+
*
|
|
157
|
+
* @category Internal/Utils
|
|
158
|
+
*/
|
|
110
159
|
export const allowedEthersErrorMessages: Set<string> = new Set([
|
|
111
160
|
"already known"
|
|
112
161
|
]);
|