@atomiqlabs/chain-starknet
Version:
Starknet specific base implementation
132 lines (131 loc) • 6.66 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.StarknetSwapRefund = void 0;
const base_1 = require("@atomiqlabs/base");
const Utils_1 = require("../../../utils/Utils");
const StarknetSwapModule_1 = require("../StarknetSwapModule");
const StarknetAction_1 = require("../../base/StarknetAction");
const StarknetFees_1 = require("../../base/modules/StarknetFees");
const Refund = [
{ name: 'Swap hash', type: 'felt' },
{ name: 'Timeout', type: 'timestamp' }
];
class StarknetSwapRefund extends StarknetSwapModule_1.StarknetSwapModule {
/**
* Action for generic Refund instruction
*
* @param signer
* @param swapData
* @param witness
* @param handlerGas
* @constructor
* @private
*/
Refund(signer, swapData, witness, handlerGas) {
return new StarknetAction_1.StarknetAction(signer, this.root, this.contract.populateTransaction.refund(swapData.toEscrowStruct(), witness), (0, StarknetAction_1.sumStarknetGas)(swapData.payIn ? StarknetSwapRefund.GasCosts.REFUND_PAY_OUT : StarknetSwapRefund.GasCosts.REFUND, handlerGas));
}
/**
* Action for cooperative refunding with signature
*
* @param sender
* @param swapData
* @param timeout
* @param signature
* @constructor
* @private
*/
RefundWithSignature(sender, swapData, timeout, signature) {
return new StarknetAction_1.StarknetAction(sender, this.root, this.contract.populateTransaction.cooperative_refund(swapData.toEscrowStruct(), signature, BigInt(timeout)), swapData.payIn ? StarknetSwapRefund.GasCosts.REFUND_PAY_OUT : StarknetSwapRefund.GasCosts.REFUND);
}
constructor(root) {
super(root);
}
async signSwapRefund(signer, swapData, authorizationTimeout) {
const authPrefix = "refund";
const authTimeout = Math.floor(Date.now() / 1000) + authorizationTimeout;
const signature = await this.root.Signatures.signTypedMessage(signer, Refund, "Refund", {
"Swap hash": "0x" + swapData.getEscrowHash(),
"Timeout": (0, Utils_1.toHex)(authTimeout)
});
return {
prefix: authPrefix,
timeout: authTimeout.toString(10),
signature: signature
};
}
async isSignatureValid(swapData, timeout, prefix, signature) {
if (prefix !== "refund")
throw new base_1.SignatureVerificationError("Invalid prefix");
const expiryTimestamp = BigInt(timeout);
const currentTimestamp = BigInt(Math.floor(Date.now() / 1000));
const isExpired = (expiryTimestamp - currentTimestamp) < BigInt(this.root.authGracePeriod);
if (isExpired)
throw new base_1.SignatureVerificationError("Authorization expired!");
const valid = await this.root.Signatures.isValidSignature(signature, swapData.claimer, Refund, "Refund", {
"Swap hash": "0x" + swapData.getEscrowHash(),
"Timeout": (0, Utils_1.toHex)(expiryTimestamp)
});
if (!valid) {
throw new base_1.SignatureVerificationError("Invalid signature!");
}
return null;
}
/**
* Creates transactions required for refunding timed out swap
*
* @param signer
* @param swapData swap data to refund
* @param check whether to check if swap is already expired and refundable
* @param feeRate fee rate to be used for the transactions
* @param witnessData
*/
async txsRefund(signer, swapData, check, feeRate, witnessData) {
const refundHandler = this.root.refundHandlersByAddress[swapData.refundHandler.toLowerCase()];
if (refundHandler == null)
throw new Error("Invalid refund handler");
if (check && !await (0, Utils_1.tryWithRetries)(() => this.root.isRequestRefundable(swapData.offerer.toString(), swapData), this.retryPolicy)) {
throw new base_1.SwapDataVerificationError("Not refundable yet!");
}
feeRate ?? (feeRate = await this.root.Fees.getFeeRate());
const { initialTxns, witness } = await refundHandler.getWitness(signer, swapData, witnessData, feeRate);
const action = this.Refund(signer, swapData, witness, refundHandler.getGas(swapData));
await action.addToTxs(initialTxns, feeRate);
this.logger.debug("txsRefund(): creating refund transaction, swap: " + swapData.getClaimHash());
return initialTxns;
}
/**
* Creates transactions required for refunding the swap with authorization signature, also unwraps WSOL to SOL
*
* @param signer
* @param swapData swap data to refund
* @param timeout signature timeout
* @param prefix signature prefix of the counterparty
* @param signature signature of the counterparty
* @param check whether to check if swap is committed before attempting refund
* @param feeRate fee rate to be used for the transactions
*/
async txsRefundWithAuthorization(signer, swapData, timeout, prefix, signature, check, feeRate) {
if (check && !await (0, Utils_1.tryWithRetries)(() => this.root.isCommited(swapData), this.retryPolicy)) {
throw new base_1.SwapDataVerificationError("Not correctly committed");
}
await (0, Utils_1.tryWithRetries)(() => this.isSignatureValid(swapData, timeout, prefix, signature), this.retryPolicy, (e) => e instanceof base_1.SignatureVerificationError);
const action = this.RefundWithSignature(signer, swapData, timeout, JSON.parse(signature));
feeRate ?? (feeRate = await this.root.Fees.getFeeRate());
this.logger.debug("txsRefundWithAuthorization(): creating refund transaction, swap: " + swapData.getClaimHash() +
" auth expiry: " + timeout + " signature: " + signature);
return [await action.tx(feeRate)];
}
/**
* Get the estimated solana transaction fee of the refund transaction, in the worst case scenario in case where the
* ATA needs to be initialized again (i.e. adding the ATA rent exempt lamports to the fee)
*/
async getRefundFee(swapData, feeRate) {
feeRate ?? (feeRate = await this.root.Fees.getFeeRate());
return StarknetFees_1.StarknetFees.getGasFee(swapData.payIn ? StarknetSwapRefund.GasCosts.REFUND_PAY_OUT.l1 : StarknetSwapRefund.GasCosts.REFUND.l1, feeRate);
}
}
exports.StarknetSwapRefund = StarknetSwapRefund;
StarknetSwapRefund.GasCosts = {
REFUND: { l1: 750, l2: 0 },
REFUND_PAY_OUT: { l1: 1250, l2: 0 }
};