@atomiqlabs/chain-evm 1.0.0-dev.22 → 1.0.0-dev.27
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/chains/citrea/CitreaBtcRelay.d.ts +21 -0
- package/dist/chains/citrea/CitreaBtcRelay.js +43 -0
- package/dist/chains/citrea/CitreaChainType.d.ts +4 -4
- package/dist/chains/citrea/CitreaFees.d.ts +29 -0
- package/dist/chains/citrea/CitreaFees.js +67 -0
- package/dist/chains/citrea/CitreaInitializer.d.ts +3 -3
- package/dist/chains/citrea/CitreaInitializer.js +13 -6
- package/dist/chains/citrea/CitreaSpvVaultContract.d.ts +6 -0
- package/dist/chains/citrea/CitreaSpvVaultContract.js +16 -0
- package/dist/chains/citrea/CitreaSwapContract.d.ts +22 -0
- package/dist/chains/citrea/CitreaSwapContract.js +98 -0
- package/dist/chains/citrea/CitreaTokens.d.ts +9 -0
- package/dist/chains/citrea/CitreaTokens.js +20 -0
- package/dist/evm/btcrelay/EVMBtcRelay.d.ts +8 -1
- package/dist/evm/btcrelay/EVMBtcRelay.js +15 -11
- package/dist/evm/chain/EVMChainInterface.d.ts +6 -6
- package/dist/evm/chain/modules/EVMFees.d.ts +8 -7
- package/dist/evm/chain/modules/EVMFees.js +3 -3
- package/dist/evm/chain/modules/EVMTokens.d.ts +2 -0
- package/dist/evm/chain/modules/EVMTokens.js +10 -2
- package/dist/evm/spv_swap/EVMSpvVaultContract.d.ts +6 -1
- package/dist/evm/spv_swap/EVMSpvVaultContract.js +4 -4
- package/dist/evm/swaps/modules/EVMLpVault.js +2 -2
- package/dist/evm/swaps/modules/EVMSwapClaim.d.ts +1 -0
- package/dist/evm/swaps/modules/EVMSwapClaim.js +40 -4
- package/dist/evm/swaps/modules/EVMSwapInit.d.ts +3 -3
- package/dist/evm/swaps/modules/EVMSwapInit.js +43 -9
- package/dist/evm/swaps/modules/EVMSwapRefund.d.ts +2 -2
- package/dist/evm/swaps/modules/EVMSwapRefund.js +42 -7
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/package.json +1 -1
- package/src/chains/citrea/CitreaBtcRelay.ts +58 -0
- package/src/chains/citrea/CitreaChainType.ts +6 -6
- package/src/chains/citrea/CitreaFees.ts +77 -0
- package/src/chains/citrea/CitreaInitializer.ts +15 -5
- package/src/chains/citrea/CitreaSpvVaultContract.ts +18 -0
- package/src/chains/citrea/CitreaSwapContract.ts +105 -0
- package/src/chains/citrea/CitreaTokens.ts +22 -0
- package/src/evm/btcrelay/EVMBtcRelay.ts +17 -12
- package/src/evm/chain/EVMChainInterface.ts +6 -6
- package/src/evm/chain/modules/EVMFees.ts +10 -11
- package/src/evm/chain/modules/EVMTokens.ts +13 -2
- package/src/evm/spv_swap/EVMSpvVaultContract.ts +5 -5
- package/src/evm/swaps/modules/EVMLpVault.ts +2 -2
- package/src/evm/swaps/modules/EVMSwapClaim.ts +36 -4
- package/src/evm/swaps/modules/EVMSwapInit.ts +44 -10
- package/src/evm/swaps/modules/EVMSwapRefund.ts +38 -7
- package/src/index.ts +1 -0
|
@@ -15,7 +15,12 @@ import { EVMBtcStoredHeader } from "../btcrelay/headers/EVMBtcStoredHeader";
|
|
|
15
15
|
export declare function packOwnerAndVaultId(owner: string, vaultId: bigint): string;
|
|
16
16
|
export declare function unpackOwnerAndVaultId(data: string): [string, bigint];
|
|
17
17
|
export declare class EVMSpvVaultContract<ChainId extends string> extends EVMContractBase<SpvVaultManager> implements SpvVaultContract<EVMTx, EVMSigner, ChainId, EVMSpvVaultData, EVMSpvWithdrawalData> {
|
|
18
|
-
|
|
18
|
+
static readonly GasCosts: {
|
|
19
|
+
DEPOSIT: number;
|
|
20
|
+
OPEN: number;
|
|
21
|
+
FRONT: number;
|
|
22
|
+
CLAIM: number;
|
|
23
|
+
};
|
|
19
24
|
readonly chainId: ChainId;
|
|
20
25
|
readonly btcRelay: EVMBtcRelay<any>;
|
|
21
26
|
readonly bitcoinRpc: BitcoinRpc<any>;
|
|
@@ -403,8 +403,8 @@ class EVMSpvVaultContract extends EVMContractBase_1.EVMContractBase {
|
|
|
403
403
|
}
|
|
404
404
|
exports.EVMSpvVaultContract = EVMSpvVaultContract;
|
|
405
405
|
EVMSpvVaultContract.GasCosts = {
|
|
406
|
-
DEPOSIT: 150000,
|
|
407
|
-
OPEN: 100000,
|
|
408
|
-
FRONT: 250000,
|
|
409
|
-
CLAIM: 250000
|
|
406
|
+
DEPOSIT: 150000 + 21000,
|
|
407
|
+
OPEN: 100000 + 21000,
|
|
408
|
+
FRONT: 250000 + 21000,
|
|
409
|
+
CLAIM: 250000 + 21000
|
|
410
410
|
};
|
|
@@ -46,6 +46,7 @@ export declare class EVMSwapClaim extends EVMSwapModule {
|
|
|
46
46
|
hex: string;
|
|
47
47
|
height: number;
|
|
48
48
|
}, requiredConfirmations: number, vout: number, commitedHeader?: EVMBtcStoredHeader, synchronizer?: RelaySynchronizer<EVMBtcStoredHeader, EVMTx, any>, feeRate?: string): Promise<EVMTx[] | null>;
|
|
49
|
+
getClaimGas(swapData: EVMSwapData): number;
|
|
49
50
|
/**
|
|
50
51
|
* Get the estimated starknet transaction fee of the claim transaction
|
|
51
52
|
*/
|
|
@@ -19,7 +19,7 @@ class EVMSwapClaim extends EVMSwapModule_1.EVMSwapModule {
|
|
|
19
19
|
//TODO: Claim with success action not supported yet!
|
|
20
20
|
const tx = await this.swapContract.claim.populateTransaction(swapData.toEscrowStruct(), witness);
|
|
21
21
|
tx.from = signer;
|
|
22
|
-
EVMFees_1.EVMFees.applyFeeRate(tx,
|
|
22
|
+
EVMFees_1.EVMFees.applyFeeRate(tx, this.getClaimGas(swapData) + (claimHandlerGas ?? 0), feeRate);
|
|
23
23
|
return tx;
|
|
24
24
|
}
|
|
25
25
|
/**
|
|
@@ -81,13 +81,46 @@ class EVMSwapClaim extends EVMSwapModule_1.EVMSwapModule {
|
|
|
81
81
|
const claimTx = await this.Claim(signer, swapData, witness, feeRate, claimHandler.getGas(swapData));
|
|
82
82
|
return [...initialTxns, claimTx];
|
|
83
83
|
}
|
|
84
|
+
getClaimGas(swapData) {
|
|
85
|
+
let totalGas = EVMSwapClaim.GasCosts.BASE;
|
|
86
|
+
if (swapData.reputation)
|
|
87
|
+
totalGas += EVMSwapClaim.GasCosts.REPUTATION;
|
|
88
|
+
if (swapData.isPayOut()) {
|
|
89
|
+
if (swapData.isToken(this.root.getNativeCurrencyAddress())) {
|
|
90
|
+
totalGas += EVMSwapClaim.GasCosts.NATIVE_TRANSFER;
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
totalGas += EVMSwapClaim.GasCosts.ERC20_TRANSFER;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
totalGas += EVMSwapClaim.GasCosts.LP_VAULT_TRANSFER;
|
|
98
|
+
}
|
|
99
|
+
if (swapData.getClaimerBounty() > 0n) {
|
|
100
|
+
if (swapData.isDepositToken(this.root.getNativeCurrencyAddress())) {
|
|
101
|
+
totalGas += EVMSwapClaim.GasCosts.NATIVE_TRANSFER;
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
totalGas += EVMSwapClaim.GasCosts.ERC20_TRANSFER;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (swapData.getSecurityDeposit() > swapData.getClaimerBounty()) {
|
|
108
|
+
if (swapData.isDepositToken(this.root.getNativeCurrencyAddress())) {
|
|
109
|
+
totalGas += EVMSwapClaim.GasCosts.NATIVE_TRANSFER;
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
totalGas += EVMSwapClaim.GasCosts.ERC20_TRANSFER;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return totalGas;
|
|
116
|
+
}
|
|
84
117
|
/**
|
|
85
118
|
* Get the estimated starknet transaction fee of the claim transaction
|
|
86
119
|
*/
|
|
87
120
|
async getClaimFee(swapData, feeRate) {
|
|
88
121
|
feeRate ?? (feeRate = await this.root.Fees.getFeeRate());
|
|
89
122
|
//TODO: Claim with success action not supported yet!
|
|
90
|
-
let gasRequired =
|
|
123
|
+
let gasRequired = this.getClaimGas(swapData);
|
|
91
124
|
const claimHandler = this.contract.claimHandlersByAddress[swapData.claimHandler.toLowerCase()];
|
|
92
125
|
if (claimHandler != null)
|
|
93
126
|
gasRequired += claimHandler.getGas(swapData);
|
|
@@ -96,6 +129,9 @@ class EVMSwapClaim extends EVMSwapModule_1.EVMSwapModule {
|
|
|
96
129
|
}
|
|
97
130
|
exports.EVMSwapClaim = EVMSwapClaim;
|
|
98
131
|
EVMSwapClaim.GasCosts = {
|
|
99
|
-
|
|
100
|
-
|
|
132
|
+
BASE: 30000 + 21000,
|
|
133
|
+
ERC20_TRANSFER: 40000,
|
|
134
|
+
NATIVE_TRANSFER: 7500,
|
|
135
|
+
LP_VAULT_TRANSFER: 10000,
|
|
136
|
+
REPUTATION: 25000
|
|
101
137
|
};
|
|
@@ -80,9 +80,9 @@ export declare class EVMSwapInit extends EVMSwapModule {
|
|
|
80
80
|
* @param feeRate fee rate to use for the transaction
|
|
81
81
|
*/
|
|
82
82
|
txsInit(sender: string, swapData: EVMSwapData, timeout: string, prefix: string, signature: string, skipChecks?: boolean, feeRate?: string): Promise<EVMTx[]>;
|
|
83
|
+
private getInitGas;
|
|
83
84
|
/**
|
|
84
|
-
* Get the estimated
|
|
85
|
-
* and also deposit for ATAs
|
|
85
|
+
* Get the estimated fee of the init transaction
|
|
86
86
|
*/
|
|
87
|
-
getInitFee(swapData
|
|
87
|
+
getInitFee(swapData: EVMSwapData, feeRate?: string): Promise<bigint>;
|
|
88
88
|
}
|
|
@@ -39,15 +39,17 @@ class EVMSwapInit extends EVMSwapModule_1.EVMSwapModule {
|
|
|
39
39
|
*/
|
|
40
40
|
async Init(sender, swapData, timeout, signature, feeRate) {
|
|
41
41
|
let value = 0n;
|
|
42
|
-
if (swapData.
|
|
43
|
-
|
|
42
|
+
if (swapData.isPayIn()) {
|
|
43
|
+
if (swapData.isOfferer(sender) && swapData.isToken(this.root.getNativeCurrencyAddress()))
|
|
44
|
+
value += swapData.getAmount();
|
|
45
|
+
}
|
|
44
46
|
if (swapData.isDepositToken(this.root.getNativeCurrencyAddress()))
|
|
45
47
|
value += swapData.getTotalDeposit();
|
|
46
48
|
const tx = await this.swapContract.initialize.populateTransaction(swapData.toEscrowStruct(), signature, timeout, "0x" + (swapData.extraData ?? ""), {
|
|
47
49
|
value
|
|
48
50
|
});
|
|
49
51
|
tx.from = sender;
|
|
50
|
-
EVMFees_1.EVMFees.applyFeeRate(tx,
|
|
52
|
+
EVMFees_1.EVMFees.applyFeeRate(tx, this.getInitGas(swapData), feeRate);
|
|
51
53
|
return tx;
|
|
52
54
|
}
|
|
53
55
|
/**
|
|
@@ -206,7 +208,7 @@ class EVMSwapInit extends EVMSwapModule_1.EVMSwapModule {
|
|
|
206
208
|
feeRate ?? (feeRate = await this.root.Fees.getFeeRate());
|
|
207
209
|
const txs = [];
|
|
208
210
|
const requiredApprovals = {};
|
|
209
|
-
if (swapData.
|
|
211
|
+
if (swapData.isPayIn() && swapData.isOfferer(sender)) {
|
|
210
212
|
if (!swapData.isToken(this.root.getNativeCurrencyAddress())) {
|
|
211
213
|
requiredApprovals[swapData.token.toLowerCase()] = swapData.amount;
|
|
212
214
|
}
|
|
@@ -225,17 +227,49 @@ class EVMSwapInit extends EVMSwapModule_1.EVMSwapModule {
|
|
|
225
227
|
" feerate: " + feeRate);
|
|
226
228
|
return txs;
|
|
227
229
|
}
|
|
230
|
+
getInitGas(swapData) {
|
|
231
|
+
let totalGas = EVMSwapInit.GasCosts.BASE;
|
|
232
|
+
if (swapData.isPayIn()) {
|
|
233
|
+
if (!swapData.isToken(this.root.getNativeCurrencyAddress())) {
|
|
234
|
+
totalGas += EVMSwapInit.GasCosts.ERC20_TRANSFER;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
totalGas += EVMSwapInit.GasCosts.LP_VAULT_TRANSFER;
|
|
239
|
+
}
|
|
240
|
+
if (swapData.getTotalDeposit() > 0) {
|
|
241
|
+
if (!swapData.isPayIn() || !swapData.isDepositToken(swapData.token)) {
|
|
242
|
+
if (!swapData.isDepositToken(this.root.getNativeCurrencyAddress())) {
|
|
243
|
+
totalGas += EVMSwapInit.GasCosts.ERC20_TRANSFER;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return totalGas;
|
|
248
|
+
}
|
|
228
249
|
/**
|
|
229
|
-
* Get the estimated
|
|
230
|
-
* and also deposit for ATAs
|
|
250
|
+
* Get the estimated fee of the init transaction
|
|
231
251
|
*/
|
|
232
252
|
async getInitFee(swapData, feeRate) {
|
|
233
253
|
feeRate ?? (feeRate = await this.root.Fees.getFeeRate());
|
|
234
|
-
|
|
254
|
+
let totalFee = EVMFees_1.EVMFees.getGasFee(this.getInitGas(swapData), feeRate);
|
|
255
|
+
if (swapData.isPayIn()) {
|
|
256
|
+
if (!swapData.isToken(this.root.getNativeCurrencyAddress())) {
|
|
257
|
+
totalFee += await this.root.Tokens.getApproveFee(feeRate);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
if (swapData.getTotalDeposit() > 0) {
|
|
261
|
+
if (!swapData.isPayIn() || !swapData.isDepositToken(swapData.token)) {
|
|
262
|
+
if (!swapData.isDepositToken(this.root.getNativeCurrencyAddress())) {
|
|
263
|
+
totalFee += await this.root.Tokens.getApproveFee(feeRate);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return totalFee;
|
|
235
268
|
}
|
|
236
269
|
}
|
|
237
270
|
exports.EVMSwapInit = EVMSwapInit;
|
|
238
271
|
EVMSwapInit.GasCosts = {
|
|
239
|
-
|
|
240
|
-
|
|
272
|
+
BASE: 45000 + 21000,
|
|
273
|
+
ERC20_TRANSFER: 40000,
|
|
274
|
+
LP_VAULT_TRANSFER: 10000
|
|
241
275
|
};
|
|
@@ -54,9 +54,9 @@ export declare class EVMSwapRefund extends EVMSwapModule {
|
|
|
54
54
|
* @param feeRate fee rate to be used for the transactions
|
|
55
55
|
*/
|
|
56
56
|
txsRefundWithAuthorization(signer: string, swapData: EVMSwapData, timeout: string, prefix: string, signature: string, check?: boolean, feeRate?: string): Promise<EVMTx[]>;
|
|
57
|
+
getRefundGas(swapData: EVMSwapData): number;
|
|
57
58
|
/**
|
|
58
|
-
* Get the estimated
|
|
59
|
-
* ATA needs to be initialized again (i.e. adding the ATA rent exempt lamports to the fee)
|
|
59
|
+
* Get the estimated transaction fee of the refund transaction
|
|
60
60
|
*/
|
|
61
61
|
getRefundFee(swapData: EVMSwapData, feeRate?: string): Promise<bigint>;
|
|
62
62
|
}
|
|
@@ -23,7 +23,7 @@ class EVMSwapRefund extends EVMSwapModule_1.EVMSwapModule {
|
|
|
23
23
|
async Refund(signer, swapData, witness, feeRate, handlerGas) {
|
|
24
24
|
const tx = await this.swapContract.refund.populateTransaction(swapData.toEscrowStruct(), witness);
|
|
25
25
|
tx.from = signer;
|
|
26
|
-
EVMFees_1.EVMFees.applyFeeRate(tx, (swapData
|
|
26
|
+
EVMFees_1.EVMFees.applyFeeRate(tx, this.getRefundGas(swapData) + (handlerGas ?? 0), feeRate);
|
|
27
27
|
return tx;
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
@@ -39,7 +39,7 @@ class EVMSwapRefund extends EVMSwapModule_1.EVMSwapModule {
|
|
|
39
39
|
async RefundWithSignature(sender, swapData, timeout, signature, feeRate) {
|
|
40
40
|
const tx = await this.swapContract.cooperativeRefund.populateTransaction(swapData.toEscrowStruct(), signature, BigInt(timeout));
|
|
41
41
|
tx.from = sender;
|
|
42
|
-
EVMFees_1.EVMFees.applyFeeRate(tx, swapData
|
|
42
|
+
EVMFees_1.EVMFees.applyFeeRate(tx, this.getRefundGas(swapData), feeRate);
|
|
43
43
|
return tx;
|
|
44
44
|
}
|
|
45
45
|
async signSwapRefund(signer, swapData, authorizationTimeout) {
|
|
@@ -116,17 +116,52 @@ class EVMSwapRefund extends EVMSwapModule_1.EVMSwapModule {
|
|
|
116
116
|
" auth expiry: " + timeout + " signature: " + signature);
|
|
117
117
|
return [tx];
|
|
118
118
|
}
|
|
119
|
+
getRefundGas(swapData) {
|
|
120
|
+
let totalGas = EVMSwapRefund.GasCosts.BASE;
|
|
121
|
+
if (swapData.reputation)
|
|
122
|
+
totalGas += EVMSwapRefund.GasCosts.REPUTATION;
|
|
123
|
+
if (swapData.isPayIn()) {
|
|
124
|
+
if (swapData.isToken(this.root.getNativeCurrencyAddress())) {
|
|
125
|
+
totalGas += EVMSwapRefund.GasCosts.NATIVE_TRANSFER;
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
totalGas += EVMSwapRefund.GasCosts.ERC20_TRANSFER;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
totalGas += EVMSwapRefund.GasCosts.LP_VAULT_TRANSFER;
|
|
133
|
+
}
|
|
134
|
+
if (swapData.getSecurityDeposit() > 0n) {
|
|
135
|
+
if (swapData.isDepositToken(this.root.getNativeCurrencyAddress())) {
|
|
136
|
+
totalGas += EVMSwapRefund.GasCosts.NATIVE_TRANSFER;
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
totalGas += EVMSwapRefund.GasCosts.ERC20_TRANSFER;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (swapData.getClaimerBounty() > swapData.getSecurityDeposit()) {
|
|
143
|
+
if (swapData.isDepositToken(this.root.getNativeCurrencyAddress())) {
|
|
144
|
+
totalGas += EVMSwapRefund.GasCosts.NATIVE_TRANSFER;
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
totalGas += EVMSwapRefund.GasCosts.ERC20_TRANSFER;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return totalGas;
|
|
151
|
+
}
|
|
119
152
|
/**
|
|
120
|
-
* Get the estimated
|
|
121
|
-
* ATA needs to be initialized again (i.e. adding the ATA rent exempt lamports to the fee)
|
|
153
|
+
* Get the estimated transaction fee of the refund transaction
|
|
122
154
|
*/
|
|
123
155
|
async getRefundFee(swapData, feeRate) {
|
|
124
156
|
feeRate ?? (feeRate = await this.root.Fees.getFeeRate());
|
|
125
|
-
return EVMFees_1.EVMFees.getGasFee(swapData
|
|
157
|
+
return EVMFees_1.EVMFees.getGasFee(this.getRefundGas(swapData), feeRate);
|
|
126
158
|
}
|
|
127
159
|
}
|
|
128
160
|
exports.EVMSwapRefund = EVMSwapRefund;
|
|
129
161
|
EVMSwapRefund.GasCosts = {
|
|
130
|
-
|
|
131
|
-
|
|
162
|
+
BASE: 35000 + 21000,
|
|
163
|
+
ERC20_TRANSFER: 40000,
|
|
164
|
+
NATIVE_TRANSFER: 7500,
|
|
165
|
+
LP_VAULT_TRANSFER: 10000,
|
|
166
|
+
REPUTATION: 25000
|
|
132
167
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -35,3 +35,4 @@ export * from "./evm/swaps/handlers/claim/btc/BitcoinNoncedOutputClaimHandler";
|
|
|
35
35
|
export * from "./evm/wallet/EVMSigner";
|
|
36
36
|
export * from "./chains/citrea/CitreaInitializer";
|
|
37
37
|
export * from "./chains/citrea/CitreaChainType";
|
|
38
|
+
export * from "./chains/citrea/CitreaFees";
|
package/dist/index.js
CHANGED
|
@@ -51,3 +51,4 @@ __exportStar(require("./evm/swaps/handlers/claim/btc/BitcoinNoncedOutputClaimHan
|
|
|
51
51
|
__exportStar(require("./evm/wallet/EVMSigner"), exports);
|
|
52
52
|
__exportStar(require("./chains/citrea/CitreaInitializer"), exports);
|
|
53
53
|
__exportStar(require("./chains/citrea/CitreaChainType"), exports);
|
|
54
|
+
__exportStar(require("./chains/citrea/CitreaFees"), exports);
|
package/package.json
CHANGED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import {EVMBtcRelay} from "../../evm/btcrelay/EVMBtcRelay";
|
|
2
|
+
import {BtcBlock} from "@atomiqlabs/base";
|
|
3
|
+
import {getLogger} from "../../utils/Utils";
|
|
4
|
+
import {CitreaFees} from "./CitreaFees";
|
|
5
|
+
|
|
6
|
+
const logger = getLogger("CitreaBtcRelay: ");
|
|
7
|
+
|
|
8
|
+
export class CitreaBtcRelay<B extends BtcBlock> extends EVMBtcRelay<B> {
|
|
9
|
+
|
|
10
|
+
public static StateDiffSize = {
|
|
11
|
+
STATE_DIFF_PER_BLOCKHEADER: 22,
|
|
12
|
+
STATE_DIFF_BASE: 30
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Estimate required synchronization fee (worst case) to synchronize btc relay to the required blockheight
|
|
17
|
+
*
|
|
18
|
+
* @param requiredBlockheight
|
|
19
|
+
* @param feeRate
|
|
20
|
+
*/
|
|
21
|
+
public async estimateSynchronizeFee(requiredBlockheight: number, feeRate?: string): Promise<bigint> {
|
|
22
|
+
feeRate ??= await this.Chain.Fees.getFeeRate();
|
|
23
|
+
const tipData = await this.getTipData();
|
|
24
|
+
const currBlockheight = tipData.blockheight;
|
|
25
|
+
|
|
26
|
+
const blockheightDelta = requiredBlockheight-currBlockheight;
|
|
27
|
+
|
|
28
|
+
if(blockheightDelta<=0) return 0n;
|
|
29
|
+
|
|
30
|
+
const numTxs = Math.ceil(blockheightDelta / this.maxHeadersPerTx);
|
|
31
|
+
|
|
32
|
+
const synchronizationFee = (BigInt(blockheightDelta) * await this.getFeePerBlock(feeRate))
|
|
33
|
+
+ CitreaFees.getGasFee(
|
|
34
|
+
EVMBtcRelay.GasCosts.GAS_BASE_MAIN * numTxs,
|
|
35
|
+
feeRate,
|
|
36
|
+
CitreaBtcRelay.StateDiffSize.STATE_DIFF_BASE * numTxs
|
|
37
|
+
);
|
|
38
|
+
logger.debug("estimateSynchronizeFee(): required blockheight: "+requiredBlockheight+
|
|
39
|
+
" blockheight delta: "+blockheightDelta+" fee: "+synchronizationFee.toString(10));
|
|
40
|
+
|
|
41
|
+
return synchronizationFee;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Returns fee required (in native token) to synchronize a single block to btc relay
|
|
46
|
+
*
|
|
47
|
+
* @param feeRate
|
|
48
|
+
*/
|
|
49
|
+
public async getFeePerBlock(feeRate?: string): Promise<bigint> {
|
|
50
|
+
feeRate ??= await this.Chain.Fees.getFeeRate();
|
|
51
|
+
return CitreaFees.getGasFee(
|
|
52
|
+
EVMBtcRelay.GasCosts.GAS_PER_BLOCKHEADER,
|
|
53
|
+
feeRate,
|
|
54
|
+
CitreaBtcRelay.StateDiffSize.STATE_DIFF_PER_BLOCKHEADER
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
}
|
|
@@ -3,13 +3,13 @@ import {EVMPreFetchVerification} from "../../evm/swaps/modules/EVMSwapInit";
|
|
|
3
3
|
import {EVMTx} from "../../evm/chain/modules/EVMTransactions";
|
|
4
4
|
import {EVMSigner} from "../../evm/wallet/EVMSigner";
|
|
5
5
|
import {EVMSwapData} from "../../evm/swaps/EVMSwapData";
|
|
6
|
-
import {EVMSwapContract} from "../../evm/swaps/EVMSwapContract";
|
|
7
6
|
import {EVMChainInterface} from "../../evm/chain/EVMChainInterface";
|
|
8
7
|
import {EVMChainEventsBrowser} from "../../evm/events/EVMChainEventsBrowser";
|
|
9
|
-
import {EVMBtcRelay} from "../../evm/btcrelay/EVMBtcRelay";
|
|
10
8
|
import { EVMSpvVaultData } from "../../evm/spv_swap/EVMSpvVaultData";
|
|
11
9
|
import { EVMSpvWithdrawalData } from "../../evm/spv_swap/EVMSpvWithdrawalData";
|
|
12
|
-
import {
|
|
10
|
+
import {CitreaSwapContract} from "./CitreaSwapContract";
|
|
11
|
+
import {CitreaBtcRelay} from "./CitreaBtcRelay";
|
|
12
|
+
import {CitreaSpvVaultContract} from "./CitreaSpvVaultContract";
|
|
13
13
|
|
|
14
14
|
export type CitreaChainType = ChainType<
|
|
15
15
|
"CITREA",
|
|
@@ -18,11 +18,11 @@ export type CitreaChainType = ChainType<
|
|
|
18
18
|
EVMTx,
|
|
19
19
|
EVMSigner,
|
|
20
20
|
EVMSwapData,
|
|
21
|
-
|
|
21
|
+
CitreaSwapContract,
|
|
22
22
|
EVMChainInterface<"CITREA", 5115>,
|
|
23
23
|
EVMChainEventsBrowser,
|
|
24
|
-
|
|
24
|
+
CitreaBtcRelay<any>,
|
|
25
25
|
EVMSpvVaultData,
|
|
26
26
|
EVMSpvWithdrawalData,
|
|
27
|
-
|
|
27
|
+
CitreaSpvVaultContract
|
|
28
28
|
>;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import {EVMFees} from "../../evm/chain/modules/EVMFees";
|
|
2
|
+
import {getLogger} from "../../utils/Utils";
|
|
3
|
+
|
|
4
|
+
export class CitreaFees extends EVMFees {
|
|
5
|
+
|
|
6
|
+
public static readonly StateDiffSize = {
|
|
7
|
+
APPROVE_DIFF_SIZE: 40,
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
protected readonly logger = getLogger("CitreaFees: ");
|
|
11
|
+
|
|
12
|
+
private _blockFeeCache: {
|
|
13
|
+
timestamp: number,
|
|
14
|
+
feeRate: Promise<{baseFee: bigint, l1Fee: bigint}>
|
|
15
|
+
} = null;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Gets evm fee rate
|
|
19
|
+
*
|
|
20
|
+
* @private
|
|
21
|
+
* @returns {Promise<bigint>} L1 gas price denominated in Wei
|
|
22
|
+
*/
|
|
23
|
+
private async __getFeeRate(): Promise<{baseFee: bigint, l1Fee: bigint}> {
|
|
24
|
+
const res = await this.provider.send("eth_getBlockByNumber", ["latest", false]);
|
|
25
|
+
const l1Fee = BigInt(res.l1FeeRate);
|
|
26
|
+
const baseFee = BigInt(res.baseFeePerGas) * this.feeMultiplierPPM / 1_000_000n;
|
|
27
|
+
|
|
28
|
+
this.logger.debug("__getFeeRate(): Base fee rate: "+baseFee.toString(10)+", l1 fee rate: "+l1Fee.toString(10));
|
|
29
|
+
|
|
30
|
+
return {baseFee, l1Fee};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Gets the gas price with caching, format: <gas price in Wei>;<transaction version: v1/v3>
|
|
35
|
+
*
|
|
36
|
+
* @private
|
|
37
|
+
*/
|
|
38
|
+
public async getFeeRate(): Promise<string> {
|
|
39
|
+
if(this._blockFeeCache==null || Date.now() - this._blockFeeCache.timestamp > this.MAX_FEE_AGE) {
|
|
40
|
+
let obj = {
|
|
41
|
+
timestamp: Date.now(),
|
|
42
|
+
feeRate: null
|
|
43
|
+
};
|
|
44
|
+
obj.feeRate = this.__getFeeRate().catch(e => {
|
|
45
|
+
if(this._blockFeeCache===obj) this._blockFeeCache=null;
|
|
46
|
+
throw e;
|
|
47
|
+
});
|
|
48
|
+
this._blockFeeCache = obj;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
let {baseFee, l1Fee} = await this._blockFeeCache.feeRate;
|
|
52
|
+
if(baseFee>this.maxFeeRatePerGas) baseFee = this.maxFeeRatePerGas;
|
|
53
|
+
|
|
54
|
+
const fee = baseFee.toString(10)+","+this.priorityFee.toString(10)+","+l1Fee.toString(10);
|
|
55
|
+
|
|
56
|
+
this.logger.debug("getFeeRate(): calculated fee: "+fee);
|
|
57
|
+
|
|
58
|
+
return fee;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Calculates the total gas fee paid for a given gas limit and state diff size at a given fee rate
|
|
64
|
+
*
|
|
65
|
+
* @param gas
|
|
66
|
+
* @param stateDiffSize
|
|
67
|
+
* @param feeRate
|
|
68
|
+
*/
|
|
69
|
+
public static getGasFee(gas: number, feeRate: string, stateDiffSize: number = 0): bigint {
|
|
70
|
+
if(feeRate==null) return 0n;
|
|
71
|
+
|
|
72
|
+
const [maxFee, priorityFee, l1StateDiffFee] = feeRate.split(",");
|
|
73
|
+
|
|
74
|
+
return (BigInt(gas) * BigInt(maxFee)) + (BigInt(stateDiffSize) * BigInt(l1StateDiffFee ?? 0n));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
}
|
|
@@ -10,6 +10,10 @@ import {EVMChainEventsBrowser} from "../../evm/events/EVMChainEventsBrowser";
|
|
|
10
10
|
import {EVMSwapData} from "../../evm/swaps/EVMSwapData";
|
|
11
11
|
import {EVMSpvVaultData} from "../../evm/spv_swap/EVMSpvVaultData";
|
|
12
12
|
import {EVMSpvWithdrawalData} from "../../evm/spv_swap/EVMSpvWithdrawalData";
|
|
13
|
+
import {CitreaFees} from "./CitreaFees";
|
|
14
|
+
import {CitreaBtcRelay} from "./CitreaBtcRelay";
|
|
15
|
+
import {CitreaSwapContract} from "./CitreaSwapContract";
|
|
16
|
+
import {CitreaTokens} from "./CitreaTokens";
|
|
13
17
|
|
|
14
18
|
const CitreaChainIds = {
|
|
15
19
|
MAINNET: null,
|
|
@@ -57,12 +61,17 @@ const CitreaContractAddresses = {
|
|
|
57
61
|
}
|
|
58
62
|
};
|
|
59
63
|
|
|
60
|
-
export type CitreaAssetsType = BaseTokenType<"CBTC">;
|
|
64
|
+
export type CitreaAssetsType = BaseTokenType<"CBTC" | "USDC">;
|
|
61
65
|
export const CitreaAssets: CitreaAssetsType = {
|
|
62
66
|
CBTC: {
|
|
63
67
|
address: "0x0000000000000000000000000000000000000000",
|
|
64
68
|
decimals: 18,
|
|
65
69
|
displayDecimals: 8
|
|
70
|
+
},
|
|
71
|
+
USDC: {
|
|
72
|
+
address: "0x2C8abD2A528D19AFc33d2ebA507c0F405c131335",
|
|
73
|
+
decimals: 6,
|
|
74
|
+
displayDecimals: 6
|
|
66
75
|
}
|
|
67
76
|
} as const;
|
|
68
77
|
|
|
@@ -86,7 +95,7 @@ export type CitreaOptions = {
|
|
|
86
95
|
}
|
|
87
96
|
}
|
|
88
97
|
|
|
89
|
-
fees?:
|
|
98
|
+
fees?: CitreaFees
|
|
90
99
|
}
|
|
91
100
|
|
|
92
101
|
export function initializeCitrea(
|
|
@@ -112,19 +121,20 @@ export function initializeCitrea(
|
|
|
112
121
|
new JsonRpcProvider(options.rpcUrl, {name: "Citrea", chainId}) :
|
|
113
122
|
options.rpcUrl;
|
|
114
123
|
|
|
115
|
-
const Fees = options.fees ?? new
|
|
124
|
+
const Fees = options.fees ?? new CitreaFees(provider, 2n * 1_000_000_000n, 1_000_000n);
|
|
116
125
|
|
|
117
126
|
const chainInterface = new EVMChainInterface("CITREA", chainId, provider, {
|
|
118
127
|
safeBlockTag: "latest",
|
|
119
128
|
maxLogsBlockRange: options.maxLogsBlockRange ?? 500
|
|
120
129
|
}, options.retryPolicy, Fees);
|
|
130
|
+
chainInterface.Tokens = new CitreaTokens(chainInterface); //Override with custom token module allowing l1 state diff based fee calculation
|
|
121
131
|
|
|
122
|
-
const btcRelay = new
|
|
132
|
+
const btcRelay = new CitreaBtcRelay(
|
|
123
133
|
chainInterface, bitcoinRpc, network, options.btcRelayContract ?? defaultContractAddresses.btcRelayContract,
|
|
124
134
|
options.btcRelayDeploymentHeight ?? defaultContractAddresses.btcRelayDeploymentHeight
|
|
125
135
|
);
|
|
126
136
|
|
|
127
|
-
const swapContract = new
|
|
137
|
+
const swapContract = new CitreaSwapContract(
|
|
128
138
|
chainInterface, btcRelay, options.swapContract ?? defaultContractAddresses.swapContract, {
|
|
129
139
|
refund: {
|
|
130
140
|
...defaultContractAddresses.handlerContracts.refund,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {EVMSpvVaultContract} from "../../evm/spv_swap/EVMSpvVaultContract";
|
|
2
|
+
import {EVMSpvWithdrawalData} from "../../evm/spv_swap/EVMSpvWithdrawalData";
|
|
3
|
+
import {EVMFees} from "../../evm/chain/modules/EVMFees";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export class CitreaSpvVaultContract extends EVMSpvVaultContract<"CITREA"> {
|
|
7
|
+
|
|
8
|
+
async getClaimFee(signer: string, withdrawalData: EVMSpvWithdrawalData, feeRate?: string): Promise<bigint> {
|
|
9
|
+
feeRate ??= await this.Chain.Fees.getFeeRate();
|
|
10
|
+
return EVMFees.getGasFee(EVMSpvVaultContract.GasCosts.CLAIM, feeRate);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async getFrontFee(signer: string, withdrawalData: EVMSpvWithdrawalData, feeRate?: string): Promise<bigint> {
|
|
14
|
+
feeRate ??= await this.Chain.Fees.getFeeRate();
|
|
15
|
+
return EVMFees.getGasFee(EVMSpvVaultContract.GasCosts.FRONT, feeRate);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
}
|