Skip to content

Commit

Permalink
feat: EVM chain swaps
Browse files Browse the repository at this point in the history
  • Loading branch information
michael1011 committed Mar 26, 2024
1 parent c1f72d3 commit 25ef8dd
Show file tree
Hide file tree
Showing 12 changed files with 1,013 additions and 625 deletions.
3 changes: 1 addition & 2 deletions lib/Core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,13 +165,12 @@ export const getOutputValue = (
export const constructClaimDetails = (
swapOutputType: SwapOutputType,
wallet: Wallet,
swapType: SwapType,
swap: Swap | ChainSwapData,
transaction: Transaction | LiquidTransaction,
preimage?: Buffer,
cooperative: boolean = false,
): ClaimDetails | LiquidClaimDetails => {
const isSubmarine = swapType === SwapType.Submarine;
const isSubmarine = swap.type === SwapType.Submarine;

let lockupVout = isSubmarine
? (swap as Swap).lockupTransactionVout
Expand Down
2 changes: 1 addition & 1 deletion lib/cli/ethereum/EthereumUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,5 @@ export const getLogsQueryStartHeight = async (
delta: number,
): Promise<number> => {
const blockHeight = await provider.getBlockNumber();
return blockHeight - delta;
return Math.max(blockHeight - delta, 0);
};
14 changes: 14 additions & 0 deletions lib/cli/ethereum/commands/Address.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Arguments } from 'yargs';
import { stringify } from '../../../Utils';
import { connectEthereum } from '../EthereumUtils';

export const command = 'address';

export const describe = 'prints the address of the signer';

export const builder = {};

export const handler = async (argv: Arguments<any>): Promise<void> => {
const signer = await connectEthereum(argv.provider);
console.log(stringify({ address: await signer.getAddress() }));
};
9 changes: 9 additions & 0 deletions lib/db/models/ChainSwapData.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { DataTypes, Model, Sequelize } from 'sequelize';
import { SwapType } from '../../consts/Enums';
import ChainSwap from './ChainSwap';

type ChainSwapDataType = {
Expand Down Expand Up @@ -97,9 +98,17 @@ class ChainSwapData extends Model implements ChainSwapDataType {
});
};

get type() {
return SwapType.Chain;
}

get lockupTransactionId() {
return this.transactionId;
}

get redeemScript() {
return this.swapTree;
}
}

export default ChainSwapData;
Expand Down
8 changes: 8 additions & 0 deletions lib/db/models/ReverseSwap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,14 @@ class ReverseSwap extends Model implements ReverseSwapType {
get type() {
return SwapType.ReverseSubmarine;
}

get theirPublicKey() {
return this.claimPublicKey;
}

get expectedAmount() {
return this.onchainAmount;
}
}

export default ReverseSwap;
Expand Down
65 changes: 62 additions & 3 deletions lib/db/repositories/ChainSwapRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import {
getSendingReceivingCurrency,
splitPairId,
} from '../../Utils';
import { SwapType, SwapUpdateEvent } from '../../consts/Enums';
import {
NotPendingChainSwapEvents,
SwapType,
SwapUpdateEvent,
SwapVersion,
} from '../../consts/Enums';
import Database from '../Database';
import ChainSwap, { ChainSwapType } from '../models/ChainSwap';
import ChainSwapData, { ChainSwapDataType } from '../models/ChainSwapData';
Expand All @@ -20,6 +25,10 @@ class ChainSwapInfo {
return SwapType.Chain;
}

get version() {
return SwapVersion.Taproot;
}

get id() {
return this.chainSwap.id;
}
Expand All @@ -28,6 +37,10 @@ class ChainSwapInfo {
return this.chainSwap.status as SwapUpdateEvent;
}

get failureReason() {
return this.chainSwap.failureReason;
}

get isSettled() {
return this.chainSwap.status === SwapUpdateEvent.TransactionClaimed;
}
Expand Down Expand Up @@ -125,6 +138,29 @@ class ChainSwapRepository {
return swaps.concat(await this.getChainSwaps(swapOptions));
};

public static getChainSwapsExpirable = async (
symbols: string[],
blockHeight: number,
) => {
const data = await ChainSwapData.findAll({
where: {
symbol: symbols,
timeoutBlockHeight: {
[Op.lte]: blockHeight,
},
},
});

const swaps = await this.getChainSwaps({
id: data.map((d) => d.swapId),
status: {
[Op.notIn]: NotPendingChainSwapEvents,
},
});

return swaps.filter((s) => symbols.includes(s.sendingData.symbol));
};

public static addChainSwap = (args: {
chainSwap: ChainSwapType;
sendingData: ChainSwapDataType;
Expand Down Expand Up @@ -172,7 +208,7 @@ class ChainSwapRepository {
transactionId: string,
onchainAmount: number,
fee: number,
vout: number,
vout?: number,
): Promise<ChainSwapInfo> =>
Database.sequelize.transaction(async (transaction) => {
swap.chainSwap = await swap.chainSwap.update(
Expand Down Expand Up @@ -224,14 +260,37 @@ class ChainSwapRepository {
return swap;
});

public static setTransactionRefunded = (
swap: ChainSwapInfo,
minerFee: number,
failureReason: string,
): Promise<ChainSwapInfo> =>
Database.sequelize.transaction(async (transaction) => {
swap.chainSwap = await swap.chainSwap.update(
{
failureReason,
status: SwapUpdateEvent.TransactionRefunded,
},
{ transaction },
);
swap.sendingData = await swap.receivingData.update(
{
fee: swap.sendingData.fee! + minerFee,
},
{ transaction },
);

return swap;
});

public static setSwapStatus = async (
swap: ChainSwapInfo,
status: SwapUpdateEvent,
reason?: string,
) => {
swap.chainSwap = await swap.chainSwap.update({
status,
reason,
failureReason: reason,
});
return swap;
};
Expand Down
54 changes: 37 additions & 17 deletions lib/service/EventHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,17 +234,29 @@ class EventHandler extends TypedEventEmitter<{
});
});

this.nursery.on('expiration', ({ swap, isReverse }) => {
this.nursery.on('expiration', (swap) => {
const newStatus = SwapUpdateEvent.SwapExpired;

if (isReverse) {
this.handleFailedReverseSwap(
swap as ReverseSwap,
newStatus,
swap.failureReason!,
);
} else {
this.handleFailedSwap(swap as Swap, newStatus, swap.failureReason!);
switch (swap.type) {
case SwapType.Submarine:
this.handleFailedSwap(swap as Swap, newStatus, swap.failureReason!);
break;

case SwapType.ReverseSubmarine:
this.handleFailedReverseSwap(
swap as ReverseSwap,
newStatus,
swap.failureReason!,
);
break;

case SwapType.Chain:
this.handleFailedChainSwap(
swap as ChainSwapInfo,
newStatus,
swap.failureReason!,
);
break;
}
});

Expand Down Expand Up @@ -286,8 +298,8 @@ class EventHandler extends TypedEventEmitter<{
}
});

this.nursery.on('coins.failedToSend', ({ type, swap }) => {
if (type === SwapType.ReverseSubmarine) {
this.nursery.on('coins.failedToSend', (swap) => {
if (swap.type === SwapType.ReverseSubmarine) {
this.handleFailedReverseSwap(
swap as ReverseSwap,
SwapUpdateEvent.TransactionFailed,
Expand All @@ -302,12 +314,20 @@ class EventHandler extends TypedEventEmitter<{
}
});

this.nursery.on('refund', ({ reverseSwap }) => {
this.handleFailedReverseSwap(
reverseSwap,
SwapUpdateEvent.TransactionRefunded,
reverseSwap.failureReason!,
);
this.nursery.on('refund', ({ swap }) => {
if (swap.type === SwapType.ReverseSubmarine) {
this.handleFailedReverseSwap(
swap as ReverseSwap,
SwapUpdateEvent.TransactionRefunded,
swap.failureReason!,
);
} else {
this.handleFailedChainSwap(
swap as ChainSwapInfo,
SwapUpdateEvent.TransactionRefunded,
swap.failureReason!,
);
}
});

this.nursery.channelNursery.on(
Expand Down
1 change: 0 additions & 1 deletion lib/service/cooperative/CoopSignerBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ abstract class CoopSignerBase<
return constructClaimDetails(
this.swapOutputType,
wallet,
swap.type,
details,
tx,
preimage,
Expand Down
Loading

0 comments on commit 25ef8dd

Please sign in to comment.