@atomiqlabs/chain-evm 1.0.0-dev.22
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/LICENSE +201 -0
- package/dist/chains/citrea/CitreaChainType.d.ts +13 -0
- package/dist/chains/citrea/CitreaChainType.js +2 -0
- package/dist/chains/citrea/CitreaInitializer.d.ts +30 -0
- package/dist/chains/citrea/CitreaInitializer.js +120 -0
- package/dist/evm/btcrelay/BtcRelayAbi.d.ts +198 -0
- package/dist/evm/btcrelay/BtcRelayAbi.js +261 -0
- package/dist/evm/btcrelay/BtcRelayTypechain.d.ts +172 -0
- package/dist/evm/btcrelay/BtcRelayTypechain.js +2 -0
- package/dist/evm/btcrelay/EVMBtcRelay.d.ts +188 -0
- package/dist/evm/btcrelay/EVMBtcRelay.js +419 -0
- package/dist/evm/btcrelay/headers/EVMBtcHeader.d.ts +33 -0
- package/dist/evm/btcrelay/headers/EVMBtcHeader.js +84 -0
- package/dist/evm/btcrelay/headers/EVMBtcStoredHeader.d.ts +56 -0
- package/dist/evm/btcrelay/headers/EVMBtcStoredHeader.js +123 -0
- package/dist/evm/chain/EVMChainInterface.d.ts +51 -0
- package/dist/evm/chain/EVMChainInterface.js +90 -0
- package/dist/evm/chain/EVMModule.d.ts +9 -0
- package/dist/evm/chain/EVMModule.js +13 -0
- package/dist/evm/chain/modules/ERC20Abi.d.ts +168 -0
- package/dist/evm/chain/modules/ERC20Abi.js +225 -0
- package/dist/evm/chain/modules/EVMAddresses.d.ts +9 -0
- package/dist/evm/chain/modules/EVMAddresses.js +26 -0
- package/dist/evm/chain/modules/EVMBlocks.d.ts +20 -0
- package/dist/evm/chain/modules/EVMBlocks.js +64 -0
- package/dist/evm/chain/modules/EVMEvents.d.ts +36 -0
- package/dist/evm/chain/modules/EVMEvents.js +122 -0
- package/dist/evm/chain/modules/EVMFees.d.ts +35 -0
- package/dist/evm/chain/modules/EVMFees.js +73 -0
- package/dist/evm/chain/modules/EVMSignatures.d.ts +29 -0
- package/dist/evm/chain/modules/EVMSignatures.js +68 -0
- package/dist/evm/chain/modules/EVMTokens.d.ts +49 -0
- package/dist/evm/chain/modules/EVMTokens.js +105 -0
- package/dist/evm/chain/modules/EVMTransactions.d.ts +89 -0
- package/dist/evm/chain/modules/EVMTransactions.js +216 -0
- package/dist/evm/contract/EVMContractBase.d.ts +22 -0
- package/dist/evm/contract/EVMContractBase.js +34 -0
- package/dist/evm/contract/EVMContractModule.d.ts +8 -0
- package/dist/evm/contract/EVMContractModule.js +11 -0
- package/dist/evm/contract/modules/EVMContractEvents.d.ts +42 -0
- package/dist/evm/contract/modules/EVMContractEvents.js +75 -0
- package/dist/evm/events/EVMChainEvents.d.ts +22 -0
- package/dist/evm/events/EVMChainEvents.js +67 -0
- package/dist/evm/events/EVMChainEventsBrowser.d.ts +86 -0
- package/dist/evm/events/EVMChainEventsBrowser.js +294 -0
- package/dist/evm/spv_swap/EVMSpvVaultContract.d.ts +64 -0
- package/dist/evm/spv_swap/EVMSpvVaultContract.js +410 -0
- package/dist/evm/spv_swap/EVMSpvVaultData.d.ts +38 -0
- package/dist/evm/spv_swap/EVMSpvVaultData.js +159 -0
- package/dist/evm/spv_swap/EVMSpvWithdrawalData.d.ts +19 -0
- package/dist/evm/spv_swap/EVMSpvWithdrawalData.js +55 -0
- package/dist/evm/spv_swap/SpvVaultContractAbi.d.ts +91 -0
- package/dist/evm/spv_swap/SpvVaultContractAbi.js +849 -0
- package/dist/evm/spv_swap/SpvVaultContractTypechain.d.ts +450 -0
- package/dist/evm/spv_swap/SpvVaultContractTypechain.js +2 -0
- package/dist/evm/swaps/EVMSwapContract.d.ts +192 -0
- package/dist/evm/swaps/EVMSwapContract.js +373 -0
- package/dist/evm/swaps/EVMSwapData.d.ts +64 -0
- package/dist/evm/swaps/EVMSwapData.js +254 -0
- package/dist/evm/swaps/EVMSwapModule.d.ts +9 -0
- package/dist/evm/swaps/EVMSwapModule.js +11 -0
- package/dist/evm/swaps/EscrowManagerAbi.d.ts +120 -0
- package/dist/evm/swaps/EscrowManagerAbi.js +985 -0
- package/dist/evm/swaps/EscrowManagerTypechain.d.ts +475 -0
- package/dist/evm/swaps/EscrowManagerTypechain.js +2 -0
- package/dist/evm/swaps/handlers/IHandler.d.ts +13 -0
- package/dist/evm/swaps/handlers/IHandler.js +2 -0
- package/dist/evm/swaps/handlers/claim/ClaimHandlers.d.ts +10 -0
- package/dist/evm/swaps/handlers/claim/ClaimHandlers.js +13 -0
- package/dist/evm/swaps/handlers/claim/HashlockClaimHandler.d.ts +20 -0
- package/dist/evm/swaps/handlers/claim/HashlockClaimHandler.js +39 -0
- package/dist/evm/swaps/handlers/claim/btc/BitcoinNoncedOutputClaimHandler.d.ts +24 -0
- package/dist/evm/swaps/handlers/claim/btc/BitcoinNoncedOutputClaimHandler.js +59 -0
- package/dist/evm/swaps/handlers/claim/btc/BitcoinOutputClaimHandler.d.ts +25 -0
- package/dist/evm/swaps/handlers/claim/btc/BitcoinOutputClaimHandler.js +51 -0
- package/dist/evm/swaps/handlers/claim/btc/BitcoinTxIdClaimHandler.d.ts +21 -0
- package/dist/evm/swaps/handlers/claim/btc/BitcoinTxIdClaimHandler.js +28 -0
- package/dist/evm/swaps/handlers/claim/btc/IBitcoinClaimHandler.d.ts +48 -0
- package/dist/evm/swaps/handlers/claim/btc/IBitcoinClaimHandler.js +63 -0
- package/dist/evm/swaps/handlers/refund/TimelockRefundHandler.d.ts +17 -0
- package/dist/evm/swaps/handlers/refund/TimelockRefundHandler.js +28 -0
- package/dist/evm/swaps/modules/EVMLpVault.d.ts +69 -0
- package/dist/evm/swaps/modules/EVMLpVault.js +131 -0
- package/dist/evm/swaps/modules/EVMSwapClaim.d.ts +53 -0
- package/dist/evm/swaps/modules/EVMSwapClaim.js +101 -0
- package/dist/evm/swaps/modules/EVMSwapInit.d.ts +88 -0
- package/dist/evm/swaps/modules/EVMSwapInit.js +241 -0
- package/dist/evm/swaps/modules/EVMSwapRefund.d.ts +62 -0
- package/dist/evm/swaps/modules/EVMSwapRefund.js +132 -0
- package/dist/evm/typechain/common.d.ts +50 -0
- package/dist/evm/typechain/common.js +2 -0
- package/dist/evm/wallet/EVMSigner.d.ts +9 -0
- package/dist/evm/wallet/EVMSigner.js +16 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.js +53 -0
- package/dist/utils/Utils.d.ts +15 -0
- package/dist/utils/Utils.js +71 -0
- package/package.json +37 -0
- package/src/chains/citrea/CitreaChainType.ts +28 -0
- package/src/chains/citrea/CitreaInitializer.ts +167 -0
- package/src/evm/btcrelay/BtcRelayAbi.ts +258 -0
- package/src/evm/btcrelay/BtcRelayTypechain.ts +371 -0
- package/src/evm/btcrelay/EVMBtcRelay.ts +517 -0
- package/src/evm/btcrelay/headers/EVMBtcHeader.ts +110 -0
- package/src/evm/btcrelay/headers/EVMBtcStoredHeader.ts +153 -0
- package/src/evm/chain/EVMChainInterface.ts +157 -0
- package/src/evm/chain/EVMModule.ts +21 -0
- package/src/evm/chain/modules/ERC20Abi.ts +222 -0
- package/src/evm/chain/modules/EVMAddresses.ts +24 -0
- package/src/evm/chain/modules/EVMBlocks.ts +75 -0
- package/src/evm/chain/modules/EVMEvents.ts +139 -0
- package/src/evm/chain/modules/EVMFees.ts +105 -0
- package/src/evm/chain/modules/EVMSignatures.ts +76 -0
- package/src/evm/chain/modules/EVMTokens.ts +115 -0
- package/src/evm/chain/modules/EVMTransactions.ts +246 -0
- package/src/evm/contract/EVMContractBase.ts +63 -0
- package/src/evm/contract/EVMContractModule.ts +16 -0
- package/src/evm/contract/modules/EVMContractEvents.ts +102 -0
- package/src/evm/events/EVMChainEvents.ts +81 -0
- package/src/evm/events/EVMChainEventsBrowser.ts +390 -0
- package/src/evm/spv_swap/EVMSpvVaultContract.ts +533 -0
- package/src/evm/spv_swap/EVMSpvVaultData.ts +201 -0
- package/src/evm/spv_swap/EVMSpvWithdrawalData.ts +70 -0
- package/src/evm/spv_swap/SpvVaultContractAbi.ts +846 -0
- package/src/evm/spv_swap/SpvVaultContractTypechain.ts +685 -0
- package/src/evm/swaps/EVMSwapContract.ts +590 -0
- package/src/evm/swaps/EVMSwapData.ts +367 -0
- package/src/evm/swaps/EVMSwapModule.ts +16 -0
- package/src/evm/swaps/EscrowManagerAbi.ts +982 -0
- package/src/evm/swaps/EscrowManagerTypechain.ts +723 -0
- package/src/evm/swaps/handlers/IHandler.ts +17 -0
- package/src/evm/swaps/handlers/claim/ClaimHandlers.ts +20 -0
- package/src/evm/swaps/handlers/claim/HashlockClaimHandler.ts +47 -0
- package/src/evm/swaps/handlers/claim/btc/BitcoinNoncedOutputClaimHandler.ts +82 -0
- package/src/evm/swaps/handlers/claim/btc/BitcoinOutputClaimHandler.ts +76 -0
- package/src/evm/swaps/handlers/claim/btc/BitcoinTxIdClaimHandler.ts +46 -0
- package/src/evm/swaps/handlers/claim/btc/IBitcoinClaimHandler.ts +115 -0
- package/src/evm/swaps/handlers/refund/TimelockRefundHandler.ts +38 -0
- package/src/evm/swaps/modules/EVMLpVault.ts +153 -0
- package/src/evm/swaps/modules/EVMSwapClaim.ts +141 -0
- package/src/evm/swaps/modules/EVMSwapInit.ts +292 -0
- package/src/evm/swaps/modules/EVMSwapRefund.ts +198 -0
- package/src/evm/typechain/common.ts +131 -0
- package/src/evm/wallet/EVMSigner.ts +23 -0
- package/src/index.ts +44 -0
- package/src/utils/Utils.ts +81 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import {ChainSwapType, RelaySynchronizer, SwapDataVerificationError} from "@atomiqlabs/base";
|
|
2
|
+
import {IClaimHandler} from "../handlers/claim/ClaimHandlers";
|
|
3
|
+
import {BitcoinOutputWitnessData} from "../handlers/claim/btc/BitcoinOutputClaimHandler";
|
|
4
|
+
import {BitcoinWitnessData} from "../handlers/claim/btc/IBitcoinClaimHandler";
|
|
5
|
+
import {Buffer} from "buffer";
|
|
6
|
+
import {EVMSwapModule} from "../EVMSwapModule";
|
|
7
|
+
import { EVMSwapData } from "../EVMSwapData";
|
|
8
|
+
import {TransactionRequest} from "ethers";
|
|
9
|
+
import {EVMFees} from "../../chain/modules/EVMFees";
|
|
10
|
+
import {EVMTx} from "../../chain/modules/EVMTransactions";
|
|
11
|
+
import {EVMBtcStoredHeader} from "../../btcrelay/headers/EVMBtcStoredHeader";
|
|
12
|
+
|
|
13
|
+
export class EVMSwapClaim extends EVMSwapModule {
|
|
14
|
+
|
|
15
|
+
private static readonly GasCosts = {
|
|
16
|
+
CLAIM: 120_000,
|
|
17
|
+
CLAIM_WITH_SUCCESS_ACTION: 150_000
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Claim action which uses the provided witness for claiming the swap
|
|
22
|
+
*
|
|
23
|
+
* @param signer
|
|
24
|
+
* @param swapData
|
|
25
|
+
* @param witness
|
|
26
|
+
* @param feeRate
|
|
27
|
+
* @param claimHandlerGas
|
|
28
|
+
* @private
|
|
29
|
+
*/
|
|
30
|
+
private async Claim(
|
|
31
|
+
signer: string,
|
|
32
|
+
swapData: EVMSwapData,
|
|
33
|
+
witness: Buffer,
|
|
34
|
+
feeRate: string,
|
|
35
|
+
claimHandlerGas?: number
|
|
36
|
+
): Promise<TransactionRequest> {
|
|
37
|
+
//TODO: Claim with success action not supported yet!
|
|
38
|
+
const tx = await this.swapContract.claim.populateTransaction(swapData.toEscrowStruct(), witness);
|
|
39
|
+
tx.from = signer;
|
|
40
|
+
EVMFees.applyFeeRate(tx, EVMSwapClaim.GasCosts.CLAIM + (claimHandlerGas ?? 0), feeRate);
|
|
41
|
+
return tx;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Creates transactions claiming the swap using a secret (for HTLC swaps)
|
|
46
|
+
*
|
|
47
|
+
* @param signer
|
|
48
|
+
* @param swapData swap to claim
|
|
49
|
+
* @param secret hex encoded secret pre-image to the HTLC hash
|
|
50
|
+
* @param checkExpiry whether to check if the swap is already expired (trying to claim an expired swap with a secret
|
|
51
|
+
* is dangerous because we might end up revealing the secret to the counterparty without being able to claim the swap)
|
|
52
|
+
* @param feeRate fee rate to use for the transaction
|
|
53
|
+
*/
|
|
54
|
+
async txsClaimWithSecret(
|
|
55
|
+
signer: string,
|
|
56
|
+
swapData: EVMSwapData,
|
|
57
|
+
secret: string,
|
|
58
|
+
checkExpiry?: boolean,
|
|
59
|
+
feeRate?: string
|
|
60
|
+
): Promise<EVMTx[]> {
|
|
61
|
+
//We need to be sure that this transaction confirms in time, otherwise we reveal the secret to the counterparty
|
|
62
|
+
// and won't claim the funds
|
|
63
|
+
if(checkExpiry && await this.contract.isExpired(swapData.claimer.toString(), swapData)) {
|
|
64
|
+
throw new SwapDataVerificationError("Not enough time to reliably pay the invoice");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const claimHandler: IClaimHandler<Buffer, string> = this.contract.claimHandlersByAddress[swapData.claimHandler.toLowerCase()];
|
|
68
|
+
if(claimHandler==null) throw new SwapDataVerificationError("Unknown claim handler!");
|
|
69
|
+
if(claimHandler.getType()!==ChainSwapType.HTLC) throw new SwapDataVerificationError("Invalid claim handler!");
|
|
70
|
+
|
|
71
|
+
feeRate ??= await this.root.Fees.getFeeRate();
|
|
72
|
+
|
|
73
|
+
const {initialTxns, witness} = await claimHandler.getWitness(signer, swapData, secret, feeRate);
|
|
74
|
+
const tx = await this.Claim(signer, swapData, witness, feeRate, claimHandler.getGas(swapData));
|
|
75
|
+
|
|
76
|
+
this.logger.debug("txsClaimWithSecret(): creating claim transaction, swap: "+swapData.getClaimHash()+" witness: ", witness.toString("hex"));
|
|
77
|
+
|
|
78
|
+
return [...initialTxns, tx];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Creates transaction claiming the swap using a confirmed transaction data (for BTC on-chain swaps)
|
|
83
|
+
*
|
|
84
|
+
* @param signer
|
|
85
|
+
* @param swapData swap to claim
|
|
86
|
+
* @param tx bitcoin transaction that satisfies the swap condition
|
|
87
|
+
* @param requiredConfirmations
|
|
88
|
+
* @param vout vout of the bitcoin transaction that satisfies the swap condition
|
|
89
|
+
* @param commitedHeader commited header data from btc relay (fetched internally if null)
|
|
90
|
+
* @param synchronizer optional synchronizer to use in case we need to sync up the btc relay ourselves
|
|
91
|
+
* @param feeRate fee rate to be used for the transactions
|
|
92
|
+
*/
|
|
93
|
+
async txsClaimWithTxData(
|
|
94
|
+
signer: string,
|
|
95
|
+
swapData: EVMSwapData,
|
|
96
|
+
tx: { blockhash: string, confirmations: number, txid: string, hex: string, height: number },
|
|
97
|
+
requiredConfirmations: number,
|
|
98
|
+
vout: number,
|
|
99
|
+
commitedHeader?: EVMBtcStoredHeader,
|
|
100
|
+
synchronizer?: RelaySynchronizer<EVMBtcStoredHeader, EVMTx, any>,
|
|
101
|
+
feeRate?: string
|
|
102
|
+
): Promise<EVMTx[] | null> {
|
|
103
|
+
const claimHandler: IClaimHandler<any, BitcoinOutputWitnessData | BitcoinWitnessData> = this.contract.claimHandlersByAddress[swapData.claimHandler.toLowerCase()];
|
|
104
|
+
if(claimHandler==null) throw new SwapDataVerificationError("Unknown claim handler!");
|
|
105
|
+
if(
|
|
106
|
+
claimHandler.getType()!==ChainSwapType.CHAIN_NONCED &&
|
|
107
|
+
claimHandler.getType()!==ChainSwapType.CHAIN_TXID &&
|
|
108
|
+
claimHandler.getType()!==ChainSwapType.CHAIN
|
|
109
|
+
) throw new SwapDataVerificationError("Invalid claim handler!");
|
|
110
|
+
|
|
111
|
+
feeRate ??= await this.root.Fees.getFeeRate();
|
|
112
|
+
|
|
113
|
+
const {initialTxns, witness} = await claimHandler.getWitness(signer, swapData, {
|
|
114
|
+
tx,
|
|
115
|
+
vout,
|
|
116
|
+
requiredConfirmations,
|
|
117
|
+
commitedHeader,
|
|
118
|
+
btcRelay: this.contract.btcRelay,
|
|
119
|
+
synchronizer,
|
|
120
|
+
}, feeRate);
|
|
121
|
+
const claimTx = await this.Claim(signer, swapData, witness, feeRate, claimHandler.getGas(swapData));
|
|
122
|
+
|
|
123
|
+
return [...initialTxns, claimTx];
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Get the estimated starknet transaction fee of the claim transaction
|
|
128
|
+
*/
|
|
129
|
+
public async getClaimFee(swapData: EVMSwapData, feeRate?: string): Promise<bigint> {
|
|
130
|
+
feeRate ??= await this.root.Fees.getFeeRate();
|
|
131
|
+
|
|
132
|
+
//TODO: Claim with success action not supported yet!
|
|
133
|
+
let gasRequired = EVMSwapClaim.GasCosts.CLAIM;
|
|
134
|
+
|
|
135
|
+
const claimHandler: IClaimHandler<any, any> = this.contract.claimHandlersByAddress[swapData.claimHandler.toLowerCase()];
|
|
136
|
+
if(claimHandler!=null) gasRequired += claimHandler.getGas(swapData);
|
|
137
|
+
|
|
138
|
+
return EVMFees.getGasFee(gasRequired, feeRate);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
}
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import {SignatureVerificationError, SwapCommitStateType, SwapDataVerificationError} from "@atomiqlabs/base";
|
|
2
|
+
import {Buffer} from "buffer";
|
|
3
|
+
import { EVMSwapModule } from "../EVMSwapModule";
|
|
4
|
+
import {EVMSwapData} from "../EVMSwapData";
|
|
5
|
+
import {keccak256, TransactionRequest, ZeroHash} from "ethers";
|
|
6
|
+
import {EVMFees} from "../../chain/modules/EVMFees";
|
|
7
|
+
import {EVMSigner} from "../../wallet/EVMSigner";
|
|
8
|
+
import {EVMTx} from "../../chain/modules/EVMTransactions";
|
|
9
|
+
import {tryWithRetries} from "../../../utils/Utils";
|
|
10
|
+
|
|
11
|
+
export type EVMPreFetchVerification = {
|
|
12
|
+
safeBlockTime?: number
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const Initialize = [
|
|
16
|
+
{ name: "swapHash", type: "bytes32" },
|
|
17
|
+
{ name: "offerer", type: "address" },
|
|
18
|
+
{ name: "claimer", type: "address" },
|
|
19
|
+
{ name: "amount", type: "uint256" },
|
|
20
|
+
{ name: "token", type: "address" },
|
|
21
|
+
{ name: "payIn", type: "bool" },
|
|
22
|
+
{ name: "payOut", type: "bool" },
|
|
23
|
+
{ name: "trackingReputation", type: "bool" },
|
|
24
|
+
{ name: "claimHandler", type: "address" },
|
|
25
|
+
{ name: "claimData", type: "bytes32" },
|
|
26
|
+
{ name: "refundHandler", type: "address" },
|
|
27
|
+
{ name: "refundData", type: "bytes32" },
|
|
28
|
+
{ name: "securityDeposit", type: "uint256" },
|
|
29
|
+
{ name: "claimerBounty", type: "uint256" },
|
|
30
|
+
{ name: "depositToken", type: "address" },
|
|
31
|
+
{ name: "claimActionHash", type: "bytes32" },
|
|
32
|
+
{ name: "deadline", type: "uint256" },
|
|
33
|
+
{ name: "extraDataHash", type: "bytes32" }
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
export class EVMSwapInit extends EVMSwapModule {
|
|
37
|
+
|
|
38
|
+
private static readonly GasCosts = {
|
|
39
|
+
INIT: 100_000,
|
|
40
|
+
INIT_PAY_IN: 130_000,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* bare Init action based on the data passed in swapData
|
|
45
|
+
*
|
|
46
|
+
* @param sender
|
|
47
|
+
* @param swapData
|
|
48
|
+
* @param timeout
|
|
49
|
+
* @param signature
|
|
50
|
+
* @param feeRate
|
|
51
|
+
* @private
|
|
52
|
+
*/
|
|
53
|
+
private async Init(sender: string, swapData: EVMSwapData, timeout: bigint, signature: string, feeRate: string): Promise<TransactionRequest> {
|
|
54
|
+
let value = 0n;
|
|
55
|
+
if(swapData.isToken(this.root.getNativeCurrencyAddress())) value += swapData.getAmount();
|
|
56
|
+
if(swapData.isDepositToken(this.root.getNativeCurrencyAddress())) value += swapData.getTotalDeposit();
|
|
57
|
+
const tx = await this.swapContract.initialize.populateTransaction(swapData.toEscrowStruct(), signature, timeout, "0x"+(swapData.extraData ?? ""), {
|
|
58
|
+
value
|
|
59
|
+
});
|
|
60
|
+
tx.from = sender;
|
|
61
|
+
EVMFees.applyFeeRate(tx, swapData.isPayIn() ? EVMSwapInit.GasCosts.INIT_PAY_IN : EVMSwapInit.GasCosts.INIT, feeRate);
|
|
62
|
+
return tx;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Returns auth prefix to be used with a specific swap, payIn=true & payIn=false use different prefixes (these
|
|
67
|
+
* actually have no meaning for the smart contract in the EVM case)
|
|
68
|
+
*
|
|
69
|
+
* @param swapData
|
|
70
|
+
* @private
|
|
71
|
+
*/
|
|
72
|
+
private getAuthPrefix(swapData: EVMSwapData): string {
|
|
73
|
+
return swapData.isPayIn() ? "claim_initialize" : "initialize";
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public async preFetchForInitSignatureVerification(): Promise<EVMPreFetchVerification> {
|
|
77
|
+
return {
|
|
78
|
+
safeBlockTime: await this.root.Blocks.getBlockTime(this.root.config.safeBlockTag)
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Signs swap initialization authorization, using data from preFetchedBlockData if provided & still valid (subject
|
|
84
|
+
* to SIGNATURE_PREFETCH_DATA_VALIDITY)
|
|
85
|
+
*
|
|
86
|
+
* @param signer
|
|
87
|
+
* @param swapData
|
|
88
|
+
* @param authorizationTimeout
|
|
89
|
+
* @public
|
|
90
|
+
*/
|
|
91
|
+
public async signSwapInitialization(
|
|
92
|
+
signer: EVMSigner,
|
|
93
|
+
swapData: EVMSwapData,
|
|
94
|
+
authorizationTimeout: number
|
|
95
|
+
): Promise<{prefix: string, timeout: string, signature: string}> {
|
|
96
|
+
const authExpiry = Math.floor(Date.now()/1000)+authorizationTimeout;
|
|
97
|
+
|
|
98
|
+
const signature = await this.root.Signatures.signTypedMessage(this.contract.contractAddress, signer, Initialize, "Initialize", {
|
|
99
|
+
"swapHash": "0x"+swapData.getEscrowHash(),
|
|
100
|
+
"offerer": swapData.offerer,
|
|
101
|
+
"claimer": swapData.claimer,
|
|
102
|
+
"amount": swapData.amount,
|
|
103
|
+
"token": swapData.token,
|
|
104
|
+
"payIn": swapData.isPayIn(),
|
|
105
|
+
"payOut": swapData.isPayOut(),
|
|
106
|
+
"trackingReputation": swapData.reputation,
|
|
107
|
+
"claimHandler": swapData.claimHandler,
|
|
108
|
+
"claimData": "0x"+swapData.getClaimHash(),
|
|
109
|
+
"refundHandler": swapData.refundHandler,
|
|
110
|
+
"refundData": swapData.refundData.startsWith("0x") ? swapData.refundData : "0x"+swapData.refundData,
|
|
111
|
+
"securityDeposit": swapData.securityDeposit,
|
|
112
|
+
"claimerBounty": swapData.claimerBounty,
|
|
113
|
+
"depositToken": swapData.depositToken,
|
|
114
|
+
"claimActionHash": ZeroHash,
|
|
115
|
+
"deadline": authExpiry,
|
|
116
|
+
"extraDataHash": keccak256("0x"+(swapData.extraData ?? ""))
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
prefix: this.getAuthPrefix(swapData),
|
|
121
|
+
timeout: authExpiry.toString(10),
|
|
122
|
+
signature
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Checks whether the provided signature data is valid, using preFetchedData if provided and still valid
|
|
128
|
+
*
|
|
129
|
+
* @param sender
|
|
130
|
+
* @param swapData
|
|
131
|
+
* @param timeout
|
|
132
|
+
* @param prefix
|
|
133
|
+
* @param signature
|
|
134
|
+
* @param preFetchData
|
|
135
|
+
* @public
|
|
136
|
+
*/
|
|
137
|
+
public async isSignatureValid(
|
|
138
|
+
sender: string,
|
|
139
|
+
swapData: EVMSwapData,
|
|
140
|
+
timeout: string,
|
|
141
|
+
prefix: string,
|
|
142
|
+
signature: string,
|
|
143
|
+
preFetchData?: EVMPreFetchVerification
|
|
144
|
+
): Promise<null> {
|
|
145
|
+
if(!swapData.isOfferer(sender) && !swapData.isClaimer(sender))
|
|
146
|
+
throw new SignatureVerificationError("TX sender not offerer nor claimer");
|
|
147
|
+
|
|
148
|
+
const signer = swapData.isOfferer(sender) ? swapData.claimer : swapData.offerer;
|
|
149
|
+
|
|
150
|
+
if(await this.contract.isExpired(sender, swapData)) {
|
|
151
|
+
throw new SignatureVerificationError("Swap will expire too soon!");
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if(prefix!==this.getAuthPrefix(swapData)) throw new SignatureVerificationError("Invalid prefix");
|
|
155
|
+
|
|
156
|
+
const currentTimestamp = BigInt(Math.floor(Date.now() / 1000));
|
|
157
|
+
const timeoutBN = BigInt(timeout);
|
|
158
|
+
const isExpired = (timeoutBN - currentTimestamp) < BigInt(this.contract.authGracePeriod);
|
|
159
|
+
if (isExpired) throw new SignatureVerificationError("Authorization expired!");
|
|
160
|
+
if(await this.isSignatureExpired(timeout, preFetchData)) throw new SignatureVerificationError("Authorization expired!");
|
|
161
|
+
|
|
162
|
+
const valid = await this.root.Signatures.isValidSignature(this.contract.contractAddress, signature, signer, Initialize, "Initialize", {
|
|
163
|
+
"swapHash": "0x"+swapData.getEscrowHash(),
|
|
164
|
+
"offerer": swapData.offerer,
|
|
165
|
+
"claimer": swapData.claimer,
|
|
166
|
+
"amount": swapData.amount,
|
|
167
|
+
"token": swapData.token,
|
|
168
|
+
"payIn": swapData.isPayIn(),
|
|
169
|
+
"payOut": swapData.isPayOut(),
|
|
170
|
+
"trackingReputation": swapData.reputation,
|
|
171
|
+
"claimHandler": swapData.claimHandler,
|
|
172
|
+
"claimData": "0x"+swapData.getClaimHash(),
|
|
173
|
+
"refundHandler": swapData.refundHandler,
|
|
174
|
+
"refundData": swapData.refundData.startsWith("0x") ? swapData.refundData : "0x"+swapData.refundData,
|
|
175
|
+
"securityDeposit": swapData.securityDeposit,
|
|
176
|
+
"claimerBounty": swapData.claimerBounty,
|
|
177
|
+
"depositToken": swapData.depositToken,
|
|
178
|
+
"claimActionHash": ZeroHash,
|
|
179
|
+
"deadline": timeoutBN,
|
|
180
|
+
"extraDataHash": keccak256("0x"+(swapData.extraData ?? ""))
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
if(!valid) throw new SignatureVerificationError("Invalid signature!");
|
|
184
|
+
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Gets expiry of the provided signature data, this is a minimum of slot expiry & swap signature expiry
|
|
190
|
+
*
|
|
191
|
+
* @param timeout
|
|
192
|
+
* @public
|
|
193
|
+
*/
|
|
194
|
+
public async getSignatureExpiry(
|
|
195
|
+
timeout: string
|
|
196
|
+
): Promise<number> {
|
|
197
|
+
const now = Date.now();
|
|
198
|
+
const timeoutExpiryTime = (parseInt(timeout)-this.contract.authGracePeriod)*1000;
|
|
199
|
+
|
|
200
|
+
if(timeoutExpiryTime<now) return 0;
|
|
201
|
+
|
|
202
|
+
return timeoutExpiryTime;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Checks whether signature is expired for good, compares the timestamp to the current "pending" block timestamp
|
|
207
|
+
*
|
|
208
|
+
* @param timeout
|
|
209
|
+
* @param preFetchData
|
|
210
|
+
* @public
|
|
211
|
+
*/
|
|
212
|
+
public async isSignatureExpired(
|
|
213
|
+
timeout: string,
|
|
214
|
+
preFetchData?: EVMPreFetchVerification
|
|
215
|
+
): Promise<boolean> {
|
|
216
|
+
if(preFetchData==null || preFetchData.safeBlockTime==null) {
|
|
217
|
+
preFetchData = await this.preFetchForInitSignatureVerification();
|
|
218
|
+
}
|
|
219
|
+
return preFetchData.safeBlockTime > parseInt(timeout);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Creates init transaction with a valid signature from an LP
|
|
224
|
+
*
|
|
225
|
+
* @param sender
|
|
226
|
+
* @param swapData swap to initialize
|
|
227
|
+
* @param timeout init signature timeout
|
|
228
|
+
* @param prefix init signature prefix
|
|
229
|
+
* @param signature init signature
|
|
230
|
+
* @param skipChecks whether to skip signature validity checks
|
|
231
|
+
* @param feeRate fee rate to use for the transaction
|
|
232
|
+
*/
|
|
233
|
+
public async txsInit(
|
|
234
|
+
sender: string,
|
|
235
|
+
swapData: EVMSwapData,
|
|
236
|
+
timeout: string,
|
|
237
|
+
prefix: string,
|
|
238
|
+
signature: string,
|
|
239
|
+
skipChecks?: boolean,
|
|
240
|
+
feeRate?: string
|
|
241
|
+
): Promise<EVMTx[]> {
|
|
242
|
+
if(
|
|
243
|
+
swapData.isClaimer(sender) && swapData.isPayIn() &&
|
|
244
|
+
swapData.isToken(this.root.getNativeCurrencyAddress())
|
|
245
|
+
) throw new Error("Cannot initialize as claimer for payIn=true and native currency!");
|
|
246
|
+
|
|
247
|
+
if(!skipChecks) {
|
|
248
|
+
const [_, payStatus] = await Promise.all([
|
|
249
|
+
swapData.isOfferer(sender) && !swapData.reputation ? Promise.resolve() : tryWithRetries(
|
|
250
|
+
() => this.isSignatureValid(sender, swapData, timeout, prefix, signature),
|
|
251
|
+
this.retryPolicy, (e) => e instanceof SignatureVerificationError
|
|
252
|
+
),
|
|
253
|
+
tryWithRetries(() => this.contract.getCommitStatus(sender, swapData), this.retryPolicy)
|
|
254
|
+
]);
|
|
255
|
+
if(payStatus.type!==SwapCommitStateType.NOT_COMMITED) throw new SwapDataVerificationError("Invoice already being paid for or paid");
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
feeRate ??= await this.root.Fees.getFeeRate();
|
|
259
|
+
|
|
260
|
+
const txs: EVMTx[] = [];
|
|
261
|
+
const requiredApprovals: {[address: string]: bigint} = {};
|
|
262
|
+
if(swapData.payIn && swapData.isOfferer(sender)) {
|
|
263
|
+
if(!swapData.isToken(this.root.getNativeCurrencyAddress())) {
|
|
264
|
+
requiredApprovals[swapData.token.toLowerCase()] = swapData.amount;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if(swapData.getTotalDeposit() !== 0n) {
|
|
268
|
+
if(!swapData.isDepositToken(this.root.getNativeCurrencyAddress())) {
|
|
269
|
+
requiredApprovals[swapData.depositToken.toLowerCase()] ??= 0n;
|
|
270
|
+
requiredApprovals[swapData.depositToken.toLowerCase()] += swapData.getTotalDeposit();
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
for(let tokenAddress in requiredApprovals) {
|
|
274
|
+
txs.push(await this.root.Tokens.Approve(sender, tokenAddress, requiredApprovals[tokenAddress], this.contract.contractAddress, feeRate));
|
|
275
|
+
}
|
|
276
|
+
txs.push(await this.Init(sender, swapData, BigInt(timeout), signature ?? "0x", feeRate));
|
|
277
|
+
|
|
278
|
+
this.logger.debug("txsInitPayIn(): create swap init TX, swap: "+swapData.getClaimHash()+
|
|
279
|
+
" feerate: "+feeRate);
|
|
280
|
+
|
|
281
|
+
return txs;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Get the estimated solana fee of the init transaction, this includes the required deposit for creating swap PDA
|
|
286
|
+
* and also deposit for ATAs
|
|
287
|
+
*/
|
|
288
|
+
async getInitFee(swapData?: EVMSwapData, feeRate?: string): Promise<bigint> {
|
|
289
|
+
feeRate ??= await this.root.Fees.getFeeRate();
|
|
290
|
+
return EVMFees.getGasFee(swapData.payIn ? EVMSwapInit.GasCosts.INIT_PAY_IN : EVMSwapInit.GasCosts.INIT, feeRate);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import {SignatureVerificationError, SwapDataVerificationError} from "@atomiqlabs/base";
|
|
2
|
+
import {tryWithRetries} from "../../../utils/Utils";
|
|
3
|
+
import {IHandler} from "../handlers/IHandler";
|
|
4
|
+
import {EVMSwapModule} from "../EVMSwapModule";
|
|
5
|
+
import {Buffer} from "buffer";
|
|
6
|
+
import {EVMSwapData} from "../EVMSwapData";
|
|
7
|
+
import {TransactionRequest} from "ethers";
|
|
8
|
+
import {EVMFees} from "../../chain/modules/EVMFees";
|
|
9
|
+
import {EVMSigner} from "../../wallet/EVMSigner";
|
|
10
|
+
import {EVMTx} from "../../chain/modules/EVMTransactions";
|
|
11
|
+
|
|
12
|
+
const Refund = [
|
|
13
|
+
{ name: "swapHash", type: "bytes32" },
|
|
14
|
+
{ name: "timeout", type: "uint256" }
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
export class EVMSwapRefund extends EVMSwapModule {
|
|
18
|
+
|
|
19
|
+
private static readonly GasCosts = {
|
|
20
|
+
REFUND: 100_000,
|
|
21
|
+
REFUND_PAY_OUT: 130_000
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Action for generic Refund instruction
|
|
26
|
+
*
|
|
27
|
+
* @param signer
|
|
28
|
+
* @param swapData
|
|
29
|
+
* @param witness
|
|
30
|
+
* @param feeRate
|
|
31
|
+
* @param handlerGas
|
|
32
|
+
* @private
|
|
33
|
+
*/
|
|
34
|
+
private async Refund(
|
|
35
|
+
signer: string,
|
|
36
|
+
swapData: EVMSwapData,
|
|
37
|
+
witness: Buffer,
|
|
38
|
+
feeRate: string,
|
|
39
|
+
handlerGas?: number
|
|
40
|
+
): Promise<TransactionRequest> {
|
|
41
|
+
const tx = await this.swapContract.refund.populateTransaction(swapData.toEscrowStruct(), witness);
|
|
42
|
+
tx.from = signer;
|
|
43
|
+
EVMFees.applyFeeRate(tx, (swapData.payIn ? EVMSwapRefund.GasCosts.REFUND_PAY_OUT : EVMSwapRefund.GasCosts.REFUND) + (handlerGas ?? 0), feeRate)
|
|
44
|
+
return tx;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Action for cooperative refunding with signature
|
|
49
|
+
*
|
|
50
|
+
* @param sender
|
|
51
|
+
* @param swapData
|
|
52
|
+
* @param timeout
|
|
53
|
+
* @param signature
|
|
54
|
+
* @param feeRate
|
|
55
|
+
* @private
|
|
56
|
+
*/
|
|
57
|
+
private async RefundWithSignature(
|
|
58
|
+
sender: string,
|
|
59
|
+
swapData: EVMSwapData,
|
|
60
|
+
timeout: string,
|
|
61
|
+
signature: string,
|
|
62
|
+
feeRate: string
|
|
63
|
+
): Promise<TransactionRequest> {
|
|
64
|
+
const tx = await this.swapContract.cooperativeRefund.populateTransaction(swapData.toEscrowStruct(), signature, BigInt(timeout));
|
|
65
|
+
tx.from = sender;
|
|
66
|
+
EVMFees.applyFeeRate(tx, swapData.payIn ? EVMSwapRefund.GasCosts.REFUND_PAY_OUT : EVMSwapRefund.GasCosts.REFUND, feeRate)
|
|
67
|
+
return tx;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public async signSwapRefund(
|
|
71
|
+
signer: EVMSigner,
|
|
72
|
+
swapData: EVMSwapData,
|
|
73
|
+
authorizationTimeout: number
|
|
74
|
+
): Promise<{ prefix: string; timeout: string; signature: string }> {
|
|
75
|
+
const authPrefix = "refund";
|
|
76
|
+
const authTimeout = Math.floor(Date.now()/1000)+authorizationTimeout;
|
|
77
|
+
|
|
78
|
+
const signature = await this.root.Signatures.signTypedMessage(this.contract.contractAddress, signer, Refund, "Refund", {
|
|
79
|
+
"swapHash": "0x"+swapData.getEscrowHash(),
|
|
80
|
+
"timeout": BigInt(authTimeout)
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
prefix: authPrefix,
|
|
85
|
+
timeout: authTimeout.toString(10),
|
|
86
|
+
signature: signature
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public async isSignatureValid(
|
|
91
|
+
swapData: EVMSwapData,
|
|
92
|
+
timeout: string,
|
|
93
|
+
prefix: string,
|
|
94
|
+
signature: string
|
|
95
|
+
): Promise<null> {
|
|
96
|
+
if(prefix!=="refund") throw new SignatureVerificationError("Invalid prefix");
|
|
97
|
+
|
|
98
|
+
const expiryTimestamp = BigInt(timeout);
|
|
99
|
+
const currentTimestamp = BigInt(Math.floor(Date.now() / 1000));
|
|
100
|
+
|
|
101
|
+
const isExpired = (expiryTimestamp - currentTimestamp) < BigInt(this.contract.authGracePeriod);
|
|
102
|
+
if(isExpired) throw new SignatureVerificationError("Authorization expired!");
|
|
103
|
+
|
|
104
|
+
const valid = await this.root.Signatures.isValidSignature(this.contract.contractAddress, signature, swapData.claimer, Refund, "Refund", {
|
|
105
|
+
"swapHash": "0x"+swapData.getEscrowHash(),
|
|
106
|
+
"timeout": BigInt(expiryTimestamp)
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
if(!valid) {
|
|
110
|
+
throw new SignatureVerificationError("Invalid signature!");
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Creates transactions required for refunding timed out swap
|
|
118
|
+
*
|
|
119
|
+
* @param signer
|
|
120
|
+
* @param swapData swap data to refund
|
|
121
|
+
* @param check whether to check if swap is already expired and refundable
|
|
122
|
+
* @param feeRate fee rate to be used for the transactions
|
|
123
|
+
* @param witnessData
|
|
124
|
+
*/
|
|
125
|
+
public async txsRefund<T>(
|
|
126
|
+
signer: string,
|
|
127
|
+
swapData: EVMSwapData,
|
|
128
|
+
check?: boolean,
|
|
129
|
+
feeRate?: string,
|
|
130
|
+
witnessData?: T
|
|
131
|
+
): Promise<EVMTx[]> {
|
|
132
|
+
const refundHandler: IHandler<any, T> = this.contract.refundHandlersByAddress[swapData.refundHandler.toLowerCase()];
|
|
133
|
+
if(refundHandler==null) throw new Error("Invalid refund handler");
|
|
134
|
+
|
|
135
|
+
if(check && !await tryWithRetries(() => this.contract.isRequestRefundable(swapData.offerer.toString(), swapData), this.retryPolicy)) {
|
|
136
|
+
throw new SwapDataVerificationError("Not refundable yet!");
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
feeRate ??= await this.root.Fees.getFeeRate();
|
|
140
|
+
|
|
141
|
+
const {initialTxns, witness} = await refundHandler.getWitness(signer, swapData, witnessData, feeRate);
|
|
142
|
+
|
|
143
|
+
const tx = await this.Refund(signer, swapData, witness, feeRate, refundHandler.getGas(swapData));
|
|
144
|
+
|
|
145
|
+
this.logger.debug("txsRefund(): creating refund transaction, swap: "+swapData.getClaimHash());
|
|
146
|
+
|
|
147
|
+
return [...initialTxns, tx];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Creates transactions required for refunding the swap with authorization signature, also unwraps WSOL to SOL
|
|
152
|
+
*
|
|
153
|
+
* @param signer
|
|
154
|
+
* @param swapData swap data to refund
|
|
155
|
+
* @param timeout signature timeout
|
|
156
|
+
* @param prefix signature prefix of the counterparty
|
|
157
|
+
* @param signature signature of the counterparty
|
|
158
|
+
* @param check whether to check if swap is committed before attempting refund
|
|
159
|
+
* @param feeRate fee rate to be used for the transactions
|
|
160
|
+
*/
|
|
161
|
+
public async txsRefundWithAuthorization(
|
|
162
|
+
signer: string,
|
|
163
|
+
swapData: EVMSwapData,
|
|
164
|
+
timeout: string,
|
|
165
|
+
prefix: string,
|
|
166
|
+
signature: string,
|
|
167
|
+
check?: boolean,
|
|
168
|
+
feeRate?: string
|
|
169
|
+
): Promise<EVMTx[]> {
|
|
170
|
+
if(check && !await tryWithRetries(() => this.contract.isCommited(swapData), this.retryPolicy)) {
|
|
171
|
+
throw new SwapDataVerificationError("Not correctly committed");
|
|
172
|
+
}
|
|
173
|
+
await tryWithRetries(
|
|
174
|
+
() => this.isSignatureValid(swapData, timeout, prefix, signature),
|
|
175
|
+
this.retryPolicy,
|
|
176
|
+
(e) => e instanceof SignatureVerificationError
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
feeRate ??= await this.root.Fees.getFeeRate();
|
|
180
|
+
|
|
181
|
+
const tx = await this.RefundWithSignature(signer, swapData, timeout, signature, feeRate);
|
|
182
|
+
|
|
183
|
+
this.logger.debug("txsRefundWithAuthorization(): creating refund transaction, swap: "+swapData.getClaimHash()+
|
|
184
|
+
" auth expiry: "+timeout+" signature: "+signature);
|
|
185
|
+
|
|
186
|
+
return [tx];
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Get the estimated solana transaction fee of the refund transaction, in the worst case scenario in case where the
|
|
191
|
+
* ATA needs to be initialized again (i.e. adding the ATA rent exempt lamports to the fee)
|
|
192
|
+
*/
|
|
193
|
+
async getRefundFee(swapData: EVMSwapData, feeRate?: string): Promise<bigint> {
|
|
194
|
+
feeRate ??= await this.root.Fees.getFeeRate();
|
|
195
|
+
return EVMFees.getGasFee(swapData.payIn ? EVMSwapRefund.GasCosts.REFUND_PAY_OUT : EVMSwapRefund.GasCosts.REFUND, feeRate);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
}
|