@atomiqlabs/lp-lib 10.3.11
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/fees/IBtcFeeEstimator.d.ts +3 -0
- package/dist/fees/IBtcFeeEstimator.js +2 -0
- package/dist/fees/OneDollarFeeEstimator.d.ts +16 -0
- package/dist/fees/OneDollarFeeEstimator.js +71 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +52 -0
- package/dist/info/InfoHandler.d.ts +17 -0
- package/dist/info/InfoHandler.js +70 -0
- package/dist/plugins/IPlugin.d.ts +118 -0
- package/dist/plugins/IPlugin.js +33 -0
- package/dist/plugins/PluginManager.d.ts +89 -0
- package/dist/plugins/PluginManager.js +263 -0
- package/dist/prices/BinanceSwapPrice.d.ts +27 -0
- package/dist/prices/BinanceSwapPrice.js +106 -0
- package/dist/prices/CoinGeckoSwapPrice.d.ts +31 -0
- package/dist/prices/CoinGeckoSwapPrice.js +76 -0
- package/dist/storage/IIntermediaryStorage.d.ts +15 -0
- package/dist/storage/IIntermediaryStorage.js +2 -0
- package/dist/storagemanager/IntermediaryStorageManager.d.ts +15 -0
- package/dist/storagemanager/IntermediaryStorageManager.js +113 -0
- package/dist/storagemanager/StorageManager.d.ts +12 -0
- package/dist/storagemanager/StorageManager.js +74 -0
- package/dist/swaps/FromBtcBaseSwap.d.ts +12 -0
- package/dist/swaps/FromBtcBaseSwap.js +16 -0
- package/dist/swaps/FromBtcBaseSwapHandler.d.ts +118 -0
- package/dist/swaps/FromBtcBaseSwapHandler.js +294 -0
- package/dist/swaps/FromBtcLnBaseSwapHandler.d.ts +25 -0
- package/dist/swaps/FromBtcLnBaseSwapHandler.js +55 -0
- package/dist/swaps/ISwapPrice.d.ts +44 -0
- package/dist/swaps/ISwapPrice.js +73 -0
- package/dist/swaps/SwapHandler.d.ts +186 -0
- package/dist/swaps/SwapHandler.js +292 -0
- package/dist/swaps/SwapHandlerSwap.d.ts +75 -0
- package/dist/swaps/SwapHandlerSwap.js +72 -0
- package/dist/swaps/ToBtcBaseSwap.d.ts +35 -0
- package/dist/swaps/ToBtcBaseSwap.js +61 -0
- package/dist/swaps/ToBtcBaseSwapHandler.d.ts +94 -0
- package/dist/swaps/ToBtcBaseSwapHandler.js +233 -0
- package/dist/swaps/frombtc_abstract/FromBtcAbs.d.ts +92 -0
- package/dist/swaps/frombtc_abstract/FromBtcAbs.js +386 -0
- package/dist/swaps/frombtc_abstract/FromBtcSwapAbs.d.ts +26 -0
- package/dist/swaps/frombtc_abstract/FromBtcSwapAbs.js +63 -0
- package/dist/swaps/frombtc_trusted/FromBtcTrusted.d.ts +55 -0
- package/dist/swaps/frombtc_trusted/FromBtcTrusted.js +586 -0
- package/dist/swaps/frombtc_trusted/FromBtcTrustedSwap.d.ts +43 -0
- package/dist/swaps/frombtc_trusted/FromBtcTrustedSwap.js +99 -0
- package/dist/swaps/frombtcln_abstract/FromBtcLnAbs.d.ts +105 -0
- package/dist/swaps/frombtcln_abstract/FromBtcLnAbs.js +731 -0
- package/dist/swaps/frombtcln_abstract/FromBtcLnSwapAbs.d.ts +29 -0
- package/dist/swaps/frombtcln_abstract/FromBtcLnSwapAbs.js +64 -0
- package/dist/swaps/frombtcln_trusted/FromBtcLnTrusted.d.ts +79 -0
- package/dist/swaps/frombtcln_trusted/FromBtcLnTrusted.js +514 -0
- package/dist/swaps/frombtcln_trusted/FromBtcLnTrustedSwap.d.ts +28 -0
- package/dist/swaps/frombtcln_trusted/FromBtcLnTrustedSwap.js +66 -0
- package/dist/swaps/tobtc_abstract/ToBtcAbs.d.ts +290 -0
- package/dist/swaps/tobtc_abstract/ToBtcAbs.js +1056 -0
- package/dist/swaps/tobtc_abstract/ToBtcSwapAbs.d.ts +29 -0
- package/dist/swaps/tobtc_abstract/ToBtcSwapAbs.js +70 -0
- package/dist/swaps/tobtcln_abstract/ToBtcLnAbs.d.ts +246 -0
- package/dist/swaps/tobtcln_abstract/ToBtcLnAbs.js +1169 -0
- package/dist/swaps/tobtcln_abstract/ToBtcLnSwapAbs.d.ts +27 -0
- package/dist/swaps/tobtcln_abstract/ToBtcLnSwapAbs.js +65 -0
- package/dist/utils/Utils.d.ts +32 -0
- package/dist/utils/Utils.js +109 -0
- package/dist/utils/coinselect2/accumulative.d.ts +6 -0
- package/dist/utils/coinselect2/accumulative.js +44 -0
- package/dist/utils/coinselect2/blackjack.d.ts +6 -0
- package/dist/utils/coinselect2/blackjack.js +41 -0
- package/dist/utils/coinselect2/index.d.ts +16 -0
- package/dist/utils/coinselect2/index.js +40 -0
- package/dist/utils/coinselect2/utils.d.ts +64 -0
- package/dist/utils/coinselect2/utils.js +121 -0
- package/dist/utils/paramcoders/IParamReader.d.ts +5 -0
- package/dist/utils/paramcoders/IParamReader.js +2 -0
- package/dist/utils/paramcoders/IParamWriter.d.ts +4 -0
- package/dist/utils/paramcoders/IParamWriter.js +2 -0
- package/dist/utils/paramcoders/LegacyParamEncoder.d.ts +10 -0
- package/dist/utils/paramcoders/LegacyParamEncoder.js +33 -0
- package/dist/utils/paramcoders/ParamDecoder.d.ts +25 -0
- package/dist/utils/paramcoders/ParamDecoder.js +234 -0
- package/dist/utils/paramcoders/ParamEncoder.d.ts +9 -0
- package/dist/utils/paramcoders/ParamEncoder.js +22 -0
- package/dist/utils/paramcoders/SchemaVerifier.d.ts +22 -0
- package/dist/utils/paramcoders/SchemaVerifier.js +85 -0
- package/dist/utils/paramcoders/server/ServerParamDecoder.d.ts +8 -0
- package/dist/utils/paramcoders/server/ServerParamDecoder.js +105 -0
- package/dist/utils/paramcoders/server/ServerParamEncoder.d.ts +11 -0
- package/dist/utils/paramcoders/server/ServerParamEncoder.js +76 -0
- package/package.json +43 -0
- package/src/fees/IBtcFeeEstimator.ts +7 -0
- package/src/fees/OneDollarFeeEstimator.ts +95 -0
- package/src/index.ts +46 -0
- package/src/info/InfoHandler.ts +106 -0
- package/src/plugins/IPlugin.ts +155 -0
- package/src/plugins/PluginManager.ts +310 -0
- package/src/prices/BinanceSwapPrice.ts +114 -0
- package/src/prices/CoinGeckoSwapPrice.ts +88 -0
- package/src/storage/IIntermediaryStorage.ts +21 -0
- package/src/storagemanager/IntermediaryStorageManager.ts +101 -0
- package/src/storagemanager/StorageManager.ts +68 -0
- package/src/swaps/FromBtcBaseSwap.ts +21 -0
- package/src/swaps/FromBtcBaseSwapHandler.ts +375 -0
- package/src/swaps/FromBtcLnBaseSwapHandler.ts +48 -0
- package/src/swaps/ISwapPrice.ts +94 -0
- package/src/swaps/SwapHandler.ts +404 -0
- package/src/swaps/SwapHandlerSwap.ts +133 -0
- package/src/swaps/ToBtcBaseSwap.ts +76 -0
- package/src/swaps/ToBtcBaseSwapHandler.ts +309 -0
- package/src/swaps/frombtc_abstract/FromBtcAbs.ts +484 -0
- package/src/swaps/frombtc_abstract/FromBtcSwapAbs.ts +77 -0
- package/src/swaps/frombtc_trusted/FromBtcTrusted.ts +661 -0
- package/src/swaps/frombtc_trusted/FromBtcTrustedSwap.ts +158 -0
- package/src/swaps/frombtcln_abstract/FromBtcLnAbs.ts +864 -0
- package/src/swaps/frombtcln_abstract/FromBtcLnSwapAbs.ts +82 -0
- package/src/swaps/frombtcln_trusted/FromBtcLnTrusted.ts +592 -0
- package/src/swaps/frombtcln_trusted/FromBtcLnTrustedSwap.ts +90 -0
- package/src/swaps/tobtc_abstract/ToBtcAbs.ts +1249 -0
- package/src/swaps/tobtc_abstract/ToBtcSwapAbs.ts +112 -0
- package/src/swaps/tobtcln_abstract/ToBtcLnAbs.ts +1422 -0
- package/src/swaps/tobtcln_abstract/ToBtcLnSwapAbs.ts +87 -0
- package/src/utils/Utils.ts +108 -0
- package/src/utils/coinselect2/accumulative.js +32 -0
- package/src/utils/coinselect2/accumulative.ts +58 -0
- package/src/utils/coinselect2/blackjack.js +29 -0
- package/src/utils/coinselect2/blackjack.ts +54 -0
- package/src/utils/coinselect2/index.js +16 -0
- package/src/utils/coinselect2/index.ts +50 -0
- package/src/utils/coinselect2/utils.js +110 -0
- package/src/utils/coinselect2/utils.ts +183 -0
- package/src/utils/paramcoders/IParamReader.ts +8 -0
- package/src/utils/paramcoders/IParamWriter.ts +8 -0
- package/src/utils/paramcoders/LegacyParamEncoder.ts +28 -0
- package/src/utils/paramcoders/ParamDecoder.ts +219 -0
- package/src/utils/paramcoders/ParamEncoder.ts +30 -0
- package/src/utils/paramcoders/SchemaVerifier.ts +97 -0
- package/src/utils/paramcoders/server/ServerParamDecoder.ts +115 -0
- package/src/utils/paramcoders/server/ServerParamEncoder.ts +76 -0
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
import {Express, Request, Response} from "express";
|
|
2
|
+
import {ISwapPrice} from "./ISwapPrice";
|
|
3
|
+
import {
|
|
4
|
+
AbstractSigner,
|
|
5
|
+
ChainType,
|
|
6
|
+
ClaimEvent,
|
|
7
|
+
InitializeEvent, RefundEvent,
|
|
8
|
+
SwapContract,
|
|
9
|
+
SwapData,
|
|
10
|
+
SwapEvent
|
|
11
|
+
} from "@atomiqlabs/base";
|
|
12
|
+
import {AuthenticatedLnd} from "lightning";
|
|
13
|
+
import {SwapHandlerSwap} from "./SwapHandlerSwap";
|
|
14
|
+
import {PluginManager} from "../plugins/PluginManager";
|
|
15
|
+
import {IIntermediaryStorage} from "../storage/IIntermediaryStorage";
|
|
16
|
+
import * as BN from "bn.js";
|
|
17
|
+
import {ServerParamEncoder} from "../utils/paramcoders/server/ServerParamEncoder";
|
|
18
|
+
import {
|
|
19
|
+
isQuoteAmountTooHigh,
|
|
20
|
+
isQuoteAmountTooLow,
|
|
21
|
+
isQuoteThrow,
|
|
22
|
+
} from "../plugins/IPlugin";
|
|
23
|
+
import {IParamReader} from "../utils/paramcoders/IParamReader";
|
|
24
|
+
|
|
25
|
+
export enum SwapHandlerType {
|
|
26
|
+
TO_BTC = "TO_BTC",
|
|
27
|
+
FROM_BTC = "FROM_BTC",
|
|
28
|
+
TO_BTCLN = "TO_BTCLN",
|
|
29
|
+
FROM_BTCLN = "FROM_BTCLN",
|
|
30
|
+
FROM_BTCLN_TRUSTED = "FROM_BTCLN_TRUSTED",
|
|
31
|
+
FROM_BTC_TRUSTED = "FROM_BTC_TRUSTED",
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type SwapHandlerInfoType = {
|
|
35
|
+
swapFeePPM: number,
|
|
36
|
+
swapBaseFee: number,
|
|
37
|
+
min: number,
|
|
38
|
+
max: number,
|
|
39
|
+
tokens: string[],
|
|
40
|
+
chainTokens: {[chainId: string]: string[]};
|
|
41
|
+
data?: any,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export type SwapBaseConfig = {
|
|
45
|
+
authorizationTimeout: number,
|
|
46
|
+
bitcoinBlocktime: BN,
|
|
47
|
+
baseFee: BN,
|
|
48
|
+
feePPM: BN,
|
|
49
|
+
max: BN,
|
|
50
|
+
min: BN,
|
|
51
|
+
maxSkew: number,
|
|
52
|
+
safetyFactor: BN,
|
|
53
|
+
swapCheckInterval: number
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export type MultichainData = {
|
|
57
|
+
chains: {
|
|
58
|
+
[identifier: string]: ChainData
|
|
59
|
+
},
|
|
60
|
+
default: string
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export type ChainData<T extends ChainType = ChainType> = {
|
|
64
|
+
signer: T["Signer"],
|
|
65
|
+
swapContract: T["Contract"],
|
|
66
|
+
chainEvents: T["Events"],
|
|
67
|
+
allowedTokens: string[],
|
|
68
|
+
btcRelay?: T["BtcRelay"]
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export type RequestData<T> = {
|
|
72
|
+
chainIdentifier: string,
|
|
73
|
+
raw: Request & {paramReader: IParamReader},
|
|
74
|
+
parsed: T,
|
|
75
|
+
metadata: any
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* An abstract class defining a singular swap service
|
|
80
|
+
*/
|
|
81
|
+
export abstract class SwapHandler<V extends SwapHandlerSwap<SwapData, S> = SwapHandlerSwap, S = any> {
|
|
82
|
+
|
|
83
|
+
abstract readonly type: SwapHandlerType;
|
|
84
|
+
|
|
85
|
+
readonly storageManager: IIntermediaryStorage<V>;
|
|
86
|
+
readonly path: string;
|
|
87
|
+
|
|
88
|
+
readonly chains: MultichainData;
|
|
89
|
+
readonly allowedTokens: {[chainId: string]: Set<string>};
|
|
90
|
+
readonly swapPricing: ISwapPrice;
|
|
91
|
+
readonly LND: AuthenticatedLnd;
|
|
92
|
+
|
|
93
|
+
abstract config: SwapBaseConfig;
|
|
94
|
+
|
|
95
|
+
logger = {
|
|
96
|
+
debug: (msg: string, ...args: any) => console.debug("SwapHandler("+this.type+"): "+msg, ...args),
|
|
97
|
+
info: (msg: string, ...args: any) => console.info("SwapHandler("+this.type+"): "+msg, ...args),
|
|
98
|
+
warn: (msg: string, ...args: any) => console.warn("SwapHandler("+this.type+"): "+msg, ...args),
|
|
99
|
+
error: (msg: string, ...args: any) => console.error("SwapHandler("+this.type+"): "+msg, ...args)
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
protected swapLogger = {
|
|
103
|
+
debug: (swap: SwapHandlerSwap | SwapEvent<SwapData> | SwapData, msg: string, ...args: any) => this.logger.debug(this.getIdentifier(swap)+": "+msg, ...args),
|
|
104
|
+
info: (swap: SwapHandlerSwap | SwapEvent<SwapData> | SwapData, msg: string, ...args: any) => this.logger.info(this.getIdentifier(swap)+": "+msg, ...args),
|
|
105
|
+
warn: (swap: SwapHandlerSwap | SwapEvent<SwapData> | SwapData, msg: string, ...args: any) => this.logger.warn(this.getIdentifier(swap)+": "+msg, ...args),
|
|
106
|
+
error: (swap: SwapHandlerSwap | SwapEvent<SwapData> | SwapData, msg: string, ...args: any) => this.logger.error(this.getIdentifier(swap)+": "+msg, ...args)
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
protected constructor(
|
|
110
|
+
storageDirectory: IIntermediaryStorage<V>,
|
|
111
|
+
path: string,
|
|
112
|
+
chainsData: MultichainData,
|
|
113
|
+
lnd: AuthenticatedLnd,
|
|
114
|
+
swapPricing: ISwapPrice
|
|
115
|
+
) {
|
|
116
|
+
this.storageManager = storageDirectory;
|
|
117
|
+
this.chains = chainsData;
|
|
118
|
+
if(this.chains.chains[this.chains.default]==null) throw new Error("Invalid default chain specified");
|
|
119
|
+
this.path = path;
|
|
120
|
+
this.LND = lnd;
|
|
121
|
+
this.swapPricing = swapPricing;
|
|
122
|
+
this.allowedTokens = {};
|
|
123
|
+
for(let chainId in chainsData.chains) {
|
|
124
|
+
this.allowedTokens[chainId] = new Set<string>(chainsData.chains[chainId].allowedTokens);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
protected getDefaultChain(): ChainData {
|
|
129
|
+
return this.chains.chains[this.chains.default];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
protected getChain(identifier: string): ChainData {
|
|
133
|
+
if(this.chains.chains[identifier]==null)
|
|
134
|
+
throw {
|
|
135
|
+
code: 20200,
|
|
136
|
+
msg: "Invalid chain specified!"
|
|
137
|
+
};
|
|
138
|
+
return this.chains.chains[identifier];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
protected abstract processPastSwaps(): Promise<void>;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Starts the watchdog checking past swaps for expiry or claim eligibility.
|
|
145
|
+
*/
|
|
146
|
+
async startWatchdog() {
|
|
147
|
+
let rerun: () => Promise<void>;
|
|
148
|
+
rerun = async () => {
|
|
149
|
+
await this.processPastSwaps().catch( e => console.error(e));
|
|
150
|
+
setTimeout(rerun, this.config.swapCheckInterval);
|
|
151
|
+
};
|
|
152
|
+
await rerun();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
protected abstract processInitializeEvent(chainIdentifier: string, event: InitializeEvent<SwapData>): Promise<void>;
|
|
156
|
+
protected abstract processClaimEvent(chainIdentifier: string, event: ClaimEvent<SwapData>): Promise<void>;
|
|
157
|
+
protected abstract processRefundEvent(chainIdentifier: string, event: RefundEvent<SwapData>): Promise<void>;
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Chain event processor
|
|
161
|
+
*
|
|
162
|
+
* @param chainIdentifier
|
|
163
|
+
* @param eventData
|
|
164
|
+
*/
|
|
165
|
+
protected async processEvent(chainIdentifier: string, eventData: SwapEvent<SwapData>[]): Promise<boolean> {
|
|
166
|
+
for(let event of eventData) {
|
|
167
|
+
if(event instanceof InitializeEvent) {
|
|
168
|
+
// this.swapLogger.debug(event, "SC: InitializeEvent: swap type: "+event.swapType);
|
|
169
|
+
await this.processInitializeEvent(chainIdentifier, event);
|
|
170
|
+
} else if(event instanceof ClaimEvent) {
|
|
171
|
+
// this.swapLogger.debug(event, "SC: ClaimEvent: swap secret: "+event.secret);
|
|
172
|
+
await this.processClaimEvent(chainIdentifier, event);
|
|
173
|
+
} else if(event instanceof RefundEvent) {
|
|
174
|
+
// this.swapLogger.debug(event, "SC: RefundEvent");
|
|
175
|
+
await this.processRefundEvent(chainIdentifier, event);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Initializes chain events subscription
|
|
184
|
+
*/
|
|
185
|
+
protected subscribeToEvents() {
|
|
186
|
+
for(let key in this.chains.chains) {
|
|
187
|
+
this.chains.chains[key].chainEvents.registerListener((events: SwapEvent<SwapData>[]) => this.processEvent(key, events));
|
|
188
|
+
}
|
|
189
|
+
this.logger.info("SC: Events: subscribed to smartchain events");
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Initializes swap handler, loads data and subscribes to chain events
|
|
194
|
+
*/
|
|
195
|
+
abstract init(): Promise<void>;
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Sets up required listeners for the REST server
|
|
199
|
+
*
|
|
200
|
+
* @param restServer
|
|
201
|
+
*/
|
|
202
|
+
abstract startRestServer(restServer: Express): void;
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Returns data to be returned in swap handler info
|
|
206
|
+
*/
|
|
207
|
+
abstract getInfoData(): any;
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Remove swap data
|
|
211
|
+
*
|
|
212
|
+
* @param hash
|
|
213
|
+
* @param sequence
|
|
214
|
+
*/
|
|
215
|
+
protected removeSwapData(hash: string, sequence: BN): Promise<void>;
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Remove swap data
|
|
219
|
+
*
|
|
220
|
+
* @param swap
|
|
221
|
+
* @param ultimateState set the ultimate state of the swap before removing
|
|
222
|
+
*/
|
|
223
|
+
protected removeSwapData(swap: V, ultimateState?: S): Promise<void>;
|
|
224
|
+
|
|
225
|
+
protected async removeSwapData(hashOrSwap: string | V, sequenceOrUltimateState?: BN | S) {
|
|
226
|
+
let swap: V;
|
|
227
|
+
if(typeof(hashOrSwap)==="string") {
|
|
228
|
+
if(!BN.isBN(sequenceOrUltimateState)) throw new Error("Sequence must be a BN instance!");
|
|
229
|
+
swap = await this.storageManager.getData(hashOrSwap, sequenceOrUltimateState);
|
|
230
|
+
} else {
|
|
231
|
+
swap = hashOrSwap;
|
|
232
|
+
if(sequenceOrUltimateState!=null && !BN.isBN(sequenceOrUltimateState)) await swap.setState(sequenceOrUltimateState);
|
|
233
|
+
}
|
|
234
|
+
if(swap!=null) await PluginManager.swapRemove(swap);
|
|
235
|
+
this.swapLogger.debug(swap, "removeSwapData(): removing swap final state: "+swap.state);
|
|
236
|
+
await this.storageManager.removeData(swap.getHash(), swap.getSequence());
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Checks whether the bitcoin amount is within specified min/max bounds
|
|
241
|
+
*
|
|
242
|
+
* @param amount
|
|
243
|
+
* @protected
|
|
244
|
+
* @throws {DefinedRuntimeError} will throw an error if the amount is outside minimum/maximum bounds
|
|
245
|
+
*/
|
|
246
|
+
protected checkBtcAmountInBounds(amount: BN): void {
|
|
247
|
+
if (amount.lt(this.config.min)) {
|
|
248
|
+
throw {
|
|
249
|
+
code: 20003,
|
|
250
|
+
msg: "Amount too low!",
|
|
251
|
+
data: {
|
|
252
|
+
min: this.config.min.toString(10),
|
|
253
|
+
max: this.config.max.toString(10)
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if(amount.gt(this.config.max)) {
|
|
259
|
+
throw {
|
|
260
|
+
code: 20004,
|
|
261
|
+
msg: "Amount too high!",
|
|
262
|
+
data: {
|
|
263
|
+
min: this.config.min.toString(10),
|
|
264
|
+
max: this.config.max.toString(10)
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Handles and throws plugin errors
|
|
272
|
+
*
|
|
273
|
+
* @param res Response as returned from the PluginManager.onHandlePost{To,From}BtcQuote
|
|
274
|
+
* @protected
|
|
275
|
+
* @throws {DefinedRuntimeError} will throw an error if the response is an error
|
|
276
|
+
*/
|
|
277
|
+
protected handlePluginErrorResponses(res: any): void {
|
|
278
|
+
if(isQuoteThrow(res)) throw {
|
|
279
|
+
code: 29999,
|
|
280
|
+
msg: res.message
|
|
281
|
+
};
|
|
282
|
+
if(isQuoteAmountTooHigh(res)) throw {
|
|
283
|
+
code: 20004,
|
|
284
|
+
msg: "Amount too high!",
|
|
285
|
+
data: {
|
|
286
|
+
min: res.data.min.toString(10),
|
|
287
|
+
max: res.data.max.toString(10)
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
if(isQuoteAmountTooLow(res)) throw {
|
|
291
|
+
code: 20003,
|
|
292
|
+
msg: "Amount too low!",
|
|
293
|
+
data: {
|
|
294
|
+
min: res.data.min.toString(10),
|
|
295
|
+
max: res.data.max.toString(10)
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Creates an abort controller that extends the responseStream's abort signal
|
|
302
|
+
*
|
|
303
|
+
* @param responseStream
|
|
304
|
+
*/
|
|
305
|
+
protected getAbortController(responseStream: ServerParamEncoder): AbortController {
|
|
306
|
+
const abortController = new AbortController();
|
|
307
|
+
const responseStreamAbortController = responseStream.getAbortSignal();
|
|
308
|
+
responseStreamAbortController.addEventListener("abort", () => abortController.abort(responseStreamAbortController.reason));
|
|
309
|
+
return abortController;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Starts a pre-fetch for signature data
|
|
314
|
+
*
|
|
315
|
+
* @param chainIdentifier
|
|
316
|
+
* @param abortController
|
|
317
|
+
* @param responseStream
|
|
318
|
+
*/
|
|
319
|
+
protected getSignDataPrefetch(chainIdentifier: string, abortController: AbortController, responseStream?: ServerParamEncoder): Promise<any> {
|
|
320
|
+
const {swapContract} = this.getChain(chainIdentifier);
|
|
321
|
+
let signDataPrefetchPromise: Promise<any> = swapContract.preFetchBlockDataForSignatures!=null ? swapContract.preFetchBlockDataForSignatures().catch(e => {
|
|
322
|
+
this.logger.error("getSignDataPrefetch(): signDataPrefetch: ", e);
|
|
323
|
+
abortController.abort(e);
|
|
324
|
+
return null;
|
|
325
|
+
}) : null;
|
|
326
|
+
|
|
327
|
+
if(signDataPrefetchPromise!=null && responseStream!=null) {
|
|
328
|
+
signDataPrefetchPromise = signDataPrefetchPromise.then(val => val==null || abortController.signal.aborted ? null : responseStream.writeParams({
|
|
329
|
+
signDataPrefetch: val
|
|
330
|
+
}).then(() => val).catch(e => {
|
|
331
|
+
this.logger.error("getSignDataPrefetch(): signDataPreFetch: error when sending sign data to the client: ", e);
|
|
332
|
+
abortController.abort(e);
|
|
333
|
+
return null;
|
|
334
|
+
}));
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
return signDataPrefetchPromise;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
protected getIdentifierFromEvent(event: SwapEvent<SwapData>): string {
|
|
341
|
+
if(event.sequence.isZero()) return event.paymentHash;
|
|
342
|
+
return event.paymentHash+"_"+event.sequence.toString(16);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
protected getIdentifierFromSwapData(swapData: SwapData): string {
|
|
346
|
+
if(swapData.getSequence().isZero()) return swapData.getHash();
|
|
347
|
+
return swapData.getHash()+"_"+swapData.getSequence().toString(16);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
protected getIdentifier(swap: SwapHandlerSwap | SwapEvent<SwapData> | SwapData) {
|
|
351
|
+
if(swap instanceof SwapHandlerSwap) {
|
|
352
|
+
return swap.getIdentifier();
|
|
353
|
+
}
|
|
354
|
+
if(swap instanceof SwapEvent) {
|
|
355
|
+
return this.getIdentifierFromEvent(swap);
|
|
356
|
+
}
|
|
357
|
+
return this.getIdentifierFromSwapData(swap);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Checks if the sequence number is between 0-2^64
|
|
362
|
+
*
|
|
363
|
+
* @param sequence
|
|
364
|
+
* @throws {DefinedRuntimeError} will throw an error if sequence number is out of bounds
|
|
365
|
+
*/
|
|
366
|
+
protected checkSequence(sequence: BN) {
|
|
367
|
+
if(sequence.isNeg() || sequence.gte(new BN(2).pow(new BN(64)))) {
|
|
368
|
+
throw {
|
|
369
|
+
code: 20060,
|
|
370
|
+
msg: "Invalid sequence"
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Checks whether a given token is supported on a specified chain
|
|
377
|
+
*
|
|
378
|
+
* @param chainId
|
|
379
|
+
* @param token
|
|
380
|
+
* @protected
|
|
381
|
+
*/
|
|
382
|
+
protected isTokenSupported(chainId: string, token: string): boolean {
|
|
383
|
+
const chainTokens = this.allowedTokens[chainId];
|
|
384
|
+
if(chainTokens==null) return false;
|
|
385
|
+
return chainTokens.has(token);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
getInfo(): SwapHandlerInfoType {
|
|
389
|
+
const chainTokens: {[chainId: string]: string[]} = {};
|
|
390
|
+
for(let chainId in this.allowedTokens) {
|
|
391
|
+
chainTokens[chainId] = Array.from<string>(this.allowedTokens[chainId]);
|
|
392
|
+
}
|
|
393
|
+
return {
|
|
394
|
+
swapFeePPM: this.config.feePPM.toNumber(),
|
|
395
|
+
swapBaseFee: this.config.baseFee.toNumber(),
|
|
396
|
+
min: this.config.min.toNumber(),
|
|
397
|
+
max: this.config.max.toNumber(),
|
|
398
|
+
data: this.getInfoData(),
|
|
399
|
+
tokens: Array.from<string>(this.allowedTokens[this.chains.default]),
|
|
400
|
+
chainTokens
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import {Lockable, StorageObject, SwapData} from "@atomiqlabs/base";
|
|
2
|
+
import {SwapHandlerType} from "./SwapHandler";
|
|
3
|
+
import {PluginManager} from "../plugins/PluginManager";
|
|
4
|
+
import * as BN from "bn.js";
|
|
5
|
+
import {deserializeBN, serializeBN} from "../utils/Utils";
|
|
6
|
+
|
|
7
|
+
export abstract class SwapHandlerSwap<T extends SwapData = SwapData, S = any> extends Lockable implements StorageObject {
|
|
8
|
+
|
|
9
|
+
chainIdentifier: string;
|
|
10
|
+
state: S;
|
|
11
|
+
|
|
12
|
+
type: SwapHandlerType;
|
|
13
|
+
data: T;
|
|
14
|
+
metadata: {
|
|
15
|
+
request: any,
|
|
16
|
+
times: {[key: string]: number},
|
|
17
|
+
[key: string]: any
|
|
18
|
+
};
|
|
19
|
+
txIds: {
|
|
20
|
+
init?: string,
|
|
21
|
+
claim?: string,
|
|
22
|
+
refund?: string
|
|
23
|
+
} = {};
|
|
24
|
+
readonly swapFee: BN;
|
|
25
|
+
readonly swapFeeInToken: BN;
|
|
26
|
+
|
|
27
|
+
protected constructor(chainIdentifier: string, swapFee: BN, swapFeeInToken: BN);
|
|
28
|
+
protected constructor(obj: any);
|
|
29
|
+
|
|
30
|
+
protected constructor(obj?: any | string, swapFee?: BN, swapFeeInToken?: BN) {
|
|
31
|
+
super();
|
|
32
|
+
if(typeof(obj)==="string" && BN.isBN(swapFee) && BN.isBN(swapFeeInToken)) {
|
|
33
|
+
this.chainIdentifier = obj;
|
|
34
|
+
this.swapFee = swapFee;
|
|
35
|
+
this.swapFeeInToken = swapFeeInToken;
|
|
36
|
+
return;
|
|
37
|
+
} else {
|
|
38
|
+
this.data = obj.data==null ? null : SwapData.deserialize(obj.data);
|
|
39
|
+
this.metadata = obj.metadata;
|
|
40
|
+
this.chainIdentifier = obj.chainIdentifier;
|
|
41
|
+
this.txIds = obj.txIds || {};
|
|
42
|
+
this.state = obj.state;
|
|
43
|
+
this.swapFee = deserializeBN(obj.swapFee);
|
|
44
|
+
this.swapFeeInToken = deserializeBN(obj.swapFeeInToken);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
serialize(): any {
|
|
49
|
+
return {
|
|
50
|
+
state: this.state,
|
|
51
|
+
data: this.data==null ? null : this.data.serialize(),
|
|
52
|
+
chainIdentifier: this.chainIdentifier,
|
|
53
|
+
metadata: this.metadata,
|
|
54
|
+
txIds: this.txIds,
|
|
55
|
+
swapFee: serializeBN(this.swapFee),
|
|
56
|
+
swapFeeInToken: serializeBN(this.swapFeeInToken)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Sets the state of the swap and also calls swap change listener on plugins
|
|
62
|
+
*
|
|
63
|
+
* @param newState
|
|
64
|
+
*/
|
|
65
|
+
setState(newState: S): Promise<void> {
|
|
66
|
+
const oldState = this.state;
|
|
67
|
+
this.state = newState;
|
|
68
|
+
return PluginManager.swapStateChange(this, oldState);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
getHash(): string {
|
|
72
|
+
return this.data.getHash();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
getSequence(): BN {
|
|
76
|
+
return this.data.getSequence();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Returns unique identifier of the swap in the form <hash>_<sequence> or just <hash> if the swap type doesn't
|
|
81
|
+
* use sequence number
|
|
82
|
+
*/
|
|
83
|
+
getIdentifier(): string {
|
|
84
|
+
if(this.getSequence()!=null) {
|
|
85
|
+
return this.chainIdentifier+"_"+this.getHash()+"_"+this.getSequence().toString(16);
|
|
86
|
+
}
|
|
87
|
+
return this.getHash();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Checks whether the swap is finished, such that it is final and either successful or failed
|
|
92
|
+
*/
|
|
93
|
+
isFinished(): boolean {
|
|
94
|
+
return this.isSuccess() || this.isFailed();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Checks whether the swap was initiated by the user
|
|
99
|
+
*/
|
|
100
|
+
abstract isInitiated(): boolean;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Checks whether the swap was finished and was successful
|
|
104
|
+
*/
|
|
105
|
+
abstract isSuccess(): boolean;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Checks whether the swap was finished and was failed
|
|
109
|
+
*/
|
|
110
|
+
abstract isFailed(): boolean;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Returns the input amount paid by the user (excluding fees)
|
|
114
|
+
*/
|
|
115
|
+
abstract getInputAmount(): BN;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Returns the total input amount paid by the user (including all fees)
|
|
119
|
+
*/
|
|
120
|
+
abstract getTotalInputAmount(): BN;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Returns the actual output amount paid out to the user
|
|
124
|
+
*/
|
|
125
|
+
abstract getOutputAmount(): BN;
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Returns swap fee, denominated in input & output tokens (the fee is paid only once, it is just represented here in
|
|
129
|
+
* both denomination for ease of use)
|
|
130
|
+
*/
|
|
131
|
+
abstract getSwapFee(): {inInputToken: BN, inOutputToken: BN};
|
|
132
|
+
|
|
133
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import {SwapHandlerSwap} from "./SwapHandlerSwap";
|
|
2
|
+
import {SwapData} from "@atomiqlabs/base";
|
|
3
|
+
import * as BN from "bn.js";
|
|
4
|
+
import {deserializeBN, serializeBN} from "../utils/Utils";
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
export abstract class ToBtcBaseSwap<T extends SwapData = SwapData, S = any> extends SwapHandlerSwap<T, S> {
|
|
8
|
+
|
|
9
|
+
quotedNetworkFee: BN;
|
|
10
|
+
readonly quotedNetworkFeeInToken: BN;
|
|
11
|
+
realNetworkFee: BN;
|
|
12
|
+
realNetworkFeeInToken: BN;
|
|
13
|
+
|
|
14
|
+
protected constructor(chainIdentifier: string, swapFee: BN, swapFeeInToken: BN, quotedNetworkFee: BN, quotedNetworkFeeInToken: BN);
|
|
15
|
+
protected constructor(obj: any);
|
|
16
|
+
|
|
17
|
+
protected constructor(obj?: any | string, swapFee?: BN, swapFeeInToken?: BN, quotedNetworkFee?: BN, quotedNetworkFeeInToken?: BN) {
|
|
18
|
+
if(typeof(obj)==="string" && BN.isBN(swapFee) && BN.isBN(swapFeeInToken) && BN.isBN(quotedNetworkFee) && BN.isBN(quotedNetworkFeeInToken)) {
|
|
19
|
+
super(obj, swapFee, swapFeeInToken);
|
|
20
|
+
this.quotedNetworkFee = quotedNetworkFee;
|
|
21
|
+
this.quotedNetworkFeeInToken = quotedNetworkFeeInToken;
|
|
22
|
+
return;
|
|
23
|
+
} else {
|
|
24
|
+
super(obj);
|
|
25
|
+
this.quotedNetworkFee = deserializeBN(obj.quotedNetworkFee);
|
|
26
|
+
this.quotedNetworkFeeInToken = deserializeBN(obj.quotedNetworkFeeInToken);
|
|
27
|
+
this.realNetworkFee = deserializeBN(obj.realNetworkFee);
|
|
28
|
+
this.realNetworkFeeInToken = deserializeBN(obj.realNetworkFeeInToken);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
serialize(): any {
|
|
33
|
+
const obj = super.serialize();
|
|
34
|
+
obj.quotedNetworkFee = serializeBN(this.quotedNetworkFee);
|
|
35
|
+
obj.quotedNetworkFeeInToken = serializeBN(this.quotedNetworkFeeInToken);
|
|
36
|
+
obj.realNetworkFee = serializeBN(this.realNetworkFee);
|
|
37
|
+
obj.realNetworkFeeInToken = serializeBN(this.realNetworkFeeInToken);
|
|
38
|
+
return obj;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
setRealNetworkFee(networkFeeInBtc: BN) {
|
|
42
|
+
this.realNetworkFee = networkFeeInBtc;
|
|
43
|
+
if(this.quotedNetworkFee!=null && this.quotedNetworkFeeInToken!=null) {
|
|
44
|
+
this.realNetworkFeeInToken = this.realNetworkFee.mul(this.quotedNetworkFeeInToken).div(this.quotedNetworkFee);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
getInputAmount(): BN {
|
|
49
|
+
return this.data.getAmount().sub(this.getSwapFee().inInputToken).sub(this.getQuotedNetworkFee().inInputToken);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
getTotalInputAmount(): BN {
|
|
53
|
+
return this.data.getAmount();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
getSwapFee(): { inInputToken: BN; inOutputToken: BN } {
|
|
57
|
+
return {inInputToken: this.swapFeeInToken, inOutputToken: this.swapFee};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Returns quoted (expected) network fee, denominated in input & output tokens (the fee is paid only once, it is
|
|
62
|
+
* just represented here in both denomination for ease of use)
|
|
63
|
+
*/
|
|
64
|
+
getQuotedNetworkFee(): { inInputToken: BN; inOutputToken: BN } {
|
|
65
|
+
return {inInputToken: this.quotedNetworkFeeInToken, inOutputToken: this.quotedNetworkFee};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Returns real network fee paid for the swap, denominated in input & output tokens (the fee is paid only once, it is
|
|
70
|
+
* just represented here in both denomination for ease of use)
|
|
71
|
+
*/
|
|
72
|
+
getRealNetworkFee(): { inInputToken: BN; inOutputToken: BN } {
|
|
73
|
+
return {inInputToken: this.realNetworkFeeInToken, inOutputToken: this.realNetworkFee};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
}
|