Skip to content

Commit

Permalink
Commit dist
Browse files Browse the repository at this point in the history
  • Loading branch information
sisou committed Oct 29, 2024
1 parent cabdaf2 commit daaa324
Show file tree
Hide file tree
Showing 15 changed files with 680 additions and 2 deletions.
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
node_modules
.DS_Store
dist
#dist
*.local

1 change: 1 addition & 0 deletions dist/libswap.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './src/SwapHandler';
1 change: 1 addition & 0 deletions dist/libswap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './src/SwapHandler';
25 changes: 25 additions & 0 deletions dist/src/BitcoinAssetAdapter.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type { ConsensusState, TransactionDetails } from '@nimiq/electrum-client';
import { AssetAdapter, SwapAsset } from './IAssetAdapter';
export { ConsensusState, TransactionDetails };
export interface BitcoinClient {
addTransactionListener(listener: (tx: TransactionDetails) => any, addresses: string[]): number | Promise<number>;
getTransactionsByAddress(address: string, sinceBlockHeight?: number, knownTransactions?: TransactionDetails[]): Promise<TransactionDetails[]>;
removeListener(handle: number): void | Promise<void>;
sendTransaction(tx: TransactionDetails | string): Promise<TransactionDetails>;
addConsensusChangedListener(listener: (consensusState: ConsensusState) => any): number | Promise<number>;
}
export declare class BitcoinAssetAdapter implements AssetAdapter<SwapAsset.BTC> {
client: BitcoinClient;
private cancelCallback;
private stopped;
constructor(client: BitcoinClient);
private findTransaction;
awaitHtlcFunding(address: string, value: number, data?: string, confirmations?: number, onPending?: (tx: TransactionDetails) => any): Promise<TransactionDetails>;
fundHtlc(serializedTx: string): Promise<TransactionDetails>;
awaitHtlcSettlement(address: string, data: string): Promise<TransactionDetails>;
awaitSwapSecret(address: string, data: string): Promise<string>;
settleHtlc(serializedTx: string, secret: string): Promise<TransactionDetails>;
awaitSettlementConfirmation(address: string, onUpdate?: (tx: TransactionDetails) => any): Promise<TransactionDetails>;
stop(reason: Error): void;
private sendTransaction;
}
98 changes: 98 additions & 0 deletions dist/src/BitcoinAssetAdapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
export class BitcoinAssetAdapter {
constructor(client) {
this.client = client;
this.cancelCallback = null;
this.stopped = false;
}
async findTransaction(address, test) {
return new Promise(async (resolve, reject) => {
const listener = (tx) => {
if (!test(tx))
return false;
cleanup();
resolve(tx);
return true;
};
const transactionListener = await this.client.addTransactionListener(listener, [address]);
let history = [];
const checkHistory = async () => {
history = await this.client.getTransactionsByAddress(address, 0, history);
for (const tx of history) {
if (listener(tx))
break;
}
};
checkHistory();
const consensusListener = await this.client.addConsensusChangedListener((consensusState) => consensusState === 'established' && checkHistory());
const historyCheckInterval = window.setInterval(checkHistory, 60 * 1000);
const cleanup = () => {
this.client.removeListener(transactionListener);
this.client.removeListener(consensusListener);
window.clearInterval(historyCheckInterval);
this.cancelCallback = null;
};
this.cancelCallback = (reason) => {
cleanup();
reject(reason);
};
});
}
async awaitHtlcFunding(address, value, data, confirmations = 0, onPending) {
return this.findTransaction(address, (tx) => {
const htlcOutput = tx.outputs.find((out) => out.address === address);
if (!htlcOutput)
return false;
if (htlcOutput.value !== value)
return false;
if (tx.confirmations < confirmations) {
if (typeof onPending === 'function')
onPending(tx);
return false;
}
if (tx.replaceByFee) {
if (tx.state === 'mined' || tx.state === 'confirmed')
return true;
if (typeof onPending === 'function')
onPending(tx);
return false;
}
return true;
});
}
async fundHtlc(serializedTx) {
if (this.stopped)
throw new Error('BitcoinAssetAdapter called while stopped');
return this.sendTransaction(serializedTx);
}
async awaitHtlcSettlement(address, data) {
return this.findTransaction(address, (tx) => tx.inputs.some((input) => input.address === address
&& typeof input.witness[4] === 'string' && input.witness[4] === data));
}
async awaitSwapSecret(address, data) {
const tx = await this.awaitHtlcSettlement(address, data);
return tx.inputs[0].witness[2];
}
async settleHtlc(serializedTx, secret) {
serializedTx = serializedTx.replace('000000000000000000000000000000000000000000000000000000000000000001', `${secret}01`);
return this.sendTransaction(serializedTx);
}
async awaitSettlementConfirmation(address, onUpdate) {
return this.findTransaction(address, (tx) => {
if (!tx.inputs.some((input) => input.address === address && input.witness.length === 5))
return false;
if (tx.state === 'mined' || tx.state === 'confirmed')
return true;
if (typeof onUpdate === 'function')
onUpdate(tx);
return false;
});
}
stop(reason) {
if (this.cancelCallback)
this.cancelCallback(reason);
this.stopped = true;
}
async sendTransaction(serializedTx) {
return this.client.sendTransaction(serializedTx);
}
}
63 changes: 63 additions & 0 deletions dist/src/Erc20AssetAdapter.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { BigNumber, Contract, Event as EthersEvent, EventFilter } from 'ethers';
import { AssetAdapter, SwapAsset } from './IAssetAdapter';
export declare enum EventType {
OPEN = "Open",
REDEEM = "Redeem",
REFUND = "Refund"
}
type OpenEventArgs = [
string,
string,
BigNumber,
string,
string,
BigNumber
];
type RedeemEventArgs = [
string,
string
];
type RefundEventArgs = [
string
];
type EventArgs<T extends EventType> = T extends EventType.OPEN ? OpenEventArgs : T extends EventType.REDEEM ? RedeemEventArgs : T extends EventType.REFUND ? RefundEventArgs : never;
type OpenResult = ReadonlyArray<any> & OpenEventArgs & {
id: string;
token: string;
amount: BigNumber;
recipient: string;
hash: string;
timeout: BigNumber;
};
type RedeemResult = ReadonlyArray<any> & RedeemEventArgs & {
id: string;
secret: string;
};
type RefundResult = ReadonlyArray<any> & RefundEventArgs & {
id: string;
};
export interface Event<T extends EventType> extends EthersEvent {
args: T extends EventType.OPEN ? OpenResult : T extends EventType.REDEEM ? RedeemResult : T extends EventType.REFUND ? RefundResult : never;
}
export type GenericEvent = Event<EventType>;
export interface Web3Client {
htlcContract: Contract;
currentBlock: () => number | Promise<number>;
startBlock: number;
endBlock?: number;
}
export declare class Erc20AssetAdapter implements AssetAdapter<SwapAsset.USDC | SwapAsset.USDC_MATIC | SwapAsset.USDT> {
client: Web3Client;
private cancelCallback;
private stopped;
constructor(client: Web3Client);
findLog<T extends EventType>(filter: EventFilter, test?: (...args: [...EventArgs<T>, Event<T>]) => boolean | Promise<boolean>): Promise<Event<T>>;
awaitHtlcFunding(htlcId: string, value: number, data?: string, confirmations?: number, onPending?: (tx: GenericEvent) => any): Promise<Event<EventType.OPEN>>;
fundHtlc(_serializedTx: string): Promise<Event<EventType.OPEN>>;
awaitHtlcSettlement(htlcId: string): Promise<Event<EventType.REDEEM>>;
awaitSwapSecret(htlcId: string): Promise<string>;
settleHtlc(_serializedTx: string, _secret: string): Promise<Event<EventType.REDEEM>>;
awaitSettlementConfirmation(htlcId: string): Promise<Event<EventType.REDEEM>>;
stop(reason: Error): void;
}
export {};
85 changes: 85 additions & 0 deletions dist/src/Erc20AssetAdapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
export var EventType;
(function (EventType) {
EventType["OPEN"] = "Open";
EventType["REDEEM"] = "Redeem";
EventType["REFUND"] = "Refund";
})(EventType || (EventType = {}));
export class Erc20AssetAdapter {
constructor(client) {
this.client = client;
this.cancelCallback = null;
this.stopped = false;
}
async findLog(filter, test) {
return new Promise(async (resolve, reject) => {
const listener = async (...args) => {
if (test && !(await test.apply(this, args)))
return false;
cleanup();
resolve(args[args.length - 1]);
return true;
};
this.client.htlcContract.on(filter, listener);
const checkHistory = async () => {
const history = await this.client.htlcContract.queryFilter(filter, this.client.startBlock, this.client.endBlock);
for (const event of history) {
if (!event.args)
continue;
if (await listener(...event.args, event))
break;
}
};
checkHistory();
const historyCheckInterval = window.setInterval(checkHistory, 60 * 1000);
const cleanup = () => {
this.client.htlcContract.off(filter, listener);
window.clearInterval(historyCheckInterval);
this.cancelCallback = null;
};
this.cancelCallback = (reason) => {
cleanup();
reject(reason);
};
});
}
async awaitHtlcFunding(htlcId, value, data, confirmations = 0, onPending) {
const filter = this.client.htlcContract.filters.Open(htlcId);
return this.findLog(filter, async (id, token, amount, recipient, hash, timeout, log) => {
if (amount.toNumber() !== value) {
console.warn(`Found ERC-20 HTLC, but amount does not match. Expected ${value}, found ${amount.toNumber()}`);
return false;
}
if (confirmations > 0) {
const logConfirmations = await this.client.currentBlock() - log.blockNumber + 1;
if (logConfirmations < confirmations) {
if (typeof onPending === 'function')
onPending(log);
return false;
}
}
return true;
});
}
async fundHtlc(_serializedTx) {
throw new Error('Method "fundHtlc" not available for ERC-20 HTLCs');
}
async awaitHtlcSettlement(htlcId) {
const filter = this.client.htlcContract.filters.Redeem(htlcId);
return this.findLog(filter);
}
async awaitSwapSecret(htlcId) {
const log = await this.awaitHtlcSettlement(htlcId);
return log.args.secret.substring(2);
}
async settleHtlc(_serializedTx, _secret) {
throw new Error('Method "settleHtlc" not available for ERC-20 HTLCs');
}
async awaitSettlementConfirmation(htlcId) {
return this.awaitHtlcSettlement(htlcId);
}
stop(reason) {
if (this.cancelCallback)
this.cancelCallback(reason);
this.stopped = true;
}
}
21 changes: 21 additions & 0 deletions dist/src/FiatAssetAdapter.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Htlc, HtlcStatus, SettlementTokens } from '@nimiq/oasis-api';
import type { AssetAdapter, FiatSwapAsset } from './IAssetAdapter';
export { Htlc as OasisHtlcDetails, SettlementTokens as OasisSettlementTokens };
export interface OasisClient {
getHtlc(id: string): Promise<Htlc>;
settleHtlc(id: string, secret: string, settlementJWS: string, tokens?: SettlementTokens): Promise<Htlc>;
}
export declare class FiatAssetAdapter implements AssetAdapter<FiatSwapAsset> {
client: OasisClient;
private cancelCallback;
private stopped;
constructor(client: OasisClient);
private findTransaction;
awaitHtlcFunding(id: string, value: number, data?: string, confirmations?: number, onUpdate?: (htlc: Htlc) => any): Promise<Htlc>;
fundHtlc(): Promise<Htlc>;
awaitHtlcSettlement(id: string): Promise<Htlc<HtlcStatus.SETTLED>>;
awaitSwapSecret(id: string): Promise<string>;
settleHtlc(settlementJWS: string, secret: string, hash: string, tokens?: SettlementTokens): Promise<Htlc>;
awaitSettlementConfirmation(id: string, onUpdate?: (tx: Htlc) => any): Promise<Htlc>;
stop(reason: Error): void;
}
Loading

0 comments on commit daaa324

Please sign in to comment.