@atomiqlabs/chain-evm 1.0.0-dev.22 → 1.0.0-dev.28

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.
Files changed (59) hide show
  1. package/dist/chains/citrea/CitreaBtcRelay.d.ts +21 -0
  2. package/dist/chains/citrea/CitreaBtcRelay.js +43 -0
  3. package/dist/chains/citrea/CitreaChainType.d.ts +4 -4
  4. package/dist/chains/citrea/CitreaFees.d.ts +29 -0
  5. package/dist/chains/citrea/CitreaFees.js +67 -0
  6. package/dist/chains/citrea/CitreaInitializer.d.ts +3 -3
  7. package/dist/chains/citrea/CitreaInitializer.js +15 -8
  8. package/dist/chains/citrea/CitreaSpvVaultContract.d.ts +15 -0
  9. package/dist/chains/citrea/CitreaSpvVaultContract.js +75 -0
  10. package/dist/chains/citrea/CitreaSwapContract.d.ts +22 -0
  11. package/dist/chains/citrea/CitreaSwapContract.js +96 -0
  12. package/dist/chains/citrea/CitreaTokens.d.ts +9 -0
  13. package/dist/chains/citrea/CitreaTokens.js +20 -0
  14. package/dist/evm/btcrelay/EVMBtcRelay.d.ts +8 -1
  15. package/dist/evm/btcrelay/EVMBtcRelay.js +15 -11
  16. package/dist/evm/chain/EVMChainInterface.d.ts +6 -6
  17. package/dist/evm/chain/EVMChainInterface.js +1 -2
  18. package/dist/evm/chain/modules/EVMAddresses.d.ts +1 -0
  19. package/dist/evm/chain/modules/EVMAddresses.js +5 -0
  20. package/dist/evm/chain/modules/EVMFees.d.ts +8 -7
  21. package/dist/evm/chain/modules/EVMFees.js +3 -3
  22. package/dist/evm/chain/modules/EVMTokens.d.ts +2 -0
  23. package/dist/evm/chain/modules/EVMTokens.js +10 -2
  24. package/dist/evm/spv_swap/EVMSpvVaultContract.d.ts +17 -3
  25. package/dist/evm/spv_swap/EVMSpvVaultContract.js +83 -13
  26. package/dist/evm/spv_swap/EVMSpvVaultData.d.ts +1 -0
  27. package/dist/evm/spv_swap/EVMSpvVaultData.js +21 -0
  28. package/dist/evm/swaps/EVMSwapContract.d.ts +4 -4
  29. package/dist/evm/swaps/EVMSwapContract.js +4 -4
  30. package/dist/evm/swaps/modules/EVMLpVault.js +2 -2
  31. package/dist/evm/swaps/modules/EVMSwapClaim.d.ts +1 -0
  32. package/dist/evm/swaps/modules/EVMSwapClaim.js +40 -4
  33. package/dist/evm/swaps/modules/EVMSwapInit.d.ts +3 -3
  34. package/dist/evm/swaps/modules/EVMSwapInit.js +43 -9
  35. package/dist/evm/swaps/modules/EVMSwapRefund.d.ts +2 -2
  36. package/dist/evm/swaps/modules/EVMSwapRefund.js +42 -7
  37. package/dist/index.d.ts +1 -0
  38. package/dist/index.js +1 -0
  39. package/package.json +2 -2
  40. package/src/chains/citrea/CitreaBtcRelay.ts +58 -0
  41. package/src/chains/citrea/CitreaChainType.ts +6 -6
  42. package/src/chains/citrea/CitreaFees.ts +77 -0
  43. package/src/chains/citrea/CitreaInitializer.ts +17 -6
  44. package/src/chains/citrea/CitreaSpvVaultContract.ts +76 -0
  45. package/src/chains/citrea/CitreaSwapContract.ts +103 -0
  46. package/src/chains/citrea/CitreaTokens.ts +22 -0
  47. package/src/evm/btcrelay/EVMBtcRelay.ts +17 -12
  48. package/src/evm/chain/EVMChainInterface.ts +7 -8
  49. package/src/evm/chain/modules/EVMAddresses.ts +6 -0
  50. package/src/evm/chain/modules/EVMFees.ts +10 -11
  51. package/src/evm/chain/modules/EVMTokens.ts +13 -2
  52. package/src/evm/spv_swap/EVMSpvVaultContract.ts +84 -14
  53. package/src/evm/spv_swap/EVMSpvVaultData.ts +24 -1
  54. package/src/evm/swaps/EVMSwapContract.ts +4 -4
  55. package/src/evm/swaps/modules/EVMLpVault.ts +2 -2
  56. package/src/evm/swaps/modules/EVMSwapClaim.ts +36 -4
  57. package/src/evm/swaps/modules/EVMSwapInit.ts +44 -10
  58. package/src/evm/swaps/modules/EVMSwapRefund.ts +38 -7
  59. package/src/index.ts +1 -0
@@ -0,0 +1,21 @@
1
+ import { EVMBtcRelay } from "../../evm/btcrelay/EVMBtcRelay";
2
+ import { BtcBlock } from "@atomiqlabs/base";
3
+ export declare class CitreaBtcRelay<B extends BtcBlock> extends EVMBtcRelay<B> {
4
+ static StateDiffSize: {
5
+ STATE_DIFF_PER_BLOCKHEADER: number;
6
+ STATE_DIFF_BASE: number;
7
+ };
8
+ /**
9
+ * Estimate required synchronization fee (worst case) to synchronize btc relay to the required blockheight
10
+ *
11
+ * @param requiredBlockheight
12
+ * @param feeRate
13
+ */
14
+ estimateSynchronizeFee(requiredBlockheight: number, feeRate?: string): Promise<bigint>;
15
+ /**
16
+ * Returns fee required (in native token) to synchronize a single block to btc relay
17
+ *
18
+ * @param feeRate
19
+ */
20
+ getFeePerBlock(feeRate?: string): Promise<bigint>;
21
+ }
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CitreaBtcRelay = void 0;
4
+ const EVMBtcRelay_1 = require("../../evm/btcrelay/EVMBtcRelay");
5
+ const Utils_1 = require("../../utils/Utils");
6
+ const CitreaFees_1 = require("./CitreaFees");
7
+ const logger = (0, Utils_1.getLogger)("CitreaBtcRelay: ");
8
+ class CitreaBtcRelay extends EVMBtcRelay_1.EVMBtcRelay {
9
+ /**
10
+ * Estimate required synchronization fee (worst case) to synchronize btc relay to the required blockheight
11
+ *
12
+ * @param requiredBlockheight
13
+ * @param feeRate
14
+ */
15
+ async estimateSynchronizeFee(requiredBlockheight, feeRate) {
16
+ feeRate ?? (feeRate = await this.Chain.Fees.getFeeRate());
17
+ const tipData = await this.getTipData();
18
+ const currBlockheight = tipData.blockheight;
19
+ const blockheightDelta = requiredBlockheight - currBlockheight;
20
+ if (blockheightDelta <= 0)
21
+ return 0n;
22
+ const numTxs = Math.ceil(blockheightDelta / this.maxHeadersPerTx);
23
+ const synchronizationFee = (BigInt(blockheightDelta) * await this.getFeePerBlock(feeRate))
24
+ + CitreaFees_1.CitreaFees.getGasFee(EVMBtcRelay_1.EVMBtcRelay.GasCosts.GAS_BASE_MAIN * numTxs, feeRate, CitreaBtcRelay.StateDiffSize.STATE_DIFF_BASE * numTxs);
25
+ logger.debug("estimateSynchronizeFee(): required blockheight: " + requiredBlockheight +
26
+ " blockheight delta: " + blockheightDelta + " fee: " + synchronizationFee.toString(10));
27
+ return synchronizationFee;
28
+ }
29
+ /**
30
+ * Returns fee required (in native token) to synchronize a single block to btc relay
31
+ *
32
+ * @param feeRate
33
+ */
34
+ async getFeePerBlock(feeRate) {
35
+ feeRate ?? (feeRate = await this.Chain.Fees.getFeeRate());
36
+ return CitreaFees_1.CitreaFees.getGasFee(EVMBtcRelay_1.EVMBtcRelay.GasCosts.GAS_PER_BLOCKHEADER, feeRate, CitreaBtcRelay.StateDiffSize.STATE_DIFF_PER_BLOCKHEADER);
37
+ }
38
+ }
39
+ exports.CitreaBtcRelay = CitreaBtcRelay;
40
+ CitreaBtcRelay.StateDiffSize = {
41
+ STATE_DIFF_PER_BLOCKHEADER: 22,
42
+ STATE_DIFF_BASE: 30
43
+ };
@@ -3,11 +3,11 @@ 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 { EVMSpvVaultContract } from "../../evm/spv_swap/EVMSpvVaultContract";
13
- export type CitreaChainType = ChainType<"CITREA", never, EVMPreFetchVerification, EVMTx, EVMSigner, EVMSwapData, EVMSwapContract<"CITREA">, EVMChainInterface<"CITREA", 5115>, EVMChainEventsBrowser, EVMBtcRelay<any>, EVMSpvVaultData, EVMSpvWithdrawalData, EVMSpvVaultContract<"CITREA">>;
10
+ import { CitreaSwapContract } from "./CitreaSwapContract";
11
+ import { CitreaBtcRelay } from "./CitreaBtcRelay";
12
+ import { CitreaSpvVaultContract } from "./CitreaSpvVaultContract";
13
+ export type CitreaChainType = ChainType<"CITREA", never, EVMPreFetchVerification, EVMTx, EVMSigner, EVMSwapData, CitreaSwapContract, EVMChainInterface<"CITREA", 5115>, EVMChainEventsBrowser, CitreaBtcRelay<any>, EVMSpvVaultData, EVMSpvWithdrawalData, CitreaSpvVaultContract>;
@@ -0,0 +1,29 @@
1
+ import { EVMFees } from "../../evm/chain/modules/EVMFees";
2
+ export declare class CitreaFees extends EVMFees {
3
+ static readonly StateDiffSize: {
4
+ APPROVE_DIFF_SIZE: number;
5
+ };
6
+ protected readonly logger: import("../../utils/Utils").LoggerType;
7
+ private _blockFeeCache;
8
+ /**
9
+ * Gets evm fee rate
10
+ *
11
+ * @private
12
+ * @returns {Promise<bigint>} L1 gas price denominated in Wei
13
+ */
14
+ private __getFeeRate;
15
+ /**
16
+ * Gets the gas price with caching, format: <gas price in Wei>;<transaction version: v1/v3>
17
+ *
18
+ * @private
19
+ */
20
+ getFeeRate(): Promise<string>;
21
+ /**
22
+ * Calculates the total gas fee paid for a given gas limit and state diff size at a given fee rate
23
+ *
24
+ * @param gas
25
+ * @param stateDiffSize
26
+ * @param feeRate
27
+ */
28
+ static getGasFee(gas: number, feeRate: string, stateDiffSize?: number): bigint;
29
+ }
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CitreaFees = void 0;
4
+ const EVMFees_1 = require("../../evm/chain/modules/EVMFees");
5
+ const Utils_1 = require("../../utils/Utils");
6
+ class CitreaFees extends EVMFees_1.EVMFees {
7
+ constructor() {
8
+ super(...arguments);
9
+ this.logger = (0, Utils_1.getLogger)("CitreaFees: ");
10
+ this._blockFeeCache = null;
11
+ }
12
+ /**
13
+ * Gets evm fee rate
14
+ *
15
+ * @private
16
+ * @returns {Promise<bigint>} L1 gas price denominated in Wei
17
+ */
18
+ async __getFeeRate() {
19
+ const res = await this.provider.send("eth_getBlockByNumber", ["latest", false]);
20
+ const l1Fee = BigInt(res.l1FeeRate);
21
+ const baseFee = BigInt(res.baseFeePerGas) * this.feeMultiplierPPM / 1000000n;
22
+ this.logger.debug("__getFeeRate(): Base fee rate: " + baseFee.toString(10) + ", l1 fee rate: " + l1Fee.toString(10));
23
+ return { baseFee, l1Fee };
24
+ }
25
+ /**
26
+ * Gets the gas price with caching, format: <gas price in Wei>;<transaction version: v1/v3>
27
+ *
28
+ * @private
29
+ */
30
+ async getFeeRate() {
31
+ if (this._blockFeeCache == null || Date.now() - this._blockFeeCache.timestamp > this.MAX_FEE_AGE) {
32
+ let obj = {
33
+ timestamp: Date.now(),
34
+ feeRate: null
35
+ };
36
+ obj.feeRate = this.__getFeeRate().catch(e => {
37
+ if (this._blockFeeCache === obj)
38
+ this._blockFeeCache = null;
39
+ throw e;
40
+ });
41
+ this._blockFeeCache = obj;
42
+ }
43
+ let { baseFee, l1Fee } = await this._blockFeeCache.feeRate;
44
+ if (baseFee > this.maxFeeRatePerGas)
45
+ baseFee = this.maxFeeRatePerGas;
46
+ const fee = baseFee.toString(10) + "," + this.priorityFee.toString(10) + "," + l1Fee.toString(10);
47
+ this.logger.debug("getFeeRate(): calculated fee: " + fee);
48
+ return fee;
49
+ }
50
+ /**
51
+ * Calculates the total gas fee paid for a given gas limit and state diff size at a given fee rate
52
+ *
53
+ * @param gas
54
+ * @param stateDiffSize
55
+ * @param feeRate
56
+ */
57
+ static getGasFee(gas, feeRate, stateDiffSize = 0) {
58
+ if (feeRate == null)
59
+ return 0n;
60
+ const [maxFee, priorityFee, l1StateDiffFee] = feeRate.split(",");
61
+ return (BigInt(gas) * BigInt(maxFee)) + (BigInt(stateDiffSize) * BigInt(l1StateDiffFee ?? 0n));
62
+ }
63
+ }
64
+ exports.CitreaFees = CitreaFees;
65
+ CitreaFees.StateDiffSize = {
66
+ APPROVE_DIFF_SIZE: 40,
67
+ };
@@ -1,9 +1,9 @@
1
1
  import { BaseTokenType, BitcoinNetwork, BitcoinRpc, ChainData, ChainInitializer, ChainSwapType } from "@atomiqlabs/base";
2
2
  import { JsonRpcApiProvider } from "ethers";
3
3
  import { EVMRetryPolicy } from "../../evm/chain/EVMChainInterface";
4
- import { EVMFees } from "../../evm/chain/modules/EVMFees";
5
4
  import { CitreaChainType } from "./CitreaChainType";
6
- export type CitreaAssetsType = BaseTokenType<"CBTC">;
5
+ import { CitreaFees } from "./CitreaFees";
6
+ export type CitreaAssetsType = BaseTokenType<"CBTC" | "USDC">;
7
7
  export declare const CitreaAssets: CitreaAssetsType;
8
8
  export type CitreaOptions = {
9
9
  rpcUrl: string | JsonRpcApiProvider;
@@ -23,7 +23,7 @@ export type CitreaOptions = {
23
23
  [type in ChainSwapType]?: string;
24
24
  };
25
25
  };
26
- fees?: EVMFees;
26
+ fees?: CitreaFees;
27
27
  };
28
28
  export declare function initializeCitrea(options: CitreaOptions, bitcoinRpc: BitcoinRpc<any>, network: BitcoinNetwork): ChainData<CitreaChainType>;
29
29
  export type CitreaInitializerType = ChainInitializer<CitreaOptions, CitreaChainType, CitreaAssetsType>;
@@ -4,14 +4,15 @@ exports.CitreaInitializer = exports.initializeCitrea = exports.CitreaAssets = vo
4
4
  const base_1 = require("@atomiqlabs/base");
5
5
  const ethers_1 = require("ethers");
6
6
  const EVMChainInterface_1 = require("../../evm/chain/EVMChainInterface");
7
- const EVMFees_1 = require("../../evm/chain/modules/EVMFees");
8
- const EVMBtcRelay_1 = require("../../evm/btcrelay/EVMBtcRelay");
9
- const EVMSwapContract_1 = require("../../evm/swaps/EVMSwapContract");
10
- const EVMSpvVaultContract_1 = require("../../evm/spv_swap/EVMSpvVaultContract");
11
7
  const EVMChainEventsBrowser_1 = require("../../evm/events/EVMChainEventsBrowser");
12
8
  const EVMSwapData_1 = require("../../evm/swaps/EVMSwapData");
13
9
  const EVMSpvVaultData_1 = require("../../evm/spv_swap/EVMSpvVaultData");
14
10
  const EVMSpvWithdrawalData_1 = require("../../evm/spv_swap/EVMSpvWithdrawalData");
11
+ const CitreaFees_1 = require("./CitreaFees");
12
+ const CitreaBtcRelay_1 = require("./CitreaBtcRelay");
13
+ const CitreaSwapContract_1 = require("./CitreaSwapContract");
14
+ const CitreaTokens_1 = require("./CitreaTokens");
15
+ const CitreaSpvVaultContract_1 = require("./CitreaSpvVaultContract");
15
16
  const CitreaChainIds = {
16
17
  MAINNET: null,
17
18
  TESTNET4: 5115
@@ -61,6 +62,11 @@ exports.CitreaAssets = {
61
62
  address: "0x0000000000000000000000000000000000000000",
62
63
  decimals: 18,
63
64
  displayDecimals: 8
65
+ },
66
+ USDC: {
67
+ address: "0x2C8abD2A528D19AFc33d2ebA507c0F405c131335",
68
+ decimals: 6,
69
+ displayDecimals: 6
64
70
  }
65
71
  };
66
72
  function initializeCitrea(options, bitcoinRpc, network) {
@@ -79,13 +85,14 @@ function initializeCitrea(options, bitcoinRpc, network) {
79
85
  const provider = typeof (options.rpcUrl) === "string" ?
80
86
  new ethers_1.JsonRpcProvider(options.rpcUrl, { name: "Citrea", chainId }) :
81
87
  options.rpcUrl;
82
- const Fees = options.fees ?? new EVMFees_1.EVMFees(provider, 2n * 1000000000n, 1000000n);
88
+ const Fees = options.fees ?? new CitreaFees_1.CitreaFees(provider, 2n * 1000000000n, 1000000n);
83
89
  const chainInterface = new EVMChainInterface_1.EVMChainInterface("CITREA", chainId, provider, {
84
90
  safeBlockTag: "latest",
85
91
  maxLogsBlockRange: options.maxLogsBlockRange ?? 500
86
92
  }, options.retryPolicy, Fees);
87
- const btcRelay = new EVMBtcRelay_1.EVMBtcRelay(chainInterface, bitcoinRpc, network, options.btcRelayContract ?? defaultContractAddresses.btcRelayContract, options.btcRelayDeploymentHeight ?? defaultContractAddresses.btcRelayDeploymentHeight);
88
- const swapContract = new EVMSwapContract_1.EVMSwapContract(chainInterface, btcRelay, options.swapContract ?? defaultContractAddresses.swapContract, {
93
+ chainInterface.Tokens = new CitreaTokens_1.CitreaTokens(chainInterface); //Override with custom token module allowing l1 state diff based fee calculation
94
+ const btcRelay = new CitreaBtcRelay_1.CitreaBtcRelay(chainInterface, bitcoinRpc, network, options.btcRelayContract ?? defaultContractAddresses.btcRelayContract, options.btcRelayDeploymentHeight ?? defaultContractAddresses.btcRelayDeploymentHeight);
95
+ const swapContract = new CitreaSwapContract_1.CitreaSwapContract(chainInterface, btcRelay, options.swapContract ?? defaultContractAddresses.swapContract, {
89
96
  refund: {
90
97
  ...defaultContractAddresses.handlerContracts.refund,
91
98
  ...options?.handlerContracts?.refund
@@ -95,7 +102,7 @@ function initializeCitrea(options, bitcoinRpc, network) {
95
102
  ...options?.handlerContracts?.claim
96
103
  }
97
104
  });
98
- const spvVaultContract = new EVMSpvVaultContract_1.EVMSpvVaultContract(chainInterface, btcRelay, bitcoinRpc, options.spvVaultContract ?? defaultContractAddresses.spvVaultContract, options.spvVaultDeploymentHeight ?? defaultContractAddresses.spvVaultDeploymentHeight);
105
+ const spvVaultContract = new CitreaSpvVaultContract_1.CitreaSpvVaultContract(chainInterface, btcRelay, bitcoinRpc, options.spvVaultContract ?? defaultContractAddresses.spvVaultContract, options.spvVaultDeploymentHeight ?? defaultContractAddresses.spvVaultDeploymentHeight);
99
106
  const chainEvents = new EVMChainEventsBrowser_1.EVMChainEventsBrowser(chainInterface, swapContract, spvVaultContract);
100
107
  return {
101
108
  chainId: "CITREA",
@@ -0,0 +1,15 @@
1
+ import { EVMSpvVaultContract } from "../../evm/spv_swap/EVMSpvVaultContract";
2
+ import { EVMSpvWithdrawalData } from "../../evm/spv_swap/EVMSpvWithdrawalData";
3
+ import { EVMSpvVaultData } from "../../evm/spv_swap/EVMSpvVaultData";
4
+ export declare class CitreaSpvVaultContract extends EVMSpvVaultContract<"CITREA"> {
5
+ static readonly StateDiffSize: {
6
+ BASE_DIFF_SIZE: number;
7
+ ERC_20_TRANSFER_DIFF_SIZE: number;
8
+ NATIVE_SELF_TRANSFER_DIFF_SIZE: number;
9
+ NATIVE_TRANSFER_DIFF_SIZE: number;
10
+ EXECUTION_SCHEDULE_DIFF_SIZE: number;
11
+ };
12
+ private calculateStateDiff;
13
+ getClaimFee(signer: string, vault?: EVMSpvVaultData, data?: EVMSpvWithdrawalData, feeRate?: string): Promise<bigint>;
14
+ getFrontFee(signer: string, vault?: EVMSpvVaultData, data?: EVMSpvWithdrawalData, feeRate?: string): Promise<bigint>;
15
+ }
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CitreaSpvVaultContract = void 0;
4
+ const EVMSpvVaultContract_1 = require("../../evm/spv_swap/EVMSpvVaultContract");
5
+ const EVMSpvVaultData_1 = require("../../evm/spv_swap/EVMSpvVaultData");
6
+ const lib_esm_1 = require("ethers/lib.esm");
7
+ const ethers_1 = require("ethers");
8
+ const CitreaFees_1 = require("./CitreaFees");
9
+ const EVMAddresses_1 = require("../../evm/chain/modules/EVMAddresses");
10
+ class CitreaSpvVaultContract extends EVMSpvVaultContract_1.EVMSpvVaultContract {
11
+ calculateStateDiff(signer, tokenStateChanges) {
12
+ let stateDiffSize = 0;
13
+ tokenStateChanges.forEach(val => {
14
+ const [address, token] = val.split(":");
15
+ if (token.toLowerCase() === this.Chain.getNativeCurrencyAddress().toLowerCase()) {
16
+ stateDiffSize += address.toLowerCase() === signer?.toLowerCase() ? CitreaSpvVaultContract.StateDiffSize.NATIVE_SELF_TRANSFER_DIFF_SIZE : CitreaSpvVaultContract.StateDiffSize.NATIVE_TRANSFER_DIFF_SIZE;
17
+ }
18
+ else {
19
+ stateDiffSize += CitreaSpvVaultContract.StateDiffSize.ERC_20_TRANSFER_DIFF_SIZE;
20
+ }
21
+ });
22
+ return stateDiffSize;
23
+ }
24
+ async getClaimFee(signer, vault, data, feeRate) {
25
+ vault ?? (vault = EVMSpvVaultData_1.EVMSpvVaultData.randomVault());
26
+ feeRate ?? (feeRate = await this.Chain.Fees.getFeeRate());
27
+ const tokenStateChanges = new Set();
28
+ let diffSize = CitreaSpvVaultContract.StateDiffSize.BASE_DIFF_SIZE;
29
+ const recipient = data != null ? data.recipient : EVMAddresses_1.EVMAddresses.randomAddress();
30
+ if (data == null || (data.rawAmounts[0] != null && data.rawAmounts[0] > 0n)) {
31
+ tokenStateChanges.add(recipient.toLowerCase() + ":" + vault.token0.token.toLowerCase());
32
+ if (data == null || data.frontingFeeRate > 0n)
33
+ tokenStateChanges.add(ethers_1.ZeroAddress + ":" + vault.token0.token.toLowerCase()); //Also needs to pay out to fronter
34
+ if (data == null || data.callerFeeRate > 0n)
35
+ tokenStateChanges.add(signer + ":" + vault.token0.token.toLowerCase()); //Also needs to pay out to caller
36
+ }
37
+ if (data == null || (data.rawAmounts[1] != null && data.rawAmounts[1] > 0n)) {
38
+ tokenStateChanges.add(recipient.toLowerCase() + ":" + vault.token1.token.toLowerCase());
39
+ if (data == null || data.frontingFeeRate > 0n)
40
+ tokenStateChanges.add(ethers_1.ZeroAddress + ":" + vault.token1.token.toLowerCase()); //Also needs to pay out to fronter
41
+ if (data == null || data.callerFeeRate > 0n)
42
+ tokenStateChanges.add(signer + ":" + vault.token1.token.toLowerCase()); //Also needs to pay out to caller
43
+ }
44
+ diffSize += this.calculateStateDiff(signer, tokenStateChanges);
45
+ if (data == null || (data.executionHash != null && data.executionHash !== lib_esm_1.ZeroHash))
46
+ diffSize += CitreaSpvVaultContract.StateDiffSize.EXECUTION_SCHEDULE_DIFF_SIZE;
47
+ const gasFee = await super.getClaimFee(signer, vault, data, feeRate);
48
+ return gasFee + CitreaFees_1.CitreaFees.getGasFee(0, feeRate, diffSize);
49
+ }
50
+ async getFrontFee(signer, vault, data, feeRate) {
51
+ vault ?? (vault = EVMSpvVaultData_1.EVMSpvVaultData.randomVault());
52
+ feeRate ?? (feeRate = await this.Chain.Fees.getFeeRate());
53
+ const tokenStateChanges = new Set();
54
+ let diffSize = CitreaSpvVaultContract.StateDiffSize.BASE_DIFF_SIZE;
55
+ if (data == null || (data.rawAmounts[0] != null && data.rawAmounts[0] > 0n)) {
56
+ tokenStateChanges.add(signer + ":" + vault.token0.token.toLowerCase());
57
+ }
58
+ if (data == null || (data.rawAmounts[1] != null && data.rawAmounts[1] > 0n)) {
59
+ tokenStateChanges.add(signer + ":" + vault.token1.token.toLowerCase());
60
+ }
61
+ diffSize += this.calculateStateDiff(signer, tokenStateChanges);
62
+ if (data == null || (data.executionHash != null && data.executionHash !== lib_esm_1.ZeroHash))
63
+ diffSize += CitreaSpvVaultContract.StateDiffSize.EXECUTION_SCHEDULE_DIFF_SIZE;
64
+ const gasFee = await super.getFrontFee(signer, vault, data, feeRate);
65
+ return gasFee + CitreaFees_1.CitreaFees.getGasFee(0, feeRate, diffSize);
66
+ }
67
+ }
68
+ exports.CitreaSpvVaultContract = CitreaSpvVaultContract;
69
+ CitreaSpvVaultContract.StateDiffSize = {
70
+ BASE_DIFF_SIZE: 50,
71
+ ERC_20_TRANSFER_DIFF_SIZE: 50,
72
+ NATIVE_SELF_TRANSFER_DIFF_SIZE: 20,
73
+ NATIVE_TRANSFER_DIFF_SIZE: 30,
74
+ EXECUTION_SCHEDULE_DIFF_SIZE: 40
75
+ };
@@ -0,0 +1,22 @@
1
+ import { EVMSwapContract } from "../../evm/swaps/EVMSwapContract";
2
+ import { EVMSwapData } from "../../evm/swaps/EVMSwapData";
3
+ export declare class CitreaSwapContract extends EVMSwapContract<"CITREA"> {
4
+ static readonly StateDiffSize: {
5
+ BASE_DIFF_SIZE: number;
6
+ REPUTATION_UPDATE_DIFF_SIZE: number;
7
+ LP_VAULT_UPDATE_DIFF_SIZE: number;
8
+ ERC_20_TRANSFER_DIFF_SIZE: number;
9
+ NATIVE_SELF_TRANSFER_DIFF_SIZE: number;
10
+ NATIVE_TRANSFER_DIFF_SIZE: number;
11
+ };
12
+ private calculateStateDiff;
13
+ /**
14
+ * Get the estimated solana fee of the commit transaction
15
+ */
16
+ getCommitFee(signer: string, swapData: EVMSwapData, feeRate?: string): Promise<bigint>;
17
+ getClaimFee(signer: string, swapData: EVMSwapData, feeRate?: string): Promise<bigint>;
18
+ /**
19
+ * Get the estimated solana transaction fee of the refund transaction
20
+ */
21
+ getRefundFee(signer: string, swapData: EVMSwapData, feeRate?: string): Promise<bigint>;
22
+ }
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CitreaSwapContract = void 0;
4
+ const EVMSwapContract_1 = require("../../evm/swaps/EVMSwapContract");
5
+ const CitreaFees_1 = require("./CitreaFees");
6
+ class CitreaSwapContract extends EVMSwapContract_1.EVMSwapContract {
7
+ calculateStateDiff(signer, tokenStateChanges) {
8
+ let stateDiffSize = 0;
9
+ tokenStateChanges.forEach(val => {
10
+ const [address, token] = val.split(":");
11
+ if (token.toLowerCase() === this.Chain.getNativeCurrencyAddress().toLowerCase()) {
12
+ stateDiffSize += address.toLowerCase() === signer?.toLowerCase() ? CitreaSwapContract.StateDiffSize.NATIVE_SELF_TRANSFER_DIFF_SIZE : CitreaSwapContract.StateDiffSize.NATIVE_TRANSFER_DIFF_SIZE;
13
+ }
14
+ else {
15
+ stateDiffSize += CitreaSwapContract.StateDiffSize.ERC_20_TRANSFER_DIFF_SIZE;
16
+ }
17
+ });
18
+ return stateDiffSize;
19
+ }
20
+ /**
21
+ * Get the estimated solana fee of the commit transaction
22
+ */
23
+ async getCommitFee(signer, swapData, feeRate) {
24
+ feeRate ?? (feeRate = await this.Chain.Fees.getFeeRate());
25
+ const tokenStateChanges = new Set();
26
+ let diffSize = CitreaSwapContract.StateDiffSize.BASE_DIFF_SIZE;
27
+ if (!swapData.isPayIn()) {
28
+ diffSize += CitreaSwapContract.StateDiffSize.LP_VAULT_UPDATE_DIFF_SIZE;
29
+ }
30
+ else {
31
+ tokenStateChanges.add(swapData.getOfferer().toLowerCase() + ":" + swapData.getToken().toLowerCase());
32
+ }
33
+ if (swapData.getTotalDeposit() > 0n) {
34
+ tokenStateChanges.add(signer.toLowerCase() + ":" + swapData.getDepositToken().toLowerCase());
35
+ }
36
+ diffSize += this.calculateStateDiff(signer, tokenStateChanges);
37
+ const gasFee = await this.Init.getInitFee(swapData, feeRate);
38
+ return gasFee + CitreaFees_1.CitreaFees.getGasFee(0, feeRate, diffSize);
39
+ }
40
+ async getClaimFee(signer, swapData, feeRate) {
41
+ feeRate ?? (feeRate = await this.Chain.Fees.getFeeRate());
42
+ const tokenStateChanges = new Set();
43
+ let diffSize = CitreaSwapContract.StateDiffSize.BASE_DIFF_SIZE;
44
+ if (swapData.reputation)
45
+ diffSize += CitreaSwapContract.StateDiffSize.REPUTATION_UPDATE_DIFF_SIZE;
46
+ if (!swapData.isPayOut()) {
47
+ diffSize += CitreaSwapContract.StateDiffSize.LP_VAULT_UPDATE_DIFF_SIZE;
48
+ }
49
+ else {
50
+ tokenStateChanges.add(swapData.getClaimer().toLowerCase() + ":" + swapData.getToken().toLowerCase());
51
+ }
52
+ if (swapData.getClaimerBounty() > 0) {
53
+ tokenStateChanges.add(signer.toLowerCase() + ":" + swapData.getDepositToken().toLowerCase());
54
+ }
55
+ if (swapData.getSecurityDeposit() > swapData.getClaimerBounty()) {
56
+ tokenStateChanges.add(swapData.getClaimer().toLowerCase() + ":" + swapData.getDepositToken().toLowerCase());
57
+ }
58
+ diffSize += this.calculateStateDiff(signer, tokenStateChanges);
59
+ const gasFee = await this.Claim.getClaimFee(swapData, feeRate);
60
+ return gasFee + CitreaFees_1.CitreaFees.getGasFee(0, feeRate, diffSize);
61
+ }
62
+ /**
63
+ * Get the estimated solana transaction fee of the refund transaction
64
+ */
65
+ async getRefundFee(signer, swapData, feeRate) {
66
+ feeRate ?? (feeRate = await this.Chain.Fees.getFeeRate());
67
+ const tokenStateChanges = new Set();
68
+ let diffSize = CitreaSwapContract.StateDiffSize.BASE_DIFF_SIZE;
69
+ if (swapData.reputation)
70
+ diffSize += CitreaSwapContract.StateDiffSize.REPUTATION_UPDATE_DIFF_SIZE;
71
+ if (!swapData.isPayIn()) {
72
+ diffSize += CitreaSwapContract.StateDiffSize.LP_VAULT_UPDATE_DIFF_SIZE;
73
+ }
74
+ else {
75
+ tokenStateChanges.add(swapData.getOfferer().toLowerCase() + ":" + swapData.getToken().toLowerCase());
76
+ }
77
+ if (swapData.getSecurityDeposit() > 0) {
78
+ tokenStateChanges.add(swapData.getOfferer().toLowerCase() + ":" + swapData.getDepositToken().toLowerCase());
79
+ }
80
+ if (swapData.getClaimerBounty() > swapData.getSecurityDeposit()) {
81
+ tokenStateChanges.add(swapData.getClaimer().toLowerCase() + ":" + swapData.getDepositToken().toLowerCase());
82
+ }
83
+ diffSize += this.calculateStateDiff(signer, tokenStateChanges);
84
+ const gasFee = await this.Refund.getRefundFee(swapData, feeRate);
85
+ return gasFee + CitreaFees_1.CitreaFees.getGasFee(0, feeRate, diffSize);
86
+ }
87
+ }
88
+ exports.CitreaSwapContract = CitreaSwapContract;
89
+ CitreaSwapContract.StateDiffSize = {
90
+ BASE_DIFF_SIZE: 35,
91
+ REPUTATION_UPDATE_DIFF_SIZE: 25,
92
+ LP_VAULT_UPDATE_DIFF_SIZE: 25,
93
+ ERC_20_TRANSFER_DIFF_SIZE: 50,
94
+ NATIVE_SELF_TRANSFER_DIFF_SIZE: 20,
95
+ NATIVE_TRANSFER_DIFF_SIZE: 30
96
+ };
@@ -0,0 +1,9 @@
1
+ import { EVMTokens } from "../../evm/chain/modules/EVMTokens";
2
+ export declare class CitreaTokens extends EVMTokens {
3
+ static readonly StateDiffSize: {
4
+ APPROVE_DIFF_SIZE: number;
5
+ TRANSFER_DIFF_SIZE: number;
6
+ };
7
+ getApproveFee(feeRate?: string): Promise<bigint>;
8
+ getTransferFee(feeRate?: string): Promise<bigint>;
9
+ }
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CitreaTokens = void 0;
4
+ const EVMTokens_1 = require("../../evm/chain/modules/EVMTokens");
5
+ const CitreaFees_1 = require("./CitreaFees");
6
+ class CitreaTokens extends EVMTokens_1.EVMTokens {
7
+ async getApproveFee(feeRate) {
8
+ feeRate ?? (feeRate = await this.root.Fees.getFeeRate());
9
+ return CitreaFees_1.CitreaFees.getGasFee(EVMTokens_1.EVMTokens.GasCosts.APPROVE, feeRate, CitreaTokens.StateDiffSize.APPROVE_DIFF_SIZE);
10
+ }
11
+ async getTransferFee(feeRate) {
12
+ feeRate ?? (feeRate = await this.root.Fees.getFeeRate());
13
+ return CitreaFees_1.CitreaFees.getGasFee(EVMTokens_1.EVMTokens.GasCosts.APPROVE, feeRate, CitreaTokens.StateDiffSize.TRANSFER_DIFF_SIZE);
14
+ }
15
+ }
16
+ exports.CitreaTokens = CitreaTokens;
17
+ CitreaTokens.StateDiffSize = {
18
+ APPROVE_DIFF_SIZE: 35,
19
+ TRANSFER_DIFF_SIZE: 55
20
+ };
@@ -9,6 +9,13 @@ import { EVMSigner } from "../wallet/EVMSigner";
9
9
  import { EVMTx } from "../chain/modules/EVMTransactions";
10
10
  import { EVMChainInterface } from "../chain/EVMChainInterface";
11
11
  export declare class EVMBtcRelay<B extends BtcBlock> extends EVMContractBase<BtcRelayTypechain> implements BtcRelay<EVMBtcStoredHeader, EVMTx, B, EVMSigner> {
12
+ static GasCosts: {
13
+ GAS_PER_BLOCKHEADER: number;
14
+ GAS_BASE_MAIN: number;
15
+ GAS_PER_BLOCKHEADER_FORK: number;
16
+ GAS_PER_BLOCKHEADER_FORKED: number;
17
+ GAS_BASE_FORK: number;
18
+ };
12
19
  SaveMainHeaders(signer: string, mainHeaders: EVMBtcHeader[], storedHeader: EVMBtcStoredHeader, feeRate: string): Promise<EVMTx>;
13
20
  SaveShortForkHeaders(signer: string, forkHeaders: EVMBtcHeader[], storedHeader: EVMBtcStoredHeader, feeRate: string): Promise<EVMTx>;
14
21
  SaveLongForkHeaders(signer: string, forkId: number, forkHeaders: EVMBtcHeader[], storedHeader: EVMBtcStoredHeader, feeRate: string, totalForkHeaders?: number): Promise<EVMTx>;
@@ -148,7 +155,7 @@ export declare class EVMBtcRelay<B extends BtcBlock> extends EVMContractBase<Btc
148
155
  */
149
156
  estimateSynchronizeFee(requiredBlockheight: number, feeRate?: string): Promise<bigint>;
150
157
  /**
151
- * Returns fee required (in SOL) to synchronize a single block to btc relay
158
+ * Returns fee required (in native token) to synchronize a single block to btc relay
152
159
  *
153
160
  * @param feeRate
154
161
  */
@@ -20,11 +20,6 @@ function serializeBlockHeader(e) {
20
20
  hash: Buffer.from(e.getHash(), "hex").reverse()
21
21
  });
22
22
  }
23
- const GAS_PER_BLOCKHEADER = 30000;
24
- const GAS_BASE_MAIN = 15000;
25
- const GAS_PER_BLOCKHEADER_FORK = 65000;
26
- const GAS_PER_BLOCKHEADER_FORKED = 10000;
27
- const GAS_BASE_FORK = 25000;
28
23
  const logger = (0, Utils_1.getLogger)("EVMBtcRelay: ");
29
24
  class EVMBtcRelay extends EVMContractBase_1.EVMContractBase {
30
25
  async SaveMainHeaders(signer, mainHeaders, storedHeader, feeRate) {
@@ -33,7 +28,7 @@ class EVMBtcRelay extends EVMContractBase_1.EVMContractBase {
33
28
  Buffer.concat(mainHeaders.map(header => header.serializeCompact()))
34
29
  ]));
35
30
  tx.from = signer;
36
- EVMFees_1.EVMFees.applyFeeRate(tx, GAS_BASE_MAIN + (GAS_PER_BLOCKHEADER * mainHeaders.length), feeRate);
31
+ EVMFees_1.EVMFees.applyFeeRate(tx, EVMBtcRelay.GasCosts.GAS_BASE_MAIN + (EVMBtcRelay.GasCosts.GAS_PER_BLOCKHEADER * mainHeaders.length), feeRate);
37
32
  return tx;
38
33
  }
39
34
  async SaveShortForkHeaders(signer, forkHeaders, storedHeader, feeRate) {
@@ -42,7 +37,7 @@ class EVMBtcRelay extends EVMContractBase_1.EVMContractBase {
42
37
  Buffer.concat(forkHeaders.map(header => header.serializeCompact()))
43
38
  ]));
44
39
  tx.from = signer;
45
- EVMFees_1.EVMFees.applyFeeRate(tx, GAS_BASE_MAIN + (GAS_PER_BLOCKHEADER * forkHeaders.length), feeRate);
40
+ EVMFees_1.EVMFees.applyFeeRate(tx, EVMBtcRelay.GasCosts.GAS_BASE_MAIN + (EVMBtcRelay.GasCosts.GAS_PER_BLOCKHEADER * forkHeaders.length), feeRate);
46
41
  return tx;
47
42
  }
48
43
  async SaveLongForkHeaders(signer, forkId, forkHeaders, storedHeader, feeRate, totalForkHeaders = 100) {
@@ -51,7 +46,7 @@ class EVMBtcRelay extends EVMContractBase_1.EVMContractBase {
51
46
  Buffer.concat(forkHeaders.map(header => header.serializeCompact()))
52
47
  ]));
53
48
  tx.from = signer;
54
- EVMFees_1.EVMFees.applyFeeRate(tx, GAS_BASE_FORK + (GAS_PER_BLOCKHEADER_FORK * forkHeaders.length) + (GAS_PER_BLOCKHEADER_FORKED * totalForkHeaders), feeRate);
49
+ EVMFees_1.EVMFees.applyFeeRate(tx, EVMBtcRelay.GasCosts.GAS_BASE_FORK + (EVMBtcRelay.GasCosts.GAS_PER_BLOCKHEADER_FORK * forkHeaders.length) + (EVMBtcRelay.GasCosts.GAS_PER_BLOCKHEADER_FORKED * totalForkHeaders), feeRate);
55
50
  return tx;
56
51
  }
57
52
  constructor(chainInterface, bitcoinRpc, bitcoinNetwork, contractAddress, contractDeploymentHeight) {
@@ -327,24 +322,26 @@ class EVMBtcRelay extends EVMContractBase_1.EVMContractBase {
327
322
  * @param feeRate
328
323
  */
329
324
  async estimateSynchronizeFee(requiredBlockheight, feeRate) {
325
+ feeRate ?? (feeRate = await this.Chain.Fees.getFeeRate());
330
326
  const tipData = await this.getTipData();
331
327
  const currBlockheight = tipData.blockheight;
332
328
  const blockheightDelta = requiredBlockheight - currBlockheight;
333
329
  if (blockheightDelta <= 0)
334
330
  return 0n;
335
- const synchronizationFee = BigInt(blockheightDelta) * await this.getFeePerBlock(feeRate);
331
+ const synchronizationFee = (BigInt(blockheightDelta) * await this.getFeePerBlock(feeRate))
332
+ + EVMFees_1.EVMFees.getGasFee(EVMBtcRelay.GasCosts.GAS_BASE_MAIN * Math.ceil(blockheightDelta / this.maxHeadersPerTx), feeRate);
336
333
  logger.debug("estimateSynchronizeFee(): required blockheight: " + requiredBlockheight +
337
334
  " blockheight delta: " + blockheightDelta + " fee: " + synchronizationFee.toString(10));
338
335
  return synchronizationFee;
339
336
  }
340
337
  /**
341
- * Returns fee required (in SOL) to synchronize a single block to btc relay
338
+ * Returns fee required (in native token) to synchronize a single block to btc relay
342
339
  *
343
340
  * @param feeRate
344
341
  */
345
342
  async getFeePerBlock(feeRate) {
346
343
  feeRate ?? (feeRate = await this.Chain.Fees.getFeeRate());
347
- return EVMFees_1.EVMFees.getGasFee(GAS_PER_BLOCKHEADER, feeRate);
344
+ return EVMFees_1.EVMFees.getGasFee(EVMBtcRelay.GasCosts.GAS_PER_BLOCKHEADER, feeRate);
348
345
  }
349
346
  /**
350
347
  * Gets fee rate required for submitting blockheaders to the main chain
@@ -417,3 +414,10 @@ class EVMBtcRelay extends EVMContractBase_1.EVMContractBase {
417
414
  }
418
415
  }
419
416
  exports.EVMBtcRelay = EVMBtcRelay;
417
+ EVMBtcRelay.GasCosts = {
418
+ GAS_PER_BLOCKHEADER: 30000,
419
+ GAS_BASE_MAIN: 15000 + 21000,
420
+ GAS_PER_BLOCKHEADER_FORK: 65000,
421
+ GAS_PER_BLOCKHEADER_FORKED: 10000,
422
+ GAS_BASE_FORK: 25000 + 21000
423
+ };
@@ -24,12 +24,12 @@ export declare class EVMChainInterface<ChainId extends string = string, EVMChain
24
24
  readonly evmChainId: EVMChainId;
25
25
  readonly config: EVMConfiguration;
26
26
  Fees: EVMFees;
27
- readonly Tokens: EVMTokens;
28
- readonly Transactions: EVMTransactions;
29
- readonly Signatures: EVMSignatures;
30
- readonly Events: EVMEvents;
31
- readonly Blocks: EVMBlocks;
32
- protected readonly logger: LoggerType;
27
+ Tokens: EVMTokens;
28
+ Transactions: EVMTransactions;
29
+ Signatures: EVMSignatures;
30
+ Events: EVMEvents;
31
+ Blocks: EVMBlocks;
32
+ protected logger: LoggerType;
33
33
  constructor(chainId: ChainId, evmChainId: EVMChainId, provider: JsonRpcApiProvider, config: EVMConfiguration, retryPolicy?: EVMRetryPolicy, evmFeeEstimator?: EVMFees);
34
34
  getBalance(signer: string, tokenAddress: string): Promise<bigint>;
35
35
  getNativeCurrencyAddress(): string;
@@ -54,8 +54,7 @@ class EVMChainInterface {
54
54
  return this.Transactions.offBeforeTxSigned(callback);
55
55
  }
56
56
  randomAddress() {
57
- const wallet = ethers_1.Wallet.createRandom();
58
- return wallet.address;
57
+ return EVMAddresses_1.EVMAddresses.randomAddress();
59
58
  }
60
59
  randomSigner() {
61
60
  const wallet = ethers_1.Wallet.createRandom();
@@ -6,4 +6,5 @@ export declare class EVMAddresses extends EVMModule<any> {
6
6
  * @param value
7
7
  */
8
8
  static isValidAddress(value: string): boolean;
9
+ static randomAddress(): string;
9
10
  }